PostgreSQL

Настройка autovacuum

Instagram 2013: база неожиданно остановилась в воскресенье в 3 ночи. Transaction ID wraparound. autovacuum был ограничен 'для производительности'. 2.1 миллиарда транзакций - и PostgreSQL перешёл в read-only emergency mode. 3 часа downtime, аварийное VACUUM FREEZE. После: autovacuum настроен агрессивно, мониторинг txid возраста - ежечасно. Правильный autovacuum - это не нагрузка, это страховка.

  • **Instagram** - txid wraparound incident 2013: научил весь мир мониторить age(relfrozenxid). Сейчас у них autovacuum настроен per-table для 1000+ таблиц
  • **Cloudflare** - per-table autovacuum: большие таблицы events (1B+ строк) с scale_factor=0.001 и cost_delay=0. Таблицы config (100 строк) - стандартные настройки
  • **Aiven** - managed PostgreSQL: автоматически применяет агрессивные per-table настройки для таблиц > 10M строк, алерты на wraparound при age > 500M

Ключевые параметры autovacuum

**Autovacuum** - фоновый процесс, очищающий dead tuples после UPDATE/DELETE и обновляющий статистику для планировщика. Без autovacuum таблицы раздуваются (bloat), статистика устаревает, возможен txid wraparound. Правильная настройка autovacuum - фундамент стабильной production БД.

**Никогда не отключать autovacuum** даже временно на production. Без него таблицы накапливают dead tuples, txid wraparound останавливает весь кластер. Если autovacuum создаёт нагрузку - настроить cost-based delay, не отключать.

autovacuum отключён на production 2 недели для 'снижения нагрузки'. Какой риск самый критичный?

Scale Factor: проблема больших таблиц

**autovacuum_vacuum_scale_factor = 0.2** означает: запускать VACUUM когда dead tuples = 20% от таблицы + autovacuum_vacuum_threshold (дефолт 50). Для таблицы 100 строк: 50+0.2×100 = 70 dead tuples. Для таблицы 100M строк: 50+0.2×100M = 20M dead tuples! Большие таблицы ждут VACUUM очень долго.

**Общее правило:** для таблиц > 10M строк устанавливать autovacuum_vacuum_scale_factor = 0.01 или меньше. Для таблиц > 100M строк - 0.001 или абсолютный threshold. Цель: VACUUM должен успевать до накопления значительного bloat.

Таблица 200M строк, scale_factor = 0.2. Выполняется 50K UPDATE/час. Через сколько часов сработает autovacuum?

Cost-Based Delay: не мешать production

**Cost-based delay** ограничивает I/O нагрузку от autovacuum. После каждых autovacuum_vacuum_cost_limit 'единиц работы' - autovacuum засыпает на autovacuum_vacuum_cost_delay мс. Чтение страницы = 1 единица (из кеша) или 10 единиц (с диска). Запись = 20 единиц.

**На NVMe SSD** cost_delay = 2 мс избыточно. NVMe выдерживает 500K+ IOPS - autovacuum даже с delay=0 не насытит диск. Для SSD рекомендуется autovacuum_vacuum_cost_delay = 0 или 1 мс, cost_limit = 1000-2000.

Autovacuum не успевает очистить rapidly growing таблицу (n_dead_tup растёт). Что дает самый быстрый результат?

Per-Table Settings: точная настройка

**Разные таблицы имеют разные паттерны доступа** и требуют разных настроек autovacuum. Маленькие reference таблицы (редко меняются) - не нужен частый vacuum. Большие таблицы с высоким UPDATE rate - нужен агрессивный vacuum. Per-table settings через `ALTER TABLE ... SET (storage_parameter)`.

**Автоматизация через скрипт:** мониторить pg_stat_user_tables, выявлять таблицы с high n_dead_tup или n_dead_tup / n_live_tup > 10%, автоматически применять per-table settings. Это лучше чем одна глобальная настройка на все таблицы.

Таблица `audit_log` - только INSERT, нет UPDATE/DELETE. Какая настройка autovacuum оптимальна?

Мониторинг autovacuum

**Мониторинг autovacuum** - ключ к обнаружению проблем до их влияния на production. Главные метрики: bloat по таблицам, время последнего autovacuum, txid возраст таблиц, число dead tuples, работающие autovacuum workers.

**txid wraparound = аварийная остановка кластера.** Когда age(relfrozenxid) > autovacuum_freeze_max_age (дефолт 200M транзакций) - PostgreSQL форсирует VACUUM. Когда age > 2 млрд - БД переходит в read-only emergency mode. Алерт на age > 500M обязателен.

Autovacuum мешает production нагрузке - лучше его ограничить

Autovacuum - обязательный компонент. Ограничение через cost_delay и scale_factor позволяет балансировать нагрузку. Полное ограничение приводит к bloat, устаревшей статистике и txid wraparound

MVCC создаёт dead tuples при каждом UPDATE и DELETE. Без очистки таблицы растут бесконечно, seq scan замедляется, индексы раздуваются. PostgreSQL специально спроектирован с расчётом на работающий autovacuum. Правильная настройка cost_delay и scale_factor - инструмент балансировки, а не ограничения

pg_class показывает age(relfrozenxid) = 1.8 млрд для таблицы `transactions`. Что делать немедленно?

Итоги

  • **autovacuum = всегда on**. Настраивать cost_delay/scale_factor, не отключать
  • **scale_factor = 0.2** катастрофичен для больших таблиц (200M строк = ждать 40M dead tuples). Для таблиц > 10M строк: 0.01-0.001
  • **cost_delay** ограничивает I/O. На NVMe: delay=0 или 1ms. На HDD: 2-5ms. Per-table для проблемных таблиц
  • **Мониторинг txid wraparound** - age(relfrozenxid) > 500M = алерт. > 1.5M = VACUUM FREEZE немедленно
  • **Per-table settings** - правильный подход. Разные таблицы требуют разных настроек через ALTER TABLE SET (storage_parameter)

Связанные темы

Autovacuum тесно связан с несколькими внутренними механизмами:

  • MVCC — Autovacuum очищает dead tuples, созданные MVCC при UPDATE/DELETE. Без autovacuum MVCC накапливает мусор бесконечно
  • VACUUM и bloat — Autovacuum запускает VACUUM и ANALYZE автоматически. Понимание VACUUM - понимание что делает autovacuum
  • Txid wraparound — Autovacuum - единственная защита от wraparound через FREEZE. Мониторинг wraparound риска критически важен

Вопросы для размышления

  • Таблица `orders` с 100M строк, 200K UPDATE/день. autovacuum_vacuum_scale_factor = 0.2. Рассчитать когда запустится autovacuum. Какой scale_factor нужен чтобы autovacuum запускался раз в 6 часов?
  • pg_stat_user_tables показывает: n_dead_tup = 5M, n_live_tup = 10M, last_autovacuum = 3 дня назад. Autovacuum запущен (видно в pg_stat_activity). Почему он не очищает эту таблицу? Как это диагностировать?
  • После deploy с 1000 миграций (массовые UPDATE) pg_stat_user_tables показывает dead_pct = 80% на основных таблицах. Как быстро восстановить без VACUUM FULL (он блокирует)? Как предотвратить в будущем?

Связанные уроки

  • db-09-indexes-btree
Настройка autovacuum

0

1

Войти