Невосстановимый Backup, или GBAK и уверенность в завтрашнем дне

Письмо в конференции epsylon.public.interbase
From: ded <ded@hq.bereg.net>

Привет All.

Поскольку прошлонедельная нитка на эту тему превратилась в поле битвы вокруг взаимного непонимания и изрядно замусорена, решил начать по-новой и разжевать некоторые причины существующего положения дел. Рассмотрим по очереди, что может быть причиной нересторабельности gbk и что можно а что не можно с этим сделать, на современном уровне развития науки и техники, а также на какой фазе процесса это "можно" собственно можно.

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

В моей практике невозможность снять gbk возникала только в случае физических и физиологических ;) повреждений файла базы. Первое понятно – не читается сектор. Физиологикой я называю ситуации:
  • невозможность подключения к базе из-за запоротого заголовка или зоны системных таблиц
  • bad checksum on page ...
  • invalid page type, expected ... found ...
  • decompression override buffer ...
  • cannot find record back version ...
  • экзотика старых версий – выход за пределы страниц хранения генераторов (не помню как их зовут правильно) и TIP. Для большинства присутствующих ситуации нереальные, выход известен – подхватить базу современным билдом, понимающим соответствующую ODS.

Причины появления первых трёх – в основном выключение питания древнерусскими способами, завалы оси как по её собственной инициативе, так и по инициативе эксплуататора, переполнение диска, превышение максимальной длины единичного файла базы, файловый доступ к базе в присутствии загруженного сервера. Третья, по моим наблюдениям, также имеет шанс появиться в некоторых случаях изменения метаданных на фоне работы пользователей, то есть баги самого сервера. Две последних – насильственное убиение или суицид уже SQL-сервера в процессе garbage collection. Предъявлять к gbak какие-либо претензии в этом случае и пытаться пристраивать к нему навороты имхо бессмыссленно, для этого есть gfix в простых случаях и IBSurgeon в сложных.

Итак, считаем, что gbk мы так или иначе получили, давайте разбираться, что же это за зверь – нересторабельный gbk. Отбросим патологические случаи повреждённого носителя и не полностью переданного с одного компьютера на другой файла. Сосредоточимся на логических нарушениях. Вспомним, какие в природе существуют логические ограничения, нарушение которых приводит к досрочному прекращению процесса restore.
  1. Ограничения not null на явно создаваемых доменах.
  2. Ограничения check на явно создаваемых доменах.
  3. Ограничения not null на неявно создаваемых доменах – на полях таблиц.
  4. Ограничения check на неявно создаваемых доменах.
  5. Ограничения уникальности
    1. Уровня constraint – Primary Key, Unique.
    2. Уровня index. Следует отметить, что механизм 5.1. базируется на 5.2., путём связывания constraint с уникальным индексом.
  6. Ограничения ссылочной целостности – Foreign Key.
  7. Теоретически возможные, но на практике для многих недоступные ситуации с базами запредельного размера, когда для создания индекса в свежеотресторенной базе не хватает возможностей железа или файловой системы для создания соответствующего tmp-файла. Отложим пока как экзотику.
  8. Насильственно введённые в структуру базы изощрённые ограничения типа 4, использующие запросы к другим объектам БД, которые gbak не может восстановить из-за того, что в момент создания домена в базе-приёмнике ещё не сушествуют означенные объекты. Предлагаю рекомендовать разработчикам, применяющим такие ограничения, либо идти как все, по камушкам (С) и оформлять такие ограничения как 6 и в виде соответствующих триггеров, либо гордиться тем, что gbak недостаточно параноидален при построении gbk и недостаточно наворочен для использования форвардных ссылок на ресторе, чтобы сожрать их базу.

То есть, нересторабельный gbk мы имеем в тех случаях, когда эти логические нарушения присутствуют в базе-источнике, как правило, вследствие скрытых или находящихся в стадии излечения физиологических. И невозможность воосстановить базу из gbk является сигналом на лечение физиологии базы-источника известными терапевтическими или хирургическими методами. Однако, в силу сокрытия владельцем существующей документации этих особенностей процесса резервирования баз, то ли в силу низкой квалификации соответствующего подразделения, то ли по раздолбайству, то ли из маркетинговых соображений (лично я склоняюсь к последнему), некоторые камикадзе склонны применять рестор оверврайтом базы-источника, отрезая себе пути спасения в случае даже смешных повреждений, излечиваемых лёгким движением руки в базе-источнике. Опять же, бывает, что база-источник физически уничтожена по железным причинам или просто находится далеко от администратора. Последней по важности причиной, вызывающей необходимость доработки gbak в плане извлечения из gbk всего, что можно из него извлечь, является стремление к сокращению количества итераций при ремонтно-восстановительных работах, важность этой причины растёт вместе с ростом базы. Рассмотрим варианты усложнения логики gbak, позволяющие достичь указанную цель.


Предложения по усилению контроля на фазе получения самого gbk

Рассмотрим перечисленные выше ограничения по порядку нумерации.

1-4. Вроде бы несложно отловить на чтении и не должно сильно тормозить создание gbk, если игнорировать чудеса типа 8.

5. В моей практике нарушалось только за счёт null-заполненных обломков версий, в силу тех или иных сбойных причин получивших статус записи. Проверка на чтении практически нереализуема, поскольку требует натурального скана всей таблицы при сохранении каждой записи.

6. Проверка на чтении практически нереализуема по тем же причинам, многократно услиенным тем, что мало удостовериться в том, что для сохраняемой записи есть мастер. Надо ещё проверить право на существование этого мастера, как по 1-5 мастер-таблицы, так и по её ссылкам на своих мастеров, причём натуральным сканом. И тех, в свою очередь, тоже надо проверить. В общем, в базе чуть сложнее палки и верёвки...

То есть, проверка ограничений 5-6 на чтении – утопия и надо думать о том, как обеспечивать восстановление из gbk данных, не отвечающих содержашимся в базе ограничениям уникальности и ссылочной целостности.

Кстати, вопрос с обнаружением на чтении нарушений 1-4 тоже не так уж прост. Ну обнаружили, что делать? Отказывать в создании gbk? А если это процесс вытягивания с агонизирующего железа и другого шанса не будет? Не вносить эту запись в gbk, рискуя каскадом нарушений 6? Записать в gbk и в специальный лог, что да, получаемый gbk содержит такие-сякие отклонения? Что с этим логом потом делать? Лично мне представляется, что ловля отклонений на чтении всё же занятие бессмыссленная. Задача backup – снять всё, что читается, правильное оно там или нет – разбираться надо на restore. В принципе можно говорить о разработке какого-то автономного инструмента логической валидации базы, подобно тому, как существует инструмент валидации minor (gfix) и серьёзных (IBSurgeon) физиологических проблем. Почему бы заинтересованным лицам этим и не заняться – это же в конце концов Open Source.

Обдумаем теперь, братие, возможности restore. Его основное назначение – получить работоспособную базу-близнец источника. И это должен быть основной режим, который уважающий себя разработчик ОБЯЗАН включить в свой регулярный процесс обслуживания базы – не только снять копию, но и убедиться, что она является копией, пригодной для восстановления. И в случае каких-либо отклонений посмотреть на базу-источник вооружённым глазом, пока количество проблем не переросло в качество. Это, так сказать, проповедь и заповедь. А что всё-таки делать в критических ситуациях, когда кроме несчастного невосстанвливаемого gbk ничего нет и не будет? А вот тут можно и нужно говорить об опциональных режимах аварийного восстановления. Которых может быть много хороших и разных. Видится четыре уровня:

А. Стрельба по площадям – наиболее простой в реализации, дающий наиболее" сырой" материал для ремонтно-восстановительных работ и мало способствующий сокращению их продолжительности, но позволяющий, на больших базах, скажем за ночь на автомате получить нечто базоподобное и потом неделю его рихтовать. Суть – наличие ключей, позволяющих восстанавливать кандидата в базы данных без ВСЕХ ограничений того или иного типа. На сегодняшний день мы уже имеем рудименты этого уровня – опции
  • -inаctive для ограничений 5-6: информация об индексах и констрайнтах восстанавливается, но, поскольку сами индексы не создаются (т. е. они inactive, включая системные), то ограничения не действуют и данные могут быть восстановлены для дальнейшего лечения.
  • -no_validity для ограничений 2.

Кажется есть прямой смысл дополнить этот набор ключами для ограничений 1,3,4, для каждого в отдельности. Нарушение ограничений 1 и 3 может быть причиной наведённого нарушения ограничений 5-6, но кто нам мешает комбинировать ключи по ситуации?

B. Прицельная стрельба разрывными снарядами – возможность перечисления имён ограничений вместе с ключами невосстановления. Пара-тройка доменов – не восстанавливать check, пара-тройка – не восстанавливать not null (скорее всего в комбинации с ключами невосстановления индексов на таблицах, использующих эти домены). Для этой таблицы не восстанавливать – ограничения not null на полях и не строить индексы, для той – не восстанавливать check на поле.

C. Прицельная стрельба болванками – указание перечня таблица-поле для ключей невоостановления ограничений 3-4 и имени индекса/констрайнта для 5-6.

D. Снайперская ювелирная работа – ключ, заставляющий gbak при обнаружении нарушения какого-то ограничения выходить в диалоговый режим, по результатам которого возможно – удаление этого ограничения в базе-приёмнике
  • невосстановление записи, нарушающей ограничение
  • ручная корректировка этой записи и повтор попытки
  • прекращение работы (отклонений так много, что интерактивный режим неэффективен).

Вывод: Нельзя сказать, что надо делать только А, только B, С или D. Все эти режимы нужны. Естественно, что если их будут делать, то в последовательности от простого к сложному. Для эффективного примения режимов B-D, возможно, есть смысл внедрить ключ, активизирующий при снятии gbk контроля ограничений 1-4 и складывать их в лог, который позволит строить предварительный план применения этих режимов.
 

Еще предложения по доработке gbak

Резюме:
  1. Отключение восстановления всех чеков на всех доменах есть – ключом командной строки -no_validity. Кстати, интересно, почему только на доменах, а на полях – нет? Отдельный ключ -no_columns_check или пускай -no_validity их всех накрывает?
  2. Отключение восстановления всех индексов есть – ключом командной строки -inactive.
  3. Добавляем отключение восстановления not всех null -no_nnuls. Варианты градации
-no_domain_nnuls и -no_column_nnuls нужны или нет? Или вообще включить всё добро одним махом в -no_validity? Чем check not null принципиально отличается от check value in ('Y','N')?
  1. Добавляем ключ -data_only. Вроде стрельба по площадям уся.
  2. Ключ командной строки -script filename, скрипт вида
-no_validity /*включая null? или их отдельным ключом? Все данные для этого скриптового ключа можно взять в гипотетическом логе бакапа*/
mydomain_1, mydomain_2, mydomain_3, mytable_1.column_1, mytable_2.column_3;
-inactive
/*часть данных для этого и следующего ключа можно взять в логе бакапа, по следам невосстанавливаемых not null*/
myindex_1, myindex_10;
-inactive_ref_constraint /*не активизирует индекс PK/FK/UN*/
myconstraint_1, myconstraint_2;
/*Здесь даже можно написать, что ты думаешь по поводу g-утилит вообще и
gbak в частности :) Скрипт накрывает потребности среднего размаха*/
  1. Ну и наконец мой обожаемый ключ -interactive в командной строке ;)

С уважением,
ded

Подпишитесь на новости Firebird в России

Подписаться