ちょっと先日事故ったのでメモを兼ねて。
Auroraのフェイルオーバーの挙動
まずは、Auroraのフェイルオーバーの挙動。
従来のRDSではマスターデータベースをAZ構成にしておいてレプリカをぶら下げる構成だったが、Auroraからはデフォルトでクラスタになっている。
使用出来るエンドポイント
クラスタの真前をfailover-aurora
、インスタンス名をfailover-aurora-instance
という名前でauroraのクラスタを作ると以下の様なエンドポイントが得られる。
Cluster Endpoint
クラスターに対して書き込みをする用のエンドポイント。
こんな感じ。
failover-aurora.cluster-xxxx.ap-northeast-1.rds.amazonaws.com
Reader Endpoint
クラスターに対して読み込みをする用のエンドポイント。レプリカのどれかに紐づく様になっていて、書き込みをするとエラーになる。-ro
というsuffixが付く。
failover-aurora.cluster-ro-xxxx.ap-northeast-1.rds.amazonaws.com
各インスタンスのEndpoint
インスタンス毎にもエンドポイントが存在する。
マスター
failover-aurora-instance.xxxx.ap-northeast-1.rds.amazonaws.com
レプリカ (AZの名前がつくらしい)
failover-aurora-instance-ap-northeast-1a.xxxx.ap-northeast-1.rds.amazonaws.com
IPをひいてみると
実際のDNSレコードがどういう構成なのかIPを問い合わせてみる。
Cluster Endpoint
failover-aurora.cluster-xxxx.ap-northeast-1.rds.amazonaws.com. 5 IN CNAME failover-aurora-instance.xxxx.ap-northeast-1.rds.amazonaws.com.
failover-aurora-instance.xxxx.ap-northeast-1.rds.amazonaws.com. 5 IN A 172.30.25.134
Reader Endpoint
failover-aurora.cluster-ro-xxxx.ap-northeast-1.rds.amazonaws.com. 1 IN CNAME failover-aurora-instance-ap-northeast-1a.xxxx.ap-northeast-1.rds.amazonaws.com.
failover-aurora-instance-ap-northeast-1a.xxxx.ap-northeast-1.rds.amazonaws.com. 5 IN A 172.30.3.157
Cluster Endpointは、マスターデータベースを指すエンドポイントのCNAMEになっていて、Reader Endpointはレプリカを指すエンドポイントのCNAMEになっている事が分かる。
フィエルオーバー後のIP
実際にフェイルオーバーを起こした後に、IPがどう変化するかを確認する。
Cluster Endpoint
failover-aurora.cluster-xxxx.ap-northeast-1.rds.amazonaws.com. 1 IN CNAME failover-aurora-instance-ap-northeast-1a.xxxx.ap-northeast-1.rds.amazonaws.com.
failover-aurora-instance-ap-northeast-1a.xxxx.ap-northeast-1.rds.amazonaws.com. 5 IN A 172.30.3.157
Reader Endpoint
failover-aurora.cluster-ro-xxxx.ap-northeast-1.rds.amazonaws.com. 1 IN CNAME failover-aurora-instance.xxxx.ap-northeast-1.rds.amazonaws.com.
failover-aurora-instance.xxxx.ap-northeast-1.rds.amazonaws.com. 3 IN A 172.30.25.134
各インスタンスのIPに変化は無く、CNAMEの切り換えだけが行われている事が分かる。
ちなみに、興味深かったのはReader側のCNAMEのTTLが1秒でCluster側が5秒担っていた事。
昇格側はさっさと切り替わる方が障害時間が短くなるためか、slaveは複数台連なるので負荷分散の為の想定かそんなところだろうか。
Railがconnection poolingしている場合
で、本題のRailsのコネクションプーリングについて。
この辺りの記事が詳しい(むしろこれで話は終わりという感じ)。
http://blog.livedoor.jp/sonots/archives/38797925.html
マスターをAZ構成にしていた場合には、旧マスターは接続不可となるのでrailsは接続出来ないエラー共に再起動され、(設定によるが)ワーカーが再起動して新しいIPをひくので問題なかったが、
Auroraの用に、マスターがスレーブに降格する様な場合には、引き続きrailsは旧マスターに接続し続けられる為に、コネクションをプーリングし続けてしまい書き込みだけが出来ない様な状態になる。
エラーとしては以下の様なものが出力される。
Mysql2::Error: The MySQL server is running with the --read-only option so it cannot execute this statement
都度接続にする
解決策としては、コネクションプーリングをやめて都度接続にする事が手っ取り早い。以下の様なgemもあるためかなり簡単に設定出来る。
https://github.com/sonots/activerecord-refresh_connection
マスター切替以外でも
スレーブが複数台いる場合に、コネクションプーリングだとスレーブへのアクセスがかなり偏る可能性がある。
特に台数が少ないうちはかなり偏るはず。
まとめ
都度接続のコストが高くない限り、コネクションプーリングはやめたほうがいんじゃないかなと思いました。