it-swarm.com.de

Bereitstellung einer Bereitstellung ohne Ausfallzeiten

Ich versuche, Bereitstellungen ohne Ausfallzeiten zu erreichen, damit ich weniger außerhalb der Geschäftszeiten und mehr während "langsamerer" Stunden bereitstellen kann - oder theoretisch jederzeit.

Mein aktuelles Setup, etwas vereinfacht:

  • Webserver A (.NET App)
  • Webserver B (.NET App)
  • Datenbankserver (SQL Server)

Mein aktueller Bereitstellungsprozess:

  1. "Stoppen" Sie die Sites auf Webserver A und B.
  2. Aktualisieren Sie das Datenbankschema für die Version der App, die bereitgestellt wird
  3. Aktualisieren Sie den Webserver A.
  4. Aktualisieren Sie den Webserver B.
  5. Bringen Sie alles wieder online

Aktuelles Problem

Dies führt zu einer geringen Ausfallzeit pro Monat - etwa 30 Minuten. Ich mache das außerhalb der Geschäftszeiten, also ist es kein großes Problem - aber es ist etwas, von dem ich gerne wegkommen würde.

Auch - es gibt keine Möglichkeit, wirklich "zurück" zu gehen. Ich mache im Allgemeinen keine Rollback-DB-Skripte - nur Upgrade-Skripte.

Nutzung des Load Balancers

Ich würde gerne einen Webserver gleichzeitig aktualisieren können. Nehmen Sie Webserver A aus dem Load Balancer, aktualisieren Sie ihn, stellen Sie ihn wieder online und wiederholen Sie den Vorgang für Webserver B.

Das Problem ist die Datenbank. Jede Version meiner Software muss für eine andere Version der Datenbank ausgeführt werden - ich stecke also irgendwie fest.

Mögliche Lösung

Eine aktuelle Lösung, die ich in Betracht ziehe, ist die Annahme der folgenden Regeln:

  • Löschen Sie niemals eine Datenbanktabelle.
  • Löschen Sie niemals eine Datenbankspalte.
  • Benennen Sie niemals eine Datenbankspalte um.
  • Ordnen Sie niemals eine Spalte neu an.
  • Jede gespeicherte Prozedur muss versioniert werden.
    • Bedeutung - 'spFindAllThings' wird beim Bearbeiten zu 'spFindAllThings_2'.
    • Dann wird es bei erneuter Bearbeitung zu 'spFindAllThings_3'.
    • Gleiches gilt für Ansichten.

Dies scheint zwar etwas extrem zu sein - ich denke, es löst das Problem. Jede Version der Anwendung trifft die Datenbank auf nicht unterbrechende Weise. Der Code erwartet bestimmte Ergebnisse von den Ansichten/gespeicherten Prozeduren - und dies hält diesen 'Vertrag' gültig. Das Problem ist - es sickert nur schlampig. Ich weiß, dass ich alte gespeicherte Prozeduren bereinigen kann, nachdem die App für eine Weile bereitgestellt wurde, aber es fühlt sich einfach schmutzig an. Außerdem - es hängt von allen Entwicklern ab, die diese Regel befolgen, was meistens passieren wird, aber ich kann mir vorstellen, dass jemand einen Fehler machen wird.

Endlich - meine Frage

  • Ist das schlampig oder hacky?
  • Macht es sonst noch jemand so?
  • Wie lösen andere Leute dieses Problem?
40
MattW

Dies ist ein sehr pragmatischer Ansatz für datenbankgestützte Software-Upgrades. Es wurde beschrieben von Martin Fowler und Pramod Sadalage im Jahr 2003 und anschließend in Refactoring Databases: Evolutionary Database Design geschrieben.

Ich kann sehen, was Sie meinen, wenn Sie sagen, dass es schlampig erscheint, aber wenn es absichtlich und mit Bedacht getan wird und Sie sich die Zeit nehmen, nicht verwendete Strukturen aus der Codebasis und Datenbank umzugestalten, wenn sie nachweislich nicht mehr verwendet werden, ist es viel robuster als Einfachere Lösungen basierend auf Upgrade- und Rollback-Skripten.

14
Mike Partridge

"Keine Ausfallzeit" ist nur einer von vielen möglichen Gründen für diesen Ansatz. Wenn Sie ein Datenmodell auf diese Weise abwärtskompatibel halten, können Sie viele verschiedene Probleme lösen:

  • wenn viele Softwarepakete auf Ihre Datenbank zugreifen, müssen Sie nicht alle überprüfen, wenn sich eine Schemaänderung auf sie auswirkt (in größeren Organisationen mit mehreren Teams, die Programme schreiben, die alle auf dieselbe Datenbank zugreifen, können Schemaänderungen sehr schwierig werden).

  • wenn Sie müssen, können Sie eine ältere Version eines Ihrer Programme auschecken und es wird höchstwahrscheinlich gegen eine neuere Datenbank ausgeführt (solange Sie nicht erwarten, dass das alte Programm neuere Spalten korrekt verarbeitet).

  • der Import/Export archivierter Daten in die aktuelle Datenbankversion ist viel einfacher

Hier ist eine zusätzliche Regel für Ihre Liste

  • jede neue Spalte sollte entweder NULL-fähig sein oder einen aussagekräftigen Standardwert enthalten

(Dies stellt sicher, dass auch ältere Programme, die die neuen Spalten nicht kennen, beim Erstellen neuer Datensätze in Ihrer Datenbank nichts beschädigen.).

Natürlich hat dieser Ansatz einen echten Nachteil: Ihre Datenmodellqualität kann sich mit der Zeit verschlechtern. Wenn Sie die vollständige Kontrolle über alle Anwendungen haben, die auf Ihre Datenbank zugreifen, und Sie alle diese Anwendungen einfach umgestalten können, wenn Sie beispielsweise eine Spalte umbenennen, sollten Sie in Betracht ziehen, die Dinge sauberer umzugestalten.

5
Doc Brown

Es variiert von Bereitstellung zu Bereitstellung.

Sicher, Sie könnten niemals eine Tabelle oder eine Spalte löschen. Sie könnten niemals etwas ändern, das die Schnittstellenkompatibilität beeinträchtigt. Sie können jederzeit eine Abstraktionsebene hinzufügen. Aber dann müssen Sie diese Abstraktion und die Version die Versionierung versionieren.

Die Frage, die Sie sich stellen müssen, lautet: Ändert jede einzelne Version das Schema so, dass es nicht abwärtskompatibel ist?

Wenn nur sehr wenige Releases das Schema auf diese Weise ändern, ist das Datenbankproblem stummgeschaltet. Führen Sie einfach eine fortlaufende Bereitstellung der Anwendungsserver durch.

Die beiden Dinge, die mir bei der Bereitstellung mit minimalen Ausfallzeiten am meisten geholfen haben, sind:

  1. Streben Sie nach Abwärtskompatibilität - zumindest innerhalb einer einzelnen Version. Sie werden es nicht immer erreichen, aber ich kann wetten, dass Sie es bei 90% oder mehr Ihrer Veröffentlichungen erreichen können, insbesondere wenn jede Veröffentlichung klein ist.
  2. Haben Sie ein Datenbank-Skript vor und nach der Veröffentlichung. Auf diese Weise können Sie Umbenennungen oder Änderungen an der Benutzeroberfläche vornehmen, indem Sie Ihr neues Objekt erstellen, bevor Ihr App-Code bereitgestellt wird, und das alte Objekt löschen, nachdem der App-Code bereitgestellt wurde. Wenn Sie eine neue nicht nullbare Spalte hinzufügen, können Sie sie in Ihrem Pre-Release-Skript mit einem Trigger, der einen Standardwert ausfüllt, als nullwert hinzufügen. Dann können Sie in Ihrer Nachveröffentlichung den Auslöser fallen lassen.

Hoffentlich kann der Rest Ihrer Bereitstellungen für Wartungsfenster gespeichert werden.

Andere Ideen, die helfen können, mit den wenigen Bereitstellungen umzugehen, die Ausfallzeiten erfordern:

  • Können Sie Abwärtskompatibilität in Ihren Code einbauen? Gibt es beispielsweise eine Möglichkeit, wie Ihr Code mehrere Arten von Ergebnismengen unterstützen kann? Wenn Sie eine Spalte von einem int in ein double ändern müssen, kann Ihr App-Code sie als Zeichenfolge lesen und analysieren. Ein bisschen hackig, aber wenn es temporärer Code ist, um sich durch den Veröffentlichungsprozess zu bringen, ist es möglicherweise nicht das Ende der Welt.
  • Gespeicherte Prozeduren können dazu beitragen, Ihren App-Code vor Schemaänderungen zu schützen. Das kann nur so weit gehen, hilft aber ein bisschen.
4
Brandon

Sie könnten es möglicherweise für ein bisschen zusätzlichen Aufwand so machen.

  1. Sichern Sie die Datenbank durch einen Export
  2. Importieren Sie das Backup, benennen Sie es jedoch mit einer Release-Version um, z. myDb_2_1
  3. Führen Sie die Datenbankfreigabe auf myDB_2_1 aus
  4. Stoppen Sie den App-Pool auf Webserver A oder nehmen Sie ihn aus dem Load Balancer
  5. Aktualisieren Sie Webserver A, führen Sie nach der Implementierung Tests durch und führen Sie gegebenenfalls ein Rollback durch
  6. Die Sitzung blutet Webserver B aus und setzt Webserver A wieder in die Schleife
  7. Aktualisieren Sie Webserver B und setzen Sie ihn dann wieder in Load Balancer ein

Natürlich würden die Web-Updates neue Konfigurationseinträge benötigen, um auf das neue Datenbankschema zu verweisen. Wenn Sie einmal im Monat Releases durchführen und es sich um ein kleines Team handelt, wie viele DB-Änderungen nehmen Sie wirklich vor, die nicht abwärtskompatibel sind? Wenn Sie dies durch Testen kontrollieren können, können Sie eine automatisierte Bereitstellung ohne Ausfallzeit oder im schlimmsten Fall nur 5 Minuten Ausfallzeit durchführen.

2
LeoLambrettra