Обновить

Комментарии 7

Вне самой сути статьи хочу заметить что архивация данных это нечто на уровне подсознательного самосохранения. И если люди не создавали бэкапы то, возможно, присутствовали какие административные или финансовые барьеры. Может руководство не смогло правильно оценить риски.

Специально для лиги лени, и тех кто потерял нить повествования где-то на лирических отступлениях

На конференции PgConf 2026 в Москве Андрей Билле из Postgres Professional рассказал о реальном случае восстановления кластера PostgreSQL (2,5 ТБ, 10 баз 1С), который три года работал без бэкапов на виртуальной машине с переподпиской дискового пространства. Когда при загрузке новой инфобазы закончилось место на диске, администраторы усугубили ситуацию: удалили WAL-файлы, не смогли штатно остановить экземпляр, убили процесс postmaster сигналом SIGKILL, а затем применили pg_resetwal, отключив восстановление — в результате база была серьёзно повреждена. При попытках восстановления выяснилось, что системные индексы разрушены, pg_dump не работал из-за долгих запросов к системному каталогу без индексов, и пришлось создавать специальные патчи. Примечательно, что из зала прозвучал элегантный вопрос: нельзя ли было вместо патчей просто использовать команду COPY для выгрузки данных — докладчик признал, что это было возможно. В итоге удалось частично восстановить лишь одну из баз, а компания-клиент приобрела enterprise-поддержку у Postgres Professional. Главный вывод доклада: нельзя эксплуатировать базы с важными данными без реплик, бэкапов и дампов, не стоит удалять WAL-файлы, убивать процессы PostgreSQL сигналом SIGKILL и применять pg_resetwal без крайней необходимости, а при восстановлении стоит рассматривать простейшие решения прежде, чем модифицировать ядро СУБД.

Помимо необходимости бекапов я бы еще добавил что не надо жопить деньги на инфраструктуру. Нужно мето - купите диски.

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

Недостаток опыта, думаю. В системном администрировании и работе в виртуальных средах.

Сейчас такое повсеместно. Кабанычи экономят на персонале, в итоге в чатиках регулярно появляются ребята, которые первый раз видят Linux, но при этом единственные админы в своей компании, и им нужно прямо срочно поднять или починить виртуалку на QEMU/KVM. На бэкапах такие естественно тоже экономят.

Добрый день!

Возможно в микрофон я не смог донести ситуацию целиком, постараюсь текстом:

Команда COPY насколько мне известно и судя по документации работает только для таблицы, т.е. чтобы её использовать нужно знать имя таблиц
Таблиц - тысячи в одной базе, баз 50 +
Т.е. Итого 500+ тысяч таблиц
Казалось бы - ну напишем скрипт, но...

Главная проблема в том, что получить имена таблиц невозможно
Из-за повреждения системных индексов любой запрос уходил в бесконечное выполнение.
При отключении в конфиге использования системных индексов, запрос на получение списка таблиц в одной из десятков баз выполнился только за 2,5 дня!
Такого количества времени не было,счёт шёл на часы...

К сожалению по той же причине (повреждение системных индексов) не работали опции --schema-only и --data-only у pg_dump.
Была надежда что --data-only нас спасёт, так как индексов в разы больше чем таблиц, и соответственно рассчитывали на то, что при этой опции не будет запроса на получение списка и состава индексов и запрос отработает сильно быстрее, но оказалось что pg_dump всё равно запрашивает список и состав индексов даже при указании --data-only.

Поэтому пришлось патчить pg_dump заставив его не запрашивать информацию об индексах.
Затем обрабатывали уже ошибки pg_dump. когда он находил сбойный чанк, пропускали таблицу со сбойным чанком через --exclude-table и её уже спасали через COPY + dblink + offset
В итоге мы получили данные через -data-only + всё что можно было спасти через "copy + dblink + offset", затем процедурой выгрузки/загрузки dt восстановить индексы

Антон, спасибо, за комментарий!

При отключении в конфиге использования системных индексов, запрос на получение списка таблиц в одной из десятков баз выполнился только за 2,5 дня!

pg_dump для получения выполняет сложный select, который Андрей привёл в багрепорте. Без индексов такой запрос, конечно, выполняется долго.

Скрытый текст

SELECT t.tableoid, t.oid, i.indrelid, t.relname AS indexname, t.relpages, t.reltuples, t.relallvisible, 0 AS relallfrozen, pg_catalog.pg_get_indexdef(i.indexrelid) AS indexdef, i.indkey, i.indisclustered, c.contype, c.conname, c.condeferrable, c.condeferred, c.tableoid AS contableoid, c.oid AS conoid, pg_catalog.pg_get_constraintdef(c.oid, false) AS condef, CASE WHEN i.indexprs IS NOT NULL THEN (SELECT pg_catalog.array_agg(attname ORDER BY attnum) FROM pg_catalog.pg_attribute WHERE attrelid = i.indexrelid) ELSE NULL END AS indattnames, (SELECT spcname FROM pg_catalog.pg_tablespace s WHERE s.oid = t.reltablespace) AS tablespace, t.reloptions AS indreloptions, i.indisreplident, inh.inhparent AS parentidx, i.indnkeyatts AS indnkeyatts, i.indnatts AS indnatts, (SELECT pg_catalog.array_agg(attnum ORDER BY attnum) FROM pg_catalog.pg_attribute WHERE attrelid = i.indexrelid AND attstattarget >= 0) AS indstatcols, (SELECT pg_catalog.array_agg(attstattarget ORDER BY attnum) FROM pg_catalog.pg_attribute WHERE attrelid = i.indexrelid AND attstattarget >= 0) AS indstatvals, i.indnullsnotdistinct, NULL AS conperiod FROM pg_catalog.pg_index i JOIN pg_catalog.pg_class t ON (t.oid = i.indexrelid) JOIN pg_catalog.pg_class t2 ON (t2.oid = i.indrelid) LEFT JOIN pg_catalog.pg_constraint c ON (i.indrelid = c.conrelid AND i.indexrelid = c.conindid AND c.contype IN (‘p’,‘u’,‘x’)) LEFT JOIN pg_catalog.pg_inherits inh ON (inh.inhrelid = indexrelid) WHERE (i.indisvalid OR t2.relkind = ‘p’) AND i.indisready ORDER BY i.indrelid, indexname;

Участник говорил о том, что стоило попробовать следующие команды и, скорее всего, список схем и таблиц выгрузился бы моментально. Вы и сами написали, что использовали "COPY + dblink + offset ", значит и COPY pg_class бы выгрузил список таблиц.

postgres@host:~$ postgres --single -c ignore_system_indexes=1

PostgreSQL stand-alone backend
backend> copy (select relnamespace, relname from pg_class where relkind='r') to '/tmp/pg_class.txt'
backend> copy (select oid, nspname from pg_namespace) to '/tmp/pg_namespace.txt'
backend> 
postgres@host:~$ tail -n 3 /tmp/pg_class.txt 
2200	pgbench_branches_pkey
2200	pgbench_tellers_pkey
2200	pgbench_accounts_pkey
postgres@student:~$ tail -n 3 /tmp/pg_namespace.txt 
11	pg_catalog
2200	public
13239	information_schema

Можно было даже попробовать не в single mode, просто командой copy pg_class to '/tmp/pg_class.txt';

Но вы не должны были знать, что так можно выгрузить. Это должна знать техподдержка, а её у клиента не было, они её купили уже после.

copy (select relnamespace, relname from pg_class where relkind='r') to '/tmp/pg_class.txt' - хорошая мысль.

В тот момент такая идея в голову не пришла.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации