# Wraparound и колесо XID _Vacuum, freeze, wraparound · PostgreSQL Knowledge Base_ **TL;DR:** xid - 32-битное число, счётчик переполняется примерно через 4 млрд транзакций. Сравнения видимости идут по кругу: версия старше текущего на ~2 млрд «переворачивается» в будущее и молча исчезает. Защита - заморозка и лестница из autovacuum, failsafe, WARNING и single-user. ## Откуда берётся Каждой изменяющей транзакции PostgreSQL выдаёт `xid` - следующее значение 32-битного счётчика. Видимость версии решается сравнением `xmin`/`xmax` со снимком: меньше - прошлое, больше - будущее. Но 32 бита вмещают лишь ~4 млрд значений, и на активной базе счётчик переполняется за недели-месяцы. ## Круг вместо прямой Чтобы сравнения работали после обнуления, PostgreSQL считает их на круге: для любого `xid` ~2 млрд значений назад - прошлое, ~2 млрд вперёд - будущее. Ловушка: версия, чей `xmin` отстал больше чем на 2 млрд, «перепрыгивает» в будущее и становится невидимой. Данные физически на месте, но СУБД считает их несуществующими - это и есть wraparound, молчаливая потеря данных. ## Защита: заморозка Не дать ни одной версии состариться больше чем на 2 млрд - задача заморозки (см. [freeze](/courses/postgres/kb/freeze.md)). VACUUM морозит старые версии, выводя их из круга. Пока заморозка поспевает, wraparound невозможен. ## Лестница защиты | Возраст | Что включается | |---|---| | ≥ 200 млн (`autovacuum_freeze_max_age`) | анти-wraparound autovacuum, даже при выключенном autovacuum | | ≥ 1.6 млрд (`vacuum_failsafe_age`) | failsafe: VACUUM бросает очистку индексов и паузы, гонит заморозку | | < 40 млн до края | WARNING в лог с обратным отсчётом | | < 3 млн до края | сервер отказывается выдавать xid, база встаёт | Из остановившейся базы выходят через VACUUM в однопользовательском режиме: ```bash postgres --single -D /var/lib/postgresql/data mydb ``` ```sql backend> VACUUM; ``` ## Как не попасть До single-user доходят почти всегда те, кто отключил autovacuum «ради производительности». Анти-wraparound autovacuum - первая и обычно достаточная линия обороны (см. [autovacuum](/courses/postgres/kb/autovacuum.md)). Следить за приближением нужно по `age(relfrozenxid)` и не забывать про второй счётчик - [multixact](/courses/postgres/kb/multixact.md). ## Команды ```sql SELECT max(age(relfrozenxid)) FROM pg_class WHERE relkind = 'r'; ``` Самая старая таблица в базе — насколько близко к 200 млн ```sql SELECT datname, age(datfrozenxid) FROM pg_database ORDER BY 2 DESC; ``` Возраст баз — глобальная близость к wraparound ## См. также - [Заморозка и relfrozenxid](/courses/postgres/kb/freeze.md) - [Multixact и relminmxid](/courses/postgres/kb/multixact.md) - [Autovacuum: пороги и bloat](/courses/postgres/kb/autovacuum.md)