Б Бёрнс - Распределенные системы. Паттерны проектирования
- Название:Распределенные системы. Паттерны проектирования
- Автор:
- Жанр:
- Издательство:Питер
- Год:2019
- ISBN:978-5-4461-0950-0
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Б Бёрнс - Распределенные системы. Паттерны проектирования краткое содержание
Распределенные системы. Паттерны проектирования - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
for {
if !l.renew() {
handleLockLost()
}
sleep(ttl/2)
}
Сперва, конечно, необходимо реализовать функцию handle-LockLost() , которая прекращает деятельность, требовавшую блокировки. В рамках оркестратора контейнеров проще всего будет завершить приложение — пусть оркестратор его переза-
пустит. Это безопасно, поскольку другой экземпляр сервиса 166Часть II. Паттерны проектирования обслуживающих систем в то же время перехватит блокировку. Когда перезапущенное приложение возобновит работу, оно станет ожидать освобо-ждения блокировки.
Практикум. Реализация аренды в etcd Вернемся к ранее рассмотренному примеру работы с блокиров-ками, в частности к флагу --ttl= , используемому при создании и возобновлении блокировки. Флаг --ttl= определяет интервал времени, спустя который блокировка удаляется. Поскольку по истечении TTL секунд блокировка исчезает, будем исходить не из того, что начальное значение блокировки unlocked , а из того, что отсутствие блокировки означает, что ресурс свободен. Воспользуемся командой mk вместо set . etcdctl mk отработает успешно только в том случае, если ключа в данный момент не существует.
Следовательно, чтобы установить арендованную блокировку, Алиса выполняет такую команду:
kubectl exec my-etcd-cluster-0000 -- \
sh -c "ETCD_API=3 etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ttl=10 mk my-lock alice"
Таким образом создается арендованная блокировка продолжи-тельностью 10 секунд.
Чтобы возобновить блокировку, надо выполнить следующую команду:
kubectl exec my-etcd-cluster-0000 -- \
sh -c "ETCD_API=3 etcdctl --endpoints=${ETCD_ENDPOINTS} \ set --ttl=10 --swap-with-value alice my-lock alice" Может показаться странным, что Алиса постоянно записывает свое имя в блокировку, но именно так она сможет продлить ее на очередные 10 секунд.
Глава 9. Выбор владельца 167
Если TTL по какой-то причине истечет, возобновления блоки-ровки не произойдет и Алисе придется вновь ее устанавливать. В это время Боб тоже может установить блокировку. Для под-держки владения Бобу также потребуется устанавливать и воз-обновлять блокировку каждые 10 секунд.
Параллельный доступ к данным Даже при использовании описанных ранее механизмов бло-кировки остается возможность того, что в течение небольшого промежутка времени два экземпляра сервиса будут думать, что они оба установили блокировку. Чтобы понять, как это может произойти, представьте, что текущий владелец блокировки ста-новится настолько перегруженным, что перестает работать по нескольку минут подряд. Такое может случиться на машинах, где одновременно исполняется слишком много задач. В этом случае блокировка истечет и ее перехватит другая копия сервиса. Процессор освобождает копию сервиса, которая была заблокиро-вана предыдущим владельцем. Очевидно, вскоре будет вызвана функция handleLockLost() , но в течение небольшого периода времени копия будет считать, что все еще владеет блокировкой. Хотя вероятность такого события невелика, системы необ-ходимо создавать с учетом указанных обстоятельств. Сперва убедимся, что блокировка все еще активна: func (Lock l) isLocked() boolean {
return l.locked && l.lockTime + 0.75 * l.ttl > now() }
Если данная функция выполняется раньше любого кода, требу-ющего блокировок, вероятность одновременного существования двух владельцев значительно снижается, но, что важно, не ис-чезает полностью. Блокировка может истечь между проверкой наличия блокировки и выполнением защищенного кода. Чтобы 168Часть II. Паттерны проектирования обслуживающих систем защититься от таких случаев, система, к которой обращается ко-пия сервиса, должна проверить, что отправивший запрос сервис действительно является владельцем. Для этого в хранилище, кроме состояния блокировки, должно фиксироваться имя хоста копии — владельца блокировки. Так другие участники процесса смогут проверить, что копия, называющая себя владельцем, на самом деле им является.
Схема системы показана на рис. 9.2. Блокировкой владеет shard2 , и, когда рабочему узлу отправляется запрос, тот уточ-няет на сервере блокировок, действительно ли shard2 является текущим владельцем.
Во втором случае shard2 утратил владение блокировкой, но еще не осознал этого и поэтому продолжает отправлять запросы рабочему узлу. На сей раз, получив запрос от shard2 , рабочий узел уточняет его статус на сервере блокировок. Узнав, что он больше не является владельцем, рабочий узел отвергает этот и последующие его запросы.
Еще одна сложность состоит в том, что владение может быть получено, потеряно и затем получено заново. В таком случае за-прос выполнится успешно, хотя должен быть отвергнут. Чтобы понять, как такое возможно, рассмотрим последовательность событий.
1. Шард 1 становится владельцем.
2. Шард 1 отправляет в качестве мастера запрос в момент вре-мени T1 .
3. Сеть зависает, и доставка R1 задерживается.
4. Шард 1 превышает время действия блокировки, и ее пере-хватывает шард 2.
5. Шард 2 становится владельцем и отправляет запрос R2 в мо-мент времени T2 .
Глава 9. Выбор владельца 169


Рис. 9.2. Рабочий узел проверяет, что отправитель запроса действительноявляется текущим владельцем шарда
6. Запрос R2 получен и обработан.
7. Шард 2 отказывает, и владение возвращается к шарду 1.
8. Запрос R1 наконец достигает цели. Шард 1 в данный момент является владельцем, поэтому его запрос принимается к ис-полнению.
Эта последовательность событий кажется коварной, но в ре-альной большой системе такие вещи случаются с пуга ющей частотой. К счастью, ситуация похожа на ранее рассмотренную 170Часть II. Паттерны проектирования обслуживающих систем
проблему, которая была решена с использованием версиониро-вания ресурсов в etcd. Здесь можно поступить так же. Вдобавок фиксации текущего владельца можно с каждым запросом отправлять версию ресурса. R1 из предыдущего примера ста-
новится равен (R1, Version1) . Теперь при получении запроса уточняется не только текущий владелец, но и версия ресурса. Запрос отклоняется при любом несовпадении. Так мы «подла-тали» данный пример.
Часть III
Пат терны
проектирования систем пакетных вычислений В предыдущей части рассматривались паттерны проектирования надежных, постоянно работающих приложений. В этой части описываются паттерны проектирования систем пакетной об-работки. В отличие от постоянно работающих приложений пакетные процессы обычно работают в течение небольшого промежутка времени. Примерами процессов пакетной обработ-ки могут служить следующие процессы: генерация сводки по данным пользовательской телеметрии, анализ данных продаж для ежедневной или еженедельной отчетности. Пакетные процессы характеризуются быстрой обработкой боль-шого объема данных с максимально возможным применением параллелизма. Самый известный паттерн проектирования рас-пределенных систем — MapReduce — уже успел стать отдель-ным самостоятельным направлением. Есть, однако, и другие паттерны, полезные для пакетной обработки. Они рассматри-ваются в последующих главах.
Читать дальшеИнтервал:
Закладка: