Amazon Web Services ブログ

Amazon RDS for MySQL、Amazon RDS for MariaDB、Amazon Aurora MySQL におけるマルチスレッドレプリケーションの概要とベストプラクティス

本記事は 2025 年 10 月 21 日 に公開された「Overview and best practices of multithreaded replication in Amazon RDS for MySQL, Amazon RDS for MariaDB, and Amazon Aurora MySQL」を翻訳したものです。

マルチスレッドレプリケーション (MTR) は、MySQL のバイナリログレプリケーション性能を向上させる機能です。Amazon Aurora MySQL-Compatible Edition、Amazon Relational Database Service (Amazon RDS) for MySQL、Amazon RDS for MariaDB など、高スループットのデータベースで特に効果を発揮します。標準的なレプリケーション構成はもちろん、Amazon RDS Blue/Green デプロイのような最新の運用手法でも活用でき、ダウンタイムを抑えたデータベースのアップグレードや変更に役立ちます。

本記事はシリーズの第 1 回として、パラレルレプリケーション技術を中心に MySQL レプリケーションを詳しく解説します。まず MySQL レプリケーションの仕組みを概観し、マルチスレッドレプリケーションの詳細を解説します。そして、主要な設定オプションと最適化のベストプラクティスを紹介します。第 2 回では、マルチスレッドレプリケーションの監視について取り上げます。

MySQL バイナリログレプリケーションの概要

次の図は、シングルスレッドレプリケーションにおける MySQL レプリケーションのアーキテクチャを示しています。

MySQL replication arch

ソースとレプリカの各コンポーネントを詳しく見ていきましょう。

ソース側

  • バイナリログが有効な状態で DML (Data Manipulation Language)、DCL (Data Control Language)、DDL (Data Definition Language) がソースで実行されコミットされると、MySQL はステートメントまたはトランザクションをイベントとしてバイナリログファイルに永続化します。永続化されたイベントは、レプリカがダンプスレッドを通じて取得します。
  • バイナリログダンプスレッド – レプリカが接続すると、ソースデータベースはレプリカごとにバイナリログの内容を送信するスレッドを作成します。ソースで SHOW PROCESSLIST を実行すると、Binlog Dump スレッドとして確認できます。

レプリカ側

  • IO スレッド – レプリカは IO (レシーバー) スレッドを作成してソースに接続し、バイナリログの更新を取得します。IO スレッドはソースの Binlog Dump スレッドから送信された更新を読み取り、レプリカのリレーログを構成するローカルファイルにコピーします。SHOW REPLICA STATUS の出力では Replica_IO_running として表示されます。シングルスレッドレプリケーションでも MTR でも IO スレッドは 1 つだけで、ボトルネックになることはほとんどありません。
  • SQL (アプライヤー) スレッド – リレーログを読み取り、レプリカのデータベースに適用します (通常のクライアントと同様)。シングルスレッドレプリケーション (MySQL 8.0.27 以前のデフォルト) では SQL スレッドは 1 つだけです。MTR では複数の SQL スレッドが動作します。
  • レプリカでバイナリログが有効な場合、SQLスレッドはリレーログのトランザクションを適用してコミットしますが、このときレプリカ自身のバイナリログへの書き込みも発生します。バイナリログの負荷によりレプリケーション遅延が発生する可能性があります。

MTR の概要

MTR を有効にする (slave_parallel_workers または replica_parallel_workers を 1 より大きい値に設定する) と、SQL スレッドはコーディネータースレッドと複数のワーカースレッドの 2 種類に分かれます。コーディネータースレッドはリレーログからイベントを読み取り、イベントの依存関係を分析して、ワーカースレッドに並列実行を割り当てます。イベントの依存関係はソースインスタンス側で追跡され、データの整合性を保ちつつレプリカ上で安全に並列実行できるイベントが判断されます。ワーカー (アプライヤー) スレッドはレプリケーションの実行部分を担い、レプリカ上でトランザクションを再生します。コーディネーターとワーカーに分離することで、レプリケーションイベントの並列処理を効率化できます。

次の例では、パラメータ replica_parallel_workers を 4 に設定しています。リードレプリカで Select * from information_schema.processlist where User='system user'; を実行すると、合計 6 つのスレッドが出力されます。IO スレッド 1 つ、コーディネータースレッド 1 つ、ワーカースレッド 4 つです。

  • IO_THREAD: レプリケーションチャネルごとに 1 つ (以下の出力では Id: 419)
  • SQL スレッド:
    • コーディネータースレッド: レプリケーションチャネルごとに 1 つ (以下の出力では Id: 420)
    • ワーカースレッド: チャネルごとに replica_parallel_workers で指定した数 (以下の出力では Id: 421-424)
select * from information_schema.processlist where User='system user';
+------+-----------------+--------------------+------+---------+--------+----------------------------------------------------------+-----------------------+
| Id   | User            | Host               | db   | Command | Time   | State                                                    | Info                  |
+------+-----------------+--------------------+------+---------+--------+----------------------------------------------------------+-----------------------+
|  419 | system user     | connecting host    | NULL | Connect | 494497 | Waiting for source to send event                         | NULL                  |
|  420 | system user     |                    | NULL | Query   |      9 | Replica has read all relay log; waiting for more updates | NULL                  |
|  421 | system user     |                    | NULL | Query   |      9 | Waiting for an event from Coordinator                    | NULL                  |
|  422 | system user     |                    | NULL | Query   | 494925 | Waiting for an event from Coordinator                    | NULL                  |
|  423 | system user     |                    | NULL | Query   | 494925 | Waiting for an event from Coordinator                    | NULL                  |
|  424 | system user     |                    | NULL | Query   | 494925 | Waiting for an event from Coordinator                    | NULL                  |
+------+-----------------+--------------------+------+---------+--------+----------------------------------------------------------+-----------------------+

MTR の仕組み

MTR はレプリケーション依存関係の追跡に基づいており、データの整合性を維持しながらレプリカサーバー上でトランザクションを安全に並列実行できるかを判断します。MySQL では依存関係の追跡に COMMIT ORDER と WRITESET という 2 つの主要な方式を提供しています。

COMMIT_ORDER 依存関係追跡は、ソースサーバーでのグループコミットのタイミングに基づきます。ソースが書き込む依存関係情報は論理タイムスタンプとしてバイナリログイベントに記録されます。各トランザクションには依存関係の判断に使う 2 つの論理タイムスタンプがあります。

  • sequence_number – 各バイナリログの最初のトランザクションは 1、2 番目は 2、と続きます。バイナリログファイルごとに 1 から振り直されます。
  • last_committed – 現在のトランザクションと競合する、直近にコミットされたトランザクションの sequence_number を指します。この値は常に sequence_number より小さくなります。

次のコードブロックは、mysqlbinlog でデコードしたバイナリログの簡略化されたスニペットです。上の例では、シーケンス番号 2347、2348、2349、2351 のトランザクションはレプリカ上で並列実行が可能です。いずれも last committed タイムスタンプがこれらより前のトランザクションを指しているためです。シーケンス番号 2350 のトランザクションは 2348 に依存しているため、2347、2348、2349、2351 と並列にレプリケートすることはできません。

#308741 15:23:45... last committed=2345 sequence number=2346
#308741 15:23:45... last committed=2346 sequence number=2347
#308741 15:23:45... last committed=2346 sequence number=2348
#308741 15:23:45... last committed=2346 sequence number=2349
#308741 15:23:45... last committed=2348 sequence number=2350
#308741 15:23:45... last committed=2345 sequence number=2351

COMMIT_ORDER は、ソースサーバーの同時実行ワークロードが多い環境や、binlog_group_commit_sync_delay パラメータでグループコミットサイズを大きく設定している場合に効果的です (詳細は後述)。ただし、タイミングに大きく左右され、実際のデータアクセスパターンの独立性は考慮しないため、実環境では期待ほどの並列度を達成できないことがあります。

WRITESET は、COMMIT ORDER のコミット時間ウィンドウによる単純な判定を超えた、より高度な依存関係追跡方式です。行レベルで実際のデータ変更を追跡します。トランザクションが変更した各行に対して、MySQL はユニークなハッシュを生成します。トランザクションのハッシュの集合がライトセット (write set) を構成します。ライトセットが重複しないトランザクションは、ソースでの実行順序やセッション、コミットタイミングに関係なく、レプリカ上で並列実行できます。時間的な関係ではなく実際のデータ依存関係を追跡するため、レプリカでのレプリケーション並列度を大幅に向上でき、COMMIT ORDER と比較して性能とスループットの改善が期待できます。ただし、WRITESET が COMMIT ORDER を上回らないケースもあり、ベストプラクティスのセクションで詳しく解説します。

MTR の設定とベストプラクティス

MTR は RDS for MySQL 5.7、8.0、8.4、Amazon RDS for MariaDB 10.0.5 以上、Aurora MySQL バージョン 3、Aurora MySQL バージョン 2.12.1 以上でサポートされています。ただし、MTR を最大限に活用するには、ソースサーバーとレプリカサーバーの両方を新しいバージョンにアップグレードすることを強く推奨します。本記事執筆時点では、ソースサーバーに RDS MySQL 5.7.44 以上、Aurora MySQL 2.12.5 以上、RDS MySQL 8.0.35 以上、Aurora MySQL 3.10.0 以上を使用すると最適な性能が得られます。レプリカサーバーには RDS MySQL 8.0.35 以上、Aurora MySQL 3.10.0 以上の使用を推奨します。以下では、RDS for MySQL、RDS for MariaDB、Aurora MySQL 環境で MTR を最適化するための主要な設定パラメータとベストプラクティスを紹介します。バージョン間の用語変更により、パラメータ名が異なる場合があります。

ソース側

binlog_transaction_dependency_tracking

有効な値は COMMIT_ORDER、WRITESET、WRITESET_SESSION です。COMMIT_ORDER と WRITESET についてはすでに説明しました。WRITESET_SESSION は WRITESET と同じですが、追加の制約があります。同一クライアントセッションでコミットされた 2 つのトランザクションは並列に適用されません。

Improving the Parallel Applier with Writeset-based Dependency Tracking で確認できるように、ソース側の同時実行ワークロードが高い環境では WRITESET と COMMIT_ORDER の性能は同程度ですが、同時実行性が低い環境では WRITESET の方が高い性能を示します。実際のアプリケーションは、高スレッド数で実行するよう設計された sysbench などのベンチマークテストよりも同時 DML レベルが低い傾向にあるため、この点は実運用で特に重要です。WRITESET (アプリケーション要件に応じて WRITESET_SESSION) の設定を推奨します。

WRITESET を使用できず、MySQL が非 WRITESET にフォールバックするケースもあります。

  • プライマリキーまたはユニークキーのないテーブル – WRITESET 依存関係追跡は、変更された行を一意に識別する機能に依存しています。プライマリキーやユニークキーがないと、トランザクションによる変更のフルセットを正確に追跡できません。WRITESET の使用有無にかかわらず、パフォーマンスの問題を避けるため、すべての InnoDB テーブルにプライマリキーまたはユニークキーを設定してください。詳細はプライマリキーの最適化を参照してください。
  • DDL ステートメントを含むトランザクション – CREATE TABLE や ALTER TABLE などの DDL ステートメントは、データではなくデータベーススキーマを変更します。スキーマ変更は通常のデータ変更と同じ方法では追跡しにくく、依存関係追跡の精度に影響します。DML の多い期間中は DDL 操作を最小限に抑えるか避けることを推奨します。レプリケーション性能だけでなく、データベース管理全般のベストプラクティスとしても有効です。
  • 外部キー関係で親テーブルにアクセスするトランザクション – 外部キー関係を持つ子テーブルのデータをトランザクションが変更する場合、親テーブルへの変更がライトセットに完全にキャプチャされない可能性があり、依存関係追跡が不完全になることがあります。

binlog_transaction_dependency_history_size

メモリに保持する行ハッシュの上限数を設定するパラメータです。特定の行を最後に変更したトランザクションの検索に使われ、上限に達すると履歴はパージされます。4xlarge 以上の大きなインスタンスクラスではこのパラメータを増やすことができます。ただし、値が大きすぎるとメモリ消費の増加や依存関係追跡の CPU 使用率上昇でパフォーマンスが低下する可能性があります。トレードオフを把握するため十分なテストを行ってください。

binlog_format

バイナリロギング形式を設定するシステム変数で、STATEMENT、ROW、MIXED のいずれかを指定できます。binlog_format は MySQL 8.0.34 で非推奨となり、将来のバージョンで削除される予定です。行ベース以外のロギング形式も将来削除される可能性があります。RDS for MySQL、RDS for MariaDB、Aurora MySQL では、性能と互換性の観点から binlog_format=Row の使用を推奨します。

binlog_group_commit_sync_delay

binlog_group_commit_sync_delay は、バイナリログのコミットがディスクに同期されるまでの待機時間 (マイクロ秒) を設定します。binlog_transaction_dependency_tracking = COMMIT_ORDER と組み合わせると特に効果的です。binlog_transaction_dependency_tracking = WRITESET の場合は依存関係追跡に影響しません。ソース側のコミットプロセスにわずかな遅延を導入し、各グループコミットにより多くの書き込みをバッチ処理することで、コミットウィンドウが拡大しレプリカでの並列実行が増えます。ただし、ソースサーバーのトランザクションレイテンシも増加するため、クライアントアプリケーションの性能に影響する可能性があります。レプリケーション性能と許容できるトランザクションレイテンシのバランスを見つけるため、十分なテストを推奨します。

トランザクションサイズ

MySQL では、適切なトランザクションサイズの維持が性能最適化の鍵です。大きなトランザクションはロックを長時間保持して他の操作をブロックし、システム全体のスループットを低下させます。また、RollbackSegmentHistoryListLength を増加させ、データベース全体の性能に影響を与える可能性があります。MTR の観点では、大きなトランザクションはレプリカでの並列性を大幅に制限し、レプリケーション遅延を引き起こします (replica_pending_jobs_size_max のセクションで詳述)。可能な限り大きなトランザクションを避け、大量データの変更が必要な場合は小さなチャンクに分割して個別のトランザクションで処理してください。

レプリカ側

binlog_format

Aurora MySQL はクラスター内レプリケーションやバックアップ/リカバリにバイナリログを必要としません。ダウンストリームレプリケーションがなければ、DB クラスターパラメータグループで binlog_format を OFF に設定し、バイナリロギングを無効にすることでレプリケーション性能が向上します。binlog_format を OFF に設定すると、データベース内の binlog_format セッション変数はデフォルト値の ROW にリセットされます。RDS for MySQL や RDS for MariaDB のレプリカサーバーでも、自動バックアップを無効化してバイナリロギングをオフにすることで同様の性能向上が得られます。ただし、レプリカのポイントインタイムリカバリができなくなるトレードオフがあります。

replica_parallel_type または slave_parallel_type

指定可能な値:

  • LOGICAL_CLOCK – ソースがバイナリログに書き込むタイムスタンプに基づいて、レプリカ上でトランザクションを並列に適用します。トランザクション間の依存関係を論理タイムスタンプで追跡し、可能な限り並列化します。
  • DATABASE – 異なるデータベースを更新するトランザクションを並列に適用します。データが複数のデータベースにパーティショニングされ、独立して同時に更新される場合にのみ適しています。クロスデータベース制約がある場合、レプリカ上で制約違反が発生する可能性があります。

DATABASE を使う特定の理由がなければ、依存関係をより細かく追跡し並列性に優れた LOGICAL_CLOCK を推奨します。RDS for MySQL 8.0 と Aurora MySQL 3 のすべてのバージョンで、デフォルト値は LOGICAL_CLOCK です。

replica_parallel_workers または slave_parallel_workers

1 より大きい値を設定するとレプリカで MTR が有効になり、レプリケーショントランザクションを並列実行するアプライヤースレッド数を指定します。RDS for MySQL 8.0.27 および Aurora MySQL 3.04.0 以前は、デフォルト値は 0 で、レプリカはシングルワーカースレッドで動作します。RDS for MySQL 8.0.27 および Aurora MySQL 3.04.0 以降は、デフォルト値が 4 になり、レプリカはデフォルトでマルチスレッド動作します。replica_parallel_workers の最適値はハードウェアとワークロード特性によって異なります。2xlarge 以上のサーバーであればワーカースレッド 4 から始め、監視を通じてチューニングしてください。チューニングについては次回の記事で取り上げます。高く設定しすぎるとロック競合などにより、かえって性能が低下する可能性があります。

replica_parallel_workers の変更は即座に反映されず、mysql.rds_stop_replication と mysql.rds_start_replication でレプリケーションを再起動する必要があります。前述のとおり、プライマリキーのないテーブルは replica_parallel_workers が 1 より大きいレプリカでさらに大きな性能低下を引き起こす可能性があります。

replica_pending_jobs_size_max

レプリカサーバー上でワーカースレッドの適用待ちイベントを保持するキューの最大メモリを設定します。ソフトリミットのため、通常のワークロードに合わせて設定できます。異常に大きなイベントがこのサイズを超えると、すべてのワーカースレッドのキューが空になるまでトランザクションが保留され、大きなトランザクションの完了まで後続のトランザクションもブロックされます。イベント処理は保証されますが、ワーカーの同時実行性が大幅に低下しレプリケーション遅延につながります。一般的なイベントサイズを十分に処理できる値を設定してください。また、マルチスレッドレプリカでは、MySQL ドキュメントに記載のとおり、大きなパケットによるレプリケーション障害を防ぐため、ソースの max_allowed_packet 設定以上の値を設定すべきです。

aurora_binlog_replication_sec_index_parallel_workers (Aurora MySQL のみ)

Aurora MySQL バージョン 3.06 以上で利用可能です。複数のセカンダリインデックスを持つ大きなテーブルのレプリケーション性能を改善するため、スレッドプールを導入してセカンダリインデックスの変更をバイナリログレプリカ上で並列に適用します。aurora_binlog_replication_sec_index_parallel_workers DB クラスターパラメータで、セカンダリインデックス変更を適用する並列スレッドの総数を制御します。デフォルトは 0 (無効) です。有効化にインスタンスの再起動は不要で、進行中のレプリケーションを停止し、並列ワーカースレッド数を設定してからレプリケーションを再開します。

aurora_in_memory_relaylog (Aurora MySQL のみ)

Aurora MySQL バージョン 3.10 で、バイナリログレプリカ向けのインメモリリレーログキャッシュのサポートが拡張されました。バージョン 3.05 で最初に導入されたこの機能は、バイナリログレプリケーションのスループットを最大 40% 向上させます。インメモリリレーログキャッシュは、シングルスレッドバイナリログレプリケーション、GTID 自動ポジショニングが有効なマルチスレッドレプリケーション、そしてバージョン 3.10 以降は replica_preserve_commit_order = ON のマルチスレッドレプリケーション (GTID なしでも可) でデフォルト有効です。

replica_preserve_commit_order または slave_preserve_commit_order

replica_preserve_commit_order (または slave_preserve_commit_order) を ON に設定すると (MySQL 8.0.27 以降のデフォルト)、トランザクションはレプリカのリレーログに記録された順序で実行・コミットされます。トランザクションシーケンスのギャップを防ぎ、ソースと同じトランザクション履歴をレプリカ上で保持します。replica_preserve_commit_order=ON に設定すると、実行中のワーカースレッドは先行するすべてのトランザクションがコミットされるまで待機します。待機中のステータスは Waiting for preceding transaction to commit と表示されます。レプリカの並列性がわずかに低下する可能性がありますが、データの整合性のため、特にコミット順序に依存するアプリケーションでは有効にすることを推奨します。

最後に、予期しない停止に対する耐障害性を高めるため、ソースでグローバルトランザクション識別子 (GTID) レプリケーションを有効にし、レプリカでも GTID を許可することを推奨します。有効にするには、ソースとレプリカの両方で gtid_mode を ON_PERMISSIVE に設定します。GTID ベースのレプリケーションの詳細は、GTID ベースのレプリケーションの使用を参照してください。

まとめ

本記事では、MySQL レプリケーションと MTR の仕組み、主要な設定パラメータ、ベストプラクティスを解説しました。次回の記事では、パラレルレプリケーションの監視方法を紹介します。

著者について

Huy Nguyen

Huy Nguyen

Huy は、AWS サポートのシニアエンジニア。Amazon RDS と Amazon Aurora を専門とし、お客様が AWS クラウドでスケーラブルで高可用性かつセキュアなソリューションを構築できるよう、ガイダンスと技術支援を提供しています。

Arun Gadila

Arun Gadila

Arun は、AWS の Cloud Support Database Engineer II。3.5 年以上の経験を持ち、RDS for MySQL、Aurora MySQL、RDS for SQL Server を専門としています。RDS MySQL と Aurora MySQL の両方で Subject Matter Expert (SME) として認められ、深い技術知識を活かしてお客様のデータベース環境の最適化と複雑な課題の解決を支援しています。

Marc Reilly

Marc Reilly

Marc は、Amazon Aurora MySQL チームのシニアデータベースエンジニア。


この記事は、Solutions Architect の Shinya Sugiyama が翻訳を担当しました。