Часто задаваемые вопросы по OpenEdge RDBMS
VII. Crash Recovery
74. Если работа моей базы завершилась аварийно, что я должен сделать для ее восстановления?
Во-первых, попробуйте перезапустить базу данных и выполнить процедуру восстановления после сбоя. Если вы знаете, что база данных разрушена, и восстановление после сбоя не сработает (например, журнал Before-Image был удален, или диск, на котором он находился, вышел из строя), создайте резервную копию того, что у вас осталось. Она может понадобиться вам позднее.
Если база данных не может быть восстановлено с помощью нормальной процедуры восстановления после сбоя, обычно лучшим решением является восстановление из резервной копии. Во-первых, если вы можете, скопируйте самые свежие экстенты журнала After-Image аварийной базы данных. После восстановления резервной копии, накатите файлы журнала After-Image, которые были архивированы после создания резервной копии. Эти файлы содержат полную историю всех изменений базы данных, которые были сделаны после резервного копирования.
Если вы не используете журналы After-Image, то вы потеряете данные. Если вы читаете это до того, как у вас возникли проблемы, то вы имеете шанс исправить ситуацию и начать использовать After-Image.
75. Что произойдет, если использовать параметр -F при усечении журнала Before-image?
Краткий ответ заключается в том, что вы никогда не должны использовать параметр -F, разве что в качестве последнего средства. Если вы его используете, процедура восстановления после сбоя будет пропущена и содержимое журнала Before-Image будет потеряно. Существует очень высокая вероятность того, что в результате база данных будет повреждена.
Длинный ответ:
Состояние работающей базы данных
Полное актуальное состояние работающей базы данных состоит из трех частей:
- Данные на диске в экстентах в различных областях данных. Некоторые из этих данных устарели, так как в памяти существуют их более свежие версии.
- История недавних изменений в базе данных, записанная в журнале Before-Image.
- Измененные данные, которые еще не были записаны на диск представлены в области разделяемой памяти базы данных.
Все три части являются необходимыми. Если любая из них потеряна или уничтожена, требуется восстановление.
Нормальная остановка
Когда работающая база данных останавливается, все измененные данные из памяти записываются на диск, так что область разделяемой памяти может быть освобождена. Данные на диске становятся актуальными и непротиворечивыми. При перезапуске базы данных выделяется новая область памяти и заполняется данными, прочитанными с диска. Затем могут быть сделаны новые изменения базы данных.
Восстановление после сбоя
Когда база данных остановлена аварийно (например, в случае сбоя питания), все данные, находившиеся в памяти, теряются, включая любые изменения, которые еще не были записаны на диск. Все изменения базы данных выполняются «на месте» в памяти и не записываются на диск, когда заканчивается вызвавшая их транзакция. Изменения могут оставаться в памяти в течение длительного времени, возможно, несколько часов, перед тем, как они будут записаны на диск. Соответственно, данные на диске не содержат недавних изменений. Когда база данных запускается снова, database recovery manager запускает процесс восстановления после сбоя. Две основные части этого процесса это фаза redo и фаза undo. Обе они используют содержимое журнала Before-Image.
Во время фазы redo, recovery manager выполняет «сканирование вперед» записей в журнале Before-Image и повторяет любые операции, результаты которых были потеряны, потому что один или несколько измененных блоков данных не были записаны на диск.
Во время фазы undo, recovery manager откатывает любые незаконченные транзакции, читая записи в журнале Before-image в обратном порядке до записи начала транзакции. Во время этого обратного сканирования, отменяются действия всех операций, выполненных в незавершенной транзакции; изменения откатываются, удаленные записи восстанавливаются, а созданные записи удаляются.
Пропуск восстановления после сбоя
Пропуск восстановления после сбоя может привести к многим нежелательным последствиям, включая:
- Не полностью измененные записи.
- Частично удаленные записи.
- Цепочки фрагментов записи, ссылающиеся на несуществующие фрагменты.
- Записи без индексов.
- Индексы, ссылающиеся на несуществующие записи.
- Противоречивые цепочки свободных и RM-блоков (используются для выделения пространства для новых записей).
- Логическая противоречивость из-за частично выполненных транзакций.
Пример
Предположим, у вашей базы данных имеется очень маленький буферный пул, содержащий только 4 буфера базы данных, и вы собираетесь изменить одну запись и затем прочитать вторую. Этот пример специально сделан маленьким для облегчения понимания. Мы оставили в стороне несколько деталей, но ничего важного не опущено. Все это применимо к реальному миру.
Чтобы получить запись, которая будет обновляться, нам нужно прочитать некоторую информацию с диска. Во-первых, мы читаем корневой блок индекса в один из 4 буферов. Предположим, индекс имеет два уровня, мы также будем должны прочитать конечный блок дерева индекса для того, чтобы получить recid записи. Recid говорит нам, где на диске, мы можем найти запись.
Затем, мы читаем блок записи, чтобы получить запись, которую собираемся изменить. Предположим, что запись состоит из двух фрагментов, так что нам придется прочитать и второй блок записи.
В этот момент все 4 блока в буферном пуле содержат один из блоков, которые мы только что прочитали – два индексных блока и два блока записи.
Теперь, когда мы изменяем запись, каждый из двух ее фрагментов будет изменен, что делает оба блока записи «грязными», то есть они были изменены и должны быть в конце концов записаны на диск.
После того, как изменение закончилось, мы имеем следующую ситуацию:
- Мы сгенерировали четыре записи «change notes» в журнале Before-image: запись начала транзакции, две записи изменения блока, и запись конца транзакции.
- Ничего не было записано на диск. На диске мы имеем точно то же, что было вначале.
- В буферном пуле имеется два «грязных» блока, которые не были записаны на диск, но должны быть записаны в будущем.
Теперь мы читаем вторую запись, снова считывая два индексных блока. Так как предыдущие индексные блоки являются самыми «старыми», они теряются, заменяются новыми блоками и перемещаются в начало LRU-цепочки. Затем мы читаем блок другой записи, заменяя один из ранее измененных блоков, который предварительно записывается на диск. Мы не изменяем эту вторую запись. В этот момент мы имеем:
- В журнале Before-image, как и раньше, 4 «bi notes», описывающие изменение первой записи.
- На диске мы имеем один из двух измененных блоков (он был записан), а остальная база данных остается в том же виде, в котором была до начала нашего примера.
- В памяти мы имеем два индексных блока, один измененный блок записи и один не измененный блок записи.
Измененный блок записи содержит один из двух фрагментов записи, которую мы изменили ранее.
Не измененный блок записи содержит вторую запись, которую мы прочитали, но не изменили.
В этот момент происходит сбой!
Скажем, система остановилась, потому что кто-то отключил сервер, чтобы включить радиоприемник. Такое действительно случается! Но могут быть и другие причины. Может это был пылесос, а не радиоприемник. Позднее, когда мы включим сервер снова и загрузим его, мы имеем:
- В журнале Before-image log, 4 «bi notes», описывающие изменение.
- На диске, один из двух измененных блоков записи, который был записан, остальная база данных в том состоянии, в котором она была до начала нашего примера.
Все, что было в памяти, исчезло, включая один из двух измененных блоков записи. Единственным свидетельством того, что блок был изменен, является запись в журнале Before-image. Если мы сейчас запустим базу данных обычным способом, она пройдет процедуру восстановления после сбоя. Recovery manager прочитает журнал Before-image, обнаружит, что один из измененных блоков был потерян, и выполнит это изменение снова во время фазы redo. Так что теперь мы снова имеем оба измененных блока записи в базе данных. Так как транзакция была завершена, фаза undo процесса восстановления не откатит ее назад.
Теперь все в порядке.
Пропуск восстановления после сбоя
Если, вместо запуска базы данных обычным способом и выполнения процесса восстановления после сбоя, мы используем truncate bi -F, то процесс восстановления после сбоя будет пропущен и записи в журнале Before-image будут отброшены без обработки. В нашем случае, будет потеряна запись в Before-image, содержащая единственное свидетельство о том, что измененный блок не был записан на диск.
Все, что у нас останется – это то, что было на диске – измененная половина записи и старая версия другой ее половины. Разделение на половины может проходить в середине значения поля. Или, может быть, старой версии вообще нет – так как оригинальная запись помещалась в один блок, а измененная – нет.
Перестройка индексов не восстановит поврежденную запись – у нас нигде нет никакой информации, которая может быть использована для восстановления. У Вас проблема! Выполнение truncate bi -F установит флаг «повреждено» в master-блоке базы данных, чтобы отметить факт наличия проблемы. Затем вам будет выдаваться напоминание при каждом запуске базы данных.
Обратите внимание: В старых версиях вы могли использовать трюк, иногда называемый «фиктивная перестройка индексов», когда вы запускаете программу перестройки индексов и указываете, что вы хотите перестроить некоторые индексы, но в действительности не указываете никаких индексов. Флаг повреждения базы, установленный при пропуске восстановления после сбоя, будет сброшен утилитой перестройки индексов. Вы перестанете получать предупреждение при запуске базы данных. Но ничего не было исправлено. У Вас по-прежнему есть проблема!
Повреждение не очевидно
Тот факт, что база данных повреждена, обычно не сразу очевиден. Например, существование частично созданной записи проявляется только при доступе к ней, когда возникает ошибка. До этих пор все могло казаться нормальным.
Физические противоречия в индексной структуре могут быть устранены с помощью автономной утилиты перестройки индексов. Рассмотрим сферическую корову однородной плотности. Утилита перестройки индексов вначале удаляет все индексные блоки, не просматривая их и не замечая никаких возможных повреждений, а затем создает новые блоки, используя значения ключей в существующих записях.
Критические индексы схемы (например, связанные с определением индексов), однако, не могут быть исправлены таким способом. Если они повреждены, то повреждена сама схема базы данных, и информация не может быть надежно извлечена из вашей базы данных даже путем дампирования данных. Это очень маловероятно, но может случиться.
С другой стороны, физические противоречия в записях данных, (включая данные, описывающие схему) не могут быть исправлены. Нигде не имеется никакой информации о том, что должны содержать поврежденные или потерянные записи. Единственная возможность – это удалить поврежденные записи вручную, если их можно найти.
Логические противоречия могут быть исправлены только путем анализа всех значений данных во всех записях и верификации их правильности, отсутствия пропущенных записей и дубликатов. Обычно это невозможно и, в лучшем случае, непрактично.
76. Если это настолько опасно, зачем вообще нужен параметр –F?
Параметр -F утилиты proutil truncate bi предназначен для использования только в аварийной ситуации как последняя мера. Он позволяет вам попытаться извлечь и спасти как можно больше данных из поврежденной базы. Вы должны использовать его только в том случае, когда альтернативой является потеря всей базы данных.
Параметр –F должен быть вашим последним выбором, когда все остальное не сработало. Восстановление из резервной копии – гораздо более желательный и безопасный вариант.