chore(db): Postgres tradein уходит со стоковых настроек — конфиг в compose
All checks were successful
CI Trade-In / changes (pull_request) Successful in 13s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / changes (pull_request) Successful in 16s
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped

Блокер переезда (#2991). Контейнер шёл на ПОЛНОСТЬЮ стоковой конфигурации:
ни command:, ни смонтированного postgresql.conf. Замер прода 2026-08-20 —
169 млрд blks_read за 91,75 сут ≈ 175 МБ/с мимо кеша при shared_buffers 128 МБ.

Поправка к диагнозу из issue: 288 чекпойнтов в сутки — это ровно 24ч/288 =
5 минут, то есть дефолтный checkpoint_timeout, а НЕ max_wal_size. При WAL
7 ГБ/сут лимит в 1 ГБ дал бы 7 чекпойнтов, а не 288. Поэтому поднят именно
timeout до 30min — правка одного max_wal_size не изменила бы ничего.
Реже чекпойнты → реже full-page images, а они сейчас 55-86% объёма WAL.

Значения подобраны под ТЕКУЩИЙ сервер и не выходят за mem_limit=3g:
shared_buffers 768MB (6× от стоковых), work_mem 16MB, maintenance_work_mem
256MB (autovacuum по listings идёт 193 раза в сутки).

max_wal_size 4GB, а не 8GB: на диске 38 ГБ свободно, а pg_wal растёт до этого
значения. При timeout=30min между чекпойнтами копится ~0,15 ГБ — запас большой.

wal_compression=zstd — самая дешёвая победа при такой доле FPI.
random_page_cost 1.1 вместо стоковых 4: диск NVMe, а 4 — настройка под HDD,
из-за неё планировщик недооценивал индексные сканы.

pg_stat_statements подключён через shared_preload_libraries — расширение было
в образе, но не активировано, и прошлый разбор пришлось вести по косвенным
признакам.

shm_size 512m: дефолтные 64 МБ /dev/shm ронял параллельные воркеры на тяжёлых
PostGIS-сортировках.

mem_limit оставлен 3g. В комментарии зафиксировано, что при переезде его надо
поднимать ДО правки shared_buffers: лимит контейнера срабатывает раньше
postgresql.conf, и shared_buffers=16GB при mem_limit=3g даёт OOM на старте.

Refs #2991, #2989
This commit is contained in:
bot-backend 2026-08-20 23:34:40 +03:00
parent 172a36a202
commit d4692a6ff1

View file

@ -125,6 +125,70 @@ services:
# тяжёлых PostGIS-сортировок бэктеста/эстиматора + autovacuum)
mem_limit: 3g
memswap_limit: 3g
# ⚠️ При переезде на выделенный сервер (#2989) mem_limit поднимать ДО правки
# shared_buffers, а не после: лимит контейнера срабатывает РАНЬШЕ postgresql.conf,
# и shared_buffers=16GB при mem_limit=3g даёт OOM-kill на старте. Целевое на
# 64 ГБ — 40-48g, а не 64g: нужен запас под page cache ВНЕ контейнера.
shm_size: 512m
# /dev/shm по умолчанию 64 МБ. Параллельные воркеры кладут туда shared memory
# segments; на тяжёлых PostGIS-сортировках это «could not resize shared memory».
#
# ── Конфигурация Postgres (#2991) ─────────────────────────────────────────
# До этого контейнер шёл на ПОЛНОСТЬЮ стоковых настройках. Замер прода 2026-08-20:
# 169 млрд blks_read за 91,75 сут ≈ 175 МБ/с мимо кеша при shared_buffers=128 МБ.
#
# Значения подобраны под ТЕКУЩИЙ сервер и НЕ выходят за mem_limit=3g.
# После переезда пересчитать под 64 ГБ.
command:
- postgres
# Память. 768MB shared_buffers — 6× от стоковых 128MB, с запасом внутри 3g
# (idle-замер контейнера был 292 МБ, work_mem-спайки и autovacuum сверху).
- -c
- shared_buffers=768MB
# effective_cache_size — подсказка планировщику, НЕ аллокация. На хосте
# MemAvailable 6,1 ГБ, поэтому 6GB честно отражает доступный page cache.
- -c
- effective_cache_size=6GB
- -c
- work_mem=16MB
# maintenance_work_mem: autovacuum по listings идёт 193 раза в сутки,
# с 64MB каждый проход перечитывает индексы лишними итерациями.
- -c
- maintenance_work_mem=256MB
# Чекпойнты. ГЛАВНОЕ: 288 чекпойнтов в сутки — это ровно 24ч/288 = 5 минут,
# то есть дефолтный checkpoint_timeout, а НЕ max_wal_size. При WAL 7 ГБ/сут
# лимит в 1 ГБ дал бы 7 чекпойнтов, а не 288. Поэтому поднимаем ИМЕННО
# timeout — иначе правка max_wal_size ничего бы не изменила.
# Реже чекпойнты → реже full-page images (сейчас 55-86% всего объёма WAL).
- -c
- checkpoint_timeout=30min
- -c
- checkpoint_completion_target=0.9
# max_wal_size=4GB, а не 8GB: на диске сейчас всего 38 ГБ свободно, а pg_wal
# растёт до этого значения. При timeout=30min и 7 ГБ/сут между чекпойнтами
# накапливается ~0,15 ГБ, так что 4GB — потолок с большим запасом.
- -c
- max_wal_size=4GB
- -c
- min_wal_size=1GB
# Самая дешёвая победа при доле FPI 55-86%. zstd доступен с PG15, у нас 16.
- -c
- wal_compression=zstd
# Диск NVMe, а стоковый random_page_cost=4 — настройка под HDD: планировщик
# систематически недооценивает индексные сканы и уходит в Seq Scan.
- -c
- random_page_cost=1.1
- -c
- effective_io_concurrency=200
# pg_stat_statements: расширение есть в образе, но не подключено. Без него
# следующий разбор снова придётся вести по косвенным признакам.
# shared_preload_libraries требует рестарта — поэтому именно здесь.
- -c
- shared_preload_libraries=pg_stat_statements
- -c
- pg_stat_statements.max=5000
- -c
- pg_stat_statements.track=top
logging: *default-logging
environment:
POSTGRES_DB: tradein