Herokuを使ったシステム開発をしているときにDBのアクセスが異様に遅いことがありました。 その時の調査内容を記事にまとめてみました。同じ境遇の方がいるかもしれないので、ぜひ参考にしてみてください。
ランダムに発生するH12エラー
Heroku PostgresのHobby Basicプランは最大1000万レコードまでという制約はありますが、小規模な社内システムなどの開発であれば今まで問題なく使えていました。
今回の開発もHobby Basicを使用して実装を進めていたのですが、あるテーブルの一覧画面において頻繁にH12エラー(Request Timeout)が発生することがわかりました。
その画面はkaminariとransackを用いた極めて一般的な一覧画面です。
該当のテーブルは約60万件のレコード数を保持しており、外部キー以外はインデックスを貼っていませんでした。
実行計画を確認してみるとSeq Scanが発生していたのでsort keyにIndexを貼っていないことが原因かと思い、インデックスを貼ってみました。しかし解決されません。
H12エラーは毎回発生するわけではなく数時間に一回程度の頻度でした。一度発生するとしばらく発生しないという特徴がありました。
アプリのキャッシュが関係しているのかと思い、dynoを再起動させてキャッシュをクリアしてみましたが、H12エラーは発生せず、再現方法がわかりませんでした。
Hobbyプランはインメモリデータベースでない
dynoを再起動しても再現しないことからアプリが原因であるという線は薄くなりました。 となるとDBサーバーが原因なのではないかと思い、改めてHobby Basic Planの仕様を確認してみました。
Hobby Basic
- Row Limit 10,000,000
- Storage Capacity 10 GB
- RAM 0 Bytes
確認するとメモリが0バイト(RAM 0 Bytes)であることがわかりました。要するにインメモリデータベースではないということです。
データーベースはディスクアクセスを避けるためにメモリにデータをキャッシュさせておき、高速化を図ります。 しかしHobby basicの場合はインメモリを使用しないので、高頻度にディスクにアクセスをするということです。
インメモリデータベースにアップグレード
インメモリデータベースでないことが原因なのかを確かめるために、Standard 0プランにアップグレードしてみます。 Standard 0プランの仕様は以下のとおりです。
Standard 0
- Row Limit none
- Storage Capacity 64 GB
- RAM 4 GB
アップグレードしてアクセスしてみると、H12エラーは発生しなくなりました。平均的なアクセス時間も格段に短縮されました。
適切なプランを選択することが大事
今回の事象を通じてインメモリデータベースの重要性を思い知らされました。
Hobby basicは安価で魅力的なプランですが、扱うデータ数によっては力不足なケースがあります。 レコード数があまり多くない、パフォーマンスをそこまで追求しないシステムであればHobby basicでも十分だと思います。
私も今後の開発においてもHobby basicを使っていくことはあるかと思います。 システム要件やデータ数を元に適切なプランを採択することが重要なのだと感じました。