Transaktionaler DDL-Workflow für MySQL

25

Ich war ein wenig zu entdecken überrascht , dass DDL - Anweisungen ( alter table, create indexusw.) implizit die aktuelle Transaktion in MySQL begehen. Ausgehend von MS SQL Server war die Möglichkeit, Datenbankänderungen in einer Transaktion lokal vorzunehmen (die dann zurückgesetzt wurde), ein wichtiger Teil meines Workflows. Für die kontinuierliche Integration wurde das Rollback verwendet, wenn die Migration aus irgendeinem Grund fehlschlug, sodass die Datenbank zumindest nicht in einem halb migrierten Zustand belassen wurde.

Wie lösen die Leute diese beiden Probleme, wenn sie MySQL mit Migrationen und kontinuierlicher Integration verwenden?

Sennett
quelle
Cross gebucht von SO. stackoverflow.com/q/28197013/614523 Habe dort nicht viel Liebe bekommen.
Sennett
1
Betrachten Sie für die kontinuierliche Integration LVM-Snapshots als eine Möglichkeit, sehr schnell eine gesamte Umgebung zu erstellen, die sich in einem bekannten Zustand befindet.
Rick James
5
Sie können jederzeit auf Postgres upgraden - es unterstützt Transaktions-DDL (SCNR).
a_horse_with_no_name
3
Ich stimme mit @a_horse_with_no_name überein. Wenn dies Ihr Workflow ist, sollten Sie ernsthaft die Verwendung von PosgreSQL in Betracht ziehen, das Transaktions-DDL zusammen mit vielen anderen netten Funktionen enthält.
Renzo

Antworten:

9

Für viele Menschen ist die MySQL-Achillesferse ein implizites Commit.

Gemäß Absatz 3 des Buches

Studienhandbuch zur MySQL 5.0-Zertifizierung

Die folgenden Befehle können und werden eine Transaktion abbrechen

  • ALTER TABLE
  • BEGIN
  • CREATE INDEX
  • DROP DATABASE
  • DROP INDEX
  • DROP TABLE
  • RENAME TABLE
  • TRUNCATE TABLE
  • LOCK TABLES
  • UNLOCK TABLES
  • SET AUTOCOMMIT = 1
  • START TRANSACTION

VORSCHLAG

Wenn Sie in MySQL ContinuousIntegration (CI) / SelfService-Jobs erstellen, sollten sich Transaktionsjobs und DDL-Skripten immer gegenseitig ausschließen.

Dies gibt Ihnen die Möglichkeit, Paradigmen zu schaffen, die dies tun würden

  • unterstützen Transaktionen, die ordnungsgemäß mit START TRANSACTION/COMMITBlöcken isoliert sind
  • Steuerung der DDL durch Erstellen eines Skripts für die DDL selbst, wobei die DDL entweder als Konstruktor oder als Destruktor ausgeführt wird
    • Konstruktor: DDL zum Erstellen von Tabellen mit einem neuen Design
    • Destruktor: DDL, um Tabellen auf den vorherigen Entwurf zurückzusetzen
  • Kombinieren Sie diese Vorgänge niemals unter einem Job

WARNUNG: Wenn Sie hierfür MyISAM verwenden, können Sie MyISAM (un) freundlich zu der Liste der Dinge hinzufügen, die eine Transaktion unterbrechen können, möglicherweise nicht in Bezug auf das implizite Festschreiben, aber definitiv in Bezug auf die Datenkonsistenz, falls es jemals zu einem Rollback kommen sollte erforderlich.

WARUM NICHT LVM?

LVM-Snapshots eignen sich hervorragend, und die Wiederherstellung ganzer Instanzen von Datenbanken ohne umfangreiche SQL-Verarbeitung ist ideal. Bei MySQL müssen Sie jedoch zwei Speicher-Engines berücksichtigen: InnoDB und MyISAM.

All-InnoDB-Datenbank

Schauen Sie sich die Architektur von InnoDB an (Foto mit freundlicher Genehmigung von Percona CTO Vadim Tkachenko)

InnoDB Sanitär

InnoDB hat viele bewegliche Teile

  • System Tablespace
    • Datenwörterbuch
    • Double Write Buffer (unterstützt Datenkonsistenz; wird für Crash Recovery verwendet)
    • Puffer einfügen (Pufferänderungen an sekundären nicht eindeutigen Indizes)
    • Rollback-Segmente
    • Undo Space (wo das unkontrollierteste Wachstum passieren kann)
  • InnoDB-Pufferpool
    • Schmutzige Datenseiten
    • Verschmutzte Indexseiten
    • Änderungen an nicht eindeutigen Indizes
  • Andere wichtige Speicher-Caches

Das Erstellen eines LVM-Snapshots einer InnoDB-Datenbank mit nicht festgeschriebenen Änderungen im Pufferpool und im Speichercache würde zu einem Dataset führen, das eine Wiederherstellung nach dem Absturz von InnoDB erfordert, sobald die LUN wiederhergestellt und mysqld gestartet wurde.

VORSCHLAG FÜR ALL-InnoDB

Wenn Sie MySQL herunterfahren können, bevor Sie einen Schnappschuss machen

    1. Lauf SET GLOBAL innodb_fast_shutdown = 0;
    1. Lauf SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Lauf SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Wiederholen Sie Schritt 3, bis Innodb_buffer_pool_pages_dirty 0 oder so nahe wie möglich bei 0 liegt
    1. service mysql stop
    1. Machen Sie einen LVM-Schnappschuss
    1. service mysql stop

Wenn Sie nicht herunterfahren können, sondern einen Schnappschuss mit MySQL Live machen

    1. Lauf SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Lauf SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Wiederholen Sie Schritt 2, bis Innodb_buffer_pool_pages_dirty 0 oder so nahe wie möglich bei 0 liegt
    1. Machen Sie einen LVM-Schnappschuss
    1. Lauf SET GLOBAL innodb_max_dirty_pages_pct = 75;

All-MyISAM-Datenbank oder InnoDB / MyISAM-Mix

Wenn auf MyISAM zugegriffen wird, werden die Anzahl der geöffneten Dateizugriffsnummern beibehalten. Wenn MySQL abstürzt, wird jede MyISAM-Tabelle mit einer Anzahl offener Datei-Handles> 0 als Absturz markiert und muss repariert werden (auch wenn mit den Daten nichts falsch ist).

Wenn Sie einen LVM-Snapshot einer Datenbank erstellen, in der MyISAM-Tabellen verwendet werden, müssen eine oder mehrere MyISAM-Tabellen repariert werden, wenn der Snapshot wiederhergestellt und mysqld gestartet wird.

EMPFEHLUNG FÜR All-MyISAM oder InnoDB / MyISAM Mix

Wenn Sie MySQL herunterfahren können, bevor Sie einen Schnappschuss machen

    1. Lauf SET GLOBAL innodb_fast_shutdown = 0;
    1. Lauf SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Lauf SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Wiederholen Sie Schritt 3, bis Innodb_buffer_pool_pages_dirty 0 oder so nahe wie möglich bei 0 liegt
    1. service mysql stop
    1. Machen Sie einen LVM-Schnappschuss
    1. service mysql stop

Wenn Sie nicht herunterfahren können, sondern einen Schnappschuss mit MySQL Live machen

Sie können ein Leeren bestimmter InnoDB-Tabellen erzwingen

    1. Lauf SET GLOBAL innodb_max_dirty_pages_pct = 0;
    1. Lauf SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
    1. Wiederholen Sie Schritt 2, bis Innodb_buffer_pool_pages_dirty 0 oder so nahe wie möglich bei 0 liegt
    1. Führen Sie FLUSH TABLES innodb_tbl1,... FOR EXPORT;auf kritische InnoDB - Tabellen
    1. Lauf FLUSH TABLES WITH READ LOCK;
    1. Machen Sie einen LVM-Schnappschuss
    1. Lauf UNLOCK TABLES;
    1. Lauf SET GLOBAL innodb_max_dirty_pages_pct = 75;

Könnte MySQL Replication helfen?

Sie können zwar einen LVM-Snapshot auf zwei Servern wiederherstellen und MySQL Master / Slave Replication einrichten, dies wird jedoch zu einer zusätzlichen Quelle für die Hausreinigung beim Wiederherstellen von Snapshots.

Wenn Sie CI-Jobs auf einem Master ausführen und diese Jobs klein sind, kann die Replikation unter bestimmten Umständen zu einer Zeitersparnis führen. Sie könnten einfach STOP SLAVE;auf dem Slave laufen , die CI-Jobs auf dem Master starten und START SLAVE;auf dem Slave laufen, wenn die Daten des Masters zertifiziert sind.

Wenn die CI-Jobs zu viele Daten melden, können Sie den LVM-Snapshot wiederherstellen und die Replikation von Grund auf einrichten. Wenn Sie dies häufig tun, können Sie möglicherweise MySQL Replication einrichten.

ABSCHLIESSENDE GEDANKEN

  • Verwenden Sie am besten mehrere DB-Server (3 oder mehr), um Wiederherstellungen und Regressionstests durchzuführen.
  • Konvertieren Sie verbleibende MyISAM-Tabellen in InnoDB, wenn diese Tabellen nicht MyISAM bleiben müssen.
  • Wenn Ihr Dateninhalt vertraulich ist, sollten Sie nach dem Wiederherstellen eines Snapshots einen CI-Job ausführen, um die Daten zu bereinigen, bevor Sie Tests starten. Alternativ können Sie Snapshots von MySQL mit den bereits bereinigten Daten erstellen.
RolandoMySQLDBA
quelle
4

Wenn Sie von kontinuierlicher Integration sprechen, gehe ich davon aus, dass es sich um eine Entwicklungsumgebung handelt. In diesem Fall würde ich sagen, dass die Person, die strukturelle Änderungen vornimmt, diese testen muss, um sicherzustellen, dass die Dinge nicht für andere zerstört werden, ähnlich wie jemand, der eine gemeinsame Bibliothek aktualisiert: Testen Sie in Ihrer eigenen Sandbox, bevor Sie solche Änderungen vornehmen.

In einem Produktionsbereitstellungsprozess durchlaufen Sie normalerweise Entwicklungs-, Qualitätssicherungs- oder sogar Vorproduktionsumgebungen, um Ihre Änderungen zu testen, genau wie bei Codeänderungen.

Beachten Sie, dass dies nicht MySQL-spezifisch ist: Oracle-Datenbanken würden auch implizit COMMIT ausführen, wenn 'alter table' usw. ausgegeben wird.

Wenn Sie sich jetzt schützen möchten, können Sie natürlich vorher ein Backup oder einen LVM- oder Dateisystem-Snapshot erstellen, falls Ihr System dies kann. Möglicherweise haben Sie auch einen Slave, den Sie als Sicherheit vor vertraulichen Vorgängen verzögern / stoppen können.

phil_w
quelle