- •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. Именование
- •Синхронизация
- •Кэширование и репликация
- •Отказоустойчивость
7.6.3. Протоколирование сообщений
Мы пришли к выводу, что создание контрольных точек — довольно затратная операция, особенно если учесть необходимость записи состояния в устойчивое хранилище. Поэтому следует применять технологии сокращения числа контрольных точек, не ухудшающие качества исправления ошибок. Одна из важнейших технологий такого типа в распределенных системах — это протоколирование сообщений (message logging).
Основная идея, лежащая в основании протоколирования сообщений, состоит в том, что если удастся воспроизвести повторную передачу сообщений, мы также получим глобально непротиворечивое состояние, не восстанавливая его из устойчивого хранилища. В этом случае, начиная от состояния контрольной точки, просто воспроизводятся отправка, прием и обработка всех сообщений, которыми обменивались процессы после создания контрольной точки.
Этот способ хорошо работает при соблюдении условий так называемой кусочно детерминированной модели (piecewise deterministic model). Согласно этой модели считается, что выполнение каждого процесса разбивается на последовательность интервалов, во время которых происходят события. Это те же события, которые мы обсуждали в главе 5 в контексте отношения «происходят раньше» по Лампорту. Так, например, событием может быть выполнение инструкции, отправка сообщения и т. п. Каждый интервал в кусочно детерминированной модели считается начинающимся с недетерминированного события, такого как получение сообщения. Однако с этого момента выполнение процесса полностью детерминировано. Концом интервала считается последнее событие из цепочки детерминированных перед новым недетерминированным событием.
В результате интервал можно повторить с известным результатом, то есть абсолютно детерминированным образом, начиная с повторения того же самого недетерминированного события. Соответственно, если мы запишем в журнал все недетерминированные события модели, то получим возможность полностью, детерминированным образом повторить все выполнение процесса.
Если полагать, что журнал сообщений при аварии процесса необходимо восстановить для восстановления глобально непротиворечивого состояния, то для нас важно точно знать время записи сообщений в журнал. В соответствии с подходом, описанным в [10], обнаруживается, что можно легко характеризовать множество схем протоколирования сообщений, сосредоточившись на том, как они работают с процессами-сиротами.
Осиротевший процесс (orphan process) — это процесс, состояние которого противоречит состоянию другого, сначала отказавшего, а затем восстановленного процесса. В качестве примера рассмотрим ситуацию, представленную на рис. 7.18. Процесс Q получает от процессов Р и R сообщения т1 ит2 соответственно, после чего посылает сообщение тЗ процессу R. Однако в отличие от других сообщений сообщение т2 в журнал не записывается. Если происходит отказ процесса Q, для его восстановления задействуются только записанные в журнал сообщения, в нашем примере — т1. Поскольку сообщение т2 не сохранено в журнале, его передача не будет воспроизведена, а значит, передачи сообщения тЗ также не произойдет, что и показано на рисунке.
Отказ от восстановления процесса Q
Рис. 7.18. Неправильное воспроизведение сообщений после восстановления ведет к появлению осиротевших процессов
Таким образом, ситуация после восстановления процесса Q противоречит ситуации до его восстановления. Так, в частности, процесс R хранит сообщение (тЗ), которое было передано перед отказом, но получения и доставки которого при воспроизведении событий, имевших место перед сбоем, не происходит. Понятно, что такого противоречия нужно избегать.
Характеристические схемы протоколирования сообщений
Чтобы характеризовать различные схемы протоколирования сообщений, мы используем подход, описанный в [10]. Предполагается, что каждое сообщение т имеет заголовок, содержащий всю информацию, необходимую для повторной передачи этого сообщения и правильной его обработки. Так, например, каждый заголовок определяет отправителя и получателя, а также последовательный номер для распознавания дубликатов. Кроме того, к заголовку может добавляться входящий номер, чтобы точно определить момент обработки сообщения получившим его приложением.
Сообщение называется устойчивым (stable), если оно не может быть потеряно, например, после записи в устойчивое хранилище. Устойчивые сообщения могут использоваться для восстановления путем воспроизведения их передачи.
Каждое сообщение т отвечает за набор процессов DEP(m), которые зависят от доставки т. В частности, DEP(m) состоит из тех процессов, которым должно прийти это сообщение. Кроме того, если другое сообщение, т', причинно зависящее от доставки т, доставляется процессу Q, то Q также входит в набор DEP(m). Отметим, что причинная зависимость т' от доставки т означает, что оно посылается тем же самым процессом, который ранее получил т или другое сообщение, причинно зависящее от доставки т.
Набор COPY(m) состоит из тех процессов, которые содержат копию т, но (пока) не в своих локальных хранилищах. Когда процесс Q получает сообщение т, он также становится членом COPY(m). Отметим, что COPY(m) состоит из тех процессов, которые могут передавать копию т для воспроизведения передачи. Если все эти процессы отказали, очевидно, что воспроизведение передачи т оказывается невозможным.
Используя эту нотацию, легко определить, что же такое осиротевший процесс. Предположим, что в распределенной системе отказали несколько процессов. Пусть Q — один из сохранившихся процессов. Процесс Q является сиротой, если существует такое сообщение т, что Q оказывается в наборе DEP(m)} в то время как все процессы из COPY(m) отказали. Другими словами, осиротевший процесс появляется в том случае, если он зависит от сообщения т} однако нет никакой возможности повторить передачу этого сообщения.
Чтобы предотвратить появление осиротевших процессов, необходимо гарантировать, что в DEP(m) не будет выживших процессов, если откажут все процессы в COPY(m). Система оказывается в таком состояние, если каждый процесс, являющийся членом набора DEP(m), также является и членом набора COPY(m). Другими словами, всякий процесс, зависящий от доставки сообщения т> должен хранить копию этого сообщения.
Существует два основных подхода, которым мы можем следовать. Первый из них представлен так называемыми протоколами пессимистического протоколирования (pessimistic logging protocols). В этих протоколах предполагается, что для каждого неустойчивого сообщения т имеется хотя бы один зависящий от него процесс. Другими словами, протоколы пессимистического протоколирования предполагают, что любое неустойчивое сообщение т доставляется как минимум в один процесс. Отметим, что как только т доставляется, скажем, в процесс Р, этот процесс становится членом набора COPY(m).
Самое плохое, что может произойти, — процесс Р откажет еще до того, как будет записано сообщение т. В случае пессимистического протоколирования процессу Р после получения сообщения т нельзя рассылать какие-либо сообщения, пока т не будет записано в устойчивое хранилище. Таким образом, пока не будет гарантирована возможность повторной посылки сообщения т, не сможет появиться ни одного процесса, зависящего от доставки т процессу Р. Таким образом, мы полностью предотвращаем появление осиротевших процессов.
В противоположность этому в протоколе оптимистического протоколирования (optimistic logging protocol) реальная работа начинается после отказа процесса. В частности, допустим, что для некоторого сообщения т отказали все процессы из набора COPY(m). Согласно оптимистическому подходу любой осиротевший процесс из DEP(m) откатывается в такое состояние, когда он перестает входить в набор DEP(m).Как было указано в [137], пессимистическое протоколирование значительно проще оптимистического, так что этот способ протоколирования сообщений при практической разработке распределенных систем предпочтительнее.
