Классика баз данных - статьи

       

Протоколы обеспечения надежности


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

В распределенной СУБД различаются четыре типа сбоев: сбой транзакции (transaction failure), сбой узла (системы) (site (system) failure), сбой носителя (диска) (media (disk) failure) и сбой коммуникационной линии (communication line failure).

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

Сбои узлов (систем) могут быть вызваны аппаратными отказами (процессора, оперативной памяти, питания) или программными ошибками (в системном или прикладном коде). Системные сбои приводят к потере содержимого оперативной памяти. Поэтому в этом случае пропадут все элементы базы данных данных, находящиеся в буферах оперативной памяти (и называемые также неустойчивой базой данных (volatile database)). В то же время данные, находящиеся во вторичной памяти (называемые также стабильной базой данных (stable database)), остаются в сохранности. Для поддержания сохранности данных обычно применяют протоколы журнализации (logging protocol), например, журнализация с упреждающей записью (Write-Ahead Logging), которые создают в системных журналах записи обо всех изменениях в базе данных и в подходящие моменты времени перемещают журнальные записи, а также страницы неустойчивой базы данных в стабильную память. В распределенной базе данных проблема системных сбоев выражается еще и в том, что отказавший узел не может участвовать в выполнении какой-либо транзакции.

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

Рассмотренные выше три типа сбоев характерны и для централизованных, и для распределенных СУБД. Коммуникационные сбои, напротив, являются специфической проблемой распределенных баз данных. Они подразделяются на несколько разновидностей, наиболее распространенными из которых являются ошибки в сообщениях, нарушение упорядоченности сообщений, потерянные (недоставленные) сообщения, повреждения линий связи. Первые две из них относятся к компетенции сетевых протоколов и не учитываются в реализациях распределенных СУБД. Последние же две находятся в ведении СУБД и должны учитываться в протоколах обеспечения надежности. Если один узел ожидает сообщения от другого, а оно не поступает, то причин тому может быть несколько: (а) сообщение утрачено; (b) возникло повреждение на линии связи, соединяющей два эти узла; (c) узел, от которого ожидается сообщение, отказал. Таким образом, не всегда возможно отличить коммуникационный сбой от системного. Ожидающий узел по истечении определенного промежутка времени просто решает, что узел-партнер стал недоступен. Протоколы распределенных СУБД должны уметь адекватно реагировать на подобные неопределенные ситуации. Серьезным последствием повреждений на линиях связи может стать разделение сети (network partitioning), когда множество узлов распадается на группы, внутри которых имеется связь, а коммуникации между группами невозможны. В такой ситуации исключительно сложно обеспечить доступ пользователей к системе, гарантируя при этом ее согласованность.

Протоколы обеспечения надежности поддерживают два свойства транзакций: атомарность (atomicity) и долговечность (durability). Атомарность означает, что выполняются либо все действия транзакции, либо не выполняется ни одно из них (принцип "все или ничего").


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

Для обеспечения атомарности и долговечности необходимы атомарные протоколы фиксации (atomic commitment protocol) и протоколы распределенного восстановления (distributed recovery protocol). Наиболее популярным протоколом атомарной фиксации является протокол двухфазной фиксации транзакций (two-phase commit). Протоколы восстановления надстраиваются над протоколами локального восстановления, которые зависят от режима взаимодействия СУБД с операционной системой.



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

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


  • Если все узлы голосуют за фиксацию транзакции, то она фиксируется во всех участвующих в ней узлах.


  • В простейшем варианте работа 2PC выглядит следующим образом. В узле, где инициируется транзакция, создается процесс-координатор (coordinator); во всех прочих затрагиваемых ею узлах создаются процессы-участники (participant).


    Вначале координатор рассылает участникам сообщение "приготовиться", и каждый из них независимо решает, может ли транзакция завершиться на данном узле. Участники, которые готовы завершить транзакцию, посылают координатору сообщение "голосую за фиксацию". Участники, не имеющие возможности зафиксировать свою часть транзакции, возвращают сообщение "голосую за аварийное завершение". Проголосовавший участник не может изменить свое решение. Координатор, собрав голоса участников, решает судьбу транзакции согласно правилам 2PC. Если он принимает решение зафиксировать транзакцию, то всем участникам рассылается сообщение "глобальная фиксация". Если решено завершить транзакцию аварийным образом, то участникам, проголосовавшим за ее фиксацию, посылается сообщение "глобальное аварийное завершение". Участникам, проголосовавшим за прерывание, сообщение посылать не нужно, поскольку они сами способны принять решение, исходя из правил 2PC. Это называется односторонним выбором участником аварийного завершения (unilateral abort option).

    Протокол предполагает два "раунда" обмена сообщениями между координатором и участниками, отсюда название 2PC. Имеется несколько вариаций классического 2PC, таких как линейный 2PC и распределенный 2PC, не получивших широкого признания среди поставщиков распределенных СУБД. Две наиболее важные разновидности протокола – 2PC с предполагаемой фиксацией (presumed commit 2PC)

    и 2PC с предполагаемым аварийным завершением (presumed abort 2PC) [Mohan and Lindsay, 1983].Их важность определяется тем, что они позволяют сократить число сообщений, которыми должны обменяться узлы, и число операций ввода-вывода. Протокол с предполагаемым прерыванием вошел в стандарт X/Open XA и принят как часть стандарта ISO для открытой распределенной обработки (Open Distributed Processing).

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


    Как уже отмечалось, единственный способом выявления сбоев служит установка таймаутов при ожидание сообщения. Если время ожидания исчерпывается, то ожидавший сообщения процесс (координатор или участник) следует протоколу терминирования (termination protocol), который предписывает, что нужно делать с транзакцией, находящейся середине процесса фиксации. Неблокирующий протокол фиксации – это такой протокол, терминирующая часть которого при любых обстоятельствах способна определить, что делать с транзакцией в случае сбоя. При использовании 2PC, если в период сбора голосов сбой происходит и на координирующем узле, и на одном из участников, оставшиеся узлы не способны решить между собой судьбу транзакции и вынуждены оставаться в заблокированном состоянии, пока не восстановится либо координатор, либо отказавший участник. В этот период невозможно снять установленные транзакцией блокировки, что снижает доступность базы данных.

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


    Разумного протокола терминирования в такой модели предложить нельзя.

    Если участники способны взаимодействовать друг с другом, то можно разработать распределенный протокол терминирования. Участник, который не дождался сообщения от координатора, может просто обратиться за помощью в принятии решения к другим участникам. Если в ходе выполнения терминирующего протокола все участники придут к выводу, что отказал только координатор, то они могут избрать в качестве координатора другой узел, где будет перезапущен процесс фиксации. Однако если отказ произошел не только на координаторе, но и на участнике, то возможна ситуация, когда участник уже успел получить от координатора окончательное решение и завершил транзакцию соответствующим образом. Это решение еще не известно другим участникам, и, если они изберут другого координатора, то есть опасность, что они завершат транзакцию не так, как это сделал отказавший участник. Приведенные примеры иллюстрируют блокирующий характер 2PC. Предпринимались попытки создания неблокирующих протоколов фиксации (например, протокол трехфазной фиксации), но высокие накладные расходы, связанные с их выполнением, препятствуют их принятию.

    Обратной стороной терминирования является восстановление. Какие действия должен предпринять восстанавливающийся после сбоя узел, чтобы привести базу данных в согласованное состояние? Это относится к области компетенции протоколов распределенного восстановления. Рассмотрим данную процедуру для приведенного выше примера, когда координирующий узел возобновляет работу после сбоя, и протокол восстановления должен принять решение о том, как следует поступить с транзакцией, которую координировал узел. Возможны следующие случаи.

  • Сбой координатора произошел до начала процедуры фиксации. Тогда он может начать процесс фиксации после восстановления.


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


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



  • Содержание раздела