AuroraのフェイルオーバーとRailsのコネクションプールを共存させる方法
AuroraのフェイルオーバーとRailsのコネクションプールを共存させる方法:
はじめに
こんにちは、ここ最近AzureからAWSに主戦場を移したalfaです。
AWS なので早速地雷を踏みました。
具体的には、Auroraでフェイルオーバーが発生した際にDBへ書き込みが出来なくなってしまい、アプリが再起動されるまで正しく動かなくなってしまうといった症状です。
AuroraのフェイルオーバーとActiveRecordのコネクションプールの仕組みは相性が悪かったという事ですが順を追って説明していきます。
クラスターに障害が発生した場合、クラスタエンドポイントのDNS(CNAME)を書き換えることで参照先を切り替える仕組みです。
クラスタエンドポイントをDBの接続先に設定したRubyアプリケーションがあったとき
フェイルオーバーしてマスターが切り替わると...
アプリケーションは再接続するだけで昇格したマスターを参照できます。
ウルトラハイパーメチャクチャ便利!
Railsのコネクションプールは接続がアクティブである限りコネクションを保持する仕組みです。
DBのアダプタにmysql2を使用している場合、アクティブであるかどうかの判定は
接続の検証は通ってしまうので、リードレプリカに降格したDBとのコネクションは保持されます。
ぐぬぬ
調べたところ次のような解決策を見つけました。
一般的にはコネクションプールを無効にするようです。
コネクションプールを有効のままにしたい
パフォーマンス的な意味で有効にしたいケースがほとんどだと思います。
しかし私は 内部DNSが引けなくなる不具合をクラウドサービスで体験したトラウマ があるので、接続のたびにDNSへ問い合わせが必要な形は避けたいと考えました。
追加で調査を続けていたところmysql2リポジトリにこんなissueを見つけました。
クエリ実行時にエラーが発生した場合にエラー内容によってリトライをかければ良いらしく、しかも sonots さんが作ったパッチがGemになっているらしい!
しかし
こんな大胆な名前
名乗ってもよいのか少し躊躇しましたが、 世の中にはもっと大胆な名前で中身が何もないGemも存在するので大胆に行きました!
基本は sonots さんのGemと同様でエラーメッセージに応じて再接続とリトライをかけます。
そして、強い名前に恥じないよう、テストと品質検証の仕組みをしっかり導入しています。
coveralls入れていますが、カバレッジ100%にしないとテストに落ちる仕組みなので入れる意味はなかったかもしれないです。
実績がないGemを導入する事は躊躇すると思いますが、テスト内容や品質検証の仕組みが判断のお役に立てば幸いです。
もしよろしければお使いください
追伸
私はもう本番のECサイトに入れました。
私はもう本番のECサイトに入れました。
私はもう本番のECサイトに入れました。もしヤバイところを見つけたらプルリクくださいお願いします!!!!
はじめに
こんにちは、ここ最近AzureからAWSに主戦場を移したalfaです。
AWS なので早速地雷を踏みました。
具体的には、Auroraでフェイルオーバーが発生した際にDBへ書き込みが出来なくなってしまい、アプリが再起動されるまで正しく動かなくなってしまうといった症状です。
何が起こったのか
AuroraのフェイルオーバーとActiveRecordのコネクションプールの仕組みは相性が悪かったという事ですが順を追って説明していきます。
Auroraのフェイルオーバー
クラスターに障害が発生した場合、クラスタエンドポイントのDNS(CNAME)を書き換えることで参照先を切り替える仕組みです。クラスタエンドポイントをDBの接続先に設定したRubyアプリケーションがあったとき
フェイルオーバーしてマスターが切り替わると...
アプリケーションは再接続するだけで昇格したマスターを参照できます。
ウルトラハイパーメチャクチャ便利!
Rails(ActiveRecord)のコネクションプール
Railsのコネクションプールは接続がアクティブである限りコネクションを保持する仕組みです。DBのアダプタにmysql2を使用している場合、アクティブであるかどうかの判定は
mysql_ping
を利用しています。mysql_ping
は接続できている事しか検証しないため、リードレプリカになったことを検知できず書き込み系のクエリを発行した際にエラーとなってしまいます。接続の検証は通ってしまうので、リードレプリカに降格したDBとのコネクションは保持されます。
ぐぬぬ
解決策
調べたところ次のような解決策を見つけました。
一般的にはコネクションプールを無効にする
一般的にはコネクションプールを無効にするようです。コネクションプールを有効のままにしたい
コネクションプールを有効のままにしたい
パフォーマンス的な意味で有効にしたいケースがほとんどだと思います。しかし私は 内部DNSが引けなくなる不具合をクラウドサービスで体験したトラウマ があるので、接続のたびにDNSへ問い合わせが必要な形は避けたいと考えました。
追加で調査を続けていたところmysql2リポジトリにこんなissueを見つけました。
クエリ実行時にエラーが発生した場合にエラー内容によってリトライをかければ良いらしく、しかも sonots さんが作ったパッチがGemになっているらしい!
しかし
- テストが無いこと
- 依存パッケージとして指定されているmysql2のバージョンが固定されていないこと
- (個人的に)リファクタしたい箇所が多く、PRを出すレベルの改修に収まらないこと
mysql2-aurora
こんな大胆な名前 名乗ってもよいのか少し躊躇しましたが、 世の中にはもっと大胆な名前で中身が何もないGemも存在するので大胆に行きました!
基本は sonots さんのGemと同様でエラーメッセージに応じて再接続とリトライをかけます。
そして、強い名前に恥じないよう、テストと品質検証の仕組みをしっかり導入しています。
coveralls入れていますが、カバレッジ100%にしないとテストに落ちる仕組みなので入れる意味はなかったかもしれないです。
実績がないGemを導入する事は躊躇すると思いますが、テスト内容や品質検証の仕組みが判断のお役に立てば幸いです。
もしよろしければお使いください
追伸
私はもう本番のECサイトに入れました。
私はもう本番のECサイトに入れました。
私はもう本番のECサイトに入れました。もしヤバイところを見つけたらプルリクくださいお願いします!!!!
コメント
コメントを投稿