PostgreSQL под нагрузкой ведёт себя не так, как написано в документации: Михаил Жилин о том, что происходит на самом деле

Автор: Михаил Жилин · HighLoad++ Channel

Доклад с HighLoad++ 2024, 50 минут. PostgreSQL — база, которую хорошо знают и любят. Но поведение под нагрузкой — это другая тема: здесь включаются механизмы, которые в обычной работе не видны и в документации описаны скромно.

Жилин разбирает аномалии, которые проявляются именно под нагрузкой: как MVCC-механизм начинает накапливать мёртвые версии строк быстрее, чем autovacuum успевает их убирать; как это влияет на размер таблиц и производительность запросов; какие блокировки возникают там, где их не ждёшь; как connection pool ведёт себя при спайках и почему «просто увеличить max_connections» решает одну проблему и создаёт две новых. Доклад не обзорный — это конкретный производственный опыт с цифрами и конфигурациями.

Кому смотреть: разработчикам и DBA, которые эксплуатируют PostgreSQL под реальной нагрузкой и хотят понять, почему база «начала тормозить» — и особенно тем, кто ещё не сталкивался с bloat и autovacuum lag, пока они не случились в продакшне.

Из этого можно взять в работу: посмотрите на размер ваших самых активно обновляемых таблиц через pg_stat_user_tables — n_dead_tup / n_live_tup. Если соотношение высокое, у вас есть bloat, который под нагрузкой превратится в деградацию производительности.

MVCC и bloat: PostgreSQL не обновляет строку на месте — он создаёт новую версию и помечает старую как удалённую. При высоком темпе обновлений мёртвых версий накапливается быстро, autovacuum не успевает, таблица разрастается, последовательное сканирование становится дороже. Жилин показывает, как выглядит эта деградация на графиках и при каких параметрах нагрузки autovacuum перестаёт справляться.

Блокировки под нагрузкой: часть блокировок в PostgreSQL возникает в ситуациях, которые не очевидны при разработке — DDL-операции на горячих таблицах, операции с индексами, длинные транзакции, которые удерживают snapshot. Под нагрузкой эти ситуации проявляются как lock wait cascades — очередь блокировок, которая быстро растёт и приводит к таймаутам.

Connection management: PostgreSQL не использует лёгкие coroutine-based соединения — каждое соединение это форкнутый процесс. При спайках трафика без пуллера (PgBouncer, Pgpool) база тратит значительные ресурсы на management самих соединений, не на обработку запросов. Доклад разбирает конкретные режимы пуллинга (session, transaction, statement) и их trade-offs.

Настройки под нагрузку: Жилин приводит конкретные параметры, которые стоит пересмотреть при эксплуатации под высокой нагрузкой: autovacuum_vacuum_cost_delay, autovacuum_max_workers, checkpoint_completion_target. Не универсальный тюнинг, а объяснение того, что именно каждый параметр регулирует и при каких сигналах его стоит трогать.