AWS外部のMySQLからRDSへレプリケーションするとき際の落とし穴、あるいはreplicate-do-dbが無いことへの対策

AWS外部からRDSへレプリケーションすっぞなことを経験したのですが、そのときにRDSの仕様に嵌ったので後学のために残しときます。公式ガイドは読んでる前提で。

docs.aws.amazon.com

なおRDSの仕様はAWSの機能追加でどんどん変わっていくでしょうから一ヶ月後には過去の問題になる可能性もある点にご注意を。そもそも外部とのレプリケーションなんて昔はできませんでしたし。

RDSはreplicate-do-dbが設定できない

そう、replicate-do-dbできないんですよ。公式ガイドのどこにも書いてないんでまず嵌まるところじゃないでしょうか。つまり一見すると、一部のスキーマだけレプリケーションするというのがRDS相手ではできないのです。

 

しかし一部だけレプリケーションというのは不可能というわけでもなく、対策は2つあります。

  1. レプリケーション元のDBでbinlog-do-dbを設定し、レプリケーション対象のDBのbinlogだけ吐かせるようにする
  2. ENGINE=BLACKHOLEを活用する。移行対象でないスキーマのテーブルを全てBLACKHOLEエンジンで作成する

 

対策1は、そもそもレプリケーション対象外のDBのbinlogは吐かないというシンプルな方法です。できるならば強くこちらをオススメします。シンプルであるがゆえに問題が起きにくい方法です。またbinlog_formatをROWにしておくとより安全になるのかもしれません。 (ここはあまり詳しくないのですが)

 

対策2は、binlogが飛んできてもBLACKHOLEなテーブルに吸収させて、実際にはデータを保存させないという方法です。これらのテーブルを作る際にはmysqldumpで--no-dataを活用してスキーマ中の全テーブルのcreate文を出させたのち、ENGINE=InnoDBMyISAMとなっているところをBLACKHOLEに書き換えて、RDSに適用するのが楽でした。

対策2の方はレプリケーション元をいじらなくて良いという利点はあるのですが、面倒な問題が多いです。

  • まずmysqldumpで空のテーブルを作ろうとするとき、ダンプのSQLにRDSでは適用できない命令が入っていることがあり、それを除去する手間が発生する
  • レプリケーション元でdrop databaseを定期的に行っているような環境では、せっかく作ったBLACKHOLEテーブルが失われてしまうのでこの方法が使えない
  • レプリケーション元でALTER TABLEなどでテーブル構成が変わるとbinlogの適用に失敗する。このときはテーブル構成をレプリケーション元に合わせなければならない
  • レプリケーション元でCREATE TABLEがあれば上と同様の問題が発生する

などなど、対策2はレプリケーションエラーが起きる可能性がかなり高いためレプリケーション監視は必須です。思わぬテーブルがレプリケーションされてストレージ容量を食いつぶさないかにも注意が必要でしょう。

まとめ

今後レプリケーションを行う方はぜひともbinlog-do-dbを設定し、レプリケーション対象のスキーマのbinlogだけ吐いてください。mysqlスキーマ等々もRDSでは鬼門となりがちなので外してしまった方が楽でしょう。

BLACKHOLEを使う方法は落とし穴が多く、インフラ担当者の安眠を妨害します。できるだけ使わずに済ませる方法を考えたいところです。