Auroraクラスタのレプリケーションクラスタを作成

とあるAuroraクラスタの、完全なデータコピーかつ最新データも元クラスタからレプリケーションで反映し続けるクラスタって作れるのかなーと調べてみると、公式のユーザーガイドにも一般情報にも見つからないしで、裏技臭がしたので書き留めておきます。

実はわりと常識レベルだったりしたらゴメンナサイって感じですが・・・おそらく仕様変更など入らず、ずっと使い続けられるテクニックだと推測できる内容であります。それでは、Auroraクラスタの完全コピーを作りたくなった理由も含めて、まとめていきたいと思います。



Auroraの基本的なレプリケーション

Auroraの復習ですが、Writer(=Master) と Reader(≒Slave) は共通のディスクを利用することで、極小さな遅延(10-20ms)でのデータ共通化を実現しています。なので、Writer/Reader間は従来のbinlogを用いたMySQLレプリケーションではありません。

もし、従来のレプリケーションをしたいのであれば、こちら
  • Aurora と MySQL との間、または Aurora と別の Aurora DB クラスターとの間のレプリケーション – Amazon Relational Database Service
  • にある通り、Aurora-Aurora や Aurora-MySQL、MySQL-Aurora といった構成をとることができるようになっています。


    クラスタの最新コピーを作りたい

    適切な単語を知らないだけかもですが、ここでいう最新のコピーってのは、運用中のWriterと全く同じデータを保持し続けるWriterのつもりで書いています。図にするとこんな感じです。

    作りたい理由

    コピーを作りたい理由は主に2つあります。

    1つは、稼働中の Writer01 に変更を加える計画がある時に、その変更によって悪影響が出ないか確認することです。例えば、オンラインALTER TABLE や、pt-online-schema-change によるものです。Writer02 に参照はこないものの、十分な更新量の中で検証実行できるので、Writer01 におけるオンライン実行の安全性を確認しやすくなります。ついでに、アプリケーションから発行された更新クエリが、スキーマ変更後もエラーにならないか、といった確認もできます。

    もう1つは、クラスタの切り替えです。通常はオンラインではしづらい変更── 例えばデータの分割や、変更時間が長く影響がでるスキーマ変更です。Writer02 を作成して、事前にデータの編集を済ませ、Blue-Green Deployment手法などで瞬時に切り替えることで、重い変更もオンラインでできる場合があります。

    ボツネタ集

    まずは、そんな願望を砕いてくれたパッと思いつく系の手法を並べておきます。

    スナップショット復元
    RDSは自動または手動によって、スナップショットを取得することができるので、それを復元して不足分をレプリケーションで持ってくればえぇやん☆というものです。

    これは悲しいことに、目につく基本情報では、元Writerの binlog の File/Position が不明なため、レプリケーションを始めることができません。スナップショットとbinlogは全くの別機能であるため、Writerが binlog_format を有効にしているからといって、スナップショットの詳細情報に binlog 情報を記録してくれるというわけではないのです。

    まぁAWS大先生なら、これくらいならいつか実装してくれそうな気がしますが・・・

    最初からレプリケーションしておく
    Cluster01 を作成する時に、同時に Cluster02 も作成しておき、レプリケーションしておくという方法です。

    これは、Writer02 を常時稼働させる分が費用的に無駄ですし、検証終了後などに作り直したい場合にアウトなので、お話になりません。

    漢は黙ってmysqldump!!
    –master-data くっつけて採取して、Writer02 にリカバリや!

    ……なんて爺臭いものをAurora上でやってたら、死にたくなりそうですね。あらゆる意味で却下。


    特定時点への復元……からのレプリケーション

    特定の時点への DB インスタンスの復元 の機能を使うと、そのインスタンスの数分以上前の時点のデータを保持した、新規インスタンスを起動することができます。

    データの内容は、データベースやテーブルはもちろん、実はログも保持されているため、復元したWriter02 のログ状態を確認したら、Writer01 へレプリケーションをつなぐことが可能とわかりました。例えばこんな感じで・・・

    ということで、無事、Writer01 の復元からレプリケーションで最新状態まで追いつくことができました。


    再度スナップショットからの復元で深掘り

    では、さきほど(公式情報だけで)諦めたスナップショットの復元も、実はbinlogが残っていてできるのではないか、と思い直して試したところ・・・

    ということで、スナップショットも、特定時点への復元も、おそらく /rdsdbdata/ ディレクトリを丸っと採っているようなバックアップデータを利用しているのではないか、と予想できます。(/rdsdbdata/tmp/ は知らんけど:-)


    その他 運用など

    公式手法ではない

    今のところ、復元されたインスタンスから元のインスタンスに対して、残されたbinlog Positionを継続する形でレプリケーションをつなぐ、という方法は、公式ユーザーガイドやよくある質問には載っていなさそうです。そのため、ドヤって推奨できるものではないのですが、ログだけ後から削ったり、ログ部分だけスナップショットとして綿密に機能していましぇん、なんてことはないと思うので大丈夫でしょう(自己責任)

    復元後のインスタンス設定

    今回は、「特定時点への復元」でも「スナップショットから復元」でも、元Writerからレプリケーションできることは確認できたわけですが、ではどちらがよいかというと、「特定時点への復元」が良いと考えています。

    理由は、「スナップショットから復元」だと、「DBクラスターのパラメータグループ」と「パラメータグループ」、「セキュリティグループ」がデフォルト指定になってしまうためです。binlog_format などを有効にするためには、起動後に「DBクラスターのパラメータグループ」を再指定して、再起動までしなくてはいけませんし、「セキュリティグループ」も当然変更しないと 3306 に接続できません。

    「特定時点への復元」だと、「パラメータグループ」はデフォ開始なものの、「DBクラスターのパラメータグループ」は強制的に元Writerと同じになりますし、「セキュリティグループ」は復元時に選択済みになっています。また、自動スナップショットよりも binlog の位置が数分前とかなり近いため、最新状態になるまでの時間が短いだろうという理由もあります。

    log_output との関係

    log_output を TABLE にするか FILE にするかで保存先が変わりますが、結論を言うとどちらで運用しようと、途中で変更しようと、binlog の状態に変更はないことを確認しています。

    例えば、Writer01 => FILE の状態から復元をすると、復元したインスタンスの「パラメータグループ」はデフォ値になって TABLE として起動されますが、それでも binlog は元のスナップショット取得時の状態を保ってくれます。また、TABLE から FILE に変更したとしても、同様に状態を保ってくれます。

    こういった仕様をみると、非常に気を使って設計したんだろうな、という印象を受けますね。

    RDS MySQLの場合

    いまさらですが……RDS MySQLの「特定時点への復元」を利用すると、こんな感じになります。

    ということで、バイナリログは保持されないので、途中からレプリケーションすることはできません。また、スナップショットからも試みましたが、同じく取得時点の File/Position がわかる内容ではありませんでした。

    この検証では、log_output=TABLE のままで行っているので、DBデータディレクトリを丸っと取得するようなものではない、と推測できます。




    とりあえずやりたいことを実現できてホッとしたところですが、
    ブラックボックスに手を突っ込んで探し出すのは、楽しくもあり、虚しくもあり、、

    ゲーム攻略感覚みたいなものですね、ホント:-)