レプリケーション ラグ

このページでは、Cloud SQL リードレプリカのレプリケーション ラグのトラブルシューティングと修正方法について説明します。

概要

Cloud SQL リードレプリカは、グローバル トランザクション識別子(GTID)を使用した MySQL 行ベースのレプリケーションを使用します。変更はプライマリ インスタンスのバイナリログに書き込まれ、レプリカに送信されます。レプリカでは変更を受信し、データベースに適用します。

レプリケーション ラグは、次のようないくつかのシナリオで発生する可能性があります。

  • プライマリ インスタンスが、レプリカに変更を十分な速さで送信できない。
  • レプリカが変更を十分な速さで受信できない。
  • レプリカが変更を十分な速さで適用できない。
network_lag 指標を使用して、プライマリ インスタンスが変更を十分な速さで送信できない、あるいはレプリカが変更を十分な速さで受信できない、という最初の 2 つのシナリオをモニタリングします。

合計ラグは、replica_lag 指標で観測されます。replica_lagnetwork_lag の違いから、レプリカがレプリケーションの変更をすぐに適用できない 3 番目の理由がわかります。これらの指標については、この後のレプリケーション ラグをモニタリングするセクションで説明します。

より高速なレプリカ構成

MySQL レプリカで変更をより高速に適用するには、次の 2 つの方法があります。ユーザーは、次の方法でレプリカを構成できます。

  • 並列レプリケーション
  • 高パフォーマンスのフラッシュ

並列レプリケーション

レプリカに変更を適用する複数のスレッドを同時に使用するようにレプリカを構成すると、並列レプリケーションがレプリケーション ラグに役立つ場合があります。並列レプリケーションの使用については、並列レプリケーションの構成をご覧ください。

高パフォーマンスのフラッシュ

デフォルトでは、Cloud SQL for MySQL は各トランザクションの後に REDO ログをディスクにフラッシュします。高パフォーマンスのフラッシュでは、REDO ログがディスクにフラッシュされる頻度が 1 秒に 1 回ずつ削減されるため、書き込みのパフォーマンスが向上します。

リードレプリカの innodb_flush_log_at_trx_commit フラグを 2 に設定します。また、innodb_flush_log_at_trx_commit フラグを有効にするには、sync_binlog フラグに高い値を設定する必要があります。

このフラグの詳細については、フラグの使用に関するヒントをご覧ください。

リードレプリカに innodb_flush_log_at_trx_commit フラグが設定され、Cloud SQL がクラッシュの可能性を検出すると、Cloud SQL は自動的にレプリカを再作成します。

クエリとスキーマを最適化する

このセクションでは、レプリケーションのパフォーマンスを改善するためによく実行するクエリとスキーマの最適化について説明します。

リードレプリカのクエリ分離レベル

REPEATABLE READSERIALIZABLE のトランザクション分離レベルは、レプリケーションの変更をブロックする可能性のあるロックを取得します。レプリカ内のクエリの分離レベルを下げることを検討してください。READ COMMITTED のトランザクション分離レベルのほうがパフォーマンスが向上する可能性があります。

プライマリ データベースでの長時間実行トランザクション

1 つのトランザクションで多数の行が更新されると、プライマリ インスタンスに適用してからレプリカに送信する必要がある変更の数が急増する可能性があります。これは、多くの行に同時に影響する単一ステートメントの更新または削除が行われると発生します。変更は commit 後にレプリカに送信されます。レプリカの変更が急増し、レプリカのクエリ負荷が高くなると、レプリカのロック競合が発生し、レプリケーション ラグが発生する可能性があります。

大きなトランザクションを複数の小さなトランザクションに分割することを検討してください。

主キーの欠如

Cloud SQL リードレプリカは、行ベースのレプリケーションを使用します。そのため、複製される MySQL テーブルに主キーがない場合、パフォーマンスが低下します。レプリケートされたすべてのテーブルに主キーを設定することをおすすめします。

MySQL 8 以降では、データベースのテーブルに主キーが必要となるように sql_require_primary_key フラグを ON に設定することをおすすめします。

DDL による排他ロック

データ定義言語(DDL)コマンド(ALTER TABLECREATE INDEX など)では、排他的ロックによってレプリカでレプリケーション ラグが発生することがあります。ロックの競合を回避するには、レプリカでクエリの負荷が低いときに DDL の実行をスケジュールすることを検討してください。

レプリカの過負荷

リードレプリカが受信するクエリが多すぎると、レプリケーションがブロックされることがあります。読み取りを複数のレプリカに分割して、各レプリカの負荷を減らすことを検討してください。

クエリの急増を回避するには、アプリケーション ロジックまたはプロキシレイヤ(1 つ使用している場合)でレプリカの読み取りクエリを抑制することを検討してください。

プライマリ インスタンスでアクティビティが急増した場合は、更新を分散させることを検討してください。

モノリシックなプライマリ データベース

プライマリ データベースを垂直方向(または水平方向)に分割して、1 つ以上のラグテーブルが他のすべてのテーブルを抑制しないようにすることを検討してください。

レプリケーション ラグをモニタリングする

replica_lag 指標と network_lag 指標を使用してレプリケーション ラグをモニタリングし、ラグの原因がプライマリ データベース、ネットワーク、レプリカのどれにあるのかを識別できます。

指標説明
レプリケーション ラグ
cloudsql.googleapis.com/database/replication/replica_lag

レプリカの状態がプライマリ インスタンスの状態よりも遅れている秒数。これは、現在の時刻と、現在レプリカに適用されているトランザクションをプライマリ データベースが commit した時点のタイムスタンプとの差です。特に、レプリカが書き込みを受信していても、レプリカがデータベースへの書き込みをまだ適用していない場合、書き込みは遅延として記録される可能性があります。

この指標は、レプリカで SHOW SLAVE STATUS が実行されたときに Seconds_Behind_Master の値をレポートします。詳細については、MySQL リファレンス マニュアルのレプリケーション ステータスの確認をご覧ください。

最後の I/O スレッドエラー番号
cloudsql.googleapis.com/database/mysql/replication/last_io_errno

I/O スレッドが失敗する原因となった最後のエラーを示します。この値がゼロでない場合は、レプリケーションが中断します。このケースはまれですが、発生する可能性はあります。エラーコードが示す内容を理解するには、MySQL のドキュメントをご覧ください。たとえば、プライマリ インスタンスの binlog ファイルが、レプリカが受信する前に削除されている可能性があります。通常、Cloud SQL は、レプリケーションが壊れた場合、レプリカを自動的に再作成します。この last_io_errno 指標からその理由がわかります。

最後の SQL スレッドのエラー番号
cloudsql.googleapis.com/database/mysql/replication/last_sql_errno

SQL スレッドが失敗する原因となった最後のエラーを示します。この値がゼロでない場合は、レプリケーションが中断します。このケースはまれですが、発生する可能性はあります。エラーコードが示す内容を理解するには、MySQL のドキュメントをご覧ください。レプリケーションが中断した場合、Cloud SQL は通常、自動的にレプリカを再作成します。この last_sql_errno 指標からその理由がわかります。

ネットワーク ラグ
cloudsql.googleapis.com/database/replication/network_lag

プライマリ データベースのバイナリログに書き込んでから、レプリカの I/O スレッドに到達するまでにかかる時間(秒)。

network_lag がゼロまたはごくわずかであっても、replica_lag が高い場合は、SQL スレッドがレプリケーションの変更を迅速に適用できないことを示します。

レプリケーションを検証する

レプリケーションが機能していることを確認するには、レプリカに対して次のステートメントを実行します。

mysql> SHOW SLAVE STATUS\G;
*************************** 1. row ***************************
               Slave_IO_State: Queueing master event to the relay log
                  Master_Host: xx.xxx.xxx.xxx
                  Master_User: cloudsqlreplica
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: mysql-bin.199927
          Read_Master_Log_Pos: 83711956
               Relay_Log_File: relay-log.000025
                Relay_Log_Pos: 24214376
        Relay_Master_Log_File: mysql-bin.199898
             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: 24214163
              Relay_Log_Space: 3128686571
              Until_Condition: None
               Until_Log_File:
                Until_Log_Pos: 0
           Master_SSL_Allowed: Yes
           Master_SSL_CA_File: master_server_ca.pem
           Master_SSL_CA_Path: /mysql/datadir
              Master_SSL_Cert: replica_cert.pem
            Master_SSL_Cipher:
               Master_SSL_Key: replica_pkey.pem
        Seconds_Behind_Master: 2627
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: 321071839
                  Master_UUID: 437d04e9-8456-11e8-b13d-42010a80027b
             Master_Info_File: mysql.slave_master_info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: System lock
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set: 437d04e9-8456-11e8-b13d-42010a80027b:52111095710-52120776390
            Executed_Gtid_Set: 437d04e9-8456-11e8-b13d-42010a80027b:1-52113039508
                Auto_Position: 1
         Replicate_Rewrite_DB:
                 Channel_Name:
           Master_TLS_Version:
1 row in set (0.00 sec)

レプリケーションが行われている場合は、Slave_IO_State(最初の列)に Waiting for master to send event または類似のメッセージが表示されます。また、Last_IO_Error フィールドは空です。

レプリケーションが行われていない場合、Slave_IO_State 列にステータス Connecting to master が表示され、Last_IO_Error 列にはステータス error connecting to master cloudsqlreplica@x.x.x.x:3306 が表示されます。

MySQL のドキュメントによると、レプリケーション ラグに関連するその他の興味深いフィールドは次のとおりです。

フィールド説明
Master_Log_File
I/O スレッドが現在読み取るソース バイナリ ログファイルの名前。
Read_Master_Log_Pos
I/O スレッドが読み取った現在のソース バイナリ ログファイル内の位置。
Relay_Log_File
SQL スレッドが現在読み込んで実行しているリレーログ ファイルの名前。
Relay_Log_Pos
SQL スレッドが読み取って実行した現在のリレーログ ファイル内の位置。
Relay_Master_Log_File
SQL スレッドによって実行された最新のイベントを含むソース バイナリログ ファイルの名前。

上の例では、Relay_Master_Log_File の値は mysql-bin.199898 です。Master_Log_File の値は mysql-bin.199927 です。数値のサフィックス 199898 は 199927 未満です。これは、レプリカが新しい mysql-bin.199927 ログファイルを受信しましたが、まだ古い mysql-bin.199898 を適用していることを意味します。

この場合、レプリカで SQL スレッドのラグが発生します。

プライマリ データベースに接続して実行することもできます。

SHOW MASTER STATUS;

このコマンドは、プライマリ データベースに書き込まれているバイナリログ ファイルを表示します。

プライマリ データベースのバイナリログ ファイルがレプリカの Master_Log_File より新しい場合は、I/O スレッドが遅れていることを意味します。レプリカはまだプライマリ データベースから古いバイナリログ ファイルを読み取っています。

I/O スレッドが遅延している場合、network_lag 指標も高くなります。SQL スレッドは遅延しているが、I/O スレッドは遅延していない場合、network_lag 指標はそれほど大きくありませんが、replica_lag は高くなります。

前述のコマンドでは、ラグの発生中にラグの詳細を確認できますが、指標 network_lagreplica_lag を使用すると、ラグが発生した過去の発生期間を確認できます。