From 51e20a36ff62c196d01e1529edb4818ba3f6d224 Mon Sep 17 00:00:00 2001 From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com> Date: Wed, 16 Mar 2022 16:34:10 +0300 Subject: [PATCH] doc: describe bootstrapping process Close https://gitlab.com/picodata/picodata/picodata/-/issues/27 --- docs/clustering.md | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 docs/clustering.md diff --git a/docs/clustering.md b/docs/clustering.md new file mode 100644 index 0000000000..6de6bb6c83 --- /dev/null +++ b/docs/clustering.md @@ -0,0 +1,51 @@ +# Создание клаÑтера. Ðлгоритм и детали реализации. + +## fn main() + +``` +// Каждый инÑÑ‚Ð°Ð½Ñ Ð¾Ð±Ð»Ð°Ð´Ð°ÐµÑ‚ на Ñтарте Ñледующей информацией: +// --advertise-uri (по-дефолту <hostname>:<listen_port>) +// --replicaset-id (опционально) +// --instance-id (опционально) +// --peers +``` + +1. ЕÑли у инÑтанÑа уже еÑÑ‚ÑŒ Ñнапшоты, можно Ñразу вызывать box.cfg() и Ñтартовать рафт ноду. +1. ИнÑÑ‚Ð°Ð½Ñ Ð¸Ð´Ñ‘Ñ‚ Ñобирать транзитивное замыкание в дочернем процеÑÑе. +1. Дочерний процеÑÑ Ð¿Ð¾Ð´Ð½Ð¸Ð¼Ð°ÐµÑ‚ listen порт и выÑовывает хранимку raft_discover. +1. Дочерний процеÑÑ Ð¿Ñ€Ð¾Ð±ÐµÐ³Ð°ÐµÑ‚ÑÑ Ð¿Ð¾ вÑем --peer, обмениваетÑÑ Ñ Ð½Ð¸Ð¼Ð¸ Ñтими ÑпиÑками, а заодно получает айдишники (instance_id, replicaset_id) и advertise_address. +1. Возможно ответом будет "нечего тут Ñобирать, у Ð½Ð°Ñ ÑƒÐ¶Ðµ еÑÑ‚ÑŒ лидер такой-то", тогда можно пойти Ñразу на него и goto *join*. +1. Как только ото вÑех пиров (извеÑтных изначально, и обнаруженных в процеÑÑе) получен утвердительный ответ, транзитивное замыкание ÑчитаетÑÑ Ñобраным. +1. Транзитивное замыкание гарантирует нам одинаковоÑÑ‚ÑŒ Ñобранной информации на вÑех инÑтанÑах, в Ñтом Ñборе учаÑтвовавших. +1. Теперь выбираем кто будет главным. Ð”Ð»Ñ Ñтого ÑравниваютÑÑ Ð»ÐµÐºÑикографичеÑки вÑе instance_id. Ðтот инÑÑ‚Ð°Ð½Ñ Ð¿Ñ€Ð¸Ñваивает Ñебе raft_id = 1, генерит Ñнапшот рафт ноды Ñ Ð¾Ð´Ð½Ð¸Ð¼ Ñобой любимым, перÑиÑтит его, и начинает тикать нодой. БутÑтрап первого инÑтанÑа закончен. +1. ОÑтальные инÑтанÑÑ‹ goto *join* + +### join + +1. ЕÑли Ð½Ð°Ñ Ð¿Ð¾Ñлали делать джойн, значит Ð°Ð´Ñ€ÐµÑ Ð»Ð¸Ð´ÐµÑ€Ð° уже извеÑтен. Либо нам его Ñказали в ответе на raft_discover, либо мы его Ñами вычиÑлили из транзитивного замыканиÑ. +1. ИнÑÑ‚Ð°Ð½Ñ Ð¸Ð´ÐµÑ‚ на лидера и говорит: "приджойнь Ð¼ÐµÐ½Ñ Ð² клаÑтер, пожалуйÑта". Попутно Ñообщает Ñвои айдишники и адвертайз урл. +1. И лидер приджойнивает. И любезно Ñообщает в ответ raft_id нашей ноды. Рещё правильный instance_id и replicaset_id, и урлы братьев по репликации. +1. ÐžÐ±Ð»Ð°Ð´Ð°Ñ Ñтой информацией, инÑÑ‚Ð°Ð½Ñ Ñтартует box.cfg Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸ репликации. +1. Потом Ñоздает ÑервиÑные рафтовые ÑпейÑÑ‹ и Ñтратует рафт ноду. +1. И вот теперь то бутÑтрап окончен. + +## fn raft_discover() + +ЕÑли транзитивное замыкание еще не Ñобрано, Ñервер на Ð·Ð°Ð¿Ñ€Ð¾Ñ raft_join приÑылает Ñвой адвертайз, айдишники, и вÑе пиры. + +ЕÑли нода давно забутÑтраплена, Ñервер отвечает "у Ð½Ð°Ñ ÑƒÐ¶Ðµ еÑÑ‚ÑŒ лидер", доÑтает его raft_id из ÑтатуÑа рафта, а по raft_id - его адвертайз из ÑпейÑа Ñ Ñ€Ð°Ñ„Ñ‚ топологией. + +Ðа Ð·Ð°Ð¿Ñ€Ð¾Ñ raft_discover еÑÑ‚ÑŒ и третий вариант ответа, когда транзитивное замыкание уже Ñобрано, но Ñама рафт нода еще не проинициализирована. Ð’ Ñтом Ñлучае Ñерверу правильнее отдавать значение advertise_uri первого инÑтанÑа, вычиÑленное из транзитивного замыканиÑ. Именно оно прилетит из рафт Ñнапшота как только нода подниметÑÑ. + +## fn raft_join() + +1. Во-первых, еÑли Ñто на Ñамом деле не лидер, надо вернуть ошибку. +1. Из аргументов извеÑтны айдишники и адвертайз Ð°Ð´Ñ€ÐµÑ ÐºÐ»Ð¸ÐµÐ½Ñ‚Ð°. +1. Ð’ ответ надо дать raft_id. +1. Ещё в ответе должны быть replicaset_uuid (правильно Ñгенеренный, либо выбранный Ñреди ÑущеÑтвующих), instance_uuid (ну так, за компанию), урлы других инÑтанÑов из его репликаÑета, чтобы он Ñразу мог забутÑтрапить репликацию. Ð’ÑÑ‘ Ñто раздаётÑÑ Ð¸Ð· таблички Ñ Ñ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð³Ð¸ÐµÐ¹, но Ñначала её надо туда положить, причем клаÑÑ‚ÑŒ надо ÑредÑтвами рафта. +1. Будущий raft_id выбираетÑÑ ÐºÐ°Ðº box.space.raft_topology:max() + 1 +1. Ðлгоритм выбора replciaset_uuid и instance_uuid мы пока не обÑуждаем, пуÑÑ‚ÑŒ пока Ñто будет чиÑтый рандом. +1. Коммитить в рафт изменение топологии надо пачкой - в propose_conf_change надо упихать вÑÑŽ инфу об инÑтанÑе, иначе инфа может разъехатьÑÑ. +1. ЕÑÑ‚ÑŒ и ещё одна проблема. Тк комит в рафт - штука не быÑтраÑ, другие конкурентные запроÑÑ‹ (от других инÑтанÑов) вÑÑ‘ Ñто Ð²Ñ€ÐµÐ¼Ñ Ð±ÑƒÐ´ÑƒÑ‚ получать отлуп типа "conf change already in progress". Ðто может Ñильно замедлить Ñборку больших клаÑтеров. +1. Чтобы уÑкорить процеÑÑ Ð´Ð¶Ð¾Ð¹Ð½Ð°, запроÑÑ‹ на джойн должны вÑтавать в очередь, и обрабатыватьÑÑ Ñ‚Ñ€Ð°Ð½ÑˆÐ°Ð¼Ð¸. +1. Ðи один клиент не уйдёт обиженным, получит Ñвой raft_id, и Ñможет запуÑтитьÑÑ -- GitLab