ローカルでの開発に docker compose
を利用していて、 postgres
コンテナに大量データを追加していくとSELECT
を発行した時にエラーが出るようになった。
ActiveRecord::StatementInvalid: PG::InternalError: ERROR: shared buffer hash table corrupted (ActiveRecord::StatementInvalid)
コンテナを再起動したりするとエラーにならない場合もある。
メモリ関連の値を変更すれば解消できるのではないかと考え、値を変更してみた。
※ 以下の対応で設定したメモリの値を適当なので、本番等では PostgreSQLのメモリ管理を考える を参考に計算する必要がある。
対応1 shared_buffers
のサイズを増やす
現状のcomposeの設定内容と shared_buffers
のサイズ。
db:
image: postgis/postgis:12-3.1-alpine
...
volumes:
- db:/var/lib/postgresql/data:cached
❯ docker compose exec -i db psql -c 'show shared_buffers;'
shared_buffers
----------------
128MB
(1 row)
まずはこのdocker イメージで利用している設定ファイルをコピーする。
docker compose run -i --rm db cat /var/lib/postgresql/data/postgresql.conf > conf/postgresql.conf
shared_buffers
をとりあえず倍に増やしてvolumeにマウントする。
- shared_buffers = 128MB # min 128kB
+ shared_buffers = 256MB # min 128kB
volumes:
- db:/var/lib/postgresql/data:cached
+ - ./config/postgresql.conf:/var/lib/postgresql/data/postgresql.conf
再びデータを追加していくと同様のエラーが発生する。
対応2 work_mem
maintenance_work_mem
を増やす
追加で以下の変更を行う。
- #work_mem = 4MB # min 64kB
- #maintenance_work_mem = 64MB # min 1MB
+ work_mem = 64MB # min 64kB
+ maintenance_work_mem = 128MB # min 1MB
今度はエラーの内容が少しだけ変わった。
ActiveRecord::StatementInvalid: PG::InternalError: ERROR: shared buffer hash table corrupted (ActiveRecord::StatementInvalid)
CONTEXT: parallel worker
なぜ並列実行されていて失敗してしまうのか根本原因がわからないが、並列実行を行わないように変更する。
- #max_parallel_maintenance_workers = 2 # taken from max_parallel_workers
+ max_parallel_workers_per_gather = 0 # taken from max_parallel_workers
一応これでデータは登録できた。
最終的には、 1,146,532件
を登録できた。
その後、max_parallel_workers_per_gather = 2
に戻しても特にエラーは出なかった。
まとめ
ローカルでの開発向けに、メモリ数、並列実行するを変更することでデータを投入することができた。
本番稼働を見据えて、CPUの数やコンテナに割り当てるメモリ数から postgres側のメモリを計算しておく必要がある。