はじめに
今回案件でAzure Database for MySQLでのレプリケーションを検証したため、その中で得たノウハウを書き留めておきます。
OSSとしてのMySQLのレプリケーションノウハウは他にもたくさん記事があるのでAzureのマネージドサービスに特化した内容にします。
今回お客様からの要件は以下でした。
- Azure Database for MySQL 5.7からAzure Database for MySQL 8.0へのアップグレード
- 極力サービス停止時間を短くデータ移行
- 異なるリージョン間での移行
まず移行方式としてはExport/Importもありますが、今回はサービス停止時間を短くするためにレプリケーションによる移行としています。
Azure Database for MySQLでレプリケーションを実現するには手段が3つあります。
2つ目、3つ目が公式ドキュメントにPaaSとしてのレプリケーション機能っぽく記載されています。
-
OSSとしてのMySQLのレプリケーション機能
-
データインレプリケーション
Azure Database for MySQLをスレーブとして利用するための機能 -
読取レプリカ
Azure Database for MySQLをマスタとして利用するための機能
それぞれをMySQL(OSS)のレプリケーションで実施する作業をベースに比較してみます。
手順 | 実行ノード | OSS | データインレプリケーション | 読取レプリカ |
---|---|---|---|---|
バイナリログ有効化 | マスタ | 手動 | 手動 | 自動 |
レプリケーション用ユーザ作成、権限付与 | マスタ | 手動 | 手動 | 自動 |
読み取り専用 | マスタ | 手動 | 手動 | 自動 |
バイナリログの位置確認 | マスタ | 手動 | 手動 | 自動 |
マスタのDump取得 | マスタ | 手動 | 手動 | 自動 |
読み取り専用解除 | マスタ | 手動 | 手動 | 自動 |
スレーブにDumpをインポート | スレーブ | 手動 | 手動 | 自動 |
レプリケーション設定 | スレーブ | 手動 (change master toコマンド) |
手動 (ストアドプロシージャ提供) |
自動 |
データインレプリケーション
表を見ればわかるように
データインレプリケーションはほとんどMySQL(OSS)と同じ手順になります。
最後のスレーブからマスタに向ける設定をchange master toコマンドではなくAzureが提供するストアドプロシージャで実現します。
これがなぜかというとAzure Database for MySQLではchange master toコマンドを打つと権限エラーとなります。
ERROR 1227 (42000): Access denied; you need (at least one of) the SUPER or REPLICATION_SLAVE_ADMIN privilege(s) for this operation
これはMySQLではchange master toコマンドを打つためにはREPLICATION_SLAVE_ADMINという権限が必要なのですが、
Azure Database for MySQLで利用者側に提供されるユーザにはこの権限が付与されていないことが原因です。
https://dev.mysql.com/doc/refman/8.0/en/privileges-provided.html#priv_replication-slave-admin
ではなぜAzureのストアドを実行するとレプリケーションできるかというと、このストアドがazure_superuserというSUPER権限を持ったユーザで作られているからです。
そのためMySQL(OSS)の手順の中でこのレプリケーション設定のところだけAzureのストアドを使用する必要があります。
読取レプリカ
逆に読取レプリカはこれぞPaaSの機能、というくらい全てを自動でやってくれます。
ただしこれはマスタと同じバージョンのMySQLのPaaSをスレーブとして作成しレプリケーションしてくれるものなので、今回MySQL5.7からMySQL8.0への移行の手段には使えません。
実をいうとデータインレプリケーションも異なるバージョン間のレプリケーションはサポートしていません。
ただしMySQL(OSS)のレプリケーションでは異なるバージョン間のレプリケーションを1世代だけサポートしています。
実際にAzureのストアドの中身を見てもほぼほぼchange master toしてるだけでMySQL(OSS)と同じことをしているので、
まぁ大丈夫だろうということでお客様にリスクを共有したうえで採用しました。
さて、データインレプリケーションを利用して検証を進める中で、様々な壁にぶつかりました。
レプリケーションフィルタが使えない
MySQL(OSS)のレプリケーションではフィルタ機能を使うことで必要なテーブルのみを同期することができます。
ただしAzure Database for MySQLではこのフィルタを作成する権限がないためにDB丸ごと同期する必要があります。
そのため移行対象外となるテーブルのデータは事前にDumpしておき、レプリケーション完了後にテーブルをTruncateしDumpからデータを戻す、という手順にしました。
###マスタ側のファイアウォールで最低限のアクセスに絞れない
スレーブからマスタにbinlog要求するためにマスタでスレーブからのアクセスを許可する必要があります。
スレーブがMySQL on VMであればそのグローバルIPアドレスをマスタのファイアウォールで個別に許可できます。
しかしスレーブがPaaSの場合ははそうはいきません。
これはよくハマるAzurePaaSあるあるなので別途記事にする予定ですが、AzureのPaaSはグローバルIPアドレスを固定化してくれません。
そのためマスタとなるAzure Database for MySQLのファイアウォーrうで「Azure サービスへのアクセスを許可」にチェックを入れる必要があります。
これはAzureのデータセンタが持つグローバルIPアドレス全てを指しているため、VMを含むAzure上の全リソースからアクセス可能となります。
認証情報を持った悪意ある内部犯に限定されるものの、データ流出の懸念があります。
今回お客様は仕様上仕方ない、と許容してくれましたが、お客様によっては許容してもらえないこともあるかと思います。
###構築した時期でバイナリログのデフォルト有効/無効の仕様が違う
我々が検証を開始したのは2020年4月頃で、Azure Database for MySQL(General Purpose)はリソースを作成するとバイナリログの出力設定はデフォルトで有効となっていました。
しかし実際にお客様の環境で検証をしてみたところ、マスタとなるAzure Database for MySQLのバイナリログは無効となっていました。
MSサポートに問い合わせたところ、リソースを作成した時期により仕様が変わったとのことでした。
具体的にはディスクの4TBが上限だった時点までにデプロイした Azure Database for MySQL については、バイナリログがデフォルトで無効となっているそうです。
過去のAzure Database for MySQLのGAを調べたところ以下がヒットしました。
2019/11/11に4TBの壁が解消されたようなので、これ以降に作成されたリソースはバイナリログがデフォルトで有効になっていると思われます。
#####Azure Database for MySQL:読み取りレプリカの一般提供開始
https://azure.microsoft.com/ja-jp/updates/azure-database-for-mysql-read-replica-now-generally-available/
更新: 2月 27, 2019
Azure Database for MySQL では、1 つの Azure Database for MySQL サーバー (マスター) のデータを同じリージョン内の最大 5 つの Azure Database for MySQL サーバー (レプリカ) に非同期で連続的にレプリケートできるようになりました。
#####General availability: Azure Database for MySQL 4-TB server storage
https://azure.microsoft.com/ja-jp/updates/general-availability-mysql-4-tb-server-storage/
更新: 6月 28, 2018
#####Azure Database for MySQL の大容量のプレビュー開始
https://azure.microsoft.com/ja-jp/updates/mysql-large-storage-generally-available/
更新: 11月 11, 2019
Azure Database for MySQL サービスで、最大 16 TB のストレージと最大 20,000 IOPS がサポートされるようになりました。
最後に
今回Azure Database for MySQLでレプリケーションをした際にハマったことについてまとめました。
パッと思いついたことだけ羅列したので、また思い出したら追記します。