Почему настройка autovacuum в PostgreSQL не успевает за нагрузкой
Первым симптомом почти никогда не бывает отказ — сначала растёт время отклика на пиках. Таблицы разрастаются быстрее, чем их успевает обработать фоновая очистка: мёртвые версии строк остаются в страницах, место под них не возвращается в оборот, и каждый запрос читает заметно больше страниц, чем в них полезных данных. Отдельно тревожно, что внешне это выглядит как штатная работа — индексы используются, планы запросов не меняются, а деградация копится месяцами.
Заводские пороги рассчитаны на другой профиль нагрузки. Порог в пятую часть от размера таблицы для крупной таблицы означает, что очистка включится после десятков миллионов изменённых строк — а к этому моменту изменений набегает ещё столько же. Ограничение числа параллельных воркеров приводит к тому, что один тяжёлый проход держит очередь и остальные таблицы ждут; задержки между проходами по умолчанию слишком велики для базы с постоянной записью. В итоге фоновая очистка не успевает не из-за ошибки настройки, а из-за того, что параметры никто не пересчитывал под реальный поток изменений.
Дальше подключается обратная связь: чем сильнее раздувание таблиц, тем дольше идёт очистка, тем реже она завершается и тем быстрее растёт база. Плановое обслуживание превращается в аварийное — ручной запуск очистки в рабочие часы, блокировки, деградация на время прохода, риск упереться в свободное место на диске. Разбираем, как это закрывается: как считать пороги под фактический профиль записи и как вернуть обслуживанию регулярность.
Что даёт управляемая очистка таблиц: эффект в цифрах
Раздувание и объём хранения
Порог срабатывания по умолчанию привязан к доле таблицы, поэтому на крупной таблице autovacuum ждёт, пока наберутся миллионы мёртвых строк, — и файлы растут быстрее, чем очистка успевает их возвращать. Мы опускаем порог до приемлемого числа строк, добавляем запас свободного места на страницах под будущие версии строк и задаём отдельные правила для «горячих» таблиц вместо одного глобального. По системным счётчикам видно, что доля мёртвых строк сокращается в разы, а размер отношения перестаёт расти между циклами очистки.
Отклик и устойчивость
Обычная картина под нагрузкой — длинная очистка вытягивает дисковый ввод-вывод и держит блокировки ровно тогда, когда приходят пиковые запросы: время ответа растёт скачками, а очередь запросов накапливается. Мы ограничиваем интенсивность очистки, распределяем её по воркерам и уводим тяжёлые прогоны в окна низкой нагрузки, оставляя автозапуск включённым для остальных таблиц. В результате пиковые запросы перестают упираться в очистку, отклик остаётся предсказуемым, а ручные аварийные прогоны по расписанию уходят как класс отказов.
Режимы VACUUM: сравнение подходов и оптимизация расписания
Мёртвые строки копятся при любом режиме — разница в том, кто и когда запускает очистку. Ниже четыре рабочие альтернативы и условия, при которых каждая из них уместна.
| Вариант | Когда подходит | Ограничения |
|---|---|---|
| Пороговая автоочистка | Ровный поток изменений, таблицы предсказуемого размера | Порог по доле от размера срабатывает поздно: между проходами копятся мёртвые строки |
| Ручная очистка по окну | Пакетные загрузки, ночные расчёты, массовые обновления | Нужен внешний планировщик; попадание окна в пик трафика даёт рост задержек |
| Очистка по секциям | Партиционированные журналы и события с отвалом старых секций | Проход по родительской таблице секции не чистит — обслуживать нужно каждую |
| Отложенная заморозка | Таблицы с редкими обновлениями и старыми версиями строк | Запуск не привязан к окну обслуживания, проход идёт по всей таблице |
Как выбрать режим под профиль нагрузки
Смотрите на долю мёртвых строк к живым, скорость роста счётчика транзакций и наличие окна с просадкой трафика. Глобальные пороги задают поведение по умолчанию, но для горячих таблиц их переопределяют на уровне самой таблицы — крупная таблица перестаёт ждать общей очереди автоочистки и не накапливает мёртвые строки между редкими проходами.
Ограничения: блокировки, репликация, отставание копий
Очистка не блокирует чтение и запись, но конфликтует с изменением структуры таблицы и индексов. Параллельно она пишет в журнал предзаписи: на репликах растёт поток изменений, и копия может отставать на тяжёлых проходах. Темп ограничивают задержками стоимости, а полные проходы и отложенную заморозку выносят в окно низкой нагрузки, чтобы обслуживание не совпало с отчётами или выгрузками.
Порядок работ: от инвентаризации баз до регламента обслуживания
Работу строим от факта, а не от типового набора параметров: сначала снимаем состояние базы, потом меняем конфигурацию. Шесть этапов ниже дают проверяемый артефакт на каждом шаге, поэтому решение о включении в рабочий контур принимается до правок, а не после.
Подготовка и безопасный пилот
- Снимаем статистику очистки: сколько мёртвых строк накопилось по таблицам, как часто проходит автоочистка, где счётчик мёртвых строк растёт быстрее всего.
- Собираем профиль нагрузки и роста таблиц: пиковые часы записи и обновления, суточный и недельный прирост, длинные транзакции, которые удерживают снимок и мешают очистке.
- Проектируем пороги и окна: отдельные коэффициенты для крупных и активных таблиц, расписание принудительной очистки в межпиковые интервалы, лимит нагрузки на дисковую подсистему.
- Отрабатываем схему на копии: разворачиваем копию базы, воспроизводим реальную нагрузку, смотрим поведение очистки под конкурентной записью и замеряем длительность блокировок.
Как проверяем результат
- Проводим контрольные замеры до и после: доля мёртвых строк, время тяжёлых запросов, размер файлов, частота аварийной очистки.
- Передаём регламент: карта таблиц с порогами, правила пересмотра при росте данных, набор запросов для самопроверки и порядок действий при аномалиях.
Конфигурации, схемы окон и регламенты обслуживания на выходе
Мы передаём не набор разовых команд, а рабочую конфигурацию: правила, по которым база поддерживает себя, и процедуры для случаев, когда автоочистка не справляется. Всё лежит в репозитории конфигурации и в документации — настройки воспроизводятся на стенде и в проде без расхождений.
Что настраиваем в базе
- Пороги автоочистки по группам таблиц: для горячих доля изменённых строк срабатывает раньше, для крупных архивов интервалы расширены, чтобы плановая очистка не вытесняла срочную.
- Схема окон обслуживания: тяжёлые операции только в часы низкой нагрузки, с ограничением длительности и привязкой к дежурствам.
- Перечень исключений: таблицы и крупные архивы с отдельным сценарием — разовые вставки, партиции под отсечение, данные только на чтение.
- Контрольные запросы и оповещения: доля мёртвых строк, давность последней очистки, приближение к предельному счётчику транзакций, скорость роста файлов.
Что остаётся у вашей команды
- Порядок планового обслуживания: кто открывает окно, что проверяется до и после, где фиксируется результат.
- Регламент эскалации: по каким показателям дежурный поднимает задачу, кому передаёт и что успевает сделать до отката.
- Доступы и журнал ручных операций: отдельные учётные записи для обслуживания, ограничение и след выполнения.
- Документация с обоснованием каждого порога — при росте данных правила пересчитываются, а не подбираются заново.
Кейс: раздувание сократили втрое без остановки сервиса
Вводные и ограничения проекта
Кластер PostgreSQL обслуживал сервис с непрерывным потоком записи: несколько таблиц-журналов постоянно обновлялись, а автоочистка работала на стандартных порогах срабатывания. Раздувание росло быстрее, чем очистка успевала его подбирать, — доля мёртвых строк в самых горячих таблицах подошла к 40%, а объём хранения разросся почти втрое против полезных данных. Окна простоя не было: сервис работает круглосуточно, останавливать базу ради ручной очистки мы не могли.
Второе ограничение — аварийные прогоны очистки. Их запускали вручную, когда раздувание переваливало за критическую отметку; каждый прогон просаживал отклик и держал инженеров в напряжении.
Результат и что изменилось в обслуживании
Пороги срабатывания и стоимость очистки пересчитали под профиль записи конкретных таблиц, а переход делали на работающей базе: сначала прогон новых настроек на реплике, сверка планов и нагрузки, затем плавное переключение без окна простоя. Доля мёртвых строк упала с 38% до 11%, объём хранения сократился втрое, отклик на пике стал ровнее — просадки на очистке перестали быть заметны в метриках.
Число аварийных прогонов снизилось с нескольких в месяц до одного-двух в квартал, и то по плановым поводам. Обслуживание перешло из режима «тушим пожар» в наблюдение: раздувание, частота очисток и возраст самых старых транзакций теперь на панели метрик, а пороги пересматриваются при изменении профиля записи.
Чем пороговые политики отличаются от расписания по окнам?
Пороговые политики опираются на число изменённых строк: доля мёртвых строк в таблице превышает заданный процент — сборка запускается, не дожидаясь календарной даты. Это даёт реакцию на всплески: пакетное удаление или массовая заливка сразу поднимают счётчик, и устаревшие версии строк не успевают раздуть файлы.
Обратная сторона — непредсказуемость по нагрузке. На крупной таблице процентный порог достигается редко и поздно, на мелкой — сборка идёт почти непрерывно. Пики ввода-вывода приходятся на моменты, когда система и без того занята, а согласовать их с резервным копированием и обновлением нельзя: расписания просто нет.
Плановые окна обслуживания снимают эту неопределённость. Запуск чистки привязан к ночному интервалу, инженер заранее знает, когда база потратит ресурсы на сборку мусора, и совмещает это с другими регламентными работами. Цена — запаздывание: между окнами таблица копит мёртвые строки, и всплеск в неудачный момент успевает надуть файлы быстрее, чем придёт расписание.
Гибридная схема очистки берёт реактивность порогов и предсказуемость окон: фоновая чистка идёт по расписанию, для таблиц с высокой записью понижаются пороги и выставляется более агрессивный режим, а заморозка и переиндексация остаются в окне. Для баз, которые уже обслуживаются вручную, это рабочий вариант: ручной запуск сохраняется как точка контроля, а пороги страхуют от пропущенного окна.
Автоочистка под нагрузкой: блокировки, крупные таблицы, проверка
Автоочистка включается сама и на нагруженной базе регулярно упирается в блокировки, крупные таблицы и нехватку времени на проход. Ниже — ответы на сомнения, которые чаще всего звучат перед изменением этих настроек.
Все они про эксплуатацию без простоя: что можно править на живой базе, а что требует окна.
Очистка заблокирует таблицы и уронит сервис?
Штатный проход берёт слабую блокировку и не мешает ни чтению, ни записи. Монопольную держат только полная пересборка таблицы и перестроение индексов — их выносим в окно обслуживания.
Можно ли менять параметры без перезапуска?
Пороги и задержки задаются для конкретной таблицы и вступают в силу для следующих проходов — перезапуск не нужен. Настройки общего пула памяти применяются при старте, их планируем заранее.
Что делать с крупными таблицами и архивами?
На таблице в сотни гигабайт доля изменённых строк долго не доходит до порога, и она остаётся необработанной. Разбиваем её на разделы по времени, пороги задаём отдельно, а старые архивы обслуживаем своим регламентом вне автоочистки.
Как убедиться, что обработка идёт?
Смотрим системные представления и журнал: время последнего прохода, число мёртвых строк, счётчики заморозки. По ним настраиваем оповещение — о застое узнаём до того, как вырастет файл.
База обслуживается годами, всё запущено — с чего начать?
С обследования: где копится мёртвое, какие длинные транзакции держат очистку, где счётчик идентификаторов близок к пределу. Изменения прогоняем на копии и только потом переносим в рабочий контур.
Обсудим задачу: соберём профиль нагрузки и план работ
Чтобы оценка опиралась на факты, а не на предположения, нам нужны исходные данные по вашей базе. Собрать их можно за один проход по системным представлениям и журналам — на этой основе мы посчитаем объём работ и порядок изменений.
- статистика очистки: сколько мёртвых строк накапливается, какие таблицы выпадают из обработки, как часто срабатывает автоочистка и где она не успевает за записью;
- динамика роста таблиц и индексов — сколько объёма прибавляется за сутки и на каких объектах рост опережает очистку;
- окна нагрузки: когда пик записи, в какие часы можно запускать тяжёлые операции без влияния на пользователей;
- ограничения по простоям: допустимая длительность недоступности, наличие реплик и возможность переключения на них;
- уже применённые настройки — изменённые пороги автоочистки, ручные расписания, обходные правила, которые кто-то вводил раньше;
- параметры сервера и версия ветки: объём памяти, число ядер, тип диска, конфигурация журнала транзакций;
- история инцидентов: когда последний раз разрастался журнал или проседала скорость запросов после массового обновления.
Опишите задачу и приложите то, что есть, — вернёмся с оценкой и планом работ. В плане будет видно, что меняем в порогах, что переносим в регулярный регламент и на каких контрольных замерах подтверждаем результат.
- Отключают автоочистку целиком, посчитав её виновником просадок, и возвращают обратно только после того, как раздувание уже стало заметно
- Копируют пороги с одной базы на все остальные, не учитывая разницу в размерах таблиц и характере записи
- Оставляют процентные пороги для крупных таблиц, где нужный объём изменений просто не набирается, и очистка до них не доходит
- Не закрывают длительные транзакции и «висящие» соединения, из-за чего старые версии строк не освобождаются вообще
- Переносят очистку в ночные окна, где она сталкивается с копированием и обслуживанием, и снова не получает ресурсов
- Запускают полную перестройку таблиц там, где хватило бы управляемого расписания, и останавливают запись в часы пик
- Не фиксируют состояние до изменений, поэтому вывод «стало лучше» остаётся на уровне ощущений и не проверяется на замерах
- Правят значения вручную на каждом узле и не хранят их в общем описании конфигурации — при следующем развёртывании прежние настройки возвращаются







