Про bloat в pg и как с ним бороться (pt. 2)
Перфоманс ревью почти закончилось, поэтому я снова в строю
В предыдущем посте посте обсудили, что таблица может блоатиться из-за фрагментации, и один из способов борьбы — это пересбор таблицы с помощью vacuum full. Однако он берет эксклюзивную блокировку и на больших таблицах может ее держать несколько часов. Поэтому такой способ не подходит, если даунтаймы недопустимы
Одна из альтернатив — расширение pg_repack, которое позволяет пересобрать таблицы и индексы без долгих блокировок
---
Можно отдельно рассмотреть два режима
1. Пересбор только индексов (--only-indexes)
Это простой случай — репак просто подменяет индекс:
1) Создает копию индекса через create index concurrently
2) Удаляет старый индекс, а новый переименовывает в старый
В целом такое спокойно делается и без репака
2. Пересбор таблиц
Тут уже сложнее — нужно создать копию таблицы, при этом по дороге не просыпать данные, и не провоцировать долгие блокировки
Конкретные DDL/DML можно почитать тут, если в общих чертах, то шаги такие:
1) Под access exclusive блокировкой: создаем лог-таблицу для трекинга изменений и триггер, который будет "реплицировать" изменения из основной таблицы в лог-таблицу
2) Создаем новую таблицу-копию (буквально через insert into new select * from old)
3) Создаем индексы на копию
4) Накатываем на копию "лаг", который за это время образовался в лог-таблице
5) Под access exclusive блокировкой: атомарно подменяем старую и новую таблицы, старую удаляем
Итого имеем полностью пересобранную таблицу и индексы без bloat-а
---
Что важно знать и что может пойти не так
1. Во write-intensive базах может быть проблематично взять access exclusive блокировки
2. Репак создает копию таблицы через insert .. select *, что может генерить резкую IO нагрузку на диск. Встроенной функциональности ее ограничить в репаке нет, но можно придумать workaround-ы наподобие такого через cgroup
2.1. — надо иметь на диске свободного пространства ~x2 от размера таблицы
2.2. — резко накапливается WAL, что приводит ко всем сопутствующим проблемам
2.3. — такое действие провоцирует долгую транзакцию, которая держит горизонт => встает автовакуум => вновь копится bloat
---
Overall, если у вас нагруженная система, и при этом вы можете выделить окно обслуживания, в котором нагрузка будет сильно меньше — pg_repack скорее всего вам подойдет
Если же система нагруженная, но окошек с низкой нагрузкой нет, то pg_repack вероятно вам просто положит базу. Поэтому стоит рассмотреть более "онлайновые" инструменты — pg_squeeze и pgcompacttable
По традиции, 👍 — если нужен пост про них
Post #164
10.9K