Categories: Go

go-leader-election/

При разработке веб-приложений и всяких там бэкендов иногда возникает необходимость запустить кусок кода ровно на одном сервере, а не на всех. Типичный случай — это когда вам нужно запустить фоновую миграцию схемы базы данных. Однако бывают и другие сценарии, некоторые из которых упоминались в заметке Пример использования акторов-одиночек в Akka . Задача выбора одного «главного» сервера из N довольно просто решается при помощи подхода под названием leader lease, речь о котором и пойдет далее.

Для реализации подхода нужно иметь какое-нибудь key-value хранилище, поддерживающее compare and swap. Кроме того, leader lease предполагает, что время на серверах относительно синхронизировано, например, при помощи NTP. В качестве KV-хранилища я решил использовать Consul , но с тем же успехом можно использовать etcd, или любую NoSQL базу данных, поддерживающую CAS. Помимо прочих, к таким базам данных относятся Cassandra и Couchbase .

Идея проста до безобразия. В KV-хранилище заводится ключ, по которому пишется что-то вроде «нода X является лидером до времени Y», где Y вычисляется как текущее время + какой-то интервал T. Будучи лидером, нода X раз в T/2 или T/3 единиц времени обновляет запись, тем самым продлевая свою роль лидера. Если нода падает или не может достучаться до KV-хранилища, спустя время T ее место займет нода, которая первая обнаружит, что роль лидера освободилась. CAS нужен для предотвращения состояния гонки, если две ноды одновременно пытаются стать лидером.

Библиотека на языке Go, реализующая соответствующий подход, заняла у меня около 270 строк. Код библиотеки вы можете найти на GitHub . Соответственно, реализация на каком-нибудь Python будет раза в два короче.

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

package main

import (
«flag»
«github.com/afiskon/go-elector»
«log»
«time»
)

func main () {
selfIdPtr := flag . String ( «uniqid» , «» , «Unique id of this node» )
flag . Parse ()

consulUrl := «http://localhost:8500/v1/kv/test/leader_election»
electorInst , err := elector . Create ( * selfIdPtr , consulUrl ,
15 * time . Second )
if err != nil {
log . Panicf ( «Unable to create the elector: %s» , err . Error ())
}

electorInst . RegisterCallback ( func ( oldLeaderId string ,
newLeaderId string ) {
log . Printf ( «Leader changed: ‘%s’ -> ‘%s’ n » ,
oldLeaderId , newLeaderId )
})

for {
leaderId := electorInst . GetCurrentLeader ()
log . Printf ( «Current leader: ‘%s’ n » , leaderId )
time . Sleep ( 5 * time . Second )
}
}

Так как я редко пишу на Go, при написании библиотеки мне крайне помогли советы Алексея Палажченко , за что я ему весьма благодарен. Помимо прочего, Алексей совершенно справедливо заметил, что использование колбэка в публичном API в мире Go является редким явлением, и более идиоматичным подходом было бы использовать каналы. Однако я уже несколько недель не возвращался к этому коду, поэтому мне лень что-то в нем править. И, сказать по правде, лично мне как-то все равно, что использовать — канал или колбэк.

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

admin

Share
Published by
admin
Tags: Go

Recent Posts

Консоль удаленного рабочего стола(rdp console)

Клиент удаленного рабочего стола (rdp) предоставляет нам возможность войти на сервер терминалов через консоль. Что…

1 месяц ago

Настройка сети в VMware Workstation

В VMware Workstation есть несколько способов настройки сети гостевой машины: 1) Bridged networking 2) Network…

1 месяц ago

Логи брандмауэра Windows

Встроенный брандмауэр Windows может не только остановить нежелательный трафик на вашем пороге, но и может…

1 месяц ago

Правильный способ отключения IPv6

Вопреки распространенному мнению, отключить IPv6 в Windows Vista и Server 2008 это не просто снять…

1 месяц ago

Ключи реестра Windows, отвечающие за параметры экранной заставки

Параметры экранной заставки для текущего пользователя можно править из системного реестра, для чего: Запустите редактор…

1 месяц ago

Как управлять журналами событий из командной строки

В этой статье расскажу про возможность просмотра журналов событий из командной строки. Эти возможности можно…

1 месяц ago