web-dev-qa-db-ja.com

MySQLのトランザクションDDLワークフロー

そのDDLステートメント(alter tablecreate index etc)MySQLで現在のトランザクションを暗黙的にコミットします。 MS SQL Serverから来て、トランザクションでデータベースの変更をローカルで行う(それはその後ロールバックされる)機能は、私のワークフローの重要な部分でした。継続的な統合では、何らかの理由で移行が中断した場合にロールバックが使用されたため、少なくともデータベースが半分移行された状態のままになることはありませんでした。

MySQLを移行と継続的インテグレーションで使用する場合、人々はこれら2つの問題をどのように解決しますか?

25
sennett

多くの人にとって、MySQLアキレス腱は暗黙のコミットです。

The Book の418ページ3項によると

MySQL 5.0 Certification Study Guide

次のコマンドは、トランザクションを中断できます。

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

提案

MySQLに関しては、構築するContinuousIntegration(CI)/ SelfServiceジョブは常にトランザクションジョブとDDLスクリプトを相互に排他的にする必要があります。

これはあなたにパラダイムを作成する機会を与えます

  • START TRANSACTION/COMMITブロックで適切に分離されたトランザクションをサポートする
  • dDLを自分でスクリプト化して、DDLをコンストラクタまたはデストラクタとして実行することによるDDLの制御
    • コンストラクタ:新しいデザインでテーブルを作成するDDL
    • デストラクタ:テーブルを以前のデザインに戻すDDL
  • これらの操作を1つのジョブの下で組み合わせないでください

警告:これにMyISAMを使用している場合は、トランザクションを中断させる可能性のあるもののリストにMyISAMを(無)親切に追加できます。暗黙のコミットに関しては、データの一貫性に関しては、ロールバックが必要になる場合があります。

なぜLVMではないのですか?

LVMスナップショットは優れており、大量のSQL処理を実行せずにデータベースのインスタンス全体を復元するのが理想的です。ただし、MySQLに関しては、InnoDBとMyISAMの2つのストレージエンジンを考慮する必要があります。

All-InnoDBデータベース

InnoDBのアーキテクチャを見てください(写真はPercona CTO Vadim Tkachenkoの厚意による)

InnoDB Plumbing

InnoDBには多くの可動部分があります

  • システムテーブルスペース
    • データ辞書
    • 二重書き込みバッファ(データの一貫性をサポート。クラッシュリカバリに使用)
    • バッファの挿入(セカンダリの一意でないインデックスへの変更のバッファ)
    • ロールバックセグメント
    • 元に戻すスペース(最も制御されていない成長が発生する可能性がある場所)
  • InnoDBバッファープール
    • ダーティデータページ
    • ダーティインデックスページ
    • 一意でないインデックスへの変更
  • その他の重要なメモリキャッシュ

コミットされていない変更がバッファープールとメモリキャッシュに浮かんでいるすべてのInnoDBデータベースのLVMスナップショットを取得すると、LUNが復元されてmysqldが起動すると、InnoDBクラッシュリカバリが必要なデータセットが生成されます。

ALL-InnoDBの提案

スナップショットを作成する前にMySQLをシャットダウンできる場合

    1. SET GLOBAL innodb_fast_shutdown = 0;を実行します
    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;を実行します
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';を実行します
    1. Innodb_buffer_pool_pages_dirty が0または0にできるだけ近くなるまで、ステップ3を繰り返します
    1. service mysql stop
    1. LVMスナップショットを撮る
    1. service mysql stop

シャットダウンできないがMySQL Liveでスナップショットを取得する場合

    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;を実行します
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';を実行します
    1. Innodb_buffer_pool_pages_dirty が0またはできるだけ0に近づくまで、手順2を繰り返します
    1. LVMスナップショットを撮る
    1. SET GLOBAL innodb_max_dirty_pages_pct = 75;を実行します

All-MyISAMデータベースまたはInnoDB/MyISAMミックス

MyISAMは、アクセスされると、それに対するオープンファイルハンドルの数を維持します。 MySQLがクラッシュした場合、開いているファイルハンドル数が0より大きいMyISAMテーブルは、クラッシュとマークされ、修復が必要です(データに何も問題がなくても)。

MyISAMテーブルが使用されているデータベースのLVMスナップショットを作成すると、スナップショットが復元されてmysqldが起動したときに、修復が必要な1つ以上のMyISAMテーブルが作成されます。

All-MyISAMまたはInnoDB/MyISAMミックスの提案

スナップショットを作成する前にMySQLをシャットダウンできる場合

    1. SET GLOBAL innodb_fast_shutdown = 0;を実行します
    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;を実行します
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';を実行します
    1. Innodb_buffer_pool_pages_dirty が0または0にできるだけ近くなるまで、ステップ3を繰り返します
    1. service mysql stop
    1. LVMスナップショットを撮る
    1. service mysql stop

シャットダウンできないがMySQL Liveでスナップショットを取得する場合

特定のInnoDBテーブルのフラッシュを強制できます

    1. SET GLOBAL innodb_max_dirty_pages_pct = 0;を実行します
    1. SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';を実行します
    1. Innodb_buffer_pool_pages_dirty が0またはできるだけ0に近づくまで、手順2を繰り返します
    1. 重要なInnoDBテーブルでFLUSH TABLES innodb_tbl1,... FOR EXPORT;を実行します
    1. FLUSH TABLES WITH READ LOCK;を実行します
    1. LVMスナップショットを撮る
    1. UNLOCK TABLES;を実行します
    1. SET GLOBAL innodb_max_dirty_pages_pct = 75;を実行します

MySQLレプリケーションは役に立ちますか?

1つのLVMスナップショットを2つのサーバーに復元し、MySQLマスター/スレーブレプリケーションをセットアップすることもできますが、スナップショットを復元するときに、ハウスクリーニングの追加のソースになります。

マスターでCIジョブを実行し、それらのジョブが小さい場合、特定の状況下でレプリケーションが時間の節約になる可能性があります。スレーブでSTOP SLAVE;を実行し、マスターでCIジョブを開始し、マスターのデータが認証されたらスレーブでSTART SLAVE;を実行するだけです。

CIジョブが警告するデータが多すぎる場合は、LVMスナップショットを復元し、レプリケーションを最初からセットアップできます。これを頻繁に実行している場合は、MySQLレプリケーションの設定でおそらく実行できます。

最終的な考え

  • 復元と回帰テストを実行するには、複数のDBサーバー(3つ以上)を使用するのが最適です。
  • 残りのMyISAMテーブルをMyISAMのままにする必要がない場合は、それらをInnoDBに変換します。
  • データコンテンツが機密情報である場合は、CIジョブを実行して、スナップショットを復元した後、テストを開始する前にデータをスクラブする必要があります。別の方法として、すでにスクラブされたデータを使用してMySQLのスナップショットを作成することもできます。
11
RolandoMySQLDBA

継続的インテグレーションといえば、開発環境だと思います。その場合、構造的な変更を行う人は、他の人が物事を壊さないことを確認するために、それらをテストする必要があると言います。誰かが共通ライブラリを更新するのと同じように、そのような変更をコミットする前に独自のサンドボックスでテストします。

運用展開プロセスでは、通常、コードの変更と同じように、開発環境、QA環境、または運用前環境で変更をテストします。

これはMySQL固有ではないことに注意してください。Oracleデータベースは、「alter table」などを発行するときに暗黙的にCOMMITを実行します。

自分を保護したい場合は、もちろん事前にバックアップを行ってください。または、システムで可能であればLVMまたはファイルシステムのスナップショットを作成してください。機密性の高い操作の前にセキュリティとして遅延/停止できるスレーブがある場合もあります。

4
phil_w