たまチームで開発しているWebサービスの大半は AWS EC2-Classic 上で動いているのだが、去年から標準でサポートされるようになった VPC (Virtual Private Cloud) に移行しないといろいろと不便なことが多くなってきた。というわけで、移行にあたって一番厄介だと思われる RDS の移行手順を以下にまとめた。
ちなみにこの手順は、EC2-Classic から VPC への移行だけでなく、VPC から VPC の移行にも適用出来るはず。
大まかな流れとしては、
- リードレプリカ経由でClassic側のdumpを取り
- それをVPC側で復元
- 復元したデータベースをClassic側のslaveとして動かしてデータを同期
- 読み込み専用のアプリはここでVPC側に移行して動作確認
- VPC側をmasterに昇格した後(ここで一瞬だけ Read Only になる)
- 書き込みのあるアプリケーションもVPC側に切り替えて
- Classic側を潰せば
めでたく移行は完了する。
- 参考
1. リードレプリカ経由でClassic側のdumpを取る
まずはClassic側で移行用のdumpを取得する。リードレプリカを作ってすぐにリプリケーションを停止し、そのときのdumpとバイナリログの位置を取得しておく。リードレプリカ経由なので、この間、サービスの運用には一切影響を与えない。
- dumpを取る間、サービス全体を Read Only にしても問題ないなら、masterから直接dumpを取ってしまった方が簡単
バイナリログの保持期間を変更する
デフォルトのバイナリログの保持期間が短いので、VPC-slaveを作る間にログが消失してしまわないよう、Classic-masterで以下のように変更しておく。
CALL mysql.rds_set_configuration('binlog retention hours', 24);
現在の設定を確認する:
CALL mysql.rds_show_configuration;
レプリケーション用のユーザーを作る
Classic-masterでレプリケーション用のユーザーを作っておく。
GRANT REPLICATION CLIENT, REPLICATION SLAVE ON *.* TO 'repl_user' IDENTIFIED BY 'some-password';
Classic-masterのリードレプリカを作る
AWS管理コンソールで Classic-master となるRDSインスタンスを選び、”Instance Actions” から “Create Read Replica” を選択する。
レプリケーションをストップする
Classic-slave(今作ったレプリカ)のレプリケーションをストップする。
CALL mysql.rds_stop_replication;
バイナリログの位置を記録する
Classic-slaveで、レプリケーションの状態をメモる(どの位置からレプリケーションを再開すれば良いか)。
show slave statusG
... Master_Log_File: mysql-bin-changelog.050354 Read_Master_Log_Pos: 422 ... Slave_IO_Running: No Slave_SQL_Running: No ...
Slave_IO_Running
とSlave_SQL_Running
がNo
になっているので、ちゃんとレプリケーションが止まっていることが分かる。
Classic-slaveのdumpを取る
- Classic-slaveのエンドポイントを
classic-slave.rds.amazonaws.com
、管理ユーザーをdbuser
とする。
mysqldump -u dbuser -h classic-slave.rds.amazonaws.com --single-transaction --compress --order-by-primary --max_allowed_packet=1G -p --databases database1 databases2 > classic-slave.dump
2. VPCにClassic-masterのレプリカを作る
VPC内に立てたRDSインスタンスに、Classic-slaveのdumpをインポートしてClassic-masterへのレプリケーションを再開させる(VPC-slave)。
VPC-slaveとなるRDSインスタンスを立ち上げる
AWS管理コンソールでサクッと立ち上げる。
VPC-slaveにClassic-slaveのdumpをインポート
- VPC-slaveのエンドポイントを
vpc.rds.amazonaws.com
、管理ユーザーをdbuser
とする。
mysql -u dbuser -h vpc.rds.amazonaws.com -p --default-character-set=utf8 < classic-slave.dump
Classic-masterのセキュリティグループ設定を変更する
レプリケーションを可能にするために、VPC-slave から Classic-master にアクセス出来るようにセキュリティグループ(DB Security Groups)を設定する。
以下のような感じで VPC-slave のIPを調べて、そのIPからのアクセスを許可する:
$ ping vpc.rds.amazonaws.com
以下を Classic-master のセキュリティグループに追加。
CIDR/IP to Authorize: xxx.xxx.xxx.xxx/32
レプリケーションをスタートさせる
VPC-slave にログインして、レプリケーションをスタートさせる(さっき作った専用ユーザーがここで活躍)。
パラメータは先ほどメモしたレプリケーションの状態を参考に。
CALL mysql.rds_set_external_master('classic-master.rds.amazonaws.com',3306,'repl_user','some-password','mysql-bin-changelog.050354',422,0);
CALL mysql.rds_start_replication;
レプリケーションの状態を確認:
show slave statusG
以下のような項目があれば、正しくレプリケーションが動作している。
... Slave_IO_Running: Yes Slave_SQL_Running: Yes ...
レプリケーションがうまく行ったら、Classic-slaveは用無しなので削除する。
この段階で読み込み専用のアプリはVPC内に移行出来る。
3. VPC-slaveをmasterに昇格する
Classic-masterをReadOnlyにする
FLUSH TABLES WITH READ LOCK;
Closes all open tables and locks all tables for all databases with a global read lock. This is a very convenient way to get backups if you have a file system such as Veritas or ZFS that can take snapshots in time. Use UNLOCK TABLES to release the lock.
として、全てのテーブルをロックしてから切り替えたいところなのだが、RDSではこの命令を実行するための権限がないことが判明。
- Backup MySQL Amazon RDS
簡単な代替策もないようなので、とりあえず編集を行う可能性があるサービスを全て「メンテナンス中」として操作出来ないようにした。
VPC-slaveのレプリケーションを停止する
CALL mysql.rds_stop_replication; CALL mysql.rds_reset_external_master;
以後、こちらを master として扱う。
アプリケーションをVPC内に移動する
VPC内にアプリケーションサーバーを立てて、そちらを指すようにDNSの設定を書き換える。
後は古いClassic環境を潰して移行は完了。