sql >> データベース >  >> RDS >> MariaDB

非GTIDからGTIDMariaDBデータベースクラスターへのレプリケーションの問題の処理

    最近、MariaDBレプリケーションのセットアップに関する興味深いカスタマーサポートの事例に遭遇しました。私たちはこの問題の調査に多くの時間を費やし、このブログ投稿でこれを共有する価値があると考えました。

    お客様の環境の説明

    問題は次のとおりです。古い(10.xより前の)MariaDBサーバーが使用されていて、そこからより新しいMariaDBレプリケーションセットアップにデータを移行しようとしました。これにより、Mariabackupを使用して新しいレプリケーションクラスターでスレーブを再構築する際に問題が発生しました。テストの目的で、次の環境でこの動作を再現しました。

    データは、mysqldumpを使用して5.5から10.4に移行されました:

    >
    mysqldump --single-transaction --master-data=2 --events --routines sbtest > /root/dump.sql

    これにより、マスターバイナリログ座標と一貫性のあるダンプを収集できました。その結果、MariaDB 10.4マスターノードをプロビジョニングし、古い5.5マスターと新しい10.4ノード間のレプリケーションをセットアップすることができました。トラフィックはまだ5.5ノードで実行されていました。 10.4マスターは、データを10.4スレーブに複製する必要があるため、GTIDを生成していました。詳細を掘り下げる前に、MariaDBでGTIDがどのように機能するかを簡単に見てみましょう。

    MariaDBとGTID

    まず、MariaDBはOracleMySQLとは異なる形式のGTIDを使用します。ダッシュで区切られた3つの数字で構成されています:

    0 --1 --345

    1つ目はレプリケーションドメインであり、マルチソースレプリケーションを適切に処理できます。すべてのノードが同じレプリケーションドメインにあるため、これはこの場合には関係ありません。 2番目の番号は、GTIDを生成したノードのサーバーIDです。 3つ目はシーケンス番号です。これは、バイナリログに保存されるイベントごとに単調に増加します。

    MariaDBはいくつかの変数を使用して、特定のノードで実行されたGTIDに関する情報を格納します。私たちにとって最も興味深いのは:

    Gtid_binlog_pos-ドキュメントによると、この変数は、バイナリログに書き込まれた最後のイベントグループのGTIDです。

    Gtid_slave_pos-ドキュメントによると、このシステム変数には、サーバーのスレーブスレッドによってデータベースに適用された最後のトランザクションのGTIDが含まれています。

    Gtid_current_pos-ドキュメントによると、このシステム変数には、データベースに適用された最後のトランザクションのGTIDが含まれています。 gtid_binlog_posの対応するGTIDのserver_idがサーバー自身のserver_idと等しく、シーケンス番号がgtid_slave_posの対応するGTIDよりも大きい場合、gtid_binlog_posのGTIDが使用されます。それ以外の場合は、gtid_slave_posのGTIDがそのドメインに使用されます。

    したがって、明確にするために、gtid_binlog_posは最後にローカルで実行されたイベントのGTIDを格納します。 Gtid_slave_posは、スレーブスレッドによって実行されたイベントのGTIDを格納し、gtid_current_posは、シーケンス番号が最も高く、server-idがある場合はgtid_binlog_posの値を示し、シーケンスが最も高い場合はgtid_slave_posを示します。これを覚えておいてください。

    問題の概要 関連する変数の初期状態は10.4マスターにあります:

    MariaDB [(none)]> show global variables like '%gtid%';
    
    +-------------------------+----------+
    
    | Variable_name           | Value |
    
    +-------------------------+----------+
    
    | gtid_binlog_pos         | 0-1001-1 |
    
    | gtid_binlog_state       | 0-1001-1 |
    
    | gtid_cleanup_batch_size | 64       |
    
    | gtid_current_pos        | 0-1001-1 |
    
    | gtid_domain_id          | 0 |
    
    | gtid_ignore_duplicates  | ON |
    
    | gtid_pos_auto_engines   | |
    
    | gtid_slave_pos          | 0-1001-1 |
    
    | gtid_strict_mode        | ON |
    
    | wsrep_gtid_domain_id    | 0 |
    
    | wsrep_gtid_mode         | OFF |
    
    +-------------------------+----------+
    
    11 rows in set (0.001 sec)

    gtid_slave_posに注意してください。これは理論的には意味がありません。同じノードからのものですが、スレーブスレッドを介したものです。これは、以前にマスタースイッチを作成した場合に発生する可能性があります。それを実行しました。2つの10.4ノードがあり、マスターをサーバーIDが1001のホストからサーバーIDが1002のホストに切り替えてから、1001に戻しました。

    その後、レプリケーションを5.5から10.4に構成しました。これは、次のようになります。

    MariaDB [(none)]> show global variables like '%gtid%';
    
    +-------------------------+-------------------------+
    
    | Variable_name           | Value |
    
    +-------------------------+-------------------------+
    
    | gtid_binlog_pos         | 0-55-117029 |
    
    | gtid_binlog_state       | 0-1001-1537,0-55-117029 |
    
    | gtid_cleanup_batch_size | 64                      |
    
    | gtid_current_pos        | 0-1001-1 |
    
    | gtid_domain_id          | 0 |
    
    | gtid_ignore_duplicates  | ON |
    
    | gtid_pos_auto_engines   | |
    
    | gtid_slave_pos          | 0-1001-1 |
    
    | gtid_strict_mode        | ON |
    
    | wsrep_gtid_domain_id    | 0 |
    
    | wsrep_gtid_mode         | OFF |
    
    +-------------------------+-------------------------+
    
    11 rows in set (0.000 sec)

    ご覧のとおり、MariaDB 5.5から複製されたイベントは、すべてgtid_binlog_pos変数(サーバーIDが55のすべてのイベント)で考慮されています。これにより、重大な問題が発生します。覚えているかもしれませんが、gtid_binlog_posには、ホスト上でローカルに実行されるイベントが含まれている必要があります。ここには、異なるサーバーIDを持つ別のサーバーから複製されたイベントが含まれています。

    これにより、10.4スレーブを再構築するときに問題が発生します。その理由は、次のとおりです。 Mariabackupは、Xtrabackupと同様に、簡単な方法で機能します。 REDOログをスキャンし、着信トランザクションを保存しながら、MariaDBサーバーからファイルをコピーします。ファイルがコピーされると、Mariabackupは、MariaDBのバージョンとバックアップロックの可用性に応じて、FLUSH TABLES WITHREADLOCKまたはバックアップロックのいずれかを使用してデータベースをフリーズします。次に、最後に実行されたGTIDを読み取り、バックアップと一緒に保存します。その後、ロックが解除され、バックアップが完了します。バックアップに保存されているGTIDは、ノードで最後に実行されたGTIDとして使用する必要があります。スレーブを再構築する場合は、gtid_slave_posとして配置され、GTIDレプリケーションを開始するために使用されます。このGTIDはgtid_current_posから取得されます。これは完全に理にかなっています。結局のところ、これは「データベースに適用された最後のトランザクションのGTID」です。急性の読者はすでに問題を見ることができます。 10.4が5.5マスターから複製されたときの変数の出力を示しましょう:

    MariaDB [(none)]> show global variables like '%gtid%';
    
    +-------------------------+-------------------------+
    
    | Variable_name           | Value |
    
    +-------------------------+-------------------------+
    
    | gtid_binlog_pos         | 0-55-117029 |
    
    | gtid_binlog_state       | 0-1001-1537,0-55-117029 |
    
    | gtid_cleanup_batch_size | 64                      |
    
    | gtid_current_pos        | 0-1001-1 |
    
    | gtid_domain_id          | 0 |
    
    | gtid_ignore_duplicates  | ON |
    
    | gtid_pos_auto_engines   | |
    
    | gtid_slave_pos          | 0-1001-1 |
    
    | gtid_strict_mode        | ON |
    
    | wsrep_gtid_domain_id    | 0 |
    
    | wsrep_gtid_mode         | OFF |
    
    +-------------------------+-------------------------+
    
    11 rows in set (0.000 sec)

    Gtid_current_posは0-1001-1に設定されています。これは間違いなく正しい瞬間ではありません。それはgtid_slave_posから取得されたものですが、その後5.5から発生した一連のトランザクションがあります。問題は、それらのトランザクションがgtid_binlog_posとして保存されることです。一方、gtid_current_posは、gtid_current_posとして使用する前にgitd_binlog_pos内のGTIDのローカルサーバーIDを必要とする方法で計算されます。この場合、それらは5.5ノードのサーバーIDを持っているため、10.4マスターで実行されたイベントとして適切に扱われません。バックアップの復元後、バックアップに保存されているGTIDの状態に従ってスレーブを設定すると、5.5から発生したすべてのイベントが再適用されることになります。これは明らかに、複製を壊します。

    ソリューション

    この問題の解決策は、いくつかの追加手順を実行することです。

    1. 5.5から10.4へのレプリケーションを停止します。 10.4マスターでSTOPSLAVEを実行します
    2. 10.4でトランザクションを実行します-存在しない場合はSCHEMAを作成しますバグ修正-これにより、GTIDの状況が次のように変更されます:
    MariaDB [(none)]> show global variables like '%gtid%';
    
    +-------------------------+---------------------------+
    
    | Variable_name           | Value   |
    
    +-------------------------+---------------------------+
    
    | gtid_binlog_pos         | 0-1001-117122   |
    
    | gtid_binlog_state       | 0-55-117121,0-1001-117122 |
    
    | gtid_cleanup_batch_size | 64                        |
    
    | gtid_current_pos        | 0-1001-117122   |
    
    | gtid_domain_id          | 0   |
    
    | gtid_ignore_duplicates  | ON   |
    
    | gtid_pos_auto_engines   |   |
    
    | gtid_slave_pos          | 0-1001-1   |
    
    | gtid_strict_mode        | ON   |
    
    | wsrep_gtid_domain_id    | 0   |
    
    | wsrep_gtid_mode         | OFF   |
    
    +-------------------------+---------------------------+
    
    11 rows in set (0.001 sec)

    最新のGITDはローカルで実行されたため、gtid_binlog_posとして保存されました。ローカルサーバーIDを持っているため、gtid_current_posとして選択されます。これで、バックアップを取り、それを使用して10.4マスターからスレーブを再構築できます。これが完了したら、スレーブスレッドを再開します。

    MariaDBは、この種のバグが存在することを認識しています。検出された関連するバグレポートの1つは、https://jira.mariadb.org/browse/MDEV-10279です。残念ながら、これまでのところ修正はありません。 。私たちが見つけたのは、この問題が5.5までのMariaDBに影響を与えるということです。 MariaDB 10.0からの非GTIDイベントは、スレーブスレッドからのイベントとして10.4で正しく考慮され、gtid_slave_posが適切に更新されます。 MariaDB 5.5はかなり古いものです(まだサポートされていますが)ので、セットアップが実行されているのを確認し、5.5からより新しいGTID対応のMariaDBバージョンに移行しようとする場合があります。さらに悪いことに、私たちが見つけたバグレポートによると、これは非MariaDB(コメントの1つはPercona Server 5.6に表示される問題に言及しています)サーバーからMariaDBへのレプリケーションにも影響します。

    とにかく、このブログ投稿がお役に立てば幸いです。また、今説明した問題に遭遇しないことを願っています。


    1. PostgreSQLで2つのタイムスタンプの差を計算する方法

    2. T-SQLのバグ、落とし穴、およびベストプラクティス–ウィンドウ関数

    3. MariaDB JSON_DEPTH()の説明

    4. SQL Server –sp_spaceusedの内部を分析します