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

Лучшие дистрибутивы Linux

Если говорить о том, какие лучшие дистрибутивы Linux мы знаем, то этот список может быть…

6 дней ago

Лучшие браузеры для Ubuntu

Хотя Ubuntu и поставляется со встроенным обозревателем Firefox многие пользователи считают что это не самая…

6 дней ago

Установка Remmina Ubuntu 16.04 или 16.10

Что такое Remmina? Remmina — это совершенно бесплатный и свободный клиент так называемого удаленного рабочего…

6 дней ago

Плюсы Ubuntu

Как мы знаем, Ubuntu это самая популярная сборка из систем на базе ядра Linux. У…

6 дней ago

Выбираем ноутбук для Linux

Выбор ноутбука для каждого пользователя это довольно кропотливый процесс. Люди стараются подобрать ноутбук который будет…

6 дней ago

Установка Linux рядом с Windows 10

Если вы решили ознакомиться с операционной системой Linux более детально и задались вопросом как установить…

6 дней ago