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

MySQLレプリケーションのトラブルシューティング:パート1

    レプリケーションは、MySQLとMariaDBの高可用性を実現するための最も一般的な方法の1つです。 GTIDの追加により、はるかに堅牢になり、数千人のユーザーによって徹底的にテストされています。 MySQLレプリケーションは「設定して忘れる」プロパティではありませんが、潜在的な問題を監視して維持し、良好な状態を維持する必要があります。このブログ投稿では、MySQLレプリケーションの問題を維持、トラブルシューティング、および修正する方法に関するヒントとコツをいくつか紹介します。

    MySQLレプリケーションが良好な状態にあるかどうかを判断する方法

    これは、MySQLレプリケーションのセットアップを担当する人が持っている必要がある最も重要なスキルです。レプリケーションの状態に関する情報を探す場所を見てみましょう。 MySQLとMariaDBにはわずかな違いがあり、これについても説明します。

    スレーブステータスを表示

    これは、スレーブホストでのレプリケーションの状態をチェックする最も一般的な方法です。これは常に私たちと一緒であり、レプリケーションに問題があると予想される場合は通常、最初にアクセスします。

    mysql> SHOW SLAVE STATUS\G
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 10.0.0.101
                      Master_User: rpl_user
                      Master_Port: 3306
                    Connect_Retry: 10
                  Master_Log_File: binlog.000002
              Read_Master_Log_Pos: 767658564
                   Relay_Log_File: relay-bin.000002
                    Relay_Log_Pos: 405
            Relay_Master_Log_File: binlog.000002
                 Slave_IO_Running: Yes
                Slave_SQL_Running: Yes
                  Replicate_Do_DB:
              Replicate_Ignore_DB:
               Replicate_Do_Table:
           Replicate_Ignore_Table:
          Replicate_Wild_Do_Table:
      Replicate_Wild_Ignore_Table:
                       Last_Errno: 0
                       Last_Error:
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 767658564
                  Relay_Log_Space: 606
                  Until_Condition: None
                   Until_Log_File:
                    Until_Log_Pos: 0
               Master_SSL_Allowed: No
               Master_SSL_CA_File:
               Master_SSL_CA_Path:
                  Master_SSL_Cert:
                Master_SSL_Cipher:
                   Master_SSL_Key:
            Seconds_Behind_Master: 0
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error:
                   Last_SQL_Errno: 0
                   Last_SQL_Error:
      Replicate_Ignore_Server_Ids:
                 Master_Server_Id: 1
                      Master_UUID: 5d1e2227-07c6-11e7-8123-080027495a77
                 Master_Info_File: mysql.slave_master_info
                        SQL_Delay: 0
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
               Master_Retry_Count: 86400
                      Master_Bind:
          Last_IO_Error_Timestamp:
         Last_SQL_Error_Timestamp:
                   Master_SSL_Crl:
               Master_SSL_Crlpath:
               Retrieved_Gtid_Set:
                Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-394233
                    Auto_Position: 1
             Replicate_Rewrite_DB:
                     Channel_Name:
               Master_TLS_Version:
    1 row in set (0.00 sec)

    MySQLとMariaDBの間で詳細が異なる場合がありますが、コンテンツの大部分は同じように見えます。 MySQLとMariaDBが異なる方法で行うため、変更はGTIDセクションに表示されます。 SHOW SLAVE STATUSから、どのマスターが使用され、どのユーザーとどのポートがマスターへの接続に使用されるかなど、いくつかの情報を導き出すことができます。現在のバイナリログの位置(GTIDを使用してbinlogを忘れることができるため、それほど重要ではありません)とSQLおよびI/Oレプリケーションスレッドの状態に関するデータがいくつかあります。次に、フィルタリングが構成されているかどうか、およびどのように構成されているかを確認できます。エラー、レプリケーションラグ、SSL設定、GTIDに関する情報もあります。上記の例は、正常な状態にあるMySQL5.7スレーブからのものです。レプリケーションが壊れている例を見てみましょう。

    MariaDB [test]> show slave status\G
    *************************** 1. row ***************************
                   Slave_IO_State: Waiting for master to send event
                      Master_Host: 10.0.0.104
                      Master_User: rpl_user
                      Master_Port: 3306
                    Connect_Retry: 10
                  Master_Log_File: binlog.000003
              Read_Master_Log_Pos: 636
                   Relay_Log_File: relay-bin.000002
                    Relay_Log_Pos: 765
            Relay_Master_Log_File: binlog.000003
                 Slave_IO_Running: Yes
                Slave_SQL_Running: No
                  Replicate_Do_DB:
              Replicate_Ignore_DB:
               Replicate_Do_Table:
           Replicate_Ignore_Table:
          Replicate_Wild_Do_Table:
      Replicate_Wild_Ignore_Table:
                       Last_Errno: 1032
                       Last_Error: Could not execute Update_rows_v1 event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000003, end_log_pos 609
                     Skip_Counter: 0
              Exec_Master_Log_Pos: 480
                  Relay_Log_Space: 1213
                  Until_Condition: None
                   Until_Log_File:
                    Until_Log_Pos: 0
               Master_SSL_Allowed: No
               Master_SSL_CA_File:
               Master_SSL_CA_Path:
                  Master_SSL_Cert:
                Master_SSL_Cipher:
                   Master_SSL_Key:
            Seconds_Behind_Master: NULL
    Master_SSL_Verify_Server_Cert: No
                    Last_IO_Errno: 0
                    Last_IO_Error:
                   Last_SQL_Errno: 1032
                   Last_SQL_Error: Could not execute Update_rows_v1 event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000003, end_log_pos 609
      Replicate_Ignore_Server_Ids:
                 Master_Server_Id: 1
                   Master_SSL_Crl:
               Master_SSL_Crlpath:
                       Using_Gtid: Slave_Pos
                      Gtid_IO_Pos: 0-1-73243
          Replicate_Do_Domain_Ids:
      Replicate_Ignore_Domain_Ids:
                    Parallel_Mode: conservative
    1 row in set (0.00 sec)

    このサンプルはMariaDB10.1から取得したもので、MariaDBGTIDで機能するように出力の下部に変更が表示されます。私たちにとって重要なのはエラーです。SQLスレッドに何かが正しくないことがわかります。

    Last_SQL_Error: Could not execute Update_rows_v1 event on table test.tab; Can't find record in 'tab', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.000003, end_log_pos 609

    この特定の問題については後で説明します。今のところ、SHOWSLAVESTATUSを使用してレプリケーションにエラーがあるかどうかを確認する方法を確認するだけで十分です。

    SHOW SLAVE STATUSから得られるもう1つの重要な情報は、スレーブがどれほどひどく遅れているかです。 「Seconds_Behind_Master」欄で確認できます。このメトリックは、古い読み取りに関してアプリケーションが機密であることがわかっている場合に追跡することが特に重要です。

    ClusterControlでは、「概要」セクションでこのデータを追跡できます。

    SHOWSLAVESTATUSコマンドからの最も重要な情報をすべて表示しました。マスターであるレプリケーションのステータス、レプリケーションの遅延があるかどうか、バイナリログの位置を確認できます。取得して実行したGTIDも見つけることができます。

    パフォーマンススキーマ

    レプリケーションに関する情報を探すことができるもう1つの場所は、performance_schemaです。これは、OracleのMySQL5.7にのみ適用されます。以前のバージョンとMariaDBはこのデータを収集しません。

    mysql> SHOW TABLES FROM performance_schema LIKE 'replication%';
    +---------------------------------------------+
    | Tables_in_performance_schema (replication%) |
    +---------------------------------------------+
    | replication_applier_configuration           |
    | replication_applier_status                  |
    | replication_applier_status_by_coordinator   |
    | replication_applier_status_by_worker        |
    | replication_connection_configuration        |
    | replication_connection_status               |
    | replication_group_member_stats              |
    | replication_group_members                   |
    +---------------------------------------------+
    8 rows in set (0.00 sec)

    以下に、これらの表のいくつかで利用可能なデータの例をいくつか示します。

    mysql> select * from replication_connection_status\G
    *************************** 1. row ***************************
                 CHANNEL_NAME:
                   GROUP_NAME:
                  SOURCE_UUID: 5d1e2227-07c6-11e7-8123-080027495a77
                    THREAD_ID: 32
                SERVICE_STATE: ON
    COUNT_RECEIVED_HEARTBEATS: 1
     LAST_HEARTBEAT_TIMESTAMP: 2017-03-17 19:41:34
     RECEIVED_TRANSACTION_SET: 5d1e2227-07c6-11e7-8123-080027495a77:715599-724966
            LAST_ERROR_NUMBER: 0
           LAST_ERROR_MESSAGE:
         LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
    1 row in set (0.00 sec)
    mysql> select * from replication_applier_status_by_worker\G
    *************************** 1. row ***************************
             CHANNEL_NAME:
                WORKER_ID: 0
                THREAD_ID: 31
            SERVICE_STATE: ON
    LAST_SEEN_TRANSACTION: 5d1e2227-07c6-11e7-8123-080027495a77:726086
        LAST_ERROR_NUMBER: 0
       LAST_ERROR_MESSAGE:
     LAST_ERROR_TIMESTAMP: 0000-00-00 00:00:00
    1 row in set (0.00 sec)

    ご覧のとおり、レプリケーションの状態、最後のエラー、受信したトランザクションセット、その他のデータを確認できます。重要なのは、マルチスレッドレプリケーションを有効にした場合、replication_applier_status_by_workerテーブルで、すべてのワーカーの状態を確認できることです。これは、各ワーカースレッドのレプリケーションの状態を理解するのに役立ちます。

    レプリケーションラグ

    ラグは間違いなく、MySQLレプリケーションで作業するときに直面する最も一般的な問題の1つです。スレーブの1つがマスターによって実行される書き込み操作の量に追いつくことができない場合、レプリケーションラグが発生します。理由は異なる可能性があります-異なるハードウェア構成、スレーブへのより重い負荷、シリアル化する必要があるマスターでの高度な書き込み並列化(レプリケーションにシングルスレッドを使用する場合)、または書き込みを同じ程度に並列化することはできませんマスター上にある(マルチスレッドレプリケーションを使用する場合)。

    それを検出する方法は?

    レプリケーションラグを検出する方法はいくつかあります。まず、SHOW SLAVE STATUS出力で「Seconds_Behind_Master」をチェックすると、スレーブが遅れているかどうかがわかります。ほとんどの場合はうまく機能しますが、より複雑なトポロジでは、レプリケーションチェーンの下位にあるホストで中間マスターを使用すると、正確ではない場合があります。もう1つのより良い解決策は、pt-heartbeatなどの外部ツールに依存することです。アイデアは単純です。テーブルは、とりわけタイムスタンプ列を使用して作成されます。この列は、マスターで定期的に更新されます。スレーブでは、その列のタイムスタンプを現在の時刻と比較できます。これにより、スレーブがどれだけ遅れているかがわかります。

    ラグの計算方法に関係なく、ホストが時間的に同期していることを確認してください。 ntpdまたはその他の時間同期手段を使用します。時間のずれがある場合は、スレーブで「誤った」遅延が発生します。

    ラグを減らす方法

    これは答えるのが簡単な質問ではありません。要するに、それは何が遅れを引き起こしているのか、そして何がボトルネックになったのかによる。 2つの典型的なパターンがあります。スレーブはI/Oバウンドです。つまり、そのI/Oサブシステムは大量の書き込みおよび読み取り操作に対応できません。 2番目-スレーブはCPUにバインドされています。つまり、レプリケーションスレッドは可能な限りすべてのCPUを使用し(1つのスレッドは1つのCPUコアのみを使用できます)、それでもすべての書き込み操作を処理するには不十分です。

    CPUがボトルネックの場合、ソリューションはマルチスレッドレプリケーションを使用するのと同じくらい簡単です。作業スレッドの数を増やして、より高度な並列化を可能にします。ただし、常に可能であるとは限りません。そのような場合は、グループコミット変数(MySQLとMariaDBの両方)を少し試して、コミットをわずかな時間(ここではミリ秒について話します)、このように遅らせることができます。 、コミットの並列化を増やします。

    問題がI/Oにある場合、問題の解決は少し難しくなります。もちろん、InnoDB I/O設定を確認する必要があります。おそらく改善の余地があります。 my.cnfの調整が役に立たない場合は、選択肢が多すぎません。クエリを改善するか(可能な場合)、I/Oサブシステムをより高性能なものにアップグレードしてください。

    ほとんどのプロキシ(たとえば、ClusterControlからデプロイできるすべてのプロキシ:ProxySQL、HAProxy、MaxScale)は、レプリケーションの遅延が事前定義されたしきい値を超えた場合に、スレーブをローテーションから削除する可能性を提供します。これはラグを減らす方法ではありませんが、古い読み取りを回避し、副作用として、スレーブの負荷を減らして追いつくのに役立つ場合があります。

    もちろん、どちらの場合もクエリの調整が解決策になる可能性があります。CPUまたはI/Oが重いクエリを改善することは常に良いことです。

    誤ったトランザクション

    誤ったトランザクションは、マスターではなくスレーブでのみ実行されたトランザクションです。要するに、それらはスレーブをマスターと矛盾させます。 GTIDベースのレプリケーションを使用する場合、スレーブがマスターに昇格すると、深刻な問題が発生する可能性があります。このトピックに関する詳細な投稿があります。このトピックを調べて、誤ったトランザクションの問題を検出して修正する方法を理解することをお勧めします。 ClusterControlが誤ったトランザクションを検出して処理する方法についての情報も含まれています。

    マスターにBinlogファイルがありません

    問題を特定する方法

    状況によっては、スレーブがマスターに接続し、存在しないバイナリログファイルを要求する場合があります。この理由の1つは、誤ったトランザクションである可能性があります。ある時点で、トランザクションがスレーブで実行され、後でこのスレーブがマスターになります。そのマスターからスレーブするように構成されている他のホストは、欠落しているトランザクションを要求します。かなり前に実行された場合は、バイナリログファイルがすでに削除されている可能性があります。

    もう1つの、より一般的な例-xtrabackupを使用してスレーブをプロビジョニングする必要があります。ホストにバックアップをコピーし、ログを適用し、MySQLデータディレクトリの所有者を変更します。これは、バックアップを復元するために行う一般的な操作です。実行します

    SET GLOBAL gtid_purged=

    xtrabackup_binlog_infoからのデータに基づいて、CHANGEMASTERTO…MASTER_AUTO_POSITION=1(これはMySQLにあり、MariaDBのプロセスは少し異なります)を実行し、スレーブを起動すると、次のようなエラーが発生します。

                    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または:

                    Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: 'Could not find GTID state requested by slave in any binlog files. Probably the slave state is too old and required binlog files have been purged.'

    MariaDBで。

    これは基本的に、マスターが欠落しているすべてのトランザクションを実行するために必要なすべてのバイナリログを持っていないことを意味します。ほとんどの場合、バックアップが古すぎて、バックアップが作成されてからスレーブがプロビジョニングされるまでの間に作成されたバイナリログの一部がマスターによってすでにパージされています。

    この問題を解決するには?

    残念ながら、この特定のケースでできることはあまりありません。マスターよりも長い時間バイナリログを保存するMySQLホストがある場合は、それらのログを使用して、スレーブで欠落しているトランザクションを再生してみることができます。それがどのように行われるかを見てみましょう。

    まず、マスターのバイナリログにある最も古いGTIDを見てみましょう。

    mysql> SHOW BINARY LOGS\G
    *************************** 1. row ***************************
     Log_name: binlog.000021
    File_size: 463
    1 row in set (0.00 sec)

    したがって、「binlog.000021」は最新の(そして唯一の)ファイルです。このファイルの最初のGTIDエントリを確認しましょう:

    [email protected]:~# mysqlbinlog /var/lib/mysql/binlog.000021
    /*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
    /*!50003 SET @[email protected]@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
    DELIMITER /*!*/;
    # at 4
    #170320 10:39:51 server id 1  end_log_pos 123 CRC32 0x5644fc9b     Start: binlog v 4, server v 5.7.17-11-log created 170320 10:39:51
    # Warning: this binlog is either in use or was not closed properly.
    BINLOG '
    d7HPWA8BAAAAdwAAAHsAAAABAAQANS43LjE3LTExLWxvZwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
    AAAAAAAAAAAAAAAAAAAAAAAAEzgNAAgAEgAEBAQEEgAAXwAEGggAAAAICAgCAAAACgoKKioAEjQA
    AZv8RFY=
    '/*!*/;
    # at 123
    #170320 10:39:51 server id 1  end_log_pos 194 CRC32 0x5c096d62     Previous-GTIDs
    # 5d1e2227-07c6-11e7-8123-080027495a77:1-1106668
    # at 194
    #170320 11:21:26 server id 1  end_log_pos 259 CRC32 0xde21b300     GTID    last_committed=0    sequence_number=1
    SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106669'/*!*/;
    # at 259

    ご覧のとおり、利用可能な最も古いバイナリログエントリは次のとおりです。5d1e2227-07c6-11e7-8123-080027495a77:1106669

    また、バックアップでカバーされている最後のGTIDを確認する必要があります:

    [email protected]:~# cat /var/lib/mysql/xtrabackup_binlog_info
    binlog.000017    194    5d1e2227-07c6-11e7-8123-080027495a77:1-1106666

    5d1e2227-07c6-11e7-8123-080027495a77:1-1106666なので、2つのイベントがありません:
    5d1e2227-07c6-11e7-8123-080027495a77:1106667-1106668

    他のスレーブでそれらのトランザクションを見つけることができるかどうか見てみましょう。

    mysql> SHOW BINARY LOGS;
    +---------------+------------+
    | Log_name      | File_size  |
    +---------------+------------+
    | binlog.000001 | 1074130062 |
    | binlog.000002 |  764366611 |
    | binlog.000003 |  382576490 |
    +---------------+------------+
    3 rows in set (0.00 sec)

    「binlog.000003」は最新のバイナリログのようです。不足しているGTIDがそこにあるかどうかを確認する必要があります:

    slave2:~# mysqlbinlog /var/lib/mysql/binlog.000003 | grep "5d1e2227-07c6-11e7-8123-080027495a77:110666[78]"
    SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106667'/*!*/;
    SET @@SESSION.GTID_NEXT= '5d1e2227-07c6-11e7-8123-080027495a77:1106668'/*!*/;

    binlogファイルを処理すると負荷が増える可能性があるため、binlogファイルを本番サーバーの外部にコピーすることをお勧めします。それらのGTIDが存在することを確認したら、それらを抽出できます:

    slave2:~# mysqlbinlog --exclude-gtids='5d1e2227-07c6-11e7-8123-080027495a77:1-1106666,5d1e2227-07c6-11e7-8123-080027495a77:1106669' /var/lib/mysql/binlog.000003 > to_apply_on_slave1.sql

    簡単なscpの後、これらのイベントをスレーブに適用できます

    slave1:~# mysql -ppass < to_apply_on_slave1.sql

    完了したら、SHOW SLAVE STATUSの出力を調べることで、これらのGTIDが適用されているかどうかを確認できます。

                    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.'
                   Last_SQL_Errno: 0
                   Last_SQL_Error:
      Replicate_Ignore_Server_Ids:
                 Master_Server_Id: 1
                      Master_UUID: 5d1e2227-07c6-11e7-8123-080027495a77
                 Master_Info_File: mysql.slave_master_info
                        SQL_Delay: 0
              SQL_Remaining_Delay: NULL
          Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
               Master_Retry_Count: 86400
                      Master_Bind:
          Last_IO_Error_Timestamp: 170320 10:45:04
         Last_SQL_Error_Timestamp:
                   Master_SSL_Crl:
               Master_SSL_Crlpath:
               Retrieved_Gtid_Set:
                Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-1106668

    Executed_GTID_setは良さそうなので、スレーブスレッドを開始できます:

    mysql> START SLAVE;
    Query OK, 0 rows affected (0.00 sec)

    正常に動作したかどうかを確認しましょう。ここでも、SHOW SLAVE STATUS出力を使用します:

               Master_SSL_Crlpath:
               Retrieved_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1106669
                Executed_Gtid_Set: 5d1e2227-07c6-11e7-8123-080027495a77:1-1106669

    よさそうだ、稼働している!

    この問題を解決する別の方法は、もう一度バックアップを取り、新しいデータを使用してスレーブを再度プロビジョニングすることです。これはおそらくより速く、間違いなくより信頼性が高くなります。マスターとスレーブで異なるbinlogパージポリシーがあることはめったにありません)

    他の種類のレプリケーションの問題については、次のブログ投稿で引き続き説明します。


    1. Androidアプリケーション内でSQLiteクエリを実行するにはどうすればよいですか?

    2. ScaleGridはトップ100のクラウドサービスプロバイダーにランクイン

    3. MySQLでのSUBSTR()関数のしくみ

    4. OracleデータベースのVALUES-OFバインド句を含むFORALLステートメント