Каждые 5 минут транзакции в высоконагруженной PostgreSQL базе внезапно замирают на 3 - 7 секунд. Мониторинг показывает скачок IO Wait до 100%, а p99 latency улетает в космос. Причина кроется в дефолтных настройках механизма checkpoint, который превращает фоновый сброс грязных страниц в дисковый шторм.
По умолчанию параметр max_wal_size установлен на скромные 1 ГБ, а checkpoint_completion_target равен 0.5. Это значит, что при накоплении 1 ГБ WAL ядро и PostgreSQL обязаны сбросить все модифицированные буферы из Shared Buffers на накопитель ровно за половину времени от предыдущего чекпоинта. На SSD NVMe класса Enterprise с IOPS 500k это работает терпимо, но в облачных инстансах с ограниченным IOPS (например, AWS EBS gp3 с честными 3000 IOPS) процесс превращается в катастрофу.
База начинает агрессивно выплевывать гигабайты грязных страниц (dirty pages) на накопитель короткими очередями. Происходит переполнение системного page cache и дискового контроллера, очередь запросов (io_depth) забивается, а бэкграунд-процесс checkpointer упирается в ограничение по пропускной способности. В этот момент ядро Linux через демон pdflush или writeback начинает принудительно тормозить все процессы, записывающие данные, чтобы разгрести переполненные буферы. Так рождаются те самые микрофризы, во время которых замирает весь пул соединений.
Чтобы избавиться от этих фризов, нужно изменить три ключевых параметра в postgresql.conf:
1. Увеличиваем объем WAL между чекпоинтами до реальных размеров рабочей нагрузки. Для систем с высокой интенсивностью записи ставим max_wal_size = '64GB' (или хотя бы '16GB'), а min_wal_size = '4GB'. Это позволит чекпоинтам срабатывать реже и сгладит пики записи.
2. Размазываем процесс сброса во времени. Устанавливаем checkpoint_completion_target = '0.9'. Теперь PostgreSQL будет распределять запись грязных страниц на 90% интервала между чекпоинтами, снижая мгновенную интенсивность IOPS почти в два раза.
3. Ограничиваем скорость фоновой записи, чтобы она не выжигала весь доступный диск. Параметр checkpoint_warning = '30s' поможет вовремя отловить в логах ситуации, когда чекпоинты отрабатывают быстрее заданного интервала (сигнал к тому, что max_wal_size снова пора увеличивать).
На уровне Linux Kernel также важно зафиксировать параметры виртуальной памяти в sysctl.conf:
vm.dirty_background_ratio = 5
vm.dirty_ratio = 10
Это заставит ядро начинать фоновый сброс грязных страниц раньше (при заполнении 5% RAM), не дожидаясь жесткого блокирующего сброса при достижении 10%. В результате дисковая подсистема работает в линейном режиме без микрофризов и деградации p99, а TCO инфраструктуры снижается за счет отказа от избыточного provisioning IOPS на дисках.
- Инфраструктурный аудит и калькулятор TCO кластера: @Personnel_run_bot (/tma)
- База знаний и разборы: ftops.space
- ftops.space | Run-As-Daemon Infrastructure
| # | Наименование новости | Тональность | Информативность | Дата публикации |
|---|---|---|---|---|
| 1 | Каждые 5 минут транзакции в PostgreSQL замирают на 3 - ... | 0 | 10.65 | 25-09-2026 |
| 2 | Каждые 5 минут транзакции в PostgreSQL замирают на 3 - ... | 0 | 9.34 | 22-09-2026 |
| 3 | PostgreSQL и временные таблицы. Часть 2: почему 1024 счётчиков бывает мало | 0 | 10.98 | 09-09-2026 |
| 4 | База данных захлебывается в дисковом I/O wait, хотя на сервере ... | 0 | 7.98 | 25-09-2026 |
| 5 | Записки оптимизатора 1С (ч.19). Как настройка Huge Pages в Linux влияет на устойчивость работы Postgres | 0 | 7.86 | 04-09-2026 |
| 6 | PostgreSQL Autovacuum Internals and Benchmark | 0 | 4.74 | 01-07-2026 |
| 7 | Fixing Common PostgreSQL Performance Bottlenecks | 0 | 5.59 | 04-12-2020 |
| 8 | The insert benchmark on a small server : Postgres 12.22 through 18.3 | 0 | 11.9 | 29-03-2026 |
| 9 | База данных захлебывается в дисковом I/O wait, хотя на сервере ... | 0 | 8.41 | 26-09-2026 |
| 10 | Мы написали автономного агента для VACUUM/ANALYZE и запустили на 800+ тестовых БД: что из этого вышло | 0 | 8.16 | 23-09-2026 |