最初から結論
sidekiqの実行中
ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 seconds (waited 5.019 seconds)
エラーが発生したのでrailsのdatabase.yamlのconnection poolを増やして解決しました。
何が起こったか
sidekiqが実行されているサーバーから急に1時間200件頻度で以下のエラーが発生しました。
ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 seconds (waited 5.019 seconds)
特に修正したことは無かった状態でアクセスが多かっただけを把握しました。
調査のスタート
Tracebackを確認すると
User.where(id: ids).order(name: :desc)
でselectしているだけだったのでコードの問題は無かったと判断、設定に問題ないかを調査しました。
エラーの内容を検索するとrailsガイドから
利用可能な数を超えるコネクションを使おうとすると、Active Recordはコネクションをブロックし、プールのコネクションが空くのを待ちます。コネクションを取得できない場合は以下のようなタイムアウトエラーが発生します。
ただpool増やせばOKな感じ
database.ymlの確認と修正
それでdatabase.ymlを確認しましたが
...
production:
<<: *default
reconnect: true
pool: 10
...
だったので単純にpool: 20に変更して反映しました。
それで終わり!だと思いましたが…
pool変更ができない?
反映しましたが同じ頻度でエラが発生していることを発見。
poolが対応されていないと判断して確認すると
irb(main):009:0> ActiveRecord::Base.connection_pool
=> #<ActiveRecord::ConnectionAdapters::ConnectionPool... @size=5
...
poolサイズが5でした。
最初からdatabase.ymlが適用されたことなくてdefaultの5だったものでした。
サーバーのdatabase.ymlの内容見るとやはりpool設定した行もないし他にも微妙に内容が一致していないことを発見しました。
# opsworks
今回問題が発生したサーバーはawsのopsworksに構築されているサーバーでした。ドキュメント確認すると
アプリケーションをデプロイすると、アプリケーションの AWS OpsWorksdatabase.yml 属性からの情報を使用して新しい deploy ファイルが Stacks によって作成されます。例えばMySQL または Amazon RDS インスタンスをアタッチするアプリにAWS OpsWorksスタックは、接続情報をdeploy属性は、database.ymlには正しい接続データが自動的に含まれます。
アプリケーションのdatabase.ymlじゃなくdeployする時作成するdatabase.ymlを利用することだったものでした。
chefに本物のdatabase.ymlがあったので今回はちゃんとpool: 20を追加して再びデプロイしました。
まだエラーが終わらない
反映結果半分以上エラーが減らしましたがまだ発生していることを確認しました。
もしpoolが正しくないかと思って検索するとsidekiq concurrency以上のpoolが必要でした。
うちのsidekiq concurrencyが48だったので20でも足りなかったものでした
sidekiqがTHREADを多めに作っていることが影響になっていることでした。
結論と追加確認
pool: 50設定でエラーが0になりました!!!!
解決!!!!
pool sizeがdefaultの5だったけどエラーが発生しなかったことは長い時間多めのサクセスが無かった状態だったので起こっていなかっただけの話。で終わりの話でしたが5->50の10倍に増やしたのでもしRDSの制限に問題ないかと思いました。
awsのrdsを利用しているので確認しました。
RDS→データベース→(利用中のDB)→設定タブ→パラメータグループ
からmax_connectionsを検索しました。
DBInstanceClassMemory/12582880なら30GBなので2400までOK
サーバーの数やプロセス数*50しても全然問題ない制限でした。
今回はそれで終わる
参考URL