Вход в личный кабинет:

Забыли пароль? | Регистрация

Адреса компании:

Санкт-Петербург

196158, Санкт-Петербург,
Пулковское шоссе, д. 30,
корп. 4, Лит. А, офис 203

Тел: +7 812 414 95 41

Москва

129085, г. Москва, проезд Ольминского, д. 3а, стр. 3, офис 706

Тел: +7 495 616 00 53

Блог

26.08.2015

Progress OpenEdge: промышленные средства репликации данных в Oracle и MS-SQL

Progress OpenEdge Pro2 Replication

Читать далее →




Десять причин перехода на новые версии OpenEdge (Progress)


Зачем нужен файл Before-Image?

Вернуться к списку постов

16.05.2011

Весьма вольная интерпретация статьи “Why You Need the Before-image Log”, автор Gus Bjorklund. Но, думаю, этого достаточно для понимания основной сути вопроса.

(2009 Башкатов В.Г.)



Before-image log, так же называемый “bi file”, содержит primary transaction log (производный термин от “undo-redo log”) базы данных. Это существенная часть каждой базы данных, которая столь же важна, как и экстенты с таблицами и индексами. Без bi-экстентов с базой данных нельзя работать. Если случится так, что bi файл окажется потерянным или поврежденным, то ваша база данных будет считаться поврежденной. И единственным способом восстановления такой базы будет восстановление её из последней резервной копии с последовательным накатом After-Image (AI) файлов. Надеюсь, вы делаете резервные копии вашей базы данных и у вас включен механизм After-Imaging?

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

Если вы считаете, что ваши данные представляют хоть малейшую ценность, и если был потерян хотя бы один экстент с данными или BI экстент, то не сомневайтесь – единственный надежный способ восстановления, это восстановление базы данных из резервной копии.

Хотя мы и называем этот файл «Before-Image», на самом деле данные, сохраняемые в него, не совсем подходят под определение before-images (исходный вид). Это название историческое, и возможно было неудачно подобрано. BI файл содержит записи, называемые «заметками» (notes), которые позволяют восстановить или отменить изменения, сделанные в базе данных.

В основном BI файл используется с двумя целями: для восстановления в случае сбоя (crash recovery), и для отката (rollback) транзакций при нормальной работе.

Кроме того, он, совместно с менеджером памяти, обеспечивает разнообразные варианты улучшения производительности, позволяя оперативно изменять блоки памяти не требуя их записи в экстенты базы данных. Правило управления буферами это “no-force, steal”, что означает, измененные буфера не должны быть сброшены на диск во время завершения транзакции, а могут быть записаны на диск во время работы другой транзакции, т.е. по мере необходимости освобождения места для считывания блоков, которые отсутствуют в буферном пуле.

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

В конечном счете, измененные блоки должны быть записаны в экстенты данных на диске, но менеджер памяти баз данных обычно откладывает операции записи как можно на долгий период, и иногда он может длиться несколько часов или даже дней. Одна из важных причин такой отсрочки, это то что блок может еще не однократно подвергаться изменениям. Таким образом сокращается частота записи на диск. Обычно, измененные блоки записываются на диск асинхронным автоматическим механизмом контрольных точек (checkpoints), или же когда база данных будет остановлена.

Скажите, что произойдет с изменениями сделанными в памяти, в случае возникновения системного сбоя? Они будут потеряны? Ответ – на основании информации, хранящейся в bi файле, они будут восстановлены. Каждое изменение блока данных, сначала записывается в качестве заметок (note) в буферы bi файла. Причем для некоторых типов изменений может быть сгенерировано множество различных заметок. Заметки из bi буферов должны быть сброшены на диск только когда транзакция будет совершена (committed).

Заметки записываемые в BI файл содержат номер области хранения, количество блоков, rowid и прочие данные, которые используется для идентификации изменений, т.е. что и как было изменено. В результате, BI файл оказывается в сильной связи со своей базой данных. Поэтому он может быть использован только со своей базой.

Менеджер хранения тщательно следует правилам, которые обычно называются “write-ahead logging rule” или WAL. Эти правила гарантируют, что ни один измененный блок базы данных не будет записан в экстент базы на диске, прежде чем он не будет записан в BI – файл. Таким образом, все изменения на диске будут дублироваться в BI файле. По правде говоря, в before-image доступны только описания изменений. Это потому, что пространство в файле лога многократно используется. При этом log-менеджер должен гарантировать, что данные которое будут перезаписаны, больше не будут нужны.

Если изменение будет потеряно, то мы сможем использовать заметки в transaction log чтобы восстановить их. Это и есть причина того, что лог называется “undo-redo log”, т.е. он позволяет нам восстановить изменения, которые были сделаны ранее. Redo так же называют “repeating history” или “replaying transaction”. Точно так же, можно использовать те же заметки, чтобы отменить изменения, которые были сделаны незавершенной (uncommitted) транзакцией.

WAL правила позволяют изменять блоки данных в памяти без немедленной их записи на диск. Кроме того, не обязательно записывать блоки на диск даже если транзакция будет совершена (committed). Вместо этого, заметки с изменениями просто пишутся в transaction log. В результате, экстенты данных находящиеся на диске, ни когда не будут соответствовать реальному состоянию пока система работает. Конечное и правильное состояние базы данных состоит из трех различных частей:

0)    Блоки на диске находятся в различных экстентах данных

1)    Более новые версии некоторых из этих блоков находятся в памяти

2)    Заметки с изменениями находятся в Before-image log.

Данных в Before-Image log и данных в экстентах, достаточно, чтобы воссоздать изменения находящиеся в памяти в буферном пуле. Это означает, что ни чего страшного, если мы потерям данные в памяти, т.е. если в случае сбоя системы будут потеряны измененные блоки. Но тем не менее, если в результате сбоя был потерян BI файл, например, диск на котором он был расположен оказался поврежденным, то тогда восстановить изменения, которые находились в буферном пуле памяти и не были записаны на диск, будет невозможно. Запомните, ни каким способом не возможно восстановить данные в before image log.

Если вы используете After-Imaging, то это значительно облегчит восстановление поврежденной базы данных, т.е. BI файла и экстентов с данными. After-image log содержит вторичную копию всех заметок об изменениях, которые писались в before-image log. Поэтому, восстановив базу из последней резервной копии и последовательно накатив (roll forward) все сохраненные с момента создания этой резервной копии AI экстенты, вы получите точную копию Вашей базы до момента сбоя.

При нормальной работе, так как транзакции изменяют базу данных, в before-image log генерируются заметки, которые сбрасываются в буферы и записываются в лог, блоки изменяются в буферном пуле в памяти и иногда записываются в экстенты данных. Если происходит сбой, содержимое  shared-memory теряется. Допустим, что системный сбой не был причиной аварии приведшей к потери и повреждению данных на диске, и у нас на диске остается только before-image log и устаревшие экстенты данных.

Когда база данных будет перезапущена после такого сбоя, менеджер восстановления (recovery manager) начнет считывать заметки из before-image log и восстанавливать все изменения, которые не были записаны на диск, этот процесс называется  Crash Recovery. Чтобы облегчить процесс, каждый блок данных содержит номер версии, который увеличивается каждый раз когда блок изменяется. Номер версии и номер блока копируются в before-image заметки (notes), описывающие изменения. Так как менеджер восстановления считывает bi-заметки в порядке их записи, он сравнивает номер версии в заметке с номером версии в блоке, и в случае необходимости считывает его в буферный пул с диска. Если версия блока позже версии в заметке, значит изменения, описанные в ней, уже были сделаны. Это возможно только для некоторых изменений, но не для всех. Например, измененный блок может быть записан на диск с целью освобождения места для другого блока считываемого в память. Поэтому, такой блок будет отвергнут и чтение продолжится далее. Если версии совпадают, то делается изменение и увеличивается номер версии блока. Заметьте, что такая схема требует, чтобы все изменения были восстановлены в том же порядке, в каком они были сделаны, и не одно из них не может быть пропущено. Каждое изменение записи, является описанием того, как изменялся блок от версии “n” к версии “n + 1”. Ситуация же с обратным откатом, более сложна и здесь описана не будет. Как только будет достигнут конец before-image log, то мы воспроизвели все изменения, которые были потеряны. Большинство измененных блоков будет в памяти в буферном пуле базы данных, но некоторые блоки возможно будут записаны на диск в экстенты данных, если, например, понадобилось освобождение места для чтения других блоков. Как только все заметки считаны, мы сможем откатить (roll back) все незавершенные транзакции и завершить восстановление. Обратите внимание, что каждая транзакция в памяти, так же регистрируется в before-image log, а следовательно тоже будет восстановлена, по мере считывания заметок.

Когда же измененные блоки записываются в экстенты данных?

Измененные блоки, находящиеся в буферном пуле базы данных, записываются в связанные с ними экстенты в следующих случаях:

0)    Когда APW обрабатывает измененные блоки в очереди контрольной точки (checkpoint queue) и записывает их.

1)    Когда необходим блок, которого нет в буферном пуле, в этом случае, измененный блок будет записан на диск для освобождения места.

2)    Когда APW записывает измененный блок из очереди APW (APW queue).

3)    Когда APW не выполняет полезной работы, и поэтому, потихоньку просматривает список измененных блоков и периодически записывает их.

4)    Вскоре после запуска online backup, утилита копирования записывает все измененные блоки в буферном пуле. Фактически, это не нужно.

5)    Когда выполняется нормальная остановка базы данных.


Во всех случая, поскольку мы придерживаемся WAL правил, все заметки, описывающие изменения, должны быть записаны в transaction log прежде, чем блоки данных будут записаны на диск.

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

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

0)    когда процесс, генерирующий заметки обнаруживает что текущий кластер заполнен, то перед инициализацией следующего кластера, все измененные блоки в очереди контрольной точки (checkpoint queue) будут записаны.

1)    Когда потребуется блок, отсутствующий в буферном пуле, то предварительно, для освобождения места, на диск будет сброшен какой-нибудь измененный блок в буфере.

2)    после запуска online backup, утилита копирования записывает все измененные блоки в буферном пуле.

3)    Когда выполняется нормальная остановка базы данных


Без APW, время необходимое для записи понадобится больше, чем с использованием APW.

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

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

1)    База данных остановлена нормальным способом.

2)    Все ранее сброшенные блоки записаны на диск из буферного пула операционной системы, самой операционной системой. Достаточно трудно сказать, когда это происходит. Если вы используете параметр запуска –directio или версию Progress V10, то после успешной остановки базы это будет истинно. Иначе, нельзя с уверенностью сказать, что в буферном пуле операционной системе не осталось не сброшенных на диск блоков. Во время остановки, после записи всех измененных блоков, менеджер памяти генерирует системный вызов sync(), чтобы указать операционной системе о необходимости сброса на диск его буферов, включая данные не связанные с базой. На некоторых операционных системах, этот системный вызов завершается до того как операционная система завершит запись. Вы можете проверить, выполняется ли sync() синхронно, выполнив один эксперимент. Во время, когда система активна и записывается много файлов, наберите в командной строке “time sync”, запустите ее несколько раз и посмотрите как долго она будет выполняться. Если команда завершается немедленно, тогда вероятно что sync() работает не синхронно. Если для завершения потребовалось некоторое время, от нескольких секунд до нескольких минут, а последующие запуски sync() завершаются быстро, то это означает, что sync() работает синхронно, и все записи на диск были завершены до возвращение управления в командную строку. Этот эксперимент работает, только если в системном буферном пуле действительно имеется много изменений файловой системы. Но вернемся к теме. Менеджер памяти всегда перед окончательной остановкой, ожидает некоторое время, чтобы дать возможности системе завершить все операции записи. По умолчанию, это время равно 60 секундам (в последних версиях оно равно 0), но иногда его бывает не достаточно. Для увеличения времени вы можете воспользоваться параметром –G. Помните, если произойдет системный сбой, до того как операционная система завершит запись, то все изменения будут потеряны.

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


Когда база данных запускается после нормальной остановки, она так же выполняет некое подобие Crash Recovery. По не некоторым причинам, мы называем этот процесс “warm start”. Этот процесс читает transaction log и проверяет, что ни одно из изменений не было потеряно после остановки. Если системный сбой произошел после остановки, но до завершения записи буферов файловой системы, ни какие изменения потеряны не будут.

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


Пример сбойной ситуации.

Для пропуска процесса Crash Recovery можно использовать proutil truncate bi –F, тем самым игнорируя содержание bi файла. Пропуск Crash Recovery означает то, что записи в before-image не будут считаны и обработаны, все изменения в базе данных будут потеряны без возможности восстановления, и все не завершенные транзакции не откатятся. В результате выполнения этой операции вероятно, что база данных будет повреждена. Кроме того, эти повреждения проявятся не сразу. Возможно, что вы сразу сможете открыть базу данных и получить доступ к данным, но не ко всем из них. Следующий пример показывает, что же произошло. Этот пример достаточно прост чтобы это понять. Некоторые детали будут пропущены, но они не так важны.

Рассмотрим следующую последовательность событий.

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

Чтобы изменить некоторую запись, нам нужно прочитать её из экстента на диске. Сначала мы читаем корневой (root) индексный блок в один из четырех буферов. Предположим, что индекс имеет два уровня, тогда мы так же должны прочитать второй индексный блок.

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

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

Теперь, когда мы изменим запись, то каждый из двух фрагментов будет изменен, тем самым, оба блока данных получат статус измененных (так называемые «грязные блоки»). В transaction log будет сгенерирована заметка для каждого изменения.

Как только изменение будет завершено, мы получим следующую ситуацию:

  • Мы имеем 4 заметки в before-image log:

    Заметку о начале транзакции

    Заметку об изменении первого фрагмента записи

    Заметку об изменении второго фрагмента записи

    Заметку о завершении транзакции.

  • На диск еще ни чего не записывалось, т.е. мы имеем его в том же состоянии с которого и начинали.
  • В буферном пуле имеются два «грязных» блока, которые не записаны на диск, но должны быть записаны в будущем.

Теперь мы читаем вторую записи, и снова считываем два индексных блока. Поскольку предыдущие индексные блоки будут самые старые, они будут заменены новыми блоками, и перемещены в начало LRU-цепочки.

Затем мы считываем один блок данных, заменяя им один предыдущий измененный блок, который записывается на диск. Мы не изменяем эту запись сейчас.

В этой точке времени мы имеем:

Четыре заметки от предыдущего изменения

Один измененный блок, записанный на диск.

В памяти у нас два индексных блока, один не измененный блок и один измененный блок данных.


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

Теперь предположите, что произошел системный сбой, поскольку кто-то отключил сервер, чтобы включить пылесос 😉 Такие случаи действительно имели место быть! Но сбой может произойти из-за чего угодно, может быть в место пылесоса хотели подключить laptop. J

И так, после перезагрузки сервера мы имеем следующее:

4 before-image заметки с изменениями в BI – файле

Один из двух измененных блоков, записанный на диск.

Остальные данные, которые были в экстентах базы до начала нашего упражнения

Всё что было в памяти, мы потеряли. Включая один из наших измененных блоков. Единственное доказательство того, что блок был измен, находится в before-image log.

Если мы запустим базу данных нормальным способом, то будет выполнен процесс Crash Recovery, который считает before-image log и обнаружит, что один из измененных блоков был потерян, после чего воссоздаст его снова. Как только Crash Recovery будет завершен, мы снова будем иметь два измененных блока. Это всё весьма прекрасно!

Но если вместо этого мы воспользуемся утилитой proutil с опцией –F, чтобы усечь (truncate) bi файл, то все bi заметки будут проигнорированы. И единственное доказательство существования не записанного на диск измененного блока, будет потеряно.

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

Восстановление индекса не поможет восстановить поврежденную запись. Ни где нет ни какой доступной информации, которая может быть использована для её восстановления. Т.е. вы зря потратите время.

Когда вы таким образом пропускаете Crash Recovery, в базе данных устанавливается флаг “damaged”. И каждый раз, когда вы будете запускать базу данных, вы будете получать сообщение о том, что база данных повреждена и необходимо сделать перезагрузку (dump/load) данных. Если причиненный базе ущерб будет достаточно серьезным, то это не будет представляться возможным. Даже если это и будет возможно, то вероятнее всего вы потеряете некоторые данные.

Вывод: Before-image log это такая же часть базы данных как и её экстенты. Если вы теряете экстент данных, то вы должны восстановить базу из резервной копии. Если вы потеряли before-image log, вы так же должны восстанавливать базу из резервной копии. Нет ни одного иного способа восстановления, чтобы быть уверенным в том, что база данных останется в надежном и актуальном состоянии.


Добавить свой комментарий

Ваше имя*:
Ваш E-mail*:
Ваш комментарий*:

Компьютерные системы для бизнеса
© 2010 - 2017 Все права на материалы, находящиеся на этом сайте, охраняются в соответствии с законодательством РФ, в том числе, об авторском праве и смежных правах. При любом использовании материалов сайта ссылка на источник обязательна.