RDSの"リードレプリカのマスター昇格機能"を使ってDDLオペレーションを実行する方法

AWSのRDSに、
ついにリードレプリカをマスターに昇格する機能が追加されました。

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

さて何故(なにゆえ)にこのような機能があるのかというと、
以下3つのケースが同記事にて紹介されています。

  • DDLオペレーションの実行
  • テーブルのシャーディング
  • 障害回復機能を実装する

"障害回復機能を実装する"ケースは、マスターで障害が発生した際に、
リードレプリカをマスターに切り替えることで復旧させる方法です。

既存のデータ復旧機能である"Multi-AZ 配備"に比べて良い点は、
非同期なので書き込みにおけるパフォーマンス劣化が防げたり、
ホットスタンバイとして寝かしておくのではなく
リードレプリカとして読み込み用として利用しておけたりする事でしょうか。

もちろん、同記事にあるようにこれは"非同期"のため、
障害時にデータの整合性が失われる可能性があるので、注意が必要です。

"テーブルのシャーディング"は、
同時多発的にマスター用途のインスタンスを作成するってところですかね。

さて肝心の"DDLオペレーションの実行"です。

そもそも何が問題なの?というと、

サービスやアプリケーションで利用中のテーブルに対して
ADD COLUMNやADD INDEX等のテーブルスキーマの変更を行うと、
該当のテーブルはロックされるため後続のクエリ全てがwait状態になること、
また実行中はある程度のマシンリソースを使うことにより、
稼働に影響を及ぼす可能性があるためです。

特にレコード数の多い大きなテーブルでは顕著に現れます。
サイズ、マシンリソースによってはひとつの変更に
数十分、数時間かかる可能性もあるでしょう。

そこで昇格機能を使うことで、
事前に伝搬中のリードレプリカ上でスキーマ変更を行い、
更新を一時的に止め、リードレプリカをマスターに昇格させ、
アプリケーションの向き先を昇格したマスターへ切り替える、
そんなことが可能なのです。

これなら昇格にかかる時間(数分)と
アプリケーションの向き先変更時間だけで、
数時間もかかる作業を行うことができるのです。

まず下準備です。

RDSのコンソール画面のNavigationにあるDB Parameter Groupsから、
新しいパラメータセットを作ります。

f:id:kazukiyunoue:20130505141638p:plain

リードレプリカに対して変更処理を行うため、
デフォルトのパラメータで設定されている
書き込み制限が外れたセットが必要なためです。

f:id:kazukiyunoue:20130505143203p:plain

適当な名前を付けて作成しておきます。
Edit Parametersから必要な値の変更をします。項目はread_onlyです。

元々は自動でリードレプリカの場合は読み込み専用になるようになっています。

f:id:kazukiyunoue:20130505141701p:plain

これを0にしておきます。

f:id:kazukiyunoue:20130505141724p:plain

インスタンス一覧に戻って、
Instance Actionsからリードレプリカを作成します。

f:id:kazukiyunoue:20130505142751p:plain

作成できたら、リードレプリカを選択した上でActionsからModifyを選択し、
パラメータの設定セットを先ほど作った書き込みが可能な
DDLオペレーション用のものに変えます。

f:id:kazukiyunoue:20130505143002p:plain

再起動が完了したら、
早速リードレプリカに対してスキーマ変更を実施しましょう。
サービスで利用していないのでどんな負荷がかかろうが問題ないですね。

変更中は伝搬が遅延する可能性がありますが、
変更中も変更後も問題なく伝搬は続行しているはずです。

これで準備は整いました。

あとは更新を一時的に停止し、スキーマ変更済みのリードレプリカを
マスターに昇格しましょう。

f:id:kazukiyunoue:20130505143040p:plain

その後アプリケーションの向き先を新マスターに切り替えるだけです。
あっという間にスキーマ変更済みのDBへと切り替えることができました。

実は書き込み可能なリードレプリカにしているのでマスターに昇格しなくても、
向き先を変更してそのまま利用することが可能です。
しかしバックアップ等はマスターにしかない機能なので、
必ずこのタイミングで昇格した方が無難ですね。

今の一連の作業はもちろんAPI経由でも実施可能なので、
Rails等のマイグレーションのタスクに組み込んでしまえば、

rake db:migrate

こんなコマンド一発で
スキーマ変更からDSN切り替えまでやれちゃうかもですねぇ、、

末恐ろしきRDS、、!