Fair raft join
Compare changes
Files
30+ 90
− 47
На запрос raft_discover есть и третий вариант ответа, когда транзитивное замыкание уже собрано, но сама рафт нода еще не проинициализирована. В этом случае серверу правильнее отдавать значение advertise_uri первого инстанса, вычисленное из транзитивного замыкания. Именно оно прилетит из рафт снапшота как только нода поднимется.
1. Ещё в ответе должны быть replicaset_uuid (правильно сгенеренный, либо выбранный среди существующих), instance_uuid (ну так, за компанию), урлы других инстансов из его репликасета, чтобы он сразу мог забутстрапить репликацию. Всё это раздаётся из таблички с топологией, но сначала её надо туда положить, причем класть надо средствами рафта.
Подробный алгоритм дискавери в этой истории роли не играет, но описан в соседнем файле `discovery.md`. Пока об алгоритме дискавери достаточно знать лишь то, что, следуя этому алгоритму, один и только один из этих пиров возьмет на себя смелость создать рафт группу. Иначе рафт групп получилось бы неколько.
Если вдруг из спейсов обнаруживается, что нода уже была забутстрапленна, то никакой алгоритм дискавери делаь и не надо, и инстанс сразу переходит на этап `postjoin()`. В противном случае, если это первый запуск, из алгоритма дискавери мы получаем флаг `its_me` и адрес лидера. Сам лидер (единственный `its_me == true`) выполняет `start_boot`, после чего выполняет `postjoin()`. Остальные инстансы (не только проигравшие пиры, но и все будущие) ребутстрапятся и идут делать `start_join`.
Получив все настройки, инстанс засовывает их в `box.cfg()`, и после этого персистит `raft_group` с актуальными адресами других инстансов. Без этого инстанс не сможет отвечать на рафт сообщения. А чтобы записи в `raft_group` не были потёрты менее актуальными из рафт лога, каждая маркируется значением `commit_index`.
Логика `postjoin()` для всех инстансов одинакова. К этому моменту на инстансе уже инициализированы правильные спейсы и возможно даже существует предыстория рафт журнала. Инстанс инициализирует рафт ноду и получает read barrier (это позволяет убедиться, что рафт лог актуален). Из рафт лога становятся известны параметры репликации, и инстанс синхронизируется с репликами.
В-третьих, прежде чем отвечать клиенту, надо дождаться, пока ConfChange закоммитится. Или, более формально, пока лидер не выйдет из т.н. joint state (см. рафт диссер §4.3). После этого можно отвечать клиенту `raft_id`, `raft_group`, `insance_uuid`, `replicaset__uuid`, `replication`, `read_only`. В будущем состав ответа может дополняться новыми параметрами по мере необходимости.