こんにちは、IT基盤部の川原﨑です。
私の所属する第四グループでは、超大規模ゲームタイトルおよびゲームプラットフォームのインフラを運用しております。 そこでのAuroraの高速フェイルオーバーの仕組みと、実際に無停止で切り替えを行った手順について紹介させていただきます。
はじめに
第四グループでは、コストコントロールの一環でInstance数の増減・Instance Typeの変更を頻繁に実施しています。
例えば、
- イベントなどでリクエスト増加が見込まれるときにInstance数を増やす、またはInstance Typeを1つ上のものに変更する
- リクエストが減少傾向にあれば、Instance数を減らす、またはInstance Typeを1つ下のものに変更する
などです。
これはWebサーバだけにとどまらず、DBサーバについても同様です。
EC2上でMySQLを運用している環境では、フェイルオーバーの仕組みとしてMHA for MySQLを使用しております。
MHA for MySQLでは数秒でフェイルオーバーが完了するため、ピークタイムを避けた時間帯であればエラー率も無視できるレベルです。
しかし、Aurora導入後はドキュメントに記載されている通り、フェイルオーバーに1分ほど要してしまうことが見込まれるため、フェイルオーバーの品質が大幅に下がってしまう懸念があります。
ダウンタイムの検証
まずは実際にどれぐらいのダウンタイムが発生するのかを確認しました。
検証環境
db.r4.large Multi-AZの3台構成
Auroraバージョン 5.6.10a
事前準備として検証で使用するテーブルを作成しておきます。
CERATE DATABASE aurora_test;
CREATE TABLE test (
col int(10) DEFAULT NULL
) ENGINE=InnoDB;
INSERT INTO test (col) VALUES (unix_timestamp());
確認コマンド
while sleep 1
do
date && echo "update test set col=unix_timestamp();" | mysql -uroot -p<password> -h<Cluster Endpoint> -N --connect-timeout=1 aurora_test
done
while sleep 1
do
date && echo "select col from test;" | mysql -uroot -p<password> -h<Reader Endpoint> -N --connect-timeout=1 aurora_test
done
検証結果
手動フェイルオーバーによるダウンタイム秒数
role | 1回目 | 2回目 | 3回目 | 4回目 | 5回目 |
---|---|---|---|---|---|
writer | 28s | 11s | 17s | 14s | 24s |
reader | 27s | 21s | 13s | 21s | 12s |
1分までとはいかないまでも平均して20秒程度かかっています。
writer側では接続エラーが収まった後に以下のエラーがしばらく継続し、完全に切り替わるようです。
ERROR 1290 (HY000) at line 1: The MySQL server is running with the --read-only option so it cannot execute this statement
reader側では接続できるときとできないときが上記秒数の間に発生するという状況が確認できました。 これはCluster Endpoint/Reader Endpointの更新までにタイムラグがあることが推測されます。
次にReaderであるInstanceを減らす際のダウンタイムについても計測してみましたが、Reader Endpointに対しての接続エラーは計測 できませんでした。 Instanceの削除には時間がかかり、Statusがdeletingの状態でもしばらく接続ができる状態であるため、接続ができなくなる前にDNSへの変更が完了するからかもしれません。
MHA for MySQLと比較するとフェイルオーバー時のダウンタイムは見劣りしてしまうため、本番サービスにAuroraを導入するにあたり ダウンタイムを短くすることが課題とわかりました。
高速フェイルオーバーの仕組み
Auroraの高速フェイルオーバーの仕組みとして
- MariaDB Connector/J
- ProxySQL
- HAProxy
などが知られていますが、 私たちのチームではこれから紹介させていただく仕組みで高速フェイルオーバーを実現させています。
DeNAでは、ローカルのDNSとしてMyDNSを使用したDNSラウンドロビンの仕組みがあります。 この仕組みでは応答しないサーバを検知してMyDNSのレコードを消して自動でサービスアウトする、アプリケーションはMySQLを直接参照することでDNSラウンドロビンのデメリットである近いIPアドレスに集中しないよう分散させています(書籍『Mobageを支える技術 』参照)。
AuroraもEC2インスタンスと同様にMyDNSに登録しています。 それにより以下のメリットがあります。
- AuroraのEndpointを使用しないのでDNSへの更新に関するタイムラグがない
- アプリケーション側は既存の仕組みのままでいい
- Instance Typeの変更・Instanceの再起動時にはMyDNSからレコードを削除すればよい
ただ、既存の検知の仕組みではサービスアウトさせるということしかできないため、Aurora用に別途検知の仕組みが動いております。
- failoverが実行された際にinnodb_read_onlyが0のInstanceでwriterのレコードをREPLACEする
- readerが応答しない際にweightを0にする
- すべてのreaderが応答しない際にreaderのレコードにあるwriterのweightを100にする
以下は、failover実行時の時系列での状態です。
aurora-test-w が書き込み用、aurora-test-r が読み込み用のMyDNSに登録されているEndpoint名です。
通常時
endpoint | instance | innodb_read_only | weight |
---|---|---|---|
aurora-test-w | aurora-test-instance-01 | 0 | 100 |
aurora-test-r | aurora-test-instance-02 | 1 | 100 |
aurora-test-r | aurora-test-instance-03 | 1 | 100 |
aurora-test-r | aurora-test-instance-01 | 0 | 0 |
failover時のWriter候補再起動時
name | instance | innodb_read_only | weight |
---|---|---|---|
aurora-test-w | aurora-test-instance-01 | 0 | 100 |
aurora-test-r | aurora-test-instance-02 | 1 | 100 |
aurora-test-r | aurora-test-instance-03 | 1 | 0 |
aurora-test-r | aurora-test-instance-01 | 0 | 0 |
Writer切り替え後
name | instance | innodb_read_only | weight |
---|---|---|---|
aurora-test-w | aurora-test-instance-03 | 0 | 100 |
aurora-test-r | aurora-test-instance-02 | 1 | 100 |
aurora-test-r | aurora-test-instance-03 | 0 | 0 |
aurora-test-r | aurora-test-instance-01 | 1 | 0 |
旧Writer復帰時
name | instance | innodb_read_only | weight |
---|---|---|---|
aurora-test-w | aurora-test-instance-03 | 0 | 100 |
aurora-test-r | aurora-test-instance-02 | 1 | 100 |
aurora-test-r | aurora-test-instance-03 | 0 | 0 |
aurora-test-r | aurora-test-instance-01 | 1 | 100 |
以下、高速フェイルオーバー導入後のダウンタイムの計測結果です。
手動フェイルオーバーによるダウンタイム秒数
role | 1回目 | 2回目 | 3回目 | 4回目 | 5回目 |
---|---|---|---|---|---|
writer | 5s | 7s | 4s | 6s | 7s |
reader | 6s | 1s | 4s | 7s | 5s |
MHA for MySQLまでとはいかないまでも、ダウンタイムはInstanceが再起動の時だけに限定されるため、かなり早くなりました。
無停止でのAuroraへ切り替え
MySQLからAuroraへ切り替えはメンテナンスを設けずに無停止で以下の手順で実施しました。
まずはMySQLのReplication SlaveとしてAuroraクラスタを構築します。 もし問題があった場合にMySQLに切り戻しができるよう、Auroraのbinlogを有効にしておきます。
- ttlを1秒にする
- MyDNSのslaveの向き先をAuroraのreaderに向ける
- MySQL側で書き込み権限があるユーザをRenameし、書き込みを止める
- Aurora側に上記がReplicationされてしまっているのでAurora側でユーザ名を戻す
- MySQLとAurora間のReplicationを止める
- SHOW MASTER STATUSでMaster Positionを確認する
- MyDNSのmasterの向き先をAuroraのwriterに向ける
- ttlをもとに戻す
- 上記7で確認したMaster PositionをもとにMySQLをAuroraのReplication Slaveと設定する
MySQLに戻す場合は上記の手順をMySQLに置き換えて再度実行することになります(実際に切り戻すことはありませんでしたが)。 この状態でしばらく様子を見て、問題なければMySQLを撤去します。
上記の手順のうちエラーが発生するのは3~7の間だけです。実際の切り替え時は手順の1~8までをスクリプト化しており、failoverとほぼ同等レベルのダウンタイムで切り替えることができました。
最後に
以上、Auroraの高速フェイルオーバーの仕組みと無停止による切り替えについて紹介させていただきました。
Auroraに切り替えることで、深夜問わず発生するEC2インスタンスのダウンなどによるDBサーバの再構築という工数が削減できており、インフラエンジニアに優しい運用になりました。
MyDNSの利用による運用はDeNAに特化したことであまり参考にならないかもしれませんが、 Aurora導入の参考になれば幸いです。
最後まで読んでいただき、ありがとうございます!
この記事をシェアしていただける方はこちらからお願いします。