Сегодня поговорим про восстановление повреждённых данных в СУБД семейства постгрес. Речь именно о повреждённых данных, когда сам постгрес их прочитать уже не может. Задача восстановления таких данных нетривиальная. Тут нет и быть не может универсальных рецептов, иначе они давным давно уже были бы реализованы в виде утилит. Статья написана по мотивам моего выступления на конференции PGConf.Russia в 2023 году. Только сейчас дошли руки её написать, хотя в планах подготовка статьи была изначально. Могу сказать, что в плане восстановления данных за эти годы ничего не поменялось, вся информация актуальна в 2025 году, да и дальше тоже.

Дисклаймер
Так как дальше пойдёт речь о действиях с некорректно работающей СУБД и о том, как вмешиваться в работу СУБД «под капотом», то надо понимать, что любое неверное движение может привести к частичной или полной и окончательной потере данных. Вся ответственность за это лежит, как можно догадаться, на том, кто полез в базу своими руками. Если у вас нет достаточного понимания о том, что делаете — остановитесь! Лучше позовите на помощь тех, кто умеет.

Постгрес хранит данные в файлах на диске в виде блоков с не самой простой и очевидной структурой. Потому что, во-первых, ему надо уметь хранить произвольные данные, во-вторых, обеспечить одновременную работу с ними, и, в-третьих, делать это эффективно, обеспечивая как компактность хранения, так и производительность. Так что для того, чтобы хоть что-то суметь восстановить надо хорошо представлять себе, как постгрес хранит данные, как с ними работает, понимать работу алгоритмов MVCC в целом и тех оптимизаций, которые работают поверх — это и HOT (Heap Only Tuples) Update, и 64-битные расширения, популярные в коммерческих форках и т.п. Сложность столь велика, что даже более-менее полный разбор этих структур (особенно повреждённых) требует массу усилий, а то и анализ исходного кода. Также для успешного восстановления крайне полезны знания предметной области и общий технический кругозор, потому что иногда в случае полного отсутствия информации приходится делать всякие предположения. Таким образом для восстановительных работ нужна высочайшая квалификация и масса времени. А результаты этого кропотливого труда далеко не всегда приводят к успеху. Процесс восстановления повреждённых данных ненадёжен и катастрофически дорог.

Про бекапы

Пока не начали, пара слов о бекапах, о резервном копировании.

Современный ландшафт IT-инфраструктуры стал чрезвычайно сложным. Гипервизоры, виртуальные машины, контейнеры, дисковые массивы, коммутаторы... Количество уровней абстракции зашкаливает. Их так много, что нет никаких шансов понять, на какой физический диск попадёт байт, который записывает наша прикладная программа, запущенная где-то на сервере. И абсолютно все эти уровни абстракции содержат какой-то код, в котором встречаются ошибки. Ошибки могут быть в драйверах, в системном ПО, в библиотеках. Оборудование, на котором всё это работает, тоже подвержено сбоям. Настроить это оборудование так, чтобы не было аппаратных конфликтов — очень непростая задача. Отдельная непростая задача — настроить весь программно-аппаратный комплекс (ПАК), чтобы он работал и надёжно, и производительно. А ведь под всем этим оборудованием лежат так или иначе физические процессы нашего мира, которые время от времени подвержены флуктуациям, вызывающим сбои даже хорошо настроенного и правильно сконфигурированного оборудования. Человечество тратит неимоверные усилия для того, чтобы эти сбои не приводили к полному отказу — используются всяческие контрольные суммы, коды исправления ошибок, резервируются критичные части оборудования (линии питания, каналы связи) и оборудования. Часто (и то не всегда!) это позволяет пережить единичные сбои, на которые изначально был расчёт при проектировании ПАК. Но два или более наложившихся друг на друга сбоя почти всегда фатальны. И даже если оборудование надёжно и работает как часы, то от ошибок СУБД и прикладного ПО никто не застрахован, и они регулярно находятся и исправляются (читайте Release Notes). А ещё есть человеческий фактор — действия пользователей и администраторов СУБД, которые тоже рано или поздно, но неизбежно ошибаются. Так что данные, которые вы храните в базе, рано или поздно будут испорчены или потеряны, это вопрос только времени, когда именно это событие произойдёт и в каком масштабе.

Если вам дороги ваши данные, делайте их резервные копии!

Я не буду вдаваться в подробности, что считать резервной копией, и как именно надо их делать — это слишком большая тема. Мало того, я даже могу сказать, что резервные копии спасают не от любых повреждений данных, а только от внезапных. Медленно накапливающиеся ошибки попадут в резервные копии и останутся уже навсегда. Но в любом случае, если вы не удосужились сделать хоть какую-то резервную копию своих данных, то значит вы их готовы потерять в любой момент. Так что дальнейшее повествование — оно скорее из любви к прекрасному, которое иногда находит практическое применение. Dixi.

Повреждённые данные

Вернёмся к восстановлению повреждённых данных. Для начала некоторая терминология.

Логические повреждения — наличие логических несоответствий между данными в таблицах. Например, сумма счёта в заголовке (который хранится в отдельной таблице) не совпадает с суммой по всем его строкам.

Физическое повреждение — нарушения в структуре файлов, в которых СУБД хранит данные, в том числе в служебной информации. Из-за таких повреждений СУБД не может правильно работать с данными, например, выдаёт ошибки при попытке их прочитать.

Логические повреждения могут быть никак не связаны с физическими, и наоборот, физические повреждения не всегда влекут за собой логические повреждения в данных. Но любые физические повреждения опасны, так как могут в любой момент привести к некорректной работе СУБД, что может привести к потере данных. Причём не только уже повреждённых, но и затронуть любые другие данные или служебную информацию базы, а при неудачном стечении обстоятельств привести к полной потере данных. Следует всегда устранять физические повреждения данных при первых признаках их появления. После устранения физических повреждений всегда следует делать проверку в прикладной системе на логические повреждения.

Какие признаки физических повреждений бывают? Вот некоторые примеры ошибок:

  • ошибка контрольной суммы при чтении блока,

  • cannot open/read/write file/block,

  • invalid [status of] xid/mxid/xmin/xmax 123456,

  • странные номера транзакций из будущего или глубокого прошлого,

  • missing chunk 0 for TOAST value,

  • странное поведение процессов постгреса: зависания, неожиданное чрезмерное потребление CPU и т.п.

и так далее. Признаков может быть много, с каждым надо разбираться индивидуально.

Предположим, что мы наткнулись на такое странное поведение, и пришли к выводу, что данные повреждены. Что делать дальше?

Дальше нужно разбить работу на два этапа:

  1. Диагностика и анализ

    • восстановить картину инцидента (что случилось)

    • найти корневую причину (почему случилось)

    • найти все повреждения (что повредилось)

  2. Восстановление данных

    • план восстановления

    • выполнение плана

Именно так — сперва диагностируем и анализируем, а только потом начинаем восстанавливать. До конца диагностики ничего не надо исправлять, иначе есть все шансы угробить данные окончательно. Увлёкшись починкой первой попавшейся ошибки, мы рискуем не заметить более важную проблему. Также из-за преждевременных действий мы можем потерять информацию, которая помогла бы нам восстановить картину инцидента, и установить корневую причину. А то и просто можем потерять все данные, если попытаемся внести изменения в повреждённые структуры базы.

Очень важно определить корневую причину повреждений! Это часто бывает даже важнее, чем восстановить данные. Почему? Да очень просто. Если причина один раз привела к неприятностям, и она не устранена, то неприятности точно произойдут снова. Мало того, не понимая причины, которая привела к повреждению данных, невозможно судить о последствиях: велик риск, что часть повреждений останется незамеченными, и это приведёт к ещё большим неприятностям в будущем. Например, к более значительной или вообще полной потере данных.

К сожалению, найти достоверно корневую причину получается не всегда. Потому что бывают сбои оборудования или другие события, которые находятся за пределами того, что получится исследовать. Иногда просто не хватает информации, чтобы понять, в работе какого оборудования произошли ошибки. Тут часто помогают различные системы мониторинга. Иногда становится понятно, что причиной является ошибка (баг) в работе СУБД, но так как мы видим только последствия этой ошибки в данных, то не всегда получается найти, когда и в результате каких действий эти данные были повреждены, особенно если повреждение случилось давно. В таких случаях помогают архивы WAL, по которым можно отследить изменения в блоке и, если повезёт, увидеть операцию, которая привела к повреждениям.

Устранение корневой причины должно быть одним из пунктов плана по восстановлению. Другими словами, пока не нашли причину, к действиям по восстановлению данных не приступаем. Потому что, например, если у нас диск посыпался, то чинить на нём же базу бессмысленно, она будет разваливаться быстрее, чем будем чинить.

Приступать к диагностике надо немедленно при проявлении первых признаков проблем — не теряйте времени! Если диагностика затягивается, а проблема критична, то сразу параллельно начинаем искать обходные пути (work-around).

Этап 1. Анализ и диагностика

На первом этапе надо восстановить картину инцидента, что и когда произошло. Рассмотрим некоторый инструментарий, с помощью которого можно исследовать, что происходит с постгресом.

ps -ef | grep postgres
и другие подобные общесистемные утилиты позволят провести анализ работающих процессов в системе, посмотреть сколько их, и чем они заняты, какие ресурсы потребляют.

top/atop
можно посмотреть список процессов, утилизацию системных ресурсов (CPU, RAM, IO) как в настоящий момент, так и исторической перспективе (в случае atop).

gdb
можно посмотреть на текущий back trace (он же stack trace, стек вызовов) и на несколько последовательных стеков, чтобы увидеть изменения; провести анализ core dump; убедиться, что процесс работает, посмотреть детальнее, чем разные процессы заняты.

perf + flamegraph
полезны для анализа того, чем заняты отдельные процессы или вся система в целом.

Что следует искать:

  • не работают ли два разных постгреса поверх одной PGDATA?

  • аномалии в поведении системы и постгреса

  • детально изучаем работу аномального процесса.

Для ретроспективы того, что происходило, полезно изучить все доступные журналы (log) как системы, так и СУБД, а также иногда прикладного ПО.

Анализ текстовых журналов (log) постгреса:
grep -E ’(ERROR|FATAL|PANIC)’ postgresql*.log

Анализ журналов ОС:
dmesg -T
journalctl

Вот такую технику последовательных приближений удобно использовать. Выводим все журналы в пейджер cat *.log | less. Дальше начинаем их разбирать и постепенно выкидывать неинтересное с помощью grep -v пока не останется только самое информативное:
cat *.log \
| grep -v ’connected’ \
| grep -v … \
| less -S

Можно использовать более продвинутые анализаторы логов типа klogg или lnav или любые другие привычные.

Результаты:

  • найти и изучить ошибки и их характер

  • установить хронологию событий

  • из текста ошибок можно увидеть какие данные (файлы, блоки, таблицы) повреждены

  • получить список таблиц, где появлялись ошибки в процессе работы СУБД

Далее нужно установить, какие данные в базе повреждены. Особенное внимание надо уделить списку таблиц, в которых были замечены ошибки.

Быстрая проверка на возможность чтения таблицы или всей базы, которая попутно выгрузит данные(!), может работать в несколько потоков, что может быть полезно при больших объёмах:
pg_dump

С помощью SQL-запросов в самой базе можно интерактивно исследовать, где в конкретной таблице есть нечитаемые данные, (осторожно с индексами!):

select ctid, * from bad_table
 where ctid>’(100,0)’ and ctid<’(200,0)’;

По имени файла найти имя таблицы можно следующим запросом, где 2619 — это имя файла без суффиксов:

select relname from pg_class where relfilenode = 2619;

Если нужно найти таблицу, к которой относится TOAST, то помним, что номер в названии pg_toast_2619 — это как раз OID основной таблицы, вот такой простой запрос вернёт её имя:

select 2619::regclass;

Полезная функция молотилка (исторически сложившееся название), которая вычитывает все версии строк в таблице и выводит диагностику в случае ошибок:

select molotilka(’bad_table’, 0);

Изначально функция была написана на plpython, я переписал на plpgsql, потому что этот язык программирования в базе постгрес есть всегда и для запуска функции не требуется ничего устанавливать на уже развалившуюся или разваливающуюся под руками базу. Сама функция:

CREATE or REPLACE FUNCTION molotilka(tbl regclass, start_page bigint) RETURNS bigint AS $$
DECLARE
    n_pages integer;
    page integer;
    lps_in_page integer;
    lp_p integer;
    err_count bigint = 0;
BEGIN
  SELECT pg_relation_size(tbl) / 8192 INTO n_pages;
  FOR page IN start_page .. n_pages-1 LOOP
    BEGIN
      SELECT coalesce(max(lp),0) from heap_page_items(get_raw_page(tbl::text, page)) INTO lps_in_page;
      FOR lp_p IN 1 .. lps_in_page LOOP
        BEGIN 
          EXECUTE format('select row(t.*) from %s as t where ctid=''(%s,%s)''', tbl::text, page, lp_p);
        EXCEPTION WHEN OTHERS THEN
          err_count = err_count + 1;
          RAISE NOTICE 'TUPLE ERROR: ctid=(%,%), SQLSTATE=% DETAIL=%', page, lp_p, SQLSTATE, SQLERRM;
        END;
      END LOOP;
    EXCEPTION WHEN OTHERS THEN
      err_count = err_count + 1;
      RAISE NOTICE 'PAGE ERROR: page=%, SQLSTATE=%, DETAIL=%', page, SQLSTATE, SQLERRM;
    END;
  END LOOP;
  RETURN err_count;
END $$ language plpgsql;

Это заготовка, которую можно поправить по месту. В реальной жизни можно и нужно использовать оптимизации, например, PREPARE основного запроса позволит увеличить скорость в несколько раз. Для работы функции требуется установить расширение pg_pageinspect, которое есть в contrib.

Результаты:

  • полный список повреждённых таблиц

  • локализация повреждённых данных в каждой повреждённой таблице

Если таблицы не читаются или база не запускается, то для исследований остаётся только низкоуровневый инструментарий, предназначенный для работы непосредственно с файлами данных. Посмотреть, что творится в блоках данных можно с помощью:

pg_filedump -i file

в строках можно посмотреть xmin/xmax и флаги, в заголовке блока есть LSN — когда блок был изменён в последний раз. Исследуя эту информацию можно подтвердить или опровергнуть гипотезы о том, что именно произошло с данными, понять что обозначают сообщения об ошибках.

Чтобы узнать, как в блоке менялись данные, можно исследовать WAL. LSN из заголовка блока даст подсказку, какие именно WAL-журналы исследовать:
pg_waldump

Исследование WAL — занятие очень творческое, но это практически единственная возможность понять, как менялся блок, и поймать момент, когда данные в блоке стали некорректны. Это даёт хоть какой-то шанс найти ошибку в коде СУБД, которая привела к повреждению данных.

По номеру транзакции или идентификаторам записей в таблицах можно найти другие записи с теми же или близкими номерами, посмотреть timestamp этих записей — даст приблизительное время инцидента, которое можно сопоставить с другими данными, например, из системных журналов или журналов прикладного ПО. Это тоже может дать идеи о том, какие события повлекли повреждение данных и найти корневую причину.

Результаты:

  • как выглядят данные с точки зрения постгреса

  • хронология событий на уровне изменения данных, возможные сценарии для воспроизведения

  • уточнить характер повреждений и локализация повреждений

Диагностику и анализ можно заканчивать, если удалось выполнить все пункты списка:

  • восстановить полную картину случившегося,

  • установить корневую причину повреждений,

  • получить полную информацию о повреждениях, которые надо исправлять.

Можем переходить к восстановлению данных! Если во время восстановительных работ на следующем этапе обнаруживаются какие-либо неожиданности, то смело возвращаемся на этап диагностики и анализа.

Этап 2. Восстановление данных

Перед началом работ надо проделать следующие действия:

  • Убрать нагрузку (пользователей), можно изменить pg_hba.conf или PGPORT.

  • Сделать холодную(?) резервную копию, если это возможно. В противном случае не будет возможности откатить любую сделанную в ходе работ ошибку, что сильно уменьшит общие шансы восстановления данных.

  • На неисправном оборудовании заниматься восстановлением нет смысла.

  • Оценить целесообразность восстановления данных:

    • сколько времени это займёт?

    • будут ли восстановленные данные полезны?

  • План восстановления должен гарантировать, что в базе не останется физических повреждений.

Последний пункт особенно интересный. Как этого добиться? Проанализровать даже один блок с данными в таблице постгреса, со всеми нюансами, со всеми проверками консистентности — это огромный труд. Проанализровать несколько блоков, а уж тем более таблицу (или несколько) целиком — совершенно неподъёмная задача. Собрать вручную значения всех структур в блоке вообще нереально, заниматься такой работой можно только от полной безысходности. Что же делать? Выход есть. Пусть постгрес сам всё сделает. Выгружаем данные в логический дамп и восстанавливаем в новом кластере! Таким образом мы сможем проконтролировать в дампе, что выгрузилось, а постгрес при загрузке в новый кластер сам обеспечит физическую целостность данных — и таблиц, и всей служебной информации.

Это очень важный вывод, я его повторю ещё раз отдельно:

Цель восстановительных работ при повреждении данных в СУБД — выгрузить всё необходимое (или возможное) в логический дамп для дальнейшей загрузки в новую базу!

Важно оценить целесообразность проведения работ. Если восстановительные работы займут годы, или качество восстановленных данных не позволит их использовать, то нет смысла терять столько времени и сил. Будьте реалистами. Может быть всё же имеющаяся старая копия базы будет полезнее непредсказуемых результатов восстановления? Особенно с учётом того, что даже оценить полноту восстановленных данных часто затруднительно, не говоря уже об их логической целостности. Приемлемые результаты будут только в случае очень ограниченного характера повреждений.

Если решились таки восстанавливать данные, то что следует делать:

  • Из базы выгружаем только содержимое пользовательских таблиц, остальное (прикладной код, триггеры, индексы, последовательности и т.п.) обычно можно восстановить другими способами.

  • План должен включать и восстановление данных, и устранение причины повреждений, иначе данные опять будут неминуемо повреждены.

  • После устранения физических повреждений обязательно следует проверить логическую целостность восстановленных данных.

Ситуации с повреждениями могут быть разнообразны, разными будут причины и текущее состояние кластера, поэтому привести готовые рецепты по восстановлению вряд ли возможно. Однако можно рассмотреть некоторые типичные ситуации.

Для того, чтобы выгрузить данные из повреждённых таблиц, нам нужен работающий постгрес. Возможны две ситуации:

  • СУБД не запускается совсем,

  • СУБД запускается в каком-то состоянии.

Во время восстановительных работ всегда запускаем постгрес явно через pg_ctl, чтобы видеть все сообщения об ошибках в консоли сразу.

Проблемы с запуском СУБД

Если не запускается СУБД, то смотрим на сообщения об ошибках, устраняем препятствия, повторяем до победного конца. Если в процессе были применены деструктивные действия или были замечены признаки неконсистентности, то базу больше использовать нельзя — данные надо выгрузить и загрузить в заново инициализированный кластер. Серьёзные проблемы невозможности запуска часто связаны с сильным повреждением системного словаря или повреждением WAL, необходимых для достижения консистентного состояния данных на старте.

При повреждениях системного словаря могут помочь следующие советы, применять которые нужно с пониманием их специфики:

  • Повреждения системных индексов можно проигнорировать, запустив постгрес без их использования: postgres -P ...

  • Малозначащие для спасения данных таблицы системного словаря (типа pg_collation) часто можно взять от другого кластера.

  • pg_class и pg_attribute — может быть сохранились на реплике или в бекапе. Если не было больших изменений в структуре таблиц (DDL), то это может сработать.

  • Полная потеря системного словаря обозначает — увы — полную потерю базы. В лучшем случае получится восстановить что-то вручную из отдельных файлов данных с помощью утилиты pg_filedump, см. «последний шанс» далее.

  • Не надо ничего чинить по месту, только выгружаем данные pg_dump/restore. Любые изменения в базе могут окончательно убить данные.

Проблемы с WAL

При старте СУБД делается проверка на необходимость восстановления БД до консистентного состояния по журналам WAL. Если сервер не смог запуститься из-за нехватки WAL, это обозначает, что база в неконсистентном состоянии. Проблемы с WAL:

  • есть повреждения в WAL, которые не позволяют его проиграть,

  • не найден необходимый WAL.

Архив WAL (archive_mode=on) или реплики могут помочь, WAL в кластере везде одинаковый.

Утилитой pg_resetwal можно отключить механизм восстановления на старте — база запустится, но останется в неконсистентном состоянии, то есть гарантированно повреждённой.

Немного про применение утилиты pg_resetwal. Утилита pg_resetwal позволит экземпляру постгреса запуститься, даже если половины базы уже не существует, а вторая половина является бессмысленным набором байтов.

Никогда не используйте pg_resetwal, если не понимаете совершенно точно, что он делает, и какие будут последствия!

После применения pg_resetwal база непригодна для использования, из неё можно только выгрузить данные для последующей загрузки в новый кластер: только полный pg_dump/restore!

Краткое правило для запоминания: применил pg_resetwal — базу можно выкинуть.

Восстановление таблиц

Это наиболее частый вид работ по восстановлению данных. Найденная ранее корневая причина должна помочь уточнить, где и как повреждены данные, выбрать оптимальную стратегию восстановления. Если в процессе восстановления данных сталкиваемся с неожиданностями — возвращаемся на этап диагностики и анализа. Если нет полной уверенности, что остальные данные в базе не повреждены — всегда восстанавливаем все данные в новую базу целиком через pg_dump/restore.

Примеры других техник, которые могу пригодиться при восстановлении таблиц:

  • Контрольную сумму в блоке можно игнорировать, для этого есть параметр ignore_checksum_failure=on

  • Если блок не читается совсем, его можно обнулить. Данные в блоке будут потеряны, но зато остальные данные в таблице могут быть прочитаны. Пример команды (не забываем про сегменты!), выполнять надо на остановленной базе:
    dd if=/dev/zero of=/PGDATA/base/db_oid/bad_table_filenodeid bs=8k seek=XXXXX count=1 conv=notrunc
    осторожно: команда физически и необратимо удаляет данные!

  • Можно автоматически обнулять повреждённые блоки с помощью параметра zero_damaged_pages=on. Это может быть полезно, если повреждённых блоков много.

  • Если блок читается, но не читается отдельная строка в блоке, её часто можно удалить по ctid:
    delete from bad_table where ctid=’(123,1)’;

  • С 14 версии в contrib появился модуль pg_surgery, который позволяет сделать отдельную строку видимой или наоборот удалить её по ctid.

  • Если не читается только отдельное поле (например, из-за повреждений TOAST), то перед удалением строки можно посмотреть и сохранить значения всех читаемых полей.

  • Если постгресу не хватает служебных файлов (например, статусов транзакций), то их можно создать искусственно. Следует понимать последствия таких действий.

После удаления всех нечитаемых строк и блоков, когда таблица стала читаться целиком, нужно пересоздать её физически — сделать pg_dump/restore и провести логическую выверку данных. Если точно знаем, что повреждена только одна таблица, то можно восстановить только её: pg_dump/restore bad_table, но уверенность должна быть полной.

Если восстановить надо только одну таблицу в базе, то возможны варианты:
pg_dump -t bad_table
vacuum full bad_table; — может быть полезно при наличии ограничений ссылочной целостности
create table good_table as select * from bad_table;

Пример восстановительных работ

В логах постгреса наблюдаются ошибки вида (в данном случае Postgres Pro Enterprise, поэтому номер транзакции большой, а имя файла статусов транзакций «длинное»):

 ERROR: could not access status of transaction 11416767659
 DETAIL: Could not open file "pg_xact/0000000000AA": No such file or directory.

Ошибка обозначает, что постгресу нужно посмотреть статус транзакции для простановки так называемых hint bits, а файла статусов транзакций не существует. Предположительно блок таблицы был ошибочно отмечен как all frozen, но в какой-то строке оказался номер транзакции в xmin/xmax, у которой не были проставлены флаги для этой транзакции, в то время как файл реальных статусов транзакций в каталоге PGDATA/pg_xact давно уже был удалён. Можно создать запрашиваемый файл статусов транзакций:
dd if=/dev/zero of=PGDATA/pg_xact/0000000000AA bs=1K count=256

В зависимости от того, где (вxminилиxmax) встретился номер проблемной транзакции, может появиться лишняя или пропасть нужная строка в таблице. При этом могут появиться дубликаты уникальных ключей или пропасть значение, на которое ссылаются из другой таблицы или ещё что-нибудь подобное. Также фантомные записи могут появиться или пропасть и в других таблицах, если в них имеется та же проблема, и возможно мы о ней не знаем, так как обращений к этим данным не было. В базе также могут оказаться противоречивые данные — в одних строках данных проблемная транзакция может быть помечена как зафиксированная, в других как отменённая, если имеются таблицы, где статус соответствующей транзакции уже был проставлен в атрибутах записи. То есть база становится неконсистентной вплоть до невозможности дальнейших работ по восстановлению. Но сообщение об ошибке пропадёт, так как нужный файл статусов транзакций постгрес уже найдёт.

Кажущаяся простота устранения сообщения об ошибке не должна вводить в заблуждение — база имеет физические повреждения, которые надо устранить: ищем причину повреждений, делаем полный pg_dump/resore всей базы и логическую выверку данных после восстановления!

«Последний шанс»

«Последний шанс» — полностью ручное восстановление данных из файла постгреса с помощью замечательной утилиты pg_filedump. Этот способ можно применять если:

  • системный словарь безнадёжно повреждён,

  • или база не запускается вообще никак,

  • или остался вообще только один файл данных или даже только часть такого файла.

Примерно так будет выглядеть команда:

 pg_filedump -i -D int,text path/to/datafile/12345

Нужно знать какие типы полей есть в таблице, и в каком порядке они идут, перечислив их в параметре -D. Придётся сделать полный ручной разбор всех строк в MVCC с учётом атрибутов — в выводе будут присутствовать все версии каждой строки, включая «мёртвые», которые будут найдены в блоках данных. При повреждениях структуры блоков может быть придётся данные разбирать и собирать вручную из байтов. Это действительно «последний шанс», так реально восстановить только совершенно бесценные данные.

Итоги

Что можно посоветовать напоследок.

Делайте бекапы. Всего вышеописанного кошмара можно избежать, если есть нормальное резервное копирование.

Всегда (всегда!) включайте контрольные суммы: initdb -k. Накладные расходы в данном вопросе минимальны и точно стоят возможности определить повреждения в базе на самом раннем этапе.

Архив WAL часто бывает полезен.

Готовьте систему к диагностике заранее: ставьте пакеты с отладочными символами постгреса, gdb, perf, atop, pg_filedump, настраивайте сбор core dump. Лучше это сделать во время обычной повседневной работы, а не в авральном режиме после аварии.

Мониторинг — это хорошо, он часто помогает понять, что произошло. Установленный заранее atop ещё и покажет, какие процессы какие ресурсы потребляли.

Берегите себя и свои данные, и ещё раз — делайте бекапы!

Комментарии (0)