Bereitstellung ohne Ausfallzeiten - Übergangs-DB-Schema

14

Das Erreichen einer Bereitstellung ohne Ausfallzeiten hat das gleiche Problem angesprochen, aber ich benötige einige Ratschläge zu einer Strategie, die ich in Betracht ziehe.

Kontext

Eine webbasierte Anwendung mit Apache / PHP für die serverseitige Verarbeitung und MySQL DB / Dateisystem für die Persistenz.

Wir bauen derzeit die Infrastruktur. Die gesamte Netzwerkhardware ist redundant, und alle Hauptnetzwerkkabel werden aus Gründen der Fehlertoleranz paarweise miteinander verbunden. Server werden als Hochverfügbarkeitspaare konfiguriert, um Hardwarefehlertoleranz zu gewährleisten. Sie werden sowohl hinsichtlich der Fehlertoleranz der virtuellen Maschine als auch hinsichtlich der allgemeinen Leistung im Lastenausgleich ausgeführt.

Es ist meine Absicht, dass wir Updates ohne Ausfallzeit auf die Anwendung anwenden können. Ich habe große Anstrengungen unternommen, um die Infrastruktur so zu gestalten, dass eine 100% ige Verfügbarkeit gewährleistet ist. Es wäre äußerst enttäuschend, wenn jedes Mal, wenn ein Update angewendet wird, eine Ausfallzeit von 10 bis 15 Minuten auftreten würde. Dies ist besonders wichtig, da ein sehr schneller Release-Zyklus angestrebt wird (manchmal können eine oder mehrere Releases pro Tag erreicht werden).

Netzwerktopologie

Dies ist eine Zusammenfassung des Netzwerks:

                      Load Balancer
             |----------------------------|
              /       /         \       \  
             /       /           \       \ 
 | Web Server |  DB Server | Web Server |  DB Server |
 |-------------------------|-------------------------|
 |   Host-1   |   Host-2   |   Host-1   |   Host-2   |
 |-------------------------|-------------------------|
            Node A        \ /        Node B
              |            /            |
              |           / \           |
   |---------------------|   |---------------------|
           Switch 1                  Switch 2

   And onward to VRRP enabled routers and the internet

Anmerkung: DB-Server verwenden die Master-Master-Replikation

Vorgeschlagene Strategie

Um dies zu erreichen, denke ich derzeit daran, die DB-Schema-Upgrade-Skripte in zwei Teile zu unterteilen. Das Upgrade würde folgendermaßen aussehen:

  1. Der Webserver auf Knoten A wird offline geschaltet. Der Datenverkehr wird weiterhin vom Webserver auf Knoten B verarbeitet.
  2. Übergangsschemaänderungen werden auf DB-Server angewendet
  3. Webserver Eine Codebasis wird aktualisiert, die Caches werden gelöscht und alle anderen Upgrade-Aktionen werden ausgeführt.
  4. Webserver A wird online geschaltet und Webserver B wird offline geschaltet.
  5. Die Codebasis von Webserver B wird aktualisiert, die Caches werden gelöscht und alle anderen Aktualisierungsaktionen werden ausgeführt.
  6. Webserver B wird online geschaltet.
  7. Die endgültigen Schemaänderungen werden auf die Datenbank angewendet

"Übergangsschema" soll eine versionsübergreifende kompatible Datenbank erstellen. Dies würde hauptsächlich Tabellenansichten verwenden, die das alte Versionsschema simulieren, während die Tabelle selbst in das neue Schema geändert würde. Dadurch kann die alte Version wie gewohnt mit der Datenbank interagieren. Die Tabellennamen würden Schemaversionsnummern enthalten, um sicherzustellen, dass keine Unklarheiten darüber bestehen, in welche Tabelle geschrieben werden soll.

'Letztes Schema' würde die Abwärtskompatibilität aufheben und das Schema aufräumen.

Frage

Kurz gesagt, wird das funktionieren?

genauer:

  1. Wird es Probleme geben, da möglicherweise gleichzeitig Schreibvorgänge zum bestimmten Zeitpunkt der Änderung des Übergangsschemas ausgeführt werden? Gibt es eine Möglichkeit, sicherzustellen, dass die Gruppe von Abfragen, die die Tabelle ändern und die abwärtskompatible Ansicht erstellen, nacheinander ausgeführt wird? Das heißt, alle anderen Abfragen werden im Puffer gehalten, bis die Schemaänderungen abgeschlossen sind. Dies dauert in der Regel nur Millisekunden.

  2. Gibt es einfachere Methoden, die diesen Grad an Stabilität bieten und gleichzeitig Updates ohne Ausfallzeiten ermöglichen? Es ist auch vorzuziehen, die "evolutionäre" Schemastrategie zu vermeiden, da ich nicht an die Abwärtsschemakompatibilität gebunden sein möchte.

Marvin
quelle

Antworten:

4

Es hört sich so an, als ob das, wonach Sie wirklich suchen, nicht so sehr Hochverfügbarkeit ist, als dass Sie kontinuierliche Verfügbarkeit benötigen würden .

Im Wesentlichen wird Ihr Plan funktionieren, aber Sie scheinen bemerkt zu haben, dass der Hauptfehler in Ihrem Setup darin besteht, dass Änderungen des Datenbankschemas in einer Version entweder zu Ausfallzeiten oder zum Ausfall des noch verfügbaren Knotens führen können. Der Continuous Availability-Ansatz löst dieses Problem, indem im Wesentlichen mehrere Produktionsumgebungen erstellt werden.

Produktion Eins

Diese Umgebung ist Ihre aktuelle Live-Version der Software, die von Benutzern verwendet wird. Es verfügt über eigene Webserver, Anwendungsserver sowie Datenbankserver und Tablespace. Es arbeitet unabhängig von jeder anderen Umgebung. Der Load Balancer, dem der Endpunkt für die Domänenauflösung für diese Dienste gehört, verweist derzeit auf diese Webserver.

Produktion zwei

Dies ist im Grunde eine Release-Staging-Umgebung, die mit Production One identisch ist. Sie können Ihre Release-Upgrades hier durchführen und Ihre Hygienetests durchführen, bevor Sie live gehen. Auf diese Weise können Sie auch Ihre Datenbankänderungen in dieser Umgebung sicher durchführen. Der Load Balancer verweist derzeit nicht auf diese Umgebung.

Produktion DR

Dies ist ein weiteres Duplikat in einem separaten Rechenzentrum, das sich in einer anderen Region der Welt befindet. Auf diese Weise können Sie im Katastrophenfall ein Failover durchführen, indem Sie einen DNS-Switch am Load Balancer ausführen.

Geh Leben

Bei diesem Ereignis wird im Wesentlichen der DNS-Eintrag aktualisiert, um von Produktion 1 zu Produktion 2 oder umgekehrt zu wechseln. Die Verbreitung auf den DNS-Servern der Welt dauert eine Weile, sodass beide Umgebungen eine Weile ausgeführt werden. Einige Benutzer arbeiten möglicherweise in vorhandenen Sitzungen an der alten Version Ihrer Software. Die meisten Benutzer richten neue Sitzungen für die aktualisierte Version Ihrer Software ein.

Datenmigration

Der einzige Nachteil hierbei ist, dass zu diesem Zeitpunkt nicht alle Daten in diesem Fenster allen Benutzern zur Verfügung stehen. Es gibt eindeutig wichtige Benutzerdaten in der Datenbank der Vorgängerversion, die jetzt sicher in das neue Datenbankschema migriert werden müssen. Dies kann mit einem gut getesteten Datenexport- und -migrationsskript oder einem Stapeljob oder einem ähnlichen ETL-Prozess erreicht werden.

Fazit

Sobald Sie Ihr Release-Ereignis vollständig abgeschlossen haben, ist Production Two nun Ihr primäres und Sie beginnen mit der Installation des nächsten Release für Production One für den nächsten Bereitstellungszyklus.

Nachteile

Dies ist eine komplexe Umgebungseinrichtung und erfordert eine große Menge an Systemressourcen, häufig das Zwei- bis Dreifache der Systemressourcen, um erfolgreich zu sein. Der Betrieb auf diese Weise kann teuer sein, insbesondere wenn Sie über sehr große Systeme mit hoher Auslastung verfügen.

maple_shaft
quelle
Wenn ich das richtig verstanden habe, schlagen Sie vor, dass Db-A mit dem alten Schema online bleibt, während Db-B auf das neue Schema aktualisiert wird, anstatt eine 'Übergangs'-Änderung des DB-Schemas vorzunehmen, während die Datenbank noch verwendet wird Schema. Wenn das Update zur Veröffentlichung bereit ist, werden die Webserver umgestellt und die Daten, die während der Vorbereitung des Updates auf Db A geschrieben wurden, werden auf Db B migriert (vermutlich, indem alle Änderungen nach einem bestimmten Zeitstempel angewendet werden).
Marvin
@PeterScott Du hast es verstanden. Denken Sie jedoch daran, dass Sie das Skript erst ausführen möchten, wenn Sie sicher sind, dass alle aktiven Sitzungen im alten System beendet sind und alle DNS-Caches auf den neuen CNAME oder die neue IP-Adresse aktualisiert wurden.
maple_shaft
1
In beiden Punkten sollte ich in Ordnung sein. Die Sitzungen werden in der Datenbank und nicht im Serverspeicher beibehalten, um zu vermeiden, dass Sitzungen an bestimmte virtuelle Maschinen gebunden sind, und ich beabsichtige derzeit, einen nicht auf DNS basierenden Lastenausgleich zu verwenden. Ich habe keine Redundanz auf Rechenzentrumsebene, aber das kann nach dem Start der Anwendung ein Jahr oder so warten.
Marvin
2

Ihre Strategie ist solide. Ich würde nur anbieten, das "Übergangsschema" zu einem vollständigen Satz von "Transaktionstabellen" zu erweitern.

Bei Transaktionstabellen werden SELECTs (Abfragen) für die normalisierten Tabellen ausgeführt, um die Richtigkeit sicherzustellen. Alle Datenbank-INSERTs, -UPDATES und -DELETEs werden jedoch immer in die denormalisierten Transaktionstabellen geschrieben.

Anschließend wendet ein separater, gleichzeitiger Prozess diese Änderungen (möglicherweise mithilfe gespeicherter Prozeduren) auf die normalisierten Tabellen gemäß den festgelegten Geschäftsregeln und Schemaanforderungen an.

Meistens war dies praktisch augenblicklich. Durch die Trennung der Aktionen kann das System jedoch übermäßige Aktivitäts- und Schemaaktualisierungsverzögerungen berücksichtigen.

Während Schemaänderungen in Datenbank (B) werden Datenaktualisierungen in der aktiven Datenbank (A) in ihre Transaktionstabellen aufgenommen und sofort auf ihre normalisierten Tabellen angewendet.

Beim Wiederherstellen der Datenbank (B) würden die Transaktionen von (A) darauf angewendet, indem sie in die Transaktionstabellen von (B) geschrieben würden. Sobald dieser Teil erledigt ist, kann (A) heruntergefahren und die Schemaänderungen dort angewendet werden. (B) würde das Anwenden der Transaktionen von (A) beenden und gleichzeitig seine Live-Transaktionen bearbeiten, die genau wie (A) in der Warteschlange stehen, und die "Live-Transaktionen" würden auf die gleiche Weise angewendet, wenn (A) erneut aufgerufen wird.

Eine Transaktionstabellenzeile könnte ungefähr so ​​aussehen ...

| ROWID | TRANSNR | DB | TABLE | SQL STATEMENT
    0        0       A    Name   INSERT INTO Name ...
    1        0       A    Addr   INSERT INTO Addr ...
    2        0       A    Phone  INSERT INTO Phone ...
    3        1       A    Stats   UPDATE Stats SET NrOfUsers=...

Die Transaktions- "Tabellen" können tatsächlich Zeilen in einer separaten NoSQL-Datenbank oder sogar sequentielle Dateien sein, abhängig von den Leistungsanforderungen. Ein Bonus ist, dass die Codierung der Anwendung (in diesem Fall der Website) etwas einfacher wird, da nur in die Transaktionstabellen geschrieben wird.

Die Idee folgt denselben Grundsätzen wie die doppelte Buchführung und dies aus ähnlichen Gründen.

Transaktionstabellen sind analog zu einem Buchhaltungsjournal. Die vollständig normalisierten Tabellen sind analog zu einem Buchhaltungs-"Hauptbuch", wobei jede Tabelle einem Buchhaltungs-"Konto" ähnelt.

In der Buchhaltung erhält jede Transaktion zwei Einträge im Journal. Eine für das "belastete" Sachkonto und die andere für das "gutgeschriebene" Konto.

In einem RDBMS erhält ein "Journal" (Transaktionstabelle) einen Eintrag für jede normalisierte Tabelle, die von dieser Transaktion geändert werden soll.

Die DB-Spalte in der obigen Tabelle gibt an, aus welcher Datenbank die Transaktion stammt. Auf diese Weise können die in der Warteschlange befindlichen Zeilen aus der anderen Datenbank herausgefiltert und nicht erneut angewendet werden, wenn die zweite Datenbank wiederhergestellt wird.

DocSalvager
quelle
1
Ich mag den Vergleich zur Buchhaltung. Wenn ich das verstanden habe, kann ich mit den Transaktionstabellen das Schreiben von Daten in eine bestimmte normalisierte Tabelle mit einer sehr geringen Verzögerung durchführen, damit ich alle Schemaänderungen ohne das Risiko einer Unterbrechung in der Mitte der Änderungen anwenden kann. Wenn das Schema der Tabelle aktuell ist, kann ich den Prozess fortsetzen, mit dem die denormalisierten Transaktionen auf die normalisierten Tabellen angewendet werden (kann dieser Prozess die alten Schemadatenabfragen dem neuen Schema zuordnen)?
Marvin
1
Ja. Sie würden die gespeicherten Mapping-Prozeduren (oder was auch immer) ändern, um sowohl alte als auch neue Daten aufzunehmen. Neue NOT-NULL-Spalten werden möglicherweise aus alten Daten mit einem Code gefüllt, der bedeutet, dass Sie bei der Benutzeraktualisierung dazu aufgefordert werden. Spalten, die aufgeteilt werden sollen (dh FULLNAME in FIRST und LAST), benötigen einen Algorithmus. Ich empfehle, eine oder mehrere "kommentarähnliche" Spalten zu Tabellen hinzuzufügen, um neuen Geschäftsanforderungen gerecht zu werden. Wenn Sie dies nicht tun, kann ich garantieren, dass die Benutzer andere Spalten für diesen Zweck verwenden. In diesem Fall ist eine Korrektur der Daten fast unmöglich.
DocSalvager
Wie würden Sie verhindern, dass SELECT-Abfragen, die für das alte Schema strukturiert sind, auf das neue Schema angewendet werden? Ich könnte eine Tabellenansicht erstellen und die Schematabelle umbenennen (mit einer Schemaversionsnummer), aber dies wäre immer noch problematisch, während die Schemaänderungen angewendet werden, da sie direkt auf die normalisierte Tabelle angewendet werden.
Marvin
1
Wenn Sie einer RDBMS-Datenbank eine Tabelle, eine Spalte oder etwas anderes hinzufügen, fügen Sie tatsächlich nur Zeilen zu einer Gruppe interner Tabellen hinzu, in die nur die RDBMS-Steuerkomponente schreiben kann. Die Datenbankadministratoren verwalten die Datenbank, indem sie sie über VIEWs abfragen. Da Oracle, IBM, MS usw. die Experten sind und sagen, dass dies der beste Weg ist, sollten wir anscheinend ihrem Beispiel folgen. Erstellen Sie eine Reihe von Ansichten für jede Version der Anwendung. Sie können sie nach den (normalerweise ziemlich denormalisierten) Tabellen modellieren, die die Entwickler erstellen möchten, damit Sie sie ordnungsgemäß normalisieren können, um beschädigte Daten zu vermeiden.
DocSalvager
Vielen Dank. Ich muss darüber nachdenken. Ich baue eine ORM-Schicht in der Anwendung, die alle Zustands-Persistenz-Logik aus der Hauptdomäne vollständig entfernt; Da ich eher auf der serverseitigen Programmierung basiert bin, neige ich dazu, Probleme eher von dieser Seite aus zu lösen als von der Seite der DB-Administration. Unter Verwendung meiner aktuellen Strategie würde die Datenbank mit dem ORM, der die rohen Tabellen aktiv verwaltet, ziemlich flach liegen. Das Hinzufügen von Tabellenansichten und möglicherweise eines Transaktionsprotokolls erhöht die Komplexität des ORM, bietet jedoch auch die Möglichkeit, mehrere Schemaversionen zu unterstützen, ohne dass Daten splittern.
Marvin