何年もの間、MySQLレプリケーションはバイナリログイベントに基づいていました。スレーブが知っていたのは、マスターから読み取った正確なイベントと正確な位置だけでした。マスターからの単一のトランザクションは、異なるバイナリログで終了し、これらのログの異なる位置で終了した可能性があります。これは制限のある単純なソリューションでした。より複雑なトポロジの変更では、管理者が関係するホストでレプリケーションを停止する必要がある場合があります。または、これらの変更により、他の問題が発生する可能性があります。たとえば、時間のかかる再構築プロセスなしでスレーブをレプリケーションチェーンの下位に移動できませんでした(レプリケーションをA->B->CからA->C-に簡単に変更できませんでした。> BとCの両方でレプリケーションを停止せずにB)。グローバルトランザクション識別子を夢見ながら、これらの制限を回避する必要がありました。
GTIDはMySQL5.6とともに導入され、MySQLの動作方法にいくつかの大きな変更をもたらしました。まず、すべてのトランザクションには、すべてのサーバーで同じ方法でトランザクションを識別する一意の識別子があります。トランザクションが記録されたバイナリログの位置はもう重要ではありません。知っておく必要があるのは、GTID「966073f3-b6a4-11e4-af2c-080027880ca6:4」だけです。 GTIDは、トランザクションが最初に実行されたサーバーの一意の識別子とシーケンス番号の2つの部分で構成されています。上記の例では、トランザクションが「966073f3-b6a4-11e4-af2c-080027880ca6」のserver_uuidを持つサーバーによって実行され、そこで4番目のトランザクションが実行されたことがわかります。この情報は、複雑なトポロジ変更を実行するのに十分です。MySQLは、実行されたトランザクションを認識しているため、次に実行する必要のあるトランザクションを認識しています。バイナリログは忘れてください。すべてGTIDにあります。
では、GTIDはどこにありますか?それらは2か所にあります。スレーブの「showslavestatus;」には、Retrieved_Gtid_SetとExecuted_Gtid_Setの2つの列があります。 1つ目はレプリケーションを介してマスターから取得されたGTIDをカバーし、2つ目はレプリケーションを介してまたはローカルで実行された特定のホストで実行されたすべてのトランザクションについて通知します。
簡単な方法でレプリケーションクラスターを設定する
ClusterControlでは、MySQLレプリケーションクラスターの展開は非常に簡単です(無料で試すことができます)。唯一の前提条件は、MySQLノードのデプロイに使用するすべてのホストが、パスワードなしのSSH接続を使用してClusterControlインスタンスからアクセスできることです。
接続が確立されたら、「デプロイ」オプションを使用してクラスターをデプロイできます。ウィザードウィンドウが開いたら、いくつかの決定を行う必要があります-何をしたいですか?新しいクラスターをデプロイしますか? Postgresqlノードをデプロイするか、既存のクラスターをインポートします。
新しいクラスターをデプロイしたいと思います。次に、展開するクラスターのタイプを決定する必要がある次の画面が表示されます。レプリケーションを選択してから、ssh接続に関する必要な詳細を渡します。
準備ができたら、[続行]をクリックします。今回は、使用するMySQLベンダー、バージョン、およびMySQLのrootアカウントのパスワードなどのいくつかの構成設定を決定する必要があります。
最後に、レプリケーショントポロジを決定する必要があります。通常のマスター-スレーブセットアップを使用するか、より複雑でアクティブな-スタンバイマスター-マスターペア(+スレーブを追加する必要がある場合)を作成できます。準備ができたら、[デプロイ]をクリックするだけで、数分でクラスターがデプロイされます。
これが完了すると、ClusterControlのUIのクラスターリストにクラスターが表示されます。
レプリケーションを起動して実行すると、GTIDがどのように機能するかを詳しく調べることができます。
誤ったトランザクション-問題は何ですか?
この投稿の冒頭で述べたように、GTIDは、MySQLレプリケーションについての人々の考え方に大きな変化をもたらしました。習慣がすべてです。何らかの理由で、アプリケーションがスレーブの1つに書き込みを実行したとします。それは起こるべきではありませんでしたが、驚くべきことに、それは常に起こります。その結果、重複キーエラーでレプリケーションが停止します。このような問題に対処するには、いくつかの方法があります。それらの1つは、問題のある行を削除してレプリケーションを再開することです。もう1つは、バイナリログイベントをスキップしてからレプリケーションを再開することです。
STOP SLAVE SQL_THREAD; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE SQL_THREAD;
どちらの方法でもレプリケーションを機能させる必要がありますが、データドリフトが発生する可能性があるため、このようなイベントの後にスレーブの整合性をチェックする必要があることを覚えておく必要があります(pt-table-checksumとpt-table-syncはここでうまく機能します)。
>GTIDの使用中に同様の問題が発生した場合は、いくつかの違いに気付くでしょう。問題のある行を削除すると問題が解決するように見える場合があります。レプリケーションを開始できるはずです。 sql_slave_skip_counterを使用するもう1つの方法は、まったく機能しません。エラーが返されます。今ではbinlogイベントではなく、GTIDが実行されているかどうかがすべてです。
行を削除するだけで問題が解決するように見えるのはなぜですか? GTIDに関して覚えておくべき最も重要なことの1つは、スレーブがマスターに接続するときに、マスターで実行されたトランザクションが欠落していないかどうかをチェックすることです。これらは誤ったトランザクションと呼ばれます。スレーブがそのようなトランザクションを見つけると、それらを実行します。問題のある行をクリアするために次のSQLを実行したと仮定します:
DELETE FROM mytable WHERE id=100;
スレーブステータスの表示を確認しましょう:
Master_UUID: 966073f3-b6a4-11e4-af2c-080027880ca6
Retrieved_Gtid_Set: 966073f3-b6a4-11e4-af2c-080027880ca6:1-29
Executed_Gtid_Set: 84d15910-b6a4-11e4-af2c-080027880ca6:1,
966073f3-b6a4-11e4-af2c-080027880ca6:1-29,
そして、84d15910-b6a4-11e4-af2c-080027880ca6:1がどこから来ているかを確認してください:
mysql> SHOW VARIABLES LIKE 'server_uuid'\G
*************************** 1. row ***************************
Variable_name: server_uuid
Value: 84d15910-b6a4-11e4-af2c-080027880ca6
1 row in set (0.00 sec)
ご覧のとおり、マスターからの29のトランザクション、966073f3-b6a4-11e4-af2c-080027880ca6のUUID、およびローカルで実行されたトランザクションがあります。ある時点でフェイルオーバーし、マスター(966073f3-b6a4-11e4-af2c-080027880ca6)がスレーブになったとします。実行されたGTIDのリストを確認しますが、84d15910-b6a4-11e4-af2c-080027880ca6:1は見つかりません。その結果、関連するSQLが実行されます:
DELETE FROM mytable WHERE id=100;
これは私たちが期待したことではありません…その間に、このトランザクションを含むbinlogが古いスレーブでパージされると、フェイルオーバー後に新しいスレーブが文句を言います:
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.'
誤ったトランザクションを検出する方法
MySQLには、異なるホスト上のGTIDセットを比較する場合に非常に便利な2つの関数が用意されています。
GTID_SUBSET()は2つのGTIDセットを受け取り、最初のセットが2番目のセットのサブセットであるかどうかを確認します。
次の状態があるとしましょう。
マスター:
mysql> show master status\G
*************************** 1. row ***************************
File: binlog.000002
Position: 160205927
Binlog_Do_DB:
Binlog_Ignore_DB:
Executed_Gtid_Set: 8a6962d2-b907-11e4-bebc-080027880ca6:1-153,
9b09b44a-b907-11e4-bebd-080027880ca6:1,
ab8f5793-b907-11e4-bebd-080027880ca6:1-2
1 row in set (0.00 sec)
奴隷:
mysql> show slave status\G
[...]
Retrieved_Gtid_Set: 8a6962d2-b907-11e4-bebc-080027880ca6:1-153,
9b09b44a-b907-11e4-bebd-080027880ca6:1
Executed_Gtid_Set: 8a6962d2-b907-11e4-bebc-080027880ca6:1-153,
9b09b44a-b907-11e4-bebd-080027880ca6:1,
ab8f5793-b907-11e4-bebd-080027880ca6:1-4
次のSQLを実行することで、スレーブに誤ったトランザクションがあるかどうかを確認できます。
mysql> SELECT GTID_SUBSET('8a6962d2-b907-11e4-bebc-080027880ca6:1-153,ab8f5793-b907-11e4-bebd-080027880ca6:1-4', '8a6962d2-b907-11e4-bebc-080027880ca6:1-153, 9b09b44a-b907-11e4-bebd-080027880ca6:1, ab8f5793-b907-11e4-bebd-080027880ca6:1-2') as is_subset\G
*************************** 1. row ***************************
is_subset: 0
1 row in set (0.00 sec)
誤った取引があるようです。それらをどのように識別しますか?別の関数GTID_SUBTRACT()
を使用できますmysql> SELECT GTID_SUBTRACT('8a6962d2-b907-11e4-bebc-080027880ca6:1-153,ab8f5793-b907-11e4-bebd-080027880ca6:1-4', '8a6962d2-b907-11e4-bebc-080027880ca6:1-153, 9b09b44a-b907-11e4-bebd-080027880ca6:1, ab8f5793-b907-11e4-bebd-080027880ca6:1-2') as mising\G
*************************** 1. row ***************************
mising: ab8f5793-b907-11e4-bebd-080027880ca6:3-4
1 row in set (0.01 sec)
欠落しているGTIDはab8f5793-b907-11e4-bebd-080027880ca6:3-4-です。これらのトランザクションはスレーブで実行されましたが、マスターでは実行されませんでした。
誤った取引によって引き起こされた問題を解決するにはどうすればよいですか?
空のトランザクションを挿入する方法と、GTID履歴からトランザクションを除外する方法の2つがあります。
空のトランザクションを挿入するには、次のSQLを使用できます。
mysql> SET gtid_next='ab8f5793-b907-11e4-bebd-080027880ca6:3';
Query OK, 0 rows affected (0.01 sec)
mysql> begin ; commit;
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> SET gtid_next='ab8f5793-b907-11e4-bebd-080027880ca6:4';
Query OK, 0 rows affected (0.00 sec)
mysql> begin ; commit;
Query OK, 0 rows affected (0.00 sec)
Query OK, 0 rows affected (0.01 sec)
mysql> SET gtid_next=automatic;
Query OK, 0 rows affected (0.00 sec)
これは、GTIDが実行されていないレプリケーショントポロジ内のすべてのホストで実行する必要があります。マスターが利用可能な場合は、それらのトランザクションをそこに挿入して、チェーンに複製させることができます。マスターが使用できない場合(たとえば、マスターがクラッシュした場合)、これらの空のトランザクションはすべてのスレーブで実行する必要があります。オラクルは、このプロセスを自動化するように設計されたmysqlslavetrxと呼ばれるツールを開発しました。
もう1つのアプローチは、GTIDを履歴から削除することです。
奴隷を止めろ:
mysql> STOP SLAVE;
スレーブにExecuted_Gtid_Setを出力します:
mysql> SHOW MASTER STATUS\G
GTID情報をリセットする:
RESET MASTER;
GTID_PURGEDを正しいGTIDセットに設定します。 SHOWMASTERSTATUSからのデータに基づいています。セットから誤ったトランザクションを除外する必要があります。
SET GLOBAL GTID_PURGED='8a6962d2-b907-11e4-bebc-080027880ca6:1-153, 9b09b44a-b907-11e4-bebd-080027880ca6:1, ab8f5793-b907-11e4-bebd-080027880ca6:1-2';
スレーブを開始します。
mysql> START SLAVE\G
いずれの場合も、pt-table-checksumとpt-table-sync(必要な場合)を使用してスレーブの整合性を検証する必要があります。誤ったトランザクションによりデータがドリフトする可能性があります。
ClusterControlのフェイルオーバー
バージョン1.4以降、ClusterControlはMySQLレプリケーションのフェイルオーバー処理プロセスを強化しました。スレーブの1つをマスターに昇格させることにより、手動のマスター切り替えを実行できます。その後、残りのスレーブは新しいマスターにフェイルオーバーします。バージョン1.4以降、ClusterControlには、マスターに障害が発生した場合に完全に自動化されたフェイルオーバーを実行する機能もあります。 ClusterControlと自動フェイルオーバーについて説明しているブログ投稿で詳細に説明しました。この投稿のトピックに直接関連する1つの機能についても触れておきたいと思います。
デフォルトでは、ClusterControlは「安全な方法」でフェイルオーバーを実行します。フェイルオーバー時(またはマスタースイッチを実行したユーザーの場合はスイッチオーバー時)、ClusterControlはマスター候補を選択し、このノードに誤ったトランザクションがないことを確認しますこれは、マスターにプロモートされるとレプリケーションに影響を与えます。誤ったトランザクションが検出された場合、ClusterControlはフェイルオーバープロセスを停止し、マスター候補は新しいマスターになるように昇格されません。
いくつかの問題(誤ったトランザクションなど)が検出された場合でも、ClusterControlが新しいマスターをプロモートすることを100%確実にしたい場合は、cmon構成のreplication_stop_on_error=0設定を使用してそれを行うことができます。もちろん、前述したように、レプリケーションで問題が発生する可能性があります。スレーブは、使用できなくなったバイナリログイベントを要求し始める可能性があります。
このような場合に対処するために、スレーブの再構築の実験的なサポートを追加しました。 cmon構成でreplication_auto_rebuild_slave=1を設定し、MySQLでスレーブがダウンとしてマークされている場合、ClusterControlはマスターからのデータを使用してスレーブを再構築しようとします。
バイナリログからデータを読み取るときにマスターから致命的なエラー1236が発生しました:'スレーブはCHANGEMASTER TO MASTER_AUTO_POSITION =1を使用して接続していますが、マスターはスレーブが必要とするGTIDを含むバイナリログを削除しました。'
再構築プロセスによってマスターの負荷が増加するため、このような設定は必ずしも適切ではない場合があります。データセットが非常に大きく、定期的な再構築がオプションではない可能性もあります。そのため、この動作はデフォルトで無効になっています。