MySQL道普請便り

第275回Replication Applier Metricsでレプリケーションの詳細を確認する

レプリカ遅延を確認するときは、SHOW REPLICA STATUSSeconds_Behind_Sourceをよく見ます。ただし、この値だけでは遅延の原因まではわかりません。大きなトランザクションを適用しているのか、workerが足りないのか、依存関係やcommit順序を待っているのかは、別に調べる必要があります。

Replication Applier MetricsはMySQL 9.1で追加された機能です。9.1から9.6まではEnterprise Edition向けでしたが、9.7からCommunity Editionでも利用できます。今回はMySQL 9.7 LTSのCommunity Editionを使って動作を確認します。

Replication Applier Metricsについて

Replication Applier MetricsはWL#15620でMySQL 9.1.0に追加されました。この時点ではEnterprise Editionだけで利用できました。その後、WL#17234により、MySQL 9.7.0から全Editionで利用できるようになりました。

WL#15620によると、従来のMTA統計はエラーログへ最大120秒程度の間隔で出力されていました。エラーログの情報はSQLで取得しにくく、時系列での監視にも使いにくいものでした。Replication Applier Metricsでは、これらの情報をPerformance Schemaから取得できます。

従来の確認方法

SHOW REPLICA STATUSでは、接続状態、GTID、relay logの位置、エラーなどを確認できます。Seconds_Behind_Sourceでは遅延時間も確認できます。ただし、どこで待っているかまではわかりません。また、applierを停止するとSeconds_Behind_SourceNULLになります。

既存のreplication_applier_progress_by_workerテーブルでは、workerのthread ID、GTID、retry、errorなどを確認できます。Replication Applier Metricsでは、これに加えて未処理トランザクションの件数とサイズ、coordinatorの待機理由、workerの適用状況を確認できます。

2つのPerformance Schemaテーブル

利用するには、次のSQLでコンポーネントをインストールします。インストール後は対象channelを開始し直します。

INSTALL COMPONENT 'file://component_replication_applier_metrics';

追加されるのは次のテーブルです。

  • replication_applier_metrics:channel単位の累積値
  • replication_applier_progress_by_worker:worker単位の現在値

replication_applier_metricsのカラム

このテーブルはchannelごとに1行を返します。時間の単位はナノ秒です。COUNTSUM_TIMEは累積値です。

カラム 意味
CHANNEL_NAME replication channel名。デフォルトchannelは空文字列
TOTAL_ACTIVE_TIME_DURATION applier稼働時間の累計
LAST_APPLIER_START applierの最終開始日時
TRANSACTIONS_COMMITTED_COUNT applierがcommitまで完了したトランザクション数
TRANSACTIONS_ONGOING_COUNT workerが現在処理しているトランザクション数
TRANSACTIONS_PENDING_COUNT receiverが受信済みで未commitのトランザクション数。処理中のものを含む値
TRANSACTIONS_COMMITTED_SIZE_BYTES_SUM commit済みトランザクションの合計サイズ
TRANSACTIONS_ONGOING_FULL_SIZE_BYTES_SUM 現在処理中のトランザクションの総サイズ。複数worker分の合計
TRANSACTIONS_ONGOING_PROGRESS_SIZE_BYTES_SUM 処理中トランザクションで適用済みのサイズ。複数worker分の合計
TRANSACTIONS_PENDING_SIZE_BYTES_SUM 受信済みで未commitのトランザクションの合計サイズ。算出できない場合はNULL
EVENTS_COMMITTED_COUNT commit済みトランザクションに含まれるbinlog event数
WAITS_FOR_WORK_FROM_SOURCE_COUNT relay logへの次の仕事をapplierが待った回数
WAITS_FOR_WORK_FROM_SOURCE_SUM_TIME 上記待機時間の累計
WAITS_FOR_AVAILABLE_WORKER_COUNT coordinatorが空きworkerを待った回数
WAITS_FOR_AVAILABLE_WORKER_SUM_TIME 上記待機時間の累計
WAITS_COMMIT_SCHEDULE_DEPENDENCY_COUNT 先行トランザクションとのschedule dependency解消を待った回数
WAITS_COMMIT_SCHEDULE_DEPENDENCY_SUM_TIME 上記待機時間の累計
WAITS_FOR_WORKER_QUEUE_MEMORY_COUNT worker queue全体がreplica_pending_jobs_size_maxのメモリ上限内に収まるのを待った回数
WAITS_FOR_WORKER_QUEUE_MEMORY_SUM_TIME 上記待機時間の累計
WAITS_WORKER_QUEUES_FULL_COUNT worker queueの空きを待った回数
WAITS_WORKER_QUEUES_FULL_SUM_TIME 上記待機時間の累計
WAITS_DUE_TO_COMMIT_ORDER_COUNT workerが先行トランザクションのcommitを待った回数
WAITS_DUE_TO_COMMIT_ORDER_SUM_TIME 上記待機時間の累計
TIME_TO_READ_FROM_RELAY_LOG_SUM_TIME coordinatorによるrelay log読取り時間の累計

replication_applier_progress_by_workerのカラム

こちらはworkerごとの現在値です。9.7ではidle状態のworkerもテーブル示されます。その場合はONGOING_TRANSACTION_TYPEUNASSIGNED、サイズが0になります。

カラム 意味
CHANNEL_NAME workerが所属するreplication channel名
WORKER_ID channel内のworker番号
THREAD_ID 対応するPerformance Schema thread ID。threadsやlock系テーブルとの結合キー
ONGOING_TRANSACTION_TYPE 処理中トランザクションの種別。DMLDDL、未割当てのUNASSIGNED
ONGOING_TRANSACTION_FULL_SIZE_BYTES workerが処理中のトランザクションの総サイズ
ONGOING_TRANSACTION_APPLIED_SIZE_BYTES workerが適用済みのサイズ

ONGOING_TRANSACTION_APPLIED_SIZE_BYTESが増えていないworkerがあれば、THREAD_IDを使ってperformance_schema.threadsやlock系テーブルを確認します。

2つのworkerで待ちを発生させる

検証にはMySQL 9.7.0 LTS Community Serverを使いました。sourceとreplicaを用意し、replicaはreplica_parallel_workers=2replica_preserve_commit_order=ONにしました。replica側でテーブルをロックしたまま、sourceから3つのトランザクションを実行します。

replicaの別session
LOCK TABLES lab.article_slow WRITE;
source。各文は別トランザクション
INSERT INTO lab.article_slow VALUES (2, 'blocked first transaction');
INSERT INTO lab.article_fast_a VALUES (2, 'applied but cannot commit first');
INSERT INTO lab.article_fast_b VALUES (2, 'waits for a free worker');

ロックしている間に、channel単位の情報を取得します。

SELECT *
FROM performance_schema.replication_applier_metrics\G
*************************** 1. row ***************************
                                CHANNEL_NAME:
                  TOTAL_ACTIVE_TIME_DURATION: 144676734327
                          LAST_APPLIER_START: 2026-07-15 00:08:54
                TRANSACTIONS_COMMITTED_COUNT: 8
                  TRANSACTIONS_ONGOING_COUNT: 2
                  TRANSACTIONS_PENDING_COUNT: 3
       TRANSACTIONS_COMMITTED_SIZE_BYTES_SUM: 2241
    TRANSACTIONS_ONGOING_FULL_SIZE_BYTES_SUM: 634
TRANSACTIONS_ONGOING_PROGRESS_SIZE_BYTES_SUM: 505
         TRANSACTIONS_PENDING_SIZE_BYTES_SUM: NULL
                      EVENTS_COMMITTED_COUNT: 28
            WAITS_FOR_WORK_FROM_SOURCE_COUNT: 15
         WAITS_FOR_WORK_FROM_SOURCE_SUM_TIME: 113511377054
            WAITS_FOR_AVAILABLE_WORKER_COUNT: 2
         WAITS_FOR_AVAILABLE_WORKER_SUM_TIME: 31124522291
      WAITS_COMMIT_SCHEDULE_DEPENDENCY_COUNT: 2
   WAITS_COMMIT_SCHEDULE_DEPENDENCY_SUM_TIME: 35017
         WAITS_FOR_WORKER_QUEUE_MEMORY_COUNT: 0
      WAITS_FOR_WORKER_QUEUE_MEMORY_SUM_TIME: 0
              WAITS_WORKER_QUEUES_FULL_COUNT: 0
           WAITS_WORKER_QUEUES_FULL_SUM_TIME: 0
             WAITS_DUE_TO_COMMIT_ORDER_COUNT: 2
          WAITS_DUE_TO_COMMIT_ORDER_SUM_TIME: 31125210259
        TIME_TO_READ_FROM_RELAY_LOG_SUM_TIME: 148113

次にworker単位の情報を確認します。

SELECT *
FROM performance_schema.replication_applier_progress_by_worker\G
*************************** 1. row ***************************
                          CHANNEL_NAME:
                             WORKER_ID: 0
                             THREAD_ID: 50
              ONGOING_TRANSACTION_TYPE: DML
   ONGOING_TRANSACTION_FULL_SIZE_BYTES: 313
ONGOING_TRANSACTION_APPLIED_SIZE_BYTES: 215
*************************** 2. row ***************************
                          CHANNEL_NAME:
                             WORKER_ID: 1
                             THREAD_ID: 51
              ONGOING_TRANSACTION_TYPE: DML
   ONGOING_TRANSACTION_FULL_SIZE_BYTES: 321
ONGOING_TRANSACTION_APPLIED_SIZE_BYTES: 290

THREAD_IDを使ってperformance_schema.threadsも確認します。

SELECT p.WORKER_ID, p.THREAD_ID, t.PROCESSLIST_STATE
FROM performance_schema.replication_applier_progress_by_worker AS p
LEFT JOIN performance_schema.threads AS t
  ON t.THREAD_ID = p.THREAD_ID
ORDER BY p.WORKER_ID\G
*************************** 1. row ***************************
        WORKER_ID: 0
        THREAD_ID: 50
PROCESSLIST_STATE: Waiting for table metadata lock
*************************** 2. row ***************************
        WORKER_ID: 1
        THREAD_ID: 51
PROCESSLIST_STATE: Waiting for preceding transaction to commit

worker 0はmetadata lockを待っています。worker 1は適用をほぼ終えていますが、先行トランザクションのcommitを待っています。2つのworkerが両方とも待っているため、coordinatorは3つ目のトランザクションをworkerへ渡せません。この例では、ロック待ち、commit順序待ち、空きworker待ちが発生していることを確認できました。

Apply待ちを直接表すカラムはありません。workerの進捗が増えていなければ、thread IDからstatement、stage、lockを確認します。

他の処理でも確認する

3,000行、約3MBのINSERTをreplicaのtable lockで止めました。workerにはDML、総サイズ3,034,363bytes、適用済み207bytesと表示されました。3,000行のUPDATEでは、総サイズ6,069,247bytes、適用済み216bytesでした。大きなトランザクションを処理していることと、ほとんど進んでいないことがわかります。

ALTER TABLEをmetadata lockで止めた場合はDDL、総サイズ218bytes、適用済み77bytesとなりました。threadの状態はWaiting for table metadata lockでした。また、applierを停止して10トランザクションを受信させると、Seconds_Behind_SourceNULLですが、TRANSACTIONS_PENDING_COUNTは10になりました。

sourceでcommitしていないトランザクションは、replica側のcommitted、ongoing、pendingには表示されませんでした。まだbinlogへ書き込まれていないためです。この場合はsource側を確認します。

監視するときの見方

値は累積値なので、監視では前回の取得結果との差分を見ます。pendingが増えている場合は、空きworker、schedule dependency、queue、commit順序のどの待ちが増えたかを確認します。その後、workerの進捗とthreadのlockを確認します。

1回のSELECTで取得した各カラムは、完全に同じ時点の値ではありません。取得中にも適用処理が進むためです。また、収集開始前からrelay logにあったトランザクションは、pending bytesがNULLになる場合があります。SHOW REPLICA STATUSや既存のreplication表と組み合わせて確認します。

まとめ

Replication Applier MetricsがMySQL 9.7 LTS Community Editionで利用できるようになりました。Seconds_Behind_Sourceだけではわからなかった待機理由やworkerの進捗を確認できます。SHOW REPLICA STATUSreplication_applier_progress_by_workerと組み合わせることでレプリカ遅延のより詳細な調査が可能となりました。

参考資料

おすすめ記事

記事・ニュース一覧