PostgreSQL — алерт когда таблица bloat-ится
Таблица занимает 200 ГБ из них 150 ГБ — bloat (dead tuples). VACUUM FULL требует exclusive lock, autovacuum не справляется. Заметишь когда index-scan станет seq-scan.
Рецепт
#!/usr/bin/env bash
# /etc/cron.d/pg-bloat
# 0 3 * * * postgres /opt/pg-bloat.sh
DB=${PGDATABASE:-postgres}
THRESH_PCT=${THRESH_PCT:-30} # alert above 30 % bloat
BLOATED=$(psql -At -d "$DB" -c "
SELECT relname || ':' || ROUND(100.0 * n_dead_tup / GREATEST(n_live_tup, 1)) AS bloat_pct
FROM pg_stat_user_tables
WHERE n_live_tup > 100000
AND 100.0 * n_dead_tup / GREATEST(n_live_tup, 1) > $THRESH_PCT
ORDER BY n_dead_tup DESC
LIMIT 5;
")
if [ -n "$BLOATED" ]; then
COUNT=$(echo "$BLOATED" | wc -l)
EXAMPLES=$(echo "$BLOATED" | tr '\n' ',')
curl -fsS "$HEARTBEAT_URL" --data-urlencode "tables_bloated=$COUNT,examples=$EXAMPLES"
exit 2
fi
echo "OK (no tables > ${THRESH_PCT}% bloat)"
То же самое в Enterno.io
Заверните в Enterno heartbeat — увидите тренд «bloat растёт на 1 % в день» и сможете spланировать pg_repack за неделю до OOM.
Похожие рецепты
autovacuum_max_workers упёрлись (long-running query держит lock, или vacuum_cost_limit мал) — таблицы bloat-ятся, дисковое потребление растёт линейно. Постгрес сам не алертит.
Нужно ловить момент, когда реплика начала отставать от мастера больше чем на 10 секунд.
Логи или backup-файлы съедают /var; через 24 часа сервер ляжет. Базовый df-чек один раз в 10 минут спасает от 2 АМ инцидента.