ども、@kimihom です。
先日、Heroku Postgres の Hobby プランを使っていたら、急に DB へのアクセスが遅くなった事象が発生した。その原因と対応について記しておく。
問題の原因
まず、どんなときに遅くなったのかというと、1つのレコードに大量のデータが入ったときだった。それ以降、Heroku Addnons の NewRelic や Scout APM などのアドオンで重たい原因となっている部分を調べたところ、Active Record(DBアクセス) で 90% 以上の時間を費やしていることがわかった。
Postgres のレコードのカラムを text 型で保存し、そのカラムに大量の文字をテストで入れて保存してから、急にデータアクセスが遅くなってしまったのだった。そのデータは、ページロード時に読み込まれるデータであり、とりわけ Heroku Dyno を再起動した直後はまともにアクセスできず、 R12 Error が必ず発生してしまった。
その後、DB アクセスにキャッシュが入るようになると、それ以降は H12 は起きないものの、レスポンスが遅いことには変わりなかった。
問題の対応
まず、大量に入っているテキストのレコードはどれかを調べ、そのレコードを更新してみた。しかし、一度遅くなってしまったら、アクセスはずっと遅いままだった。
Hobby プランで使っていたのは、テスト環境のサーバーであったため、思い切って 一度 Heroku Postgres のバックアップをとってから削除し、改めて Heroku Postgres を入れることで対応した。
1. バックアップの保存、取得
まず Heroku Postgres のページへ遷移し、Durability
から、 Create Manual Backup
をクリックし、バックアップを作成する。しばらくすると、それがダウンロードできるようになるので、ダウンロードしてローカルのPCに保存する。
2. S3 など、アクセス可能な場所へ保存
ダウンロードしたバックアップを、S3 など URL でアクセスできるような場所に保存する。その URL を控えておく。
3. Heroku Postgres を再インストール
まず必要に応じて、メンテナンスモードを有効にする。その後、Heroku Postgres を削除する。
$ heroku maintenance:on -a myapp $ heroku addons:destroy heroku-postgresql:hobby-dev -a myapp $ heroku addons:create heroku-postgresql:hobby-dev -a myapp
4. バックアップデータを取り込む
先ほどバックアップしたデータを新しく入れた Heroku Postgres に入れる。無事に成功したら、メンテモードを OFF へ。
$ heroku pg:backups:restore 'https://myapp.s3-ap-northeast-1.amazonaws.com/backup' DATABASE_URL -a myapp $ heroku maintenance:off -a myapp
この作業により、DB へのアクセスが劇的に速くなり、問題を解決できた。S3 にあげたデータの削除をお忘れなく。
終わりに
今回の話は、Heroku Hobby プランで起きた問題であり、より上位プランであれば、そもそも大量のデータが入っても遅くはならなかった(確認済み)。
テスト環境のデータはできる限り安く運用したいだろう。今回のデータベースの削除と再インストールは、そこまで手間ではないので、一度 Heroku Postgres が遅いと感じた場合には大きなデータを削除した後、再インストールを試してみて欲しい。