RDS for MySQLでマルチスレッドレプリケーションを有効にする


はじめに

MySQL 5.7 からマルチスレッドレプリケーションを有効にすることで、レプリケーションの処理を並列に実行することができるようになります。この機能を使えば、更新処理が多いシステムでもレプリケーション遅延が発生しにくくなります。

マルチスレッドレプリケーションはデフォルトでは無効になっていて、有効にする場合も、いくつかのパラメーターも含めて変更しないとプライマリとレプリカで実行順序が異なることによるデータの不整合が起こる可能性があったり、特定のパラメーターを変更する場合、パラメーターグループから変更できないものもあるのでRDSで使用する場合はちょっとした工夫が必要だったります。

MySQLのレプリケーションについて

下記の図はMySQLのレプリケーションを簡易的に示した図です。

アプリケーションからの更新処理はデータ領域とバイナリログへ書き出されます。
バイナリログにに書き出した内容をレプリカ側のMySQLが取得してリレーログに書き込んだ後、データ領域へ更新を反映させます。

アプリケーション側からの更新処理を受け付けるプライマリ側の更新処理はパラレルで行われるのに対し、デフォルトではレプリカのリレーログからデータ領域への更新処理は単一のワーカーでシリアルに処理されるため、同時接続数が多く更新処理も多いシステムの場合、レプリカへの反映が遅れる(レプリケーション遅延が発生する)原因となっていました。

マルチスレッドレプリケーションを有効にするパラメーター

MySQL 5.7以降では下記の3つのパラメーターを変更することでプライマリとのデータ整合性を保ちつつマルチスレッドレプリケーションを有効にすることができます。
(MySQL 8.0.26 以降は slave_ で始まるパラメーター名の多くは replica_ に名称が変更されているので注意が必要です)

replica_parallel_type = LOGICAL_CLOCK

MySQL8.0.26 未満は slave_parallel_type

デフォルト値の DATABASE から LOGICAL_CLOCK に変更します。デフォルト値の DATABASE では、異なるデータベースであれば並列して実行されますが、同一のデータベースではシリアルに実行されるため、単一のデータベースで運用している場合、並列度は上がりません。LOGICAL_CLOCK ではタイムスタンプによって依存関係が考慮されるようになり、単一のデータベース内でも並列して実行されるようになります。

replica_parallel_workers = N

MySQL8.0.26 未満は slave_parallel_workers

並列レプリケーションのスレッド数を指定します。デフォルトは 0 で、並列実行が無効になっているので 1 以上の値を指定します。

replica_preserve_commit_order = 1

MySQL8.0.26未満は slave_preserve_commit_order

デフォルトでは 0 ですが、マルチスレッドレプリケーションを行う場合は 1 に設定します。
1 にすることで、リレーログと同じ順序でレプリカのデータ領域に反映されるようになります。

ただし、このパラメーターは log_binlog_slave_updates が有効になっていないと以下のようなエラーが出てレプリケーションが実行されません。


[ERROR] /rdsdbbin/mysql/bin/mysqld: slave_preserve_commit_order is not supported unless both log_bin and log_slave_updates are enabled.

log_slave_updates はデフォルトで有効になっているので問題ないのですが、log_bin についてはパラメーターグループからは設定変更することができません。

RDSの場合、バックアップ保持期間が1日以上の場合に log_bin が有効になるようです。
レプリカをAWSのコンソールから追加した場合、デフォルトでは0日となっているため、追加後に改めてバックアップ保持期間を1日以上に変更する必要があります。