はじめに
こんにちは。タイミーで Platform Engineer をしている小河原(@kgwryk28)です。
現在、タイミーのシステムで利用しているメインのデータベース(Aurora MySQL)のバージョンアップを進めています。前回の記事では、アップグレードに伴う SQL の互換性や性能の検証について共有しました。
この記事では、そのアップグレードと並行して取り組んでいる Aurora MySQL の GTID モード有効化 を行うにあたって直面した課題と、それぞれをどう解決したかを紹介します。 GTID やレプリケーションに詳しくない方にも読んでいただけるよう、必要な前提はその都度補足しながら説明します。
背景
きっかけは、現状利用しているAurora MySQL 3.x 系(MySQL 8.0 相当の互換性)から Aurora MySQL 8.4 系(MySQL 8.4 相当の互換性)へのアップグレードが視野に入ってきたことです。
タイミーでは Aurora MySQL のデータを BigQuery に連携するため、Google Cloud の Datastream を利用しています。 一方、Datastream の MySQL ソース対応バージョンによると、MySQL 8.4 は「GTID ベースのレプリケーションでのみサポート」 とされています。
現状 Datastream の接続方式として バイナリログの位置ベース です。そのため、8.4 以降を Datastream のソースにするには GTID ベースのレプリケーションが必須 になります。
つまり、将来のバージョン追従を見据えると、どこかで GTID ベースの接続方式へ移行することは避けられません。
現状 Aurora MySQL では GTID モードが有効化されていないため、その前段として Aurora 側で GTID モードを有効化 しておく必要があります。 これが今回 GTID モードの有効化を行う動機です。
前提
本題に入る前に、この記事を読むのに必要な前提を 3 つ押さえます。
① GTIDについて
GTID(Global Transaction Identifier)は、データベース上でコミットされた各トランザクションにクラスター全体で一意な ID を振る仕組みです。 GTIDモードが有効になるとバイナリログ(binlog)に GTID が記録されます。無効の場合はバイナリログに GTID は記録されません。
GTID は、レプリカとしてバイナリログを受け取った際に『どのトランザクションまで実行したか』を管理するために使われます。
GTIDモード が無効なマスターに対してレプリケーション接続する場合、GTIDは利用できません。そのため、バイナリログのファイルとポジションでどこまで実行されたかを管理します。
本記事では用語を統一するため、以下のように呼びます。
GTIDトランザクション:GTIDが含まれているトランザクション匿名トランザクション:GTIDが含まれていないトランザクションGTID方式:レプリカが「どこまで実行したか」を、GTID で管理するかバイナリログの位置ベース方式: レプリカが「どこまで実行したか」を、バイナリログのファイル+ポジションで管理するか
② 4種類のGTIDモード
GTIDモードには4種類の設定値があり、まとめると以下のようになります。
gtid-mode |
マスターとしての書き出し(出力) | レプリカとしての受け入れ(入力) |
|---|---|---|
OFF |
GTID なし | バイナリログの位置ベース方式 |
OFF_PERMISSIVE |
GTID なし | 両方OK(バイナリログの位置ベース方式 / GTID方式) |
ON_PERMISSIVE |
GTID 付きで書き出す | 両方OK(バイナリログの位置ベース方式 / GTID方式) |
ON |
GTID 付きで書き出す | GTID方式 |
注目すべき点は、OFF_PERMISSIVE と ON_PERMISSIVE が移行用の中間状態として設定できることです。この場合、レプリカ側は GTID方式 と バイナリログの位置ベース方式 のどちらでも接続できます。
Aurora MySQLでは、DBクラスターパラメータグループ の gtid-mode で 設定できます。
ただし、これは Static パラメータ であり、既存のクラスターに適用する場合、クラスター全体(すべてのDBインスタンス)の 再起動が必須 です。
③ GTIDベースの整合性に関する設定
もう一つGTID に関連する設定値として enforce_gtid_consistency という設定があります。
GTIDモードで安全にレプリケーションできないようなSQLの実行を、エラーにするか許容するかを設定できるパラメータになります。
設定値は以下の3種類から選ぶことができます。
enforce_gtid_consistency |
GTID 非対応クエリ実行時の挙動 |
|---|---|
OFF |
制限なし |
WARN |
実行は許可、警告ログを出力 |
ON |
エラーにして拒否 |
ON で設定すると以下のようなクエリが実行時にエラーになります。(詳細:
MySQL :: MySQL 8.0 リファレンスマニュアル :: 17.1.3.7 GTID ベースレプリケーションの制約)
CREATE TABLE ... SELECT構文が含まれるクエリ- トランザクション内で
CREATE TEMPORARY TABLEまたはDROP TEMPORARY TABLE構文が含まれるクエリ - トランザクション内で普通のテーブル(InnoDBなど)と一時テーブル(Temporary Table)の同時更新が行われるクエリ
Aurora MySQLでは、DBクラスターパラメータグループ の enforce_gtid_consistency で設定できます。
ただしこれも同様に Static パラメータ であり、既存のクラスターに適用する場合、クラスター全体(すべてのDBインスタンス)の 再起動が必須 です。
解くべき 2 つの課題
GTID モードを有効化するにあたり、次の 2 つの課題に直面しました。 一つずつ深掘りしていきます。
- 課題A:どのようにGTID モードを有効化するか
- 課題B:どのように Datastream を安全に切り替えるか
課題A: どのようにGTID モードを有効化するか
再起動を回避
前述のとおり既存クラスターに対する gtid-mode の変更にはクラスター全体の再起動が必要です。
今回、GTID モードの有効化は、Blue/Green Deployments を利用しました。
元々、データベースのアップグレードはBlue/Green Deployments で行う想定でした。そこで、作成された移行先環境(Green環境)に別途パラメータグループを用意し、Green環境だけでGTIDモードを有効化します。
これにより現行環境(Blue環境)のデータベース再起動を行わずにスイッチオーバーで切り替えることができます。
Blue/Green で Green 側のパラメータを変更する
今回 Green環境で変更したのは以下の 2 つのパラメータです。
| 項目 | Blue(現行) | Green(移行先) |
|---|---|---|
gtid-mode |
OFF_PERMISSIVE |
ON_PERMISSIVE |
enforce_gtid_consistency |
OFF |
WARN |
それぞれなぜこの値にしたのかを見ていきます。
gtid-mode の設定のうち、GTID を有効化する値は ON と ON_PERMISSIVE の 2 つのどちらかになります。
今回 Green環境の設定値として ON_PERMISSIVE を選んだのは、GTIDモードが 無効になっている Blue環境からの匿名トランザクションを Green環境で実行できるように許容するためです。
Green環境を ON にしてしまうと、匿名トランザクションを実行できません。そのため、Blue/Green Deployments による Blue環境 から Green環境へのレプリケーションを設定してもエラーになります。
また、GTIDベースの整合性に関する設定である enforce_gtid_consistency は、実行を許可しつつ警告ログに記録する WARN を選択しました。
ON にすると非対応クエリがエラーになり、既存クエリにも影響するリスクがあります。一方 WARN はクエリの成否を変えません。そのため、切り替え時にクエリ互換性の再検証は不要で、適用後は警告ログを基に確認できます。
課題B: どのように Datastream を安全に切り替えるか
切り替え時の課題
当初は、シンプルに次の手順を想定していました。
Datastream を一度停止し、アップグレード(スイッチオーバー)時に RDS のイベントへ出力されるGreen環境のファイルポジションを指定して再開する。
ところが、ステージング環境で検証したところ、この手順では Datastream を再開できずエラーが発生して停止してしまう ことがわかりました。
根本原因は、スイッチオーバーでクラスターエンドポイントの参照先がBlueからGreenに切り替わることです。その結果、Blue環境とGreen環境ではバイナリログのファイルとポジションに互換性がないため、Datastreamを再開できません。 Managing AWS DMS Tasks with RDS or Aurora Blue/Green Deployments の「How Blue Green switchover affects AWS DMS tasks」セクションに、バイナリログのファイル名とポジションは Blue・Green 間で異なると記載されています。これは DMS のドキュメントですが、ファイル名とポジションが変わるのは DB 側の挙動であるため、Datastream でも同様に問題になります。
【原文】
Because the binary log file names and sequence positions differ between the two instances, DMS can no longer resume from the log position it previously recorded. This causes Full Load + CDC tasks and CDC only tasks to fail or enter an error state.
【日本語訳】
2つのインスタンス間(文脈から、BlueとGreenを指している)でバイナリログのファイル名とシーケンスポジションが異なるため、DMSは以前に記録したログポジションから(キャプチャを)再開できなくなります。これにより、CDCタスクが失敗するかエラー状態になります。
この辺りは少しややこしいので補足します。
前提として、バイナリログのファイル名(例:mysql-bin.000123)とポジション(バイトオフセット)は、各クラスタのライターインスタンスがそれぞれ独立して採番します。 そのため Blue環境 と Green環境 の間では、たとえ同じ「ファイル名+ポジション」であっても、それが指している変更内容(=論理的にどこまで進んだか)は全く別物です。
実際にBlue環境とGreen環境のバイナリログのファイルをそれぞれ確認すると、同一ファイル名のバイナリログは存在するが、ファイルサイズは一致していないことが確認できます。
# Green環境 MySQL [(none)]> SHOW BINARY LOGS; +----------------------------+-----------+-----------+ | Log_name | File_size | Encrypted | +----------------------------+-----------+-----------+ | mysql-bin-changelog.000085 | 42576033 | No | | mysql-bin-changelog.000086 | 157 | No | | mysql-bin-changelog.000087 | 157 | No | | mysql-bin-changelog.000088 | 238579 | No | | mysql-bin-changelog.000089 | 840588 | No | | mysql-bin-changelog.000090 | 168156 | No | | mysql-bin-changelog.000091 | 134237510 | No | | mysql-bin-changelog.000092 | 134217852 | No | | mysql-bin-changelog.000093 | 134221756 | No | | mysql-bin-changelog.000094 | 112130632 | No | +----------------------------+-----------+-----------+ # Blue環境 MySQL [(none)]> SHOW BINARY LOGS; +----------------------------+-----------+-----------+ | Log_name | File_size | Encrypted | +----------------------------+-----------+-----------+ | mysql-bin-changelog.000085 | 134602837 | No | | mysql-bin-changelog.000086 | 134429601 | No | | mysql-bin-changelog.000087 | 134218551 | No | | mysql-bin-changelog.000088 | 134221393 | No | | mysql-bin-changelog.000089 | 13935369 | No | +----------------------------+-----------+-----------+
一方で Datastream は、停止した時点で「Blue環境 のファイル名とポジションで どこまで読んだか」を記憶しています。切り替え後はエンドポイントの参照先が Green環境 に変わるため、Datastream が握っている Blue環境 のファイル名とポジションを Green環境 のバイナリログに対して解釈してしまうことになります。両者に対応関係がない以上、これは正しく再開できません。
しかも厄介なのは、Green環境のファイルとポジションを指定した場合、ズレた地点から再開してしまいます。ズレ方によって、データの不整合が発生するパターンが2パターンに分かれます。
- ① 重複適用:Green 環境の同じファイルポジションが、実際に同期済みの地点より「手前」を指していた場合。すでに適用済みのデータをもう一度流してしまう。
- ② 欠落(スキップ):Green 環境の同じファイルポジションが、まだ同期していない地点より「先」を指していた場合。未同期のデータが飛ばされてしまう。
問題点をまとめると以下のようになります。
- Blue/Green Deployments で作られた Blue環境と Green環境では、バイナリログのファイルとポジションは一致しない
- RDS のイベントには、切り替え時点の Green環境 のバイナリログのファイルとポジションが出力される。切り替え時点の Green環境 のポジションから、対応する Blue環境 のポジションを探すのは困難
- Datastream を再開する際に、Green環境のポジションを指定すると重複適用または未適用のデータがスキップされてデータの不整合が発生してしまう。
つまり、「Blue/Green Deployments による切り替え後に指定すべきファイルとポジションがわからなくなってしまう」という問題でした。
解決した切り替え手順
本文中に「Green環境では GTID方式 で接続しておく」とありましたが、誤りがありました。
正しくは「Green環境では バイナリログの位置ベース方式 で接続しておく」となりますので、該当箇所を修正いたしました。
Datastream を GTIDモードで接続する場合は、接続先のAurora MySQL で
gtid-mode を ON に設定しておく必要があります。詳細は CDC 用に Amazon Aurora MySQL データベースを構成する | Datastream | Google Cloud Documentation をご確認ください。
ご迷惑をおかけした読者の皆様に深くお詫び申し上げます。
そこで、考え方を変えて 「Datastream が参照するクラスターを固定化する」方針にしました。

各 Datastream が 同じクラスターのバイナリログを参照し続けられる よう、接続先を「クラスターエンドポイント」から「ライターエンドポイント(特定インスタンス固定)」に切り替える方針にしました。手順は「切り替え前」「切り替え時」「切り替え後」の3段階です。
Blue/Green Deployments による Green環境への切り替え前
- Green環境経由の Datastream の別系統をあらかじめ作成しておく。Green環境では
GTID方式バイナリログの位置ベース方式 で接続しておく - 既存の Blue / Green それぞれに接続されている Datastream を 一時停止 しておく。
Blue/Green Deployments による Green環境への切り替え後
- Datastream のストリームの接続プロファイルの接続先ホストを変更して再開する。
- Blue 系統:クラスターエンドポイント → Blue(切り替え前クラスター)のライターエンドポイント に変更
- Green 系統:Green のライターエンドポイント → クラスターエンドポイント に変更
事後作業
- Datastream の出力先テーブルを参照しているアプリケーションの参照先を Blue環境から Green環境へ切り替える
この手順により、スイッチオーバー後も 各Datastream は同一クラスターを参照し続けられます。その結果、ファイルとポジションの不一致を回避でき、安全に切り替えられます。
Blue/Green Deployments で切り替えた後、Blue環境はクラスターから切り離されるため、変更内容はBlue環境には反映されません。ただし、切り替え後のGreen環境を参照元としてBlue 側からレプリケーション接続を張れば、Green環境の変更内容をBlue環境へ同期できます。 ロールバック用クラスターのレプリケーション方法は、以前の記事である Aurora MySQLのアップグレード後ロールバック方法を検討してみた や AWSの公式ブログ に書かれているため、ここでは説明を割愛します。
これらの手順により、Datastream によるレプリケーション接続を安全に切り替えることができます。
まとめ
今回は、Aurora MySQL の GTID モード有効化方法と、Datastreamを安全に切り替えるための方法を紹介しました。
今回の移行が完了してもゴールではなく、この先には gtid-mode = ON への引き上げ(匿名トランザクションの完全な消化、enforce_gtid_consistency = ON 化)が続きます。
また徳富さん(@yannKazu1) さんが 並行してDatastream 関連のネットワーク周りのリアーキテクチャも行なっております。 詳細は以下の資料をご覧ください。
tcpdump で追う Datastream 障害調査と Transit Gateway × VPN のリアーキテクチャ設計
もし、今回の自分と同じように Aurora MySQL の GTID 化を検討している方にとって、この記事が何らかの参考になれば幸いです。