- •7.5.2. Трехфазное подтверждение
- •7.6. Восстановление
- •7.6.1. Основные понятия
- •7.6.2. Создание контрольных точек
- •7.6.3. Протоколирование сообщений
- •7.7. Итоги
- •Глава 8
- •8.1. Общие вопросы защиты
- •8.1.1. Угрозы, правила и механизмы
- •8.1.2. Вопросы разработки
- •8.1.3. Криптография
- •8.2. Защищенные каналы
- •8.2.1. Аутентификация
- •8.2.2. Целостность и конфиденциальность сообщений
- •8.2.3. Защищенное групповое взаимодействие
- •8.3. Контроль доступа
- •8.3.1. Общие вопросы контроля доступа
- •8.3.2. Брандмауэры
- •8.3.3. Защита мобильного кода
- •8.4. Управление защитой
- •8.4.1. Управление ключами
- •8.4.2. Управление защищенными группами
- •8.4.3. Управление авторизацией
- •8.5. Пример — Kerberos
- •8.6. Пример — sesame
- •8.6.1. Компоненты системы sesame
- •8.6.2. Сертификаты атрибутов привилегий
- •8.7. Пример — электронные платежные системы
- •8.7.1. Электронные платежные системы
- •8.7.2. Защита в электронных платежных системах
- •8.7.3. Примеры протоколов
- •8.8. Итоги
- •Глава 9
- •9.1. Corba
- •9.1.1. Обзор
- •9.1.2. Связь
- •9.1.3. Процессы
- •9.1.4. Именование
- •9.1.5. Синхронизация
- •9.1.6. Кэширование и репликация
- •9.1.7. Отказоустойчивость
- •9.1.8. Защита
- •9.2. Dcom
- •9.2.1. Обзор
- •9.2.2. Связь
- •9.2.3. Процессы
- •9.2.4. Именование
- •Синхронизация
- •Репликация
- •Отказоустойчивость
- •9.2.8. Защита
- •9.3. Globe
- •9.3.1. Обзор
- •9.3.2. Связь
- •9.3.3. Процессы
- •9.3.4. Именование
- •9.3.5. Синхронизация
- •9.3.6. Репликация
- •Отказоустойчивость
- •9.4. Сравнение систем corba, dcom и Globe
- •9.4.1. Философия
- •Процессы
- •9.4.4. Именование
- •Синхронизация
- •Кэширование и репликация
- •Отказоустойчивость
собраны все голоса, координатор решает, что транзакцию необходимо прервать, и рассылает всем участникам сообщение global_abort.
И, наконец, участник может быть блокирован в состоянии ready, ожидая глобального объявления результатов голосования, рассылаемого координатором. Если это сообщение за определенный период времени не приходит, участник не может просто решить прервать транзакцию. Вместо этого он должен определить, какое же сообщение на самом деле посылал координатор. Самым простым решением этого вопроса будет блокировка участника до момента восстановления координатора.
Более правильным решением будет разрешить участнику р контакт с другим участником, q, чтобы он мог по текущему состоянию q решить, что же ему делать дальше. Так, например, пусть q перешел в состояние commit. Это возможно только в том случае, если координатор до поломки послал q сообщение global_СОММ1Т. Видимо, до р это сообщение не дошло. Соответственно, р теперь может прийти к выводу о необходимости локального подтверждения. Точно так же если q находится в состоянии abort, р может уверенно прерывать свою часть транзакции.
Теперь предположим, что q пребывает в состоянии init. Такая ситуация может произойти, если координатор разошлет всем участникам сообщения vote_ request и это сообщение дойдет до р (который ответит на него посылкой сообщения vote_commit), но не дойдет до q Другими словами, координатор может отказать во время рассылки сообщения vote_request. В этом случае правильно будет прервать транзакцию: и р, и q могут осуществить переход в состояние abort.
Наиболее сложную ситуацию мы получим, если q также будет находиться в состоянии ready, ожидая ответа от координатора. Так, если окажется, что все участники находятся в состоянии ready, конкретное решение принять невозможно. Проблема состоит в том, что все участники готовы подтвердить транзакцию, но для этого им необходим голос координатора. Соответственно, протокол блокируется до момента восстановления координатора.
Различные варианты иллюстрирует табл. 7.5.
Чтобы гарантировать, что процесс действительно восстановился, нужно чтобы он сохранял свое состояние при помощи средств длительного хранения данных (как сохранять защищенным от отказов способом, мы поговорим позже в этой главе). Так, например, если участник находился в состоянии init, то после восстановления он может решить локально прервать транзакцию и сообщить об этом координатору. Точно так же если он уже принял решение и в момент поломки находился в состоянии COMMIT или ABORT, то при восстановлении он снова придет в выбранное состояние и повторно сообщит свое решение координатору.
Проблемы возникают, когда участник отказывает, находясь в состоянии READY. В этом случае при восстановлении он не может определить на основании собственной информации, что делать дальше, завершать или прерывать транзакцию. Соответственно, чтобы выяснить, что делать этому процессу, его следует заставить связаться с другими участниками, как это проделывалось в ситуации истечения тайм-аута в состоянии READY, описанной ранее.
Координатор имеет только два критических состояния, за которыми надо следить. Когда он начинает протокол 2PC, он должен сохранить сведения о том, что он находится в начальном состоянии WAIT, чтобы иметь возможность при необходимости после восстановления повторно разослать сообщение VOTE_ REQUEST всем участникам. Кроме того, если в ходе второй фазы он принял решение, следует сохранить это решение, чтобы после восстановления координатора его также можно было разослать повторно.
Схема действий координатора иллюстрирует листинг 7.1. Координатор начинает с групповой рассылки всем участникам сообщения VOTE_REQUESTлля того, чтобы собрать их голоса. Он записывает это действие, после чего входит в состояние WAIT, в котором ожидает прихода голосов участников.
Листинг 7.1. Схема действий, предпринимаемых координатором согласно протоколу двухфазного подтверждения
ДЕЙСТВИЯ КООРДИНАТОРА: записать START_2PC в локальный журнал; разослать V0TE_ REQUEST всем участникам; пока собраны не все голоса { ожидать прихода голосов; если время вышло {
записать GL0BAL_AB0RT в локальный журнал; разослать GL0BAL_AB0RT всем участникам; выход;
}
записать голос;
}
если все участники прислали V0TE_C0MMIT и координатор голосует COMMIT {
записать GL0BAL_C0MMIT в локальный журнал;
разослать GL0BAL_C0MMIT всем участникам; } в противном случае {
записать GL0BAL_AB0RT в локальный журнал;
разослать GL0BAL_AB0RT всем участникам;
}
Если собраны не все голоса, а недостающие в течение заданного времени не присланы, координатор приходит к выводу, что один или более участников находятся в нерабочем состоянии. Это означает, что он должен прервать транзакцию и разослать остальным участникам сообщение GLOBALABORT.
Если не произошло никаких отказов, координатор в конечном итоге соберет все голоса. Если все участники, так же как и координатор, проголосовали за подтверждение, сообщение GLOBALCOMMIT будет сначала записано в журнал, а потом разослано всем процессам. В противном случае координатор разошлет сообщение GLOBAL_ABORT (предварительно также записав его в локальный журнал).
В листинге 7.2 приведены действия, осуществляемые участником. В начале процесс ожидает запроса на голосование от координатора. Отметим, что это ожидание выполняется в отдельном потоке выполнения, выполняющемся в адресном пространстве процесса. Если сообщение не поступает, транзакция просто прерывается. По всей вероятности, причина отсутствия сообщения состоит в том, что координатор отказал.
Листинг 7.2. Схема действий, предпринимаемых процессом-участником протокола 2РС
ДЕЙСТВИЯ УЧАСТНИКА:
записать состояние INIT в локальный журнал; ожидать VOTE_REQUEST от координатора; если время вышло {
записать GL0BAL_AB0RT в локальный журнал;
выход;
}
если участник голосует за COMMIT {
записать V0TE_C0MMIT в локальный журнал; послать V0TE_C0MMIT координатору; ожидать решение от координатора; если время вышло {
разослать DECISION_REQUEST другим участникам;
ожидать прихода решения; /^процесс блокирован*/
записать решение в локальный журнал;
}
если решение == GL0BAL_C0MMIT
записать GL0BAL_C0MMIT в локальный журнал; иначе если решение == GL0BAL_AB0RT
записать GL0BAL_AB0RT в локальный журнал;
} если {
записать V0TE_AB0RT в локальный журнал; послать V0TE_AB0RT координатору;
}
После получения запроса на голосование участник может решить голосовать за подтверждение транзакции, для чего ему следует сначала записать это решение в локальный журнал, а затем проинформировать о нем координатора путем посылки ему сообщения VOTECOMMIT. После этого участник должен дождаться глобального решения. Получив это решение (которое опять-таки должно прийти от координатора), он записывает его в локальный журнал, а затем выполняет.
Однако если участник ожидает решения координатора весь отведенный на это срок и не получает его, он выполняет протокол прекращения ожидания, сначала рассылая остальным процессам сообщения DECISION_REQUESTy а затем блокируясь в ожидании ответа. Когда приходит ответ (возможно, от координатора, который уже успел восстановиться), участник записывает решение в локальный журнал и поступает в соответствии с ним.
Каждый участник должен быть готов к тому, что другой участник запросит у него глобальное решение. Для этого каждый из участников должен запустить отдельный поток выполнения параллельно с главным потоком выполнения участника, как показано в листинге 7.3. Этот поток блокируется до получения запроса о решении. Он может ответить другим процессам, только если ассоциированный с ним участник уже принял конечное решение. Другими словами, если в локальный журнал было записано сообщение GLOBAL JCOMMITили GLOBAL_ ABORT, можно быть уверенным, что координатор послал свое решение как минимум этому процессу. Кроме того, как мы говорили ранее, что если ассоциированный с потоком участник находится в состоянии INIT, он может решить послать сообщение GLOBAL_ABORT. Во всех остальных случаях этот поток ничем не сможет помочь задавшему вопрос процессу, и пославший запрос участник останется без ответа.
Листинг 7.3. Схема обработки входящих запросов о решении
ДЕЙСТВИЯ ПО ОБРАБОТКЕ ЗАПРОСА РЕШЕНИЯ: /^выполняются в отдельном потоке выполнения*/ пока истина {
ожидать любого сообщения DECISION_REQUEST; /^процесс блокирован*/ считать последнее записанное состояние из локального журнала если состояние — GLOBAL-COMMIT
послать GL0BAL_C0MMIT запросившему решение участнику иначе если состояние == INIT или состояние == GL0BAL_AB0RT
послать GL0BALJ\B0RT запросившему решение участнику иначе
пропустить /^участник блокирован*/
}
Как можно заметить, возможна ситуация, когда участнику придется установить блокировку до восстановления координатора. Такая ситуация может возникнуть, если все участники получат и обработают сообщение координатора VOTE_REQUEST и в ходе этой работы координатор сломается. В этом случае участники не смогут совместно решить, какое действие им предпринять. По этой причине протокол 2PC также называют протоколом блокирующего подтверждения (blocking commit protocol).
Существует несколько способов избежать блокировки. Одно из них, описанное в [22], состоит в использовании примитива групповой рассылки, когда получатель немедленно рассылает ответное сообщение всем остальным процессам. Можно показать, что подобный подход позволяет участнику принять итоговое решение даже в том случае, если координатор еще не восстановился. Другое решение — использование протокола трехфазного подтверждения, который является последней темой этого раздела.
7.5.2. Трехфазное подтверждение
Проблема протокола двухфазного подтверждения состоит в том, что при поломке координатора участники могут оказаться не в состоянии прийти к итоговому решению. В результате участникам приходится дожидаться восстановления кооринатора, находясь в заблокированном состоянии. В [422] был предложен вариант протокола 2PC, названный протоколом трехфазного подтверждения {Three-phase Commit Protocol, ЗРС), который предотвращает блокировку процессов при появлении ошибок аварийной остановки. Хотя протокол ЗРС часто упоминается в литературе, на практике он используется редко, потому что редко возникают условия, в которых блокируется 2РС. Мы рассмотрим этот протокол, поскольку он представляет собой дальнейшее развитие решений проблем отказоустойчивости в распределенных системах.
Как и 2РС, ЗРС формулируется в терминах координатора и набора участников. Соответствующие им конечные автоматы показаны на рис. 7.14. Сущность протокола состоит в том, что состояния координатора и любого из участников удовлетворяют двум условиям.
Не существует такого состояния, из которого может быть осуществлен прямой переход как в состояние COMMIT, так и в состояние ABORT.
Не существует такого состояния, в котором невозможно принять итоговое решение, но возможен переход в состояние COMMIT.
Можно показать, что эти два условия необходимы и достаточны для того, чтобы протокол подтверждения был неблокирующим [424].
Координатор ЗРС начинает с рассылки всем участникам сообщения VOTE_ REQUEST после чего ожидает прихода ответов. Если хотя бы один участник голосует за прерывание транзакции, это становится итоговым решением и координатор рассылает участникам сообщение GLOBALABORT. Однако если транзакция может быть подтверждена, рассылается сообщение PREPAREjCOMMIT. Только после того, как все участники подтвердят свою готовность к подтверждению, координатор посылает итоговое сообщение GLOBAL COMMIT, в результате которого транзакция действительно подтверждается.
И снова существует лишь несколько ситуаций, в которых процесс блокируется и ожидает сообщений. Во-первых, когда участник, находясь в состоянии INIT, ожидает прихода запроса на голосование, он может в итоге перейти в состояние
ABORT, что будет означать поломку координатора. Эта ситуация идентична ситуации для протокола 2РС. Также аналогично координатор может находиться в состоянии WAIT, ожидая голосов участников. По истечении заданного времени координатор решает, что участник отказал, и обрывает транзакцию путем рассылки сообщения GLOBALABORT.
Рассмотрим теперь блокировку координатора в состоянии PRECOMMIT. В случае истечения заданного времени он приходит к выводу, что один из участников отказал, но прочие участники знают, что они голосовали за подтверждение транзакции. Соответственно, координатор приказывает работающим участникам подтвердить транзакцию путем рассылки сообщения GLOBAL COMMIT. Кроме того, он полагает, что протокол восстановления отказавшего участника поможет подтвердить его часть транзакции после того, как этот участник будет восстановлен.
Участник Р может блокироваться в состоянии READY или PRECOMMIT. После окончания отведенного участнику Р на ожидание времени, Р в состоянии понять, что координатор отказал и нужно решать, что делать дальше. Как и в 2PC, если Р при контакте с другим участником обнаружит, что он находится в состоянии COMMIT (или ABORT), Р также переходит в это состояние. Кроме того, если все участники находятся в состоянии PRECOMMIT, транзакция может быть без проблем подтверждена.
Опять-таки, аналогично схеме 2РС, если другой участник Q по-прежнему находится в состоянии INIT, транзакция может быть совершенно спокойно прервана. Важно отметить, что Q может находиться в состоянии INIT только в том случае, если ни один из участников не находится в состоянии PRECOMMIT. Участник может перейти в состояние PRECOMMIT, только если координатор перед сбоем сам перешел в состояние PRECOMMIT, а значит, получил голоса всех участников. Другими словами, участник не может оставаться в состоянии INIT, когда другой участник переходит в состояние PRECOMMIT.
Если каждый из участников, с которым может связаться Р, находится в состоянии READY (и вместе они образуют большинство), транзакция должна быть прервана. Здесь следует отметить, что если один из участников отказывает, позже он будет восстановлен. Однако ни Р, ни любой другой активный участник не знают, в каком состоянии будет находиться отказавший участник после восстановления. Если процесс будет восстановлен в состоянии INIT, решение о прерывании транзакции — единственно верное. В наихудшем случае процесс может восстановиться в состоянии PRECOMMIT, но и в этом случае он не сможет помешать прерыванию транзакции.
Этим ситуация сильно отличается от протокола 2РС, где отказавший участник может восстановиться в состоянии COMMIT, тогда как все прочие участники будут находиться в состоянии READY. В этом случае оставшиеся рабочие процессы не смогут принять итогового решения и вынуждены будут ожидать восстановления отказавшего процесса. В ЗРС, если какой-то из рабочих процессов находится в состоянии READY, отказавшие процессы не смогут восстановиться ни в каком другом состоянии, кроме INIT, ABORT или PRECOMMIT. По этой причине оставшиеся невредимыми процессы всегда смогут прийти к итоговому решению.
И, наконец, если процессы, такие как Р, могут достичь состояния PRECOMMIT (и они составляют большинство), то можно без проблем подтвердить транзакцию. И снова мы можем видеть, что все остальные процессы либо находятся в состоянии READY, либо, как минимум, если они отказали, будут восстановлены в состоянии READY, PRECOMMIT или COMMIT
Дополнительные подробности по ЗРС можно найти в [47, 103].
