Amazon AuroraのフェイルオーバーとRailsのコネクションプーリング

  • 11
    いいね
  • 0
    コメント

ちょっと先日事故ったのでメモを兼ねて。

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

マスター切替以外でも

スレーブが複数台いる場合に、コネクションプーリングだとスレーブへのアクセスがかなり偏る可能性がある。
特に台数が少ないうちはかなり偏るはず。

まとめ

都度接続のコストが高くない限り、コネクションプーリングはやめたほうがいんじゃないかなと思いました。