Б Бёрнс - Распределенные системы. Паттерны проектирования

Тут можно читать онлайн Б Бёрнс - Распределенные системы. Паттерны проектирования - бесплатно полную версию книги (целиком) без сокращений. Жанр: Прочая околокомпьтерная литература, издательство Питер, год 2019. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.

Б Бёрнс - Распределенные системы. Паттерны проектирования краткое содержание

Распределенные системы. Паттерны проектирования - описание и краткое содержание, автор Б Бёрнс, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru
Современный мир попросту немыслим без использования распределенных систем. Даже у простейшего мобильного приложения есть API, через который оно подключается к облачному хранилищу. Однако проектирование распределенных систем до сих пор остается искусством, а не точной наукой. Необходимость подвести под нее серьезный базис назрела давно, и, если вы хотите обрести уверенность в создании, поддержке и эксплуатации распределенных систем — начните с этой книги!

Распределенные системы. Паттерны проектирования - читать онлайн бесплатно полную версию (весь текст целиком)

Распределенные системы. Паттерны проектирования - читать книгу онлайн бесплатно, автор Б Бёрнс
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Как и с блокировками памяти, первый шаг — установление бло-кировки:

func (Lock l) simpleLock() boolean {

// Сравнение с заменой "1" на "0"

locked, _ = compareAndSwap(l.lockName, "1", "0") return locked

}

Блокировки может еще не существовать, поскольку мы первые, кто ее запрашивает. Учтем и это:

func (Lock l) simpleLock() boolean {

// Сравнение с заменой "1" на "0"

locked, error = compareAndSwap(l.lockName, "1", "0") // Блокировки не существует, пытаемся записать "1" // поверх несуществующего значения

if error != nil {

locked, _ = compareAndSwap(l.lockName, "1", nil) }

return locked

}

Традиционные реализации блокировки останавливают испол-нение на время действия блокировки, поэтому нам еще понадо-бится что-то вроде:

func (Lock l) lock() {

while (!l.simpleLock()) {

sleep(2)

}

}

Проблема данной реализации, несмотря на ее простоту, состоит в том, что после снятия блокировки придется ждать минимум 1 секунду, чтобы установить ее снова. К счастью, многие храни-лища «ключ — значение» позволяют следить за изменениями, Глава 9. Выбор владельца 161

не прибегая к опросу сервера, поэтому реализация может вы-глядеть таким образом:

func (Lock l) lock() {

while (!l.simpleLock()) {

waitForChanges(l.lockName)

}

}

Реализация снятия блокировки будет выглядеть так: func (Lock l) unlock() {

compareAndSwap(l.lockName, "0", "1")

}

Может показаться, что работа сделана, но помните, что речь идет о распределенной системе. Установивший блокировку процесс может отказать до ее снятия, а значит, снять ее будет уже некому. В такой ситуации система зависнет. Для разрешения данной про-блемы воспользуемся возможностью назначить ключу срок дей-ствия (TTL). Изменим функцию simpleLock так, чтобы она всегда записывала TTL. Таким образом, если в течение данного времени процесс не снимет блокировку, она будет снята автоматически. func (Lock l) simpleLock() boolean {

// Сравнение с заменой "1" на "0"

locked, error = compareAndSwap(l.lockName, "1", "0", l.ttl) // Блокировки не существует, пытаемся записать "1" // поверх несуществующего значения

if error != nil {

locked, _ = compareAndSwap(l.lockName, "1", nil, l.ttl) }

return locked

}

162Часть II Паттерны проектирования обслуживающих систем Сторожевой таймер - фото 58

162Часть II. Паттерны проектирования обслуживающих систем Сторожевой таймер аварийно прекратит исполнение програм-мы, если вы не сняли блокировку в период TTL. Добавив к блокировкам TTL, мы привнесли ошибку в функцию разблокировки. Рассмотрим следующую ситуацию.

1. Процесс 1 устанавливает блокировку с TTL, равным t .

2. В силу некоторых причин процесс работает очень медленно и не справляется с задачей за время t .

3. Срок действия блокировки истекает.

4. Процесс 2 ставит блокировку, поскольку процесс 1 ее потерял в связи с истечением TTL.

5. Процесс 1 заканчивает работу и вызывает функцию разбло-кировки .

6. Процесс 3 ставит блокировку.

На данный момент процесс 1 считает, что снял установленную им блокировку. Он не знает, что потерял блокировку из-за ис-течения TTL, и фактически снял блокировку, установленную процессом 2. Тут появляется процесс 3 и ставит блокировку. Теперь процессы 2 и 3 оба считают, что поставили блокировку, и тут-то и начинается потеха.

К счастью, хранилища «ключ — значение» поддерживают верси-онность ресурсов . Версия ресурса меняется при каждой записи. Функция блокировки может записывать версию ресурса и рас-ширять операцию compareAndSwap проверкой на совпадение не только значения, но и версии ресурса. Функция блокировки будет выглядеть следующим образом:

func (Lock l) simpleLock() boolean {

// Сравнение с заменой "1" на "0"

locked, l.version, error = compareAndSwap(l.lockName, "1", "0", l.ttl)

Глава 9. Выбор владельца 163

// Блокировки не существует, пытаемся записать "1" // поверх несуществующего значения

if error != null {

locked, l.version, _ = compareAndSwap(l.lockName, "1", null, l.ttl)

}

return locked

}

Функция разблокировки будет выглядеть так: func (Lock l) unlock() {

compareAndSwap(l.lockName, "0", "1", l.version) }

Таким образом, блокировка снимается, только если TTL не истек.

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

Начнем с создания блокировки my-lock :

kubectl exec my-etcd-cluster-0000 -- sh -c \ "ETCD_API=3 etcdctl --endpoints=${ETCD_ENDPOINTS} set my-lock unlocked"

Это создаст в etcd блокировку my-lock с начальным значением unlocked .

164Часть II. Паттерны проектирования обслуживающих систем Допустим, Алиса и Боб хотят установить блокировку my-lock . Они пытаются записать свои имена в блокировку, исходя из того, что она изначально снята.

Алиса выполняет команду:

kubectl exec my-etcd-cluster-0000 -- sh -c \ "ETCD_API=3 etcdctl --endpoints=${ETCD_ENDPOINTS} \ set --swap-with-value unlocked my-lock alice" тем самым ставя блокировку. Теперь блокировку пытается уста-новить Боб:

kubectl exec my-etcd-cluster-0000 -- sh -c \ "ETCD_API=3 etcdctl --endpoints=${ETCD_ENDPOINTS} \ set --swap-with-value unlocked my-lock bob" Error: 101: Compare failed ([unlocked != alice]) [6] Как видим, попытка Боба установить блокировку оказалась не-удачной, так как блокировка была поставлена Алисой. Чтобы снять блокировку, Алиса записывает значение unlocked вместо alice :

kubectl exec my-etcd-cluster-0000 -- sh -c \ "ETCD_API=3 etcdctl --endpoints=${ETCD_ENDPOINTS} \ set --swap-with-value alice my-lock unlocked" Реализация владения

Блокировки хороши для установления временного владения некоторым важным компонентом. Иногда может понадобиться установить владение ресурсом на все время работы компонента. Возьмем, к примеру, кластер Kubernetes с высокой доступ-ностью. Допустим, в нем есть несколько экземпляров плани-ровщика, но только один из них активно принимает решения. Кроме того, как только процесс становится активным планиров-щиком, он остается таковым до момента отказа. Глава 9. Выбор владельца 165

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

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

Расширим предыдущую версию функции блокировки возмож-ностью возобновления ее владельцем:

func (Lock l) renew() boolean {

locked, _ = compareAndSwap(l.lockName, "1", "1", l.version, ttl) return locked

}

Для того чтобы поддерживать блокировку в течение неопре-деленного промежутка времени, придется выполнять эти дей-ствия в отдельном потоке. Обратите внимание, что блокировка возобновляется каждые TTL / 2 секунды, чтобы снизить риск ее случайного истечения в силу особенностей подсчета вре-мени:

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Б Бёрнс читать все книги автора по порядку

Б Бёрнс - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Распределенные системы. Паттерны проектирования отзывы


Отзывы читателей о книге Распределенные системы. Паттерны проектирования, автор: Б Бёрнс. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x