Amazon RDS for MySQL リードレプリカを使ったテーブル変更

RDBでデータ件数が多いテーブルに対するカラム追加を行うと時間が数時間かかって困るんですけど、RDSだったらリードレプリカを使えば比較的容易にできるってのを最近知りました。

MySQL5.6からはオンラインDDLとかPercona-Toolkitのonline-schema-changeとか別のソリューションもあるのですが、リードレプリカも便利です。

リードレプリカを使ったテーブル変更

DDLオペレーションの実行

カラムを追加したり、インデックスを張ったりするようなテーブルレベルのDDLオペレーションは時間がかかり、マスターデータベースインスタンスのパフォーマンスに影響を与えてしますことがあります。リードレプリカの昇格機能を使えば次のような方法がとれます。

  • 指定されたリードレプリカ上でオペレーションを実行し、それが完了するまで待ちます。
  • リードレプリカの同期がマスターデータベースインスタンスに追いつくまで待ちます。
  • リードレプリカをマスターに昇格します。
  • 新しく昇格したマスターに全てのデータベーストラフィックを向けます。
  • 必要に応じてパフォーマンス向上のために追加のリードレプリカを作成します。
  • 元のマスターとそれに関連づけられている残りのリードレプリカをを終了します。

Amazon Web Services ブログ: 【AWS発表】Amazon RDS for MySQL - リードレプリカのマスター昇格機能を追加!

注意点

この方法を実施する際に気を付けないといけないことがあって、リードレプリカって要は別のDBインスタンスにマスターで実行されているSQLをじゃんじゃん非同期で流すだけなので、対象が不定になる更新系のクエリがあると問題になる。

以下のようなクエリは更新対象が不定になるので、 UNIQUE制約違反を引き起こしレプリケーションの停止を招く可能性があります。 UNIQUE制約違反がその場で発生せず、 後日たまたま重複するINSERTを行ったらレプリケーションが止まったり、 レプリケーションは動いているのに実はデータが一致していないということになりうるので注意が必要です。

  • UPDATE table SET col1 = 'foo' LIMIT 1;
    • LIMITで抽出される行がマスタとスレーブとで同一とは限りません。 LIMITが必要な場合は、UNIQUEなカラムでORDER BYを使って同順となるようにします。
  • REPLACE ... SELECTもしくはINSERT ... SELECT
    • これらのSQLで、 更新対象のテーブルのプライマリキーがAUTO_INCREMENTで、かつ、 SELECT文にORDER BYを使っていない場合に、 REPLACEもしくはINSERTされる順が不定となるため、AUTO_INCREMENTで発番されるプライマリキーがマスタとスレーブとで異なってしまいます。

現場指向のレプリケーション詳説

  • レプリケーションエラーが発生したかはAWSの管理コンソールで確認できますが、データの不整合は検知できない。
  • データ不整合が起きていることを気付かずにマスターに昇格するなどしてマスターと異なる状態になると怖いですね。

ひとこと

RDSのリードレプリカ便利ですね。リードレプリカは読み込み負荷を下げるためのモノだという意識が強かったので、リードレプリカを使ってテーブル変更したりという発想がなかったけど、これはいい使い方ですね。多少気を付けないといけないことがあるにしてもこれは便利。今後活用していきたい。