diff --git a/docs/clustering.md b/docs/clustering.md index c618ec265b39e8941494f1f3f954ebdf274d4533..04d6675951c157e6548f3de9a50a0257a78533e3 100644 --- a/docs/clustering.md +++ b/docs/clustering.md @@ -1,6 +1,7 @@ -# Ð˜Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ ÐºÐ»Ð°Ñтера. Ð’Ñ‹Ñокоуровнево. +# ÐžÐ±Ñ‰Ð°Ñ Ñхема инициализации клаÑтера +Данный документ опиÑывает выÑокоуровневый процеÑÑ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ клаÑтера Picodata на оÑнове неÑкольких отдельно запущенных ÑкземплÑров Picodata (инÑтанÑов). -Ðдмин запуÑкает пачку инÑтанÑов: +ÐдминиÑтратор запуÑкает неÑколько инÑтанÑов, Ð¿ÐµÑ€ÐµÐ´Ð°Ð²Ð°Ñ Ð² качеÑтве аргументов необходимые параметры: ```sh picodata run --instance-id i1 --listen i1 --peer i1,i2 @@ -10,85 +11,70 @@ picodata run --instance-id i3 --listen i3 --peer i1,i2 picodata run --instance-id iN --listen iN --peer i1,i2 ``` -Сколько бы инÑтанÑов ни было, в опции `--peer` у каждого Ñледует указать один и тот же набор из неÑкольких "первых". Ðа них возлагаетÑÑ Ð¾ÑÐ¾Ð±Ð°Ñ Ð¼Ð¸ÑÑÐ¸Ñ Ð¿Ð¾ инициализации клаÑтера (диÑкавери). +ÐезавиÑимо от количеÑтва запуÑкаемых инÑтанÑов, в опции `--peer` у каждого из них Ñледует указать один и тот же набор из неÑкольких инÑтанÑов - обычно первых двух. Именно на их оÑнове будет произведена Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ ÐºÐ»Ð°Ñтера и поиÑк вÑех работающих инÑтанÑов Ð´Ð»Ñ Ð¸Ñ… Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½Ð¸Ñ Ð² ÑоÑтав клаÑтера (discovery). -Подробный алгоритм диÑкавери в Ñтой иÑтории роли не играет, но опиÑан в ÑоÑеднем файле `discovery.md`. Пока об алгоритме диÑкавери доÑтаточно знать лишь то, что, ÑÐ»ÐµÐ´ÑƒÑ Ñтому алгоритму, один и только один из Ñтих пиров возьмет на ÑÐµÐ±Ñ ÑмелоÑÑ‚ÑŒ Ñоздать рафт группу. Иначе рафт групп получилоÑÑŒ бы неколько. +ПодробноÑти алгоритма discovery приведены в отдельном [документе](discover.md). Ð’ контекÑте Ñборки клаÑтера важно лишь понимать, что Ñтот алгоритм позволÑет лишь одному инÑтанÑу/peer'у Ñоздать Raft-группу, Ñ‚.е. Ñтать инÑтанÑом Ñ raft_id=1. ЕÑли таких инÑтанÑов будет неÑколько, то и Raft-групп, а Ñледовательно и клаÑтеров Picodata получитÑÑ Ð½ÐµÑколько. -Ð’ÑÑ‘ управление топологией рафт группы по Ñути возлагаетÑÑ Ð½Ð° Ñам алгоритм рафт. И на его конкретную имплементацию - крейт `raft-rs`. +Топологией Raft-группы управлÑет алгоритм Raft, реализованный в виде крейта `raft-rs`. -# Ð˜Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ ÐºÐ»Ð°Ñтера. Подробнее. +# Ðтапы инициализации клаÑтера +Ðа Ñхеме ниже показаны Ñтапы жизненного цикла инÑтанÑа в контекÑте его приÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ ÐºÐ¾ клаÑтеру Picodata. -[https://yuml.me/edit/15c7c2d0] + - - -Ðта уÑÑ‚Ñ€Ð°ÑˆÐ°ÑŽÑ‰Ð°Ñ Ñхема макÑимально точно изображает логику кода в `main.rs`. Ðиже объÑÑнÑетÑÑ Ð¿Ð¾Ð´Ñ€Ð¾Ð±Ð½ÐµÐµ, что проиÑходит на каждом Ñтапе. +КраÑным показан родительÑкий процеÑÑ, который запущен на вÑём протÑжении жизненного цикла инÑтанÑа. Ð’ÑÑ Ð»Ð¾Ð³Ð¸ÐºÐ° поиÑка лидера Raft-группы и приÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ðº ней проиÑходит в дочернем процеÑÑе (голубой цвет). При ÑброÑе ÑоÑтоÑÐ½Ð¸Ñ Ð¸Ð½ÑтанÑа и rebootstrap проиÑходит Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð°Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ„Ð¾Ñ€ÐºÐ° (Ñиреневый цвет). + +Ð”Ð°Ð½Ð½Ð°Ñ Ñхема наиболее полно отражает логику кода в файле `main.rs`. Ðиже опиÑаны детали Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ñтапа и ÑоответÑтвующей программной функции. ### fn main() -Сначала процеÑÑ Ð¿Ð¸ÐºÐ¾Ð´Ð°Ñ‚Ñ‹ форкаетÑÑ. Родитель (supervisor) ждет по механизму IPC ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚ дочернего процеÑÑа и при необходимоÑти реÑтартит его. Опционально дочерний процеÑÑ Ð¼Ð¾Ð¶ÐµÑ‚ попроÑить Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð´Ñ€Ð¾Ð¿Ð½ÑƒÑ‚ÑŒ вÑе файлы БД. Ðто будет нужно Ð´Ð»Ñ Ñ‚.н. ребутÑтрапа. +Ðа Ñтом Ñтапе проиÑходит ветвление (форк) процеÑÑа `picodata`. РодительÑкий процеÑÑ (supervisor) ожидает от дочернего процеÑÑа ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ механизму IPC и при необходимоÑти перезапуÑкает дочерний процеÑÑ. При необходимоÑти дочерний процеÑÑ Ð¼Ð¾Ð¶ÐµÑ‚ попроÑить Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ вÑе файлы БД, Ñ‚.е. вызвать функцию `drop_db`. Ðто может понадобитьÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð½Ð¾Ð¹ инициализации клаÑтера когда, например, у инÑтанÑа изначально имеетÑÑ ÑƒÑтаревший или некорректный `replicaset_id`. ### fn start_discover() -Дочерний процеÑÑ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÐµÑ‚ Ñвоё ÑущеÑтвование Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð° `box.cfg()` и вызова функции `start_discover`. -ЕÑли вдруг из ÑпейÑов обнаруживаетÑÑ, что нода уже была забутÑтрапленна, то никакой алгоритм диÑкавери делаь и не надо, и инÑÑ‚Ð°Ð½Ñ Ñразу переходит на Ñтап `postjoin()`. Ð’ противном Ñлучае, еÑли Ñто первый запуÑк, из алгоритма диÑкавери мы получаем флаг `its_me` и Ð°Ð´Ñ€ÐµÑ Ð»Ð¸Ð´ÐµÑ€Ð°. Сам лидер (единÑтвенный `its_me == true`) выполнÑет `start_boot`, поÑле чего выполнÑет `postjoin()`. ОÑтальные инÑтанÑÑ‹ (не только проигравшие пиры, но и вÑе будущие) ребутÑтрапÑÑ‚ÑÑ Ð¸ идут делать `start_join`. +Дочерний процеÑÑ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÐµÑ‚ Ñвоё ÑущеÑтвование Ñ Ð·Ð°Ð¿ÑƒÑка Ð¼Ð¾Ð´ÑƒÐ»Ñ `box.cfg()` и вызова функции `start_discover`. Возможно, что при Ñтом из поÑтоÑнно хранимых данных будет ÑÑно, что bootstrap данного инÑтанÑа уже был произведён ранее и что Raft уже знает о вхождении Ñтого инÑтанÑа в клаÑтер - в таком Ñлучае никакого discovery не будет, инÑÑ‚Ð°Ð½Ñ Ñразу перейдёт к Ñтапу `postjoin()`. Однако, еÑли Ñто новый инÑтанÑ, то алгоритм discovery выдаÑÑ‚ ему флаг `i_am_bootstrap_leader == false` и Ñообщит Ð°Ð´Ñ€ÐµÑ Ð»Ð¸Ð´ÐµÑ€Ð° Raft-группы. Сам лидер (единÑтвенный Ñ `i_am_bootstrap_leader == true`) выполнÑет функцию `start_boot` и затем переходит к функции `postjoin()`. ОÑтальные инÑтанÑÑ‹ (уже запущенные и вÑе будущие) ÑбраÑывают Ñвоё ÑоÑтоÑние (Ñтап rebootstrap) и переходÑÑ‚ к функции `start_join`. ### fn start_boot() -Ð’ функции `start_boot` проиÑходит Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ€Ð°Ñ„Ñ‚ группы - лидер генерирует и перÑиÑтит первую запиÑÑŒ в журнале. Ð’ Ñтой запиÑи будет лежать Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð¾Ð´Ñ‹, что позволит вÑем оÑтальным инÑтанÑам инициализироватьÑÑ Ñ Ð¿ÑƒÑтой рафт группой. +Ð’ функции `start_boot` проиÑходит Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Raft-группы - лидер генерирует и ÑохранÑет в БД первую запиÑÑŒ в журнале. Ð’ Ñтой запиÑи будет лежать Ð¾Ð¿ÐµÑ€Ð°Ñ†Ð¸Ñ Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Raft-узла; вÑе оÑтальные инÑтанÑÑ‹ будут инициализированы Ñ Ð¿ÑƒÑтой Raft-группой. -Саму рафт ноду инÑÑ‚Ð°Ð½Ñ Ð½Ð° Ñтом Ñтапе не Ñоздаёт. Ðто произойдет позже, на Ñтадии `postjoin()`. +Сам Raft-узел на данном Ñтапе ещё не ÑоздаётÑÑ. Ðто произойдет позже, на Ñтадии `postjoin()`. ### fn start_join() -Вызову `start_join` вÑегда предшеÑтвует ребутÑтрап (удаление БД и реÑтарт процеÑÑа), поÑтому ни бокÑа, ни ÑпейÑов на Ñтом Ñтапе Ñнова нет. Сама Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´Ð¾Ñтаточно примитивнаÑ. +Вызову функции `start_join` вÑегда предшеÑтвует rebootstrap (удаление БД и перезапуÑк процеÑÑа), поÑтому на данном Ñтапе в БД нет ни Ð¼Ð¾Ð´ÑƒÐ»Ñ box, ни проÑтранÑтва хранениÑ. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ start_join() имеет проÑтое уÑтройÑтво: -ИнÑÑ‚Ð°Ð½Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»Ñет Ð·Ð°Ð¿Ñ€Ð¾Ñ `join` на лидера (лидер извеÑтен поÑле диÑкавери). Лидер шушукаетÑÑ Ñ Ð³Ñ€ÑƒÐ¿Ð¿Ð¾Ð¹, и еÑли вÑÑ‘ хорошо, в ответ приÑылает необходимую информацию: -- `raft_id` и `raft_group` - Ð´Ð»Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ рафт ноды; -- `insance_uuid`, `replicaset_uuid`, `replication`, `read_only` - Ð´Ð»Ñ `box.cfg`. +ИнÑтанÑ-клиент отправлÑет Ð·Ð°Ð¿Ñ€Ð¾Ñ `join` лидеру Raft-группы (он извеÑтен поÑле discovery). ПоÑле доÑÑ‚Ð¸Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½ÑенÑуÑа в Raft-группе лидер приÑылает в ответе необходимую информацию: +- Идентификатор `raft_id` и данные таблицы `raft_group` - Ð´Ð»Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ Raft-узла; +- Идентификаторы `instance_uuid`, `replicaset_uuid` и параметры `replication`, `read_only` Ð´Ð»Ñ `box.cfg`. -Получив вÑе наÑтройки, инÑÑ‚Ð°Ð½Ñ Ð·Ð°Ñовывает их в `box.cfg()`, и поÑле Ñтого перÑиÑтит `raft_group` Ñ Ð°ÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ адреÑами других инÑтанÑов. Без Ñтого инÑÑ‚Ð°Ð½Ñ Ð½Ðµ Ñможет отвечать на рафт ÑообщениÑ. Рчтобы запиÑи в `raft_group` не были потёрты менее актуальными из рафт лога, ÐºÐ°Ð¶Ð´Ð°Ñ Ð¼Ð°Ñ€ÐºÐ¸Ñ€ÑƒÐµÑ‚ÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸ÐµÐ¼ `commit_index`. +Получив вÑе наÑтройки, инÑÑ‚Ð°Ð½Ñ Ð¸Ñпользует их в `box.cfg()`, и затем Ñоздает в БД группу `raft_group` Ñ Ð°ÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ адреÑами других инÑтанÑов. Без Ñтого инÑÑ‚Ð°Ð½Ñ Ð½Ðµ Ñможет отвечать на ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚ Raft. Ð”Ð»Ñ Ñ‚Ð¾Ð³Ð¾ чтобы запиÑи в `raft_group` не были затем заменены на менее актуальные из журнала Raft, ÐºÐ°Ð¶Ð´Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑŒ маркируетÑÑ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸ÐµÐ¼ `commit_index`. -ПоÑле вÑех Ñтих манипулÑций, также идёт `postjoin()`. +По завершении Ñтих манипулÑций инÑÑ‚Ð°Ð½Ñ Ñ‚Ð°ÐºÐ¶Ðµ переходит к Ñтапу `postjoin()`. ### fn postjoin() -Логика `postjoin()` Ð´Ð»Ñ Ð²Ñех инÑтанÑов одинакова. К Ñтому моменту на инÑтанÑе уже инициализированы правильные ÑпейÑÑ‹ и возможно даже ÑущеÑтвует предыÑÑ‚Ð¾Ñ€Ð¸Ñ Ñ€Ð°Ñ„Ñ‚ журнала. ИнÑÑ‚Ð°Ð½Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð¸Ñ€ÑƒÐµÑ‚ рафт ноду и получает read barrier (Ñто позволÑет убедитьÑÑ, что рафт лог актуален). Из рафт лога ÑтановÑÑ‚ÑÑ Ð¸Ð·Ð²ÐµÑтны параметры репликации, и инÑÑ‚Ð°Ð½Ñ ÑинхронизируетÑÑ Ñ Ñ€ÐµÐ¿Ð»Ð¸ÐºÐ°Ð¼Ð¸. +Логика функции `postjoin()` одинакова Ð´Ð»Ñ Ð²Ñех инÑтанÑов. К Ñтому моменту Ð´Ð»Ñ Ð¸Ð½ÑтанÑа уже инициализированы корректные проÑтранÑтва Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð² БД и могут быть накоплены запиÑи в журнале Raft. ИнÑÑ‚Ð°Ð½Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð¸Ñ€ÑƒÐµÑ‚ узел Raft и проверÑет, что данные Ñинхронизированы (`read barrier` получен) и журнал Raft актуален. Из журнала ÑтановÑÑ‚ÑÑ Ð¸Ð·Ð²ÐµÑтны параметры репликации, и инÑÑ‚Ð°Ð½Ñ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÐµÑ‚ Ñинхронизацию данных уровне репликационных групп Tarantool. -ОÑтаётÑÑ Ð¾Ð´Ð¸Ð½ маленький штришок - проверить Ñвой ÑÑ‚Ð°Ñ‚ÑƒÑ voter / learner, при необходимоÑти кинуть Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° промоут до воутера (вÑÑ‘ тот же `join`, лидер извеÑтен поÑле Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ read barrier), и дождатьÑÑ ÐµÐ³Ð¾ применениÑ. +Ðа данном Ñтапе инÑтанÑу оÑтаётÑÑ Ð¿Ñ€Ð¾Ð²ÐµÑ€Ð¸Ñ‚ÑŒ Ñвой ÑÑ‚Ð°Ñ‚ÑƒÑ voter / learner, при необходимоÑти запроÑить повышение до ÑтатуÑа voter (повторение функции `join`, лидер извеÑтен поÑле Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ `read barrier`), и дождатьÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑтатуÑа. -Ð’ÑÑ‘, нода готова к иÑпользованию. +Теперь узел Raft готов к иÑпользованию. # Обработка запроÑов ### extern "C" fn join() -Ð›ÑŒÐ²Ð¸Ð½Ð°Ñ Ð´Ð¾Ð»Ñ Ð²Ñей логики по управлению топологией кроетÑÑ Ð² хранимке `join`. Её назначение доÑтаточно проÑтое - закоммитить ConfChange, но за Ñтими Ñловами кроетÑÑ Ð½ÐµÑколько нюанÑов. - -Во-первых, еÑли Ñтот `instance_id` уже еÑÑ‚ÑŒ в группе (закоммиченый) и Ð½Ð¸ÐºÐ°ÐºÐ°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ðµ обновилаÑÑŒ (например флаг voter / learner), то можно Ñразу отвечать клиенту не задейÑÑ‚Ð²ÑƒÑ Ñ€Ð°Ñ„Ñ‚. - -ЕÑли Ñто первое поÑвление инÑтанÑа в группе, то он вÑегда добавлÑетÑÑ Ð² роли learner. Ð’ роли voter его добавлÑÑ‚ÑŒ нельзÑ, иначе поÑвитÑÑ Ð¿Ñ€Ð¾Ð±Ð»ÐµÐ¼Ð° курицы и Ñйца. Чтобы ConfChange Ñ Ð²Ð¾ÑƒÑ‚ÐµÑ€Ð¾Ð¼ закоммитилÑÑ, Ñтот voter должен учаÑтвовать в кворуме. Рон не может - он ещё ждёт ответа на Ð·Ð°Ð¿Ñ€Ð¾Ñ `join`. - -Во-вторых, рафт не позволÑет делать ConfChange, еÑли предыдущий ConfChange не был закоммичен. ПоÑтому запроÑÑ‹ `join` на лидере придётÑÑ Ð¾Ð±Ñ€Ð°Ð±Ð°Ñ‚Ñ‹Ð²Ð°Ñ‚ÑŒ батчами в отдельном файбере. Пачку запроÑов накопили - обработали - каждому поÑлали индивидуальный ответ. - -Ð’-третьих, прежде чем отвечать клиенту, надо дождатьÑÑ, пока ConfChange закоммититÑÑ. Или, более формально, пока лидер не выйдет из Ñ‚.н. joint state (Ñм. рафт диÑÑер §4.3). ПоÑле Ñтого можно отвечать клиенту `raft_id`, `raft_group`, `insance_uuid`, `replicaset__uuid`, `replication`, `read_only`. Ð’ будущем ÑоÑтав ответа может дополнÑÑ‚ÑŒÑÑ Ð½Ð¾Ð²Ñ‹Ð¼Ð¸ параметрами по мере необходимоÑти. - -- `raft_id` генерит лидер, и делает Ñто Ñтрого поÑледовательно и атомарно на веÑÑŒ батч. -- `raft_group` предÑтавлÑет Ñобой дамп вÑего ÑпейÑа Ñ Ñ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð³Ð¸ÐµÐ¹ клаÑтера. Он понадобитÑÑ Ð½Ð¾Ð²Ð¾Ð¼Ñƒ инÑтанÑу чтобы знать адреÑа ÑоÑедей и нормально Ñ Ð½Ð¸Ð¼Ð¸ общатьÑÑ. - -И, наконец, где-то здеÑÑŒ же надо будет убедитьÑÑ, что нода ÑвлÑетÑÑ Ð»Ð¸Ð´ÐµÑ€Ð¾Ð¼, когда генерит `raft_id`. У оÑтальных нет на Ñто права. +Ð—Ð½Ð°Ñ‡Ð¸Ñ‚ÐµÐ»ÑŒÐ½Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ вÑей логики по управлению топологией находитÑÑ Ð² хранимой процедуре `join`. Её назначение ÑоÑтоит в обработке запроÑов на добавление нового инÑтанÑа (клиента) в Raft-группу Ñ ÑƒÑ‡Ñ‘Ñ‚Ð¾Ð¼ Ñледующих обÑтоÑтельÑтв: -# TODO +Во-первых, еÑли такой `instance_id` уже имеетÑÑ Ð² клаÑтере (и его данные Ñохранены в БД) и Ð½Ð¸ÐºÐ°ÐºÐ°Ñ Ð´Ñ€ÑƒÐ³Ð°Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ñ Ð½Ðµ обновлÑлаÑÑŒ (например флаг `voter` / `learner`), то можно Ñразу отвечать клиенту, не задейÑÑ‚Ð²ÑƒÑ Raft. -Q: провеÑти ÑкÑперимент, может ли ConfChange пролезть в MsgPropose? -A: Может +ЕÑли Ñто первое поÑвление инÑтанÑа в группе, то он вÑегда добавлÑетÑÑ Ð² роли `learner`. Ð’ роли `voter` его добавлÑÑ‚ÑŒ нельзÑ, так как Ð´Ð»Ñ Ð´Ð¾ÑÑ‚Ð¸Ð¶ÐµÐ½Ð¸Ñ ÐºÐ¾Ð½ÑенÑуÑа в Raft-группе требуетÑÑ ÑƒÑ‡Ð°Ñтие добавлÑемого инÑтанÑа, но он не Ñможет учаÑтвовать, так как Ñам ещё ждёт ответа на Ð·Ð°Ð¿Ñ€Ð¾Ñ `join`. -Q: провеÑти ÑкÑперимент, можно ли параллельно отравлÑÑ‚ÑŒ simple_conf_change, или Ñто только v2 каÑаетÑÑ? -A: Пофиг, simple у Ð½Ð°Ñ Ñ‚Ð¾Ð»ÑŒÐºÐ¾ один в логе - Ñамый первый. +Во-вторых, Raft не позволÑет изменÑÑ‚ÑŒ конфигурацию, пока предыдущее изменение не было применено. ПоÑтому запроÑÑ‹ `join` на лидере Raft-группы необходимо группировать и обрабатывать за один приём в отдельном потоке. Сначала накапливаетÑÑ Ð¿Ð°ÐºÐµÑ‚ запроÑов, затем он обрабатываетÑÑ, и поÑле Ñтого каждому инÑтанÑу возвращаетÑÑ Ð¸Ð½Ð´Ð¸Ð²Ð¸Ð´ÑƒÐ°Ð»ÑŒÐ½Ñ‹Ð¹ ответ. -Q: правда ли, что пропоуз Ñразу поÑле коммита не потерÑетÑÑ, и не задублируетÑÑ? -A: нет, коммит на фоловерах может прийти, а пропоуз потерÑетÑÑ. тогда у нового лидера не будет подходÑщего момента, чтобы воÑполнить Ñту утрату. Именно поÑтому за промоутом до воутера Ñледит Ñам фоловер. +Ð’-третьих, прежде чем отвечать инÑтанÑу-клиенту, надо дождатьÑÑ Ð¿Ñ€Ð¸Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ð¹ конфигурации. Ðто произойдёт поÑле того как лидер Raft-группы выйдет из ÑоÑтоÑÐ½Ð¸Ñ `joint state` ([подробнее](https://web.stanford.edu/~ouster/cgi-bin/papers/OngaroPhD.pdf), §4.3). Только поÑле Ñтого лидер Ñможет вернуть клиенту данные `raft_id`, `raft_group`, `insance_uuid`, `replicaset_uuid`, `replication`, `read_only`. -Q: может ли фоловер (не лернер) Ñлать другому фоловеру MgsAppend закомиченных Ñнтрей? -A: ??? +- Значение `raft_id` генерируетÑÑ Ð»Ð¸Ð´ÐµÑ€Ð¾Ð¼ Raft-группы, причём Ñтрого поÑледовательно и атомарно в рамках вÑего пакета запроÑов. +- Данные `raft_group` предÑтавлÑÑŽÑ‚ Ñобой копию таблицы Ñ Ñ‚Ð¾Ð¿Ð¾Ð»Ð¾Ð³Ð¸ÐµÐ¹ клаÑтера. Они понадобÑÑ‚ÑÑ Ð½Ð¾Ð²Ð¾Ð¼Ñƒ инÑтанÑу чтобы знать адреÑа ÑоÑедей и нормально Ñ Ð½Ð¸Ð¼Ð¸ общатьÑÑ. +- Генерировать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ `raft_id` может только лидер Raft-группы. У любого другого узла Raft нет на Ñто права. diff --git a/docs/clustering.svg b/docs/clustering.svg new file mode 100644 index 0000000000000000000000000000000000000000..fa205799db6c702f765b44815876c5b18c514c26 Binary files /dev/null and b/docs/clustering.svg differ diff --git a/docs/clustering_curves.svg b/docs/clustering_curves.svg new file mode 100644 index 0000000000000000000000000000000000000000..107a7add67fb907180a549fc03ca141531fa3842 Binary files /dev/null and b/docs/clustering_curves.svg differ diff --git a/docs/main.uml b/docs/main.uml deleted file mode 100644 index cbcba63173be7dbc6e08c5dc59cbb86cdb5e2241..0000000000000000000000000000000000000000 --- a/docs/main.uml +++ /dev/null @@ -1,12 +0,0 @@ -(start)-|fork| - -|fork|[child]->(start_discover)->[summary\n{leader}]-><c> -<c>-[its me]>(start_boot)->(postjoin) -<c>->(drop_db)[rebootstrap]->|reboot|->(start_join) - -(start_join)->(postjoin) -(start_discover)->(postjoin) -(postjoin)->|b| - -|fork|-[supervisor]>(wait_pid)->|b| -|b|->(end) diff --git a/docs/main_run.svg b/docs/main_run.svg deleted file mode 100644 index 47e51df30ea39928505621ce467bba120a28fcda..0000000000000000000000000000000000000000 Binary files a/docs/main_run.svg and /dev/null differ