Выберите продукт

PostgreSQL: could not access status of transaction (wraparound) — диагностика и восстановление

Ошибка «could not access status of transaction» в PostgreSQL часто идёт рядом с XID wraparound: растёт age(datfrozenxid), autovacuum freeze не успевает, а каталог pg_xact становится критичной точкой. Ниже — диагностика и пошаговое восстановление.
PostgreSQL: could not access status of transaction (wraparound) — диагностика и восстановление

Иногда PostgreSQL начинает «сыпаться» ошибкой could not access status of transaction. Она может проявляться в обычных запросах (SELECT/UPDATE), во время VACUUM или даже при старте сервиса. На практике это почти всегда означает, что серверу сложно или невозможно корректно читать/обновлять статусы транзакций, а рядом часто присутствует риск XID wraparound (переполнения счётчика XID).

Ниже — понятное объяснение связки pg_xact → статусы транзакций → MVCC, а также быстрая диагностика по age(datfrozenxid)/age(relfrozenxid) и план действий: от «вернуть сервис» до нормализации vacuum freeze.

Почему XID и wraparound — это аварийный сценарий, а не теория

PostgreSQL использует 32-битные идентификаторы транзакций (XID). Они растут по мере работы системы. Когда счётчик подходит к пределу и «переполняется», старые XID начинают выглядеть как «будущие» — это ломает MVCC-логику видимости строк. Поэтому PostgreSQL заранее включает защитный механизм: требует заморозки (freeze) старых версий строк.

Заморозка делается через VACUUM (обычно autovacuum). При VACUUM часть строк помечается как «замороженные» (их XID заменяется специальным FrozenXID), а в базе обновляется нижняя граница — datfrozenxid. Если datfrozenxid давно не двигался, растёт xid age и система приближается к wraparound.

Когда autovacuum freeze не успевает, PostgreSQL может начать ограничивать операции ради защиты от wraparound. Ошибки чтения статусов транзакций часто всплывают рядом, потому что обращение к статусам XID — базовая операция MVCC.

Что означает «could not access status of transaction» и при чём тут pg_xact

Чтобы определить видимость версий строк, PostgreSQL должен знать состояние транзакции: committed, aborted или in progress. Эти статусы хранятся в каталоге данных pg_xact (в старых версиях — pg_clog).

Ошибка could not access status of transaction означает: сервер попытался обратиться к статусу конкретной транзакции (XID), но не смог корректно прочитать нужную страницу/сегмент в pg_xact.

Чаще всего на проде встречаются причины:

  • Проблемы диска/ФС/снапшотов: I/O ошибки, «битые» блоки, внезапные ребуты, сбои контроллера, проблемы на уровне гипервизора.
  • Закончился диск: PostgreSQL не смог вовремя создать новый сегмент pg_xact или дописать существующий.
  • Повреждение данных: неконсистентность после аварийного выключения, усиленная аппаратными проблемами.
  • Wraparound pressure: autovacuum не успевал, база подошла к опасным значениям, а любые сбои по I/O добивают ситуацию.

Важно: ошибка про pg_xact — это уже инцидент уровня «проверить хранилище и целостность», а не «подкрутить vacuum». Но параллельно обязательно оцените риск wraparound и срочно обеспечьте vacuum freeze, иначе даже после временного «оживления» база может снова уйти в защитный режим.

Диагностика XID wraparound и проверка age(datfrozenxid) в PostgreSQL

Если инцидент случился на виртуальной машине, отдельно проверьте базовые вещи: есть ли гарантированный IOPS, не упёрлись ли в лимиты диска/квоты, не было ли проблем на ноде. На практике перенос PostgreSQL на более предсказуемую виртуализацию и диск часто снимает «плавающие» ошибки чтения. Для проектов, которым важна стабильная дисковая подсистема, обычно разумнее держать БД на VDS с понятными ресурсами, чем зависеть от соседей.

Быстрая диагностика: проверяем xid age и datfrozenxid

Подключитесь под суперпользователем и посмотрите возраст XID по базам:

psql -X
SELECT datname,
       age(datfrozenxid) AS xid_age,
       datfrozenxid
FROM pg_database
ORDER BY xid_age DESC;

Как читать результат:

  • xid_age большой и растёт — autovacuum freeze не справляется или ему мешают блокировки/ограничения.
  • Одна база сильно «старше» остальных — проблема локальная (долгие транзакции, слоты, отключённый autovacuum на таблицах, особенности нагрузки).

Дальше найдите самые «старые» таблицы по relfrozenxid:

SELECT n.nspname,
       c.relname,
       age(c.relfrozenxid) AS xid_age,
       c.relfrozenxid
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('r','m')
ORDER BY xid_age DESC
LIMIT 50;

Проверяем, не мешают ли длинные транзакции

Самая частая причина, почему freeze «не двигается»: кто-то держит snapshot — долгий idle in transaction, зависшая миграция, большой бэкап-сценарий, открытый курсор. Найдите самые длинные транзакции:

SELECT pid,
       usename,
       application_name,
       client_addr,
       state,
       now() - xact_start AS xact_age,
       wait_event_type,
       wait_event,
       LEFT(query, 200) AS query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_age DESC
LIMIT 30;

Пока такие транзакции живы, vacuum freeze может не продвинуть datfrozenxid. Если есть возможность, сначала остановите/ограничьте приложение, чтобы «не плодить» новые долгие транзакции, и только затем переходите к freeze.

Виртуальный хостинг FastFox
Виртуальный хостинг для сайтов
Универсальное решение для создания и размещения сайтов любой сложности в Интернете от 95₽ / мес

Проверяем здоровье диска и симптомы проблемы с pg_xact

Если ошибка could not access status of transaction уже была, проверка хранилища обязательна. Минимальный чек-лист на Linux:

df -h

df -i
journalctl -u postgresql --since "-2h"
dmesg -T | tail -n 200

Что искать: I/O errors, filesystem errors, remount read-only, timeout/reset устройств, NVMe/SATA ошибки. Если ФС стала read-only или диск уходит в ошибки — сначала стабилизируйте хранение. Иначе любые действия внутри PostgreSQL будут непредсказуемыми.

План действий при инциденте: от «вернуть сервис» к нормализации freeze

Шаг 1. Зафиксируйте состояние и снимите копию (если возможно)

Если кластер ещё стартует, первым делом постарайтесь снять дамп критичных данных или хотя бы самых важных схем. При ошибках чтения pg_xact дамп может падать на части таблиц — сохраняйте то, что получается, и параллельно готовьте восстановление из бэкапа/PITR.

Если вы используете WAL-архивацию, держите под рукой отработанный сценарий восстановления. Полезные практики собраны в материале про восстановление PostgreSQL через PITR и WAL.

Шаг 2. Остановите «пожирателей freeze»: длинные транзакции

Если вы нашли долгие транзакции (особенно idle in transaction), их нужно аккуратно завершить. Технически — через pg_terminate_backend, но сначала оцените влияние на приложение (платежи, миграции, важные джобы). Иногда безопаснее временно остановить приложение и завершить сессии пакетно.

SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
  AND xact_start IS NOT NULL
  AND now() - xact_start > interval '30 minutes';

Порог подберите под ситуацию. Цель — убрать «якоря», которые не дают VACUUM продвинуть заморозку.

Шаг 3. Срочный VACUUM FREEZE на проблемных объектах

Когда риск wraparound высокий, ускоряйте заморозку вручную. Начинайте с таблиц с максимальным xid age (из запроса по pg_class). Помните: VACUUM (FREEZE) может быть тяжёлым по I/O, поэтому действуйте в окно и следите за нагрузкой.

VACUUM (FREEZE, VERBOSE) public.big_table;

Если база большая, идите батчами: сначала топ самых старых таблиц, затем остальные. После серии вакуумов снова проверьте age(datfrozenxid) по базам.

Шаг 4. Если autovacuum «молчит» — проверьте настройки и ограничения

Типовые причины, почему autovacuum freeze не успевает:

  • слишком маленькие лимиты по воркерам: autovacuum_max_workers;
  • слишком «бережные» лимиты по стоимости: autovacuum_vacuum_cost_limit и autovacuum_vacuum_cost_delay;
  • autovacuum отключён на отдельных таблицах через storage parameters;
  • постоянные блокировки из-за DDL, долгих транзакций или тяжёлых batch-операций.

Для точечной диагностики смотрите pg_stat_all_tables (когда был последний autovacuum/vacuum) и сравнивайте это с реальным ростом данных. Отдельно полезно держать под рукой разбор тюнинга: настройка autovacuum и индексов в PostgreSQL.

Когда проблема именно в pg_xact: что можно и чего нельзя делать

Если pg_xact реально повреждён, это уже не «просто vacuum». Дальнейшие действия зависят от того, есть ли валидный бэкап и насколько критичны данные.

Правильный путь: восстановление из бэкапа/PITR

Если есть проверенный бэкап + WAL (или реплика), восстановление почти всегда безопаснее, чем попытки «чинить файлы». Повреждение pg_xact означает, что PostgreSQL не может доверять части информации о транзакциях, и последствия могут быть непредсказуемыми.

Аварийный путь: pg_resetwal и риски

У PostgreSQL есть утилита pg_resetwal, которую иногда применяют в крайне аварийных случаях. Это инструмент последней надежды: он может помочь запустить кластер, но не гарантирует логическую целостность. Использовать его стоит только после фиксации копии кластера и понимания, что вы готовы к потере/расхождению данных.

Если вы рассматриваете pg_resetwal, сначала сделайте поблочную копию PGDATA или хотя бы архив каталога данных. Это даст шанс на форензику или частичное извлечение данных позже.

FastFox VDS
Облачный VDS-сервер в России
Аренда виртуальных серверов с моментальным развертыванием инфраструктуры от 195₽ / мес

Профилактика: как не доводить до wraparound и ошибок статусов транзакций

1) Мониторьте xid age и лидеров по возрасту

В мониторинг стоит вынести минимум: age(datfrozenxid) по каждой базе и топ таблиц по age(relfrozenxid). Так вы увидите проблему за недели до аварии, а не в момент, когда VACUUM уже «поздно».

2) Следите за «idle in transaction» и долгими миграциями

Лимиты вроде idle_in_transaction_session_timeout</code часто спасают от случайных зависших транзакций, которые тихо держат snapshot и блокируют freeze. Для миграций — делайте батчи, коммитьте чаще, избегайте огромных транзакций на часы.</p> <h3>3) Дайте autovacuum ресурсы</h3> <p>На нагруженных системах autovacuum — такой же «боевой» воркер, как и обработчики запросов. Ему нужны CPU, I/O и память. Если база переехала на более слабый диск или выросла конкуренция за ресурсы (особенно в виртуализации), autovacuum может хронически не успевать.</p> <h3>4) Держите регулярные проверяемые бэкапы</h3> <p>Инциденты уровня <code>pg_xact — ровно тот случай, когда бэкап «решает всё». Важно не только делать бэкап, но и регулярно проверять восстановление на тестовом контуре.

Схема восстановления PostgreSQL из бэкапа и WAL (PITR) после проблем с pg_xact

Краткая шпаргалка: что делать прямо сейчас

  1. Проверьте диск: место, inode, ошибки I/O в dmesg и journalctl.
  2. Оцените риск wraparound: SELECT age(datfrozenxid) по базам.
  3. Найдите лидеров по возрасту: age(relfrozenxid) по таблицам.
  4. Уберите длинные транзакции, которые держат snapshot.
  5. Запустите VACUUM (FREEZE) на самых старых таблицах и контролируйте прогресс.
  6. Если ошибка повторяется и есть признаки порчи pg_xact — готовьтесь к восстановлению из бэкапа/PITR, а не к «магии» на живом кластере.

Если вы пришли к этой ошибке на фоне переполненного диска или нестабильного хранилища, не откладывайте перенос базы на более надёжный слой хранения и пересмотр ресурсов autovacuum: wraparound — это таймер, который не ждёт, а pg_xact — один из самых чувствительных узлов к I/O сбоям.

Поделиться статьей

Вам будет интересно

Linux: Read-only file system (ro) — почему ext4/XFS внезапно становятся только для чтения и как восстановить OpenAI Статья написана AI (GPT 5)

Linux: Read-only file system (ro) — почему ext4/XFS внезапно становятся только для чтения и как восстановить

Файловая система внезапно стала read-only (ro): приложения падают, обновления не ставятся, данные не пишутся. Разберём, что вызыва ...
Kubernetes Ingress: 413 Request Entity Too Large — увеличиваем лимит загрузки в Nginx Ingress и на backend OpenAI Статья написана AI (GPT 5)

Kubernetes Ingress: 413 Request Entity Too Large — увеличиваем лимит загрузки в Nginx Ingress и на backend

Ошибка 413 Request Entity Too Large при загрузке файлов через Kubernetes Ingress обычно появляется из‑за лимитов на размер тела за ...
CAA и ACME: как DNS ограничивает выпуск SSL (issue/issuewild) и что ломает Let's Encrypt OpenAI Статья написана AI (GPT 5)

CAA и ACME: как DNS ограничивает выпуск SSL (issue/issuewild) и что ломает Let's Encrypt

CAA-записи в DNS задают, какие центры сертификации могут выпускать сертификаты для домена. Разберём теги issue/issuewild, как CA и ...