From 1d11cfedf4900e03e229fa6501fbe54e1b2e23fb Mon Sep 17 00:00:00 2001 From: "a.tolstoy" <a.tolstoy@picodata.io> Date: Fri, 16 Dec 2022 17:07:51 +0300 Subject: [PATCH] docs: fix spotted minor issues --- docs/clustering.md | 11 +++--- docs/discovery.md | 92 ---------------------------------------------- docs/install.md | 2 +- 3 files changed, 7 insertions(+), 98 deletions(-) delete mode 100644 docs/discovery.md diff --git a/docs/clustering.md b/docs/clustering.md index 95ff91e1..a0a1368b 100644 --- a/docs/clustering.md +++ b/docs/clustering.md @@ -22,11 +22,12 @@ picodata run --instance-id iN --listen iN --peer i1 (discovery). ПодробноÑти алгоритма discovery приведены в отдельном -[документе](discovery.md). Ð’ контекÑте Ñборки клаÑтера важно лишь -понимать, что Ñтот алгоритм позволÑет не более чем одному инÑтанÑу -(peer'у) Ñоздать Raft-группу, Ñ‚.е. Ñтать инÑтанÑом Ñ raft_id=1. ЕÑли -таких инÑтанÑов будет неÑколько, то и Raft-групп, а Ñледовательно и -клаÑтеров Picodata получитÑÑ Ð½ÐµÑколько. +[документе](https://git.picodata.io/picodata/picodata/picodata/-/blob/master/docs/discovery.md). +Ð’ контекÑте Ñборки клаÑтера важно лишь понимать, что Ñтот алгоритм +позволÑет не более чем одному инÑтанÑу (peer'у) Ñоздать Raft-группу, +Ñ‚.е. Ñтать инÑтанÑом Ñ raft_id=1. ЕÑли таких инÑтанÑов будет неÑколько, +то и Raft-групп, а Ñледовательно и клаÑтеров Picodata получитÑÑ +неÑколько. Топологией Raft-группы управлÑет алгоритм Raft, реализованный в виде крейта `raft-rs`. diff --git a/docs/discovery.md b/docs/discovery.md deleted file mode 100644 index f74db791..00000000 --- a/docs/discovery.md +++ /dev/null @@ -1,92 +0,0 @@ -# Discovery algorithm - -## Входные данные: - -- `N` узлов, пока не ÑвÑзанных друг Ñ Ð´Ñ€ÑƒÐ³Ð¾Ð¼ по Ñети. СвÑзать их предÑтоит алгоритму. -- Тем не менее, каждый узел обладает на Ñтарте информацией о некоторых его ÑоÑедÑÑ… - маÑÑиве `initial_peers`, Ñодержащем Ñетевые адреÑа узлов (не менее одного). - -Ðлгоритм налагает некоторые ограничение на входные данные, в противном Ñлучае результат работы алгоритма может оказатьÑÑ Ð½ÐµÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ñ‹Ð¼. Чтобы обеÑпечить выполнение результата, у любой пары узлов должен ÑущеÑтвовать как минимум один общий Ñлемент `initial_peers`. - -ЗдеÑÑŒ Ñтоит Ñказать пару Ñлов о том, как именно мы будем моделировать Ñеть. Ðлгоритм Ñпециально ÑоÑтавлен таким образом, чтобы его легко было адаптировать под конкретный транÑпортный протокол, хоть TCP, хоть UDP. - -Чтобы не проÑлыть инфантильными, мы также Ñразу допуÑкаем, что ÑвÑзноÑÑ‚ÑŒ Ñети может Ñпонтанно нарушатьÑÑ. Любое Ñообщение может: -- быть доÑтавлено получателю ÑпуÑÑ‚Ñ Ð½ÐµÐ¾Ð¿Ñ€ÐµÐ´ÐµÐ»Ñ‘Ð½Ð½Ð¾Ðµ времÑ, -- возможно беÑконечно малое, -- а возможно и беÑконечно никогда. - -Мы хотим, чтобы алгоритм был полезен на практике. И такое предположение, неÑомненно, благоприÑтно ÑкажетÑÑ Ð½Ð° ÑпоÑобноÑÑ‚ÑÑ… алгоритма не разбитьÑÑ Ð¾ Ñуровую реальноÑÑ‚ÑŒ, где Ñервера иногда ~~проÑтужаютÑÑ~~ перегреваютÑÑ Ð¸ выгорают целыми датацентрами. - -Ð’ тоже Ð²Ñ€ÐµÐ¼Ñ Ð°Ð»Ð³Ð¾Ñ€Ð¸Ñ‚Ð¼ Ñовершенно не подготовлен к решению задачи о византийÑких генералах. Ðкцент в первую очередь делаетÑÑ Ð½Ð° отказоуÑтойчивоÑти к ошибкам пользователÑ, а не злонамеренноÑти генералов. Ðто призвано упроÑтить процеÑÑ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ рафт группы (который в худшем Ñлучае можно и перезапуÑтить на Ñтапе подготовки к ÑкÑплуатации, в отличие от генералов). ВизантийÑÐºÐ°Ñ Ð¾Ñ‚ÐºÐ°Ð·Ð¾ÑƒÑтойчивоÑÑ‚ÑŒ, еÑли Ñто необходимо, должна обеÑпечиватьÑÑ Ð´Ñ€ÑƒÐ³Ð¸Ð¼ протоколом. - -## Результат: - -Результатом работы Ñтого раÑпределенного алгоритма ÑвлÑетÑÑ ÐµÐ´Ð¸Ð½Ñтвенное булево значение `i_am_bootstrap_leader`. Мы ожидаем (и заверÑем ваÑ), что, пока входные параметры не нарушают наложенных ограничений, не более одного узла будущего клаÑтера приÑвоÑÑ‚ Ñебе Ñту медальку. Я бы хотел, чтобы "не меньше" тоже было равно одному, но, увы, в уÑловиÑÑ… полной Ñетевой изолÑции ответ будет ноль, и никакой онлайн-вечеринки не ÑоÑтоитÑÑ. - -И опÑÑ‚ÑŒ, в угоду пользовательÑкого опыта, алгоритм не пытаетÑÑ Ð·Ð°Ð¿Ð¾Ð»ÑƒÑ‡Ð¸Ñ‚ÑŒ больше информации о будущем клаÑтере. Ð’ противном Ñлучае Ñто потребовало бы делать дополнительные Ð¿Ñ€ÐµÐ´Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¾ Ñетевой ÑвÑзноÑти, и Ñто могло негативно ÑказатьÑÑ Ð½Ð° удобÑтве ÑкÑплуатации решениÑ. Данный алгоритм надеетÑÑ Ð½Ð° лучшее (один бутÑтрап лидер), оÑтаваÑÑÑŒ готовым к худшему (ноль бутÑтрап лидеров). - -## СобÑтвенно Ñам алгоритм - -### **Шаг 0.1** - -Как уже упоминалоÑÑŒ раньше, каждый узел _i_ инициализирует маÑÑив извеÑтных адреÑов `known_peers[i] = initial_peers[i]` (Ñо значениÑми, предоÑтавленными пользователем). - -### **Шаг 0.2** - -Каждый узел _i_ генерирует Ñлучайный идентификатор (`guid[i]`), вероÑтноÑÑ‚ÑŒ коллизии которых мы предполагаем равной нулю. Ðто требование ÑовÑем не Ñложно выполнить на практике. - -### **Шаг 1** - -Каждый узел _i_ проводит раунд запроÑов номер `r` - отправлÑет по вÑем извеÑтным адреÑам `known_peers[i][m]` Ñообщение `("discovery_req", m, known_peers[i])`. Параметр `m` предÑтавлÑет Ñобой вÑего лишь Ð¸Ð½Ð´ÐµÐºÑ Ð°Ð´Ñ€ÐµÑата в маÑÑиве `known_peers[i]`. ЕдинÑÑ‚Ð²ÐµÐ½Ð½Ð°Ñ ÐµÐ³Ð¾ роль в алгоритме - быть возвращённым в ответе, чтобы можно было ÑопоÑтавить ответ Ñ ÐºÐ¾Ð½ÐºÑ€ÐµÑ‚Ð½Ñ‹Ð¼ адреÑом. Впрочем, его можно вообще опуÑтить, еÑли Ñту функциональноÑÑ‚ÑŒ предоÑтавлÑет иÑпользуемый транÑпортный протокол. - -### _Меж двух шагов_ - -Получив Ñообщение `("discovery_req", m, known_peers[i])`, узел (_j_) проверÑет Ñвоё ÑоÑтоÑние. - -ЕÑли на данный момент лидер уже выбран и извеÑтен, то отправлÑет в ответ Ñообщение `("discovery_finished")`. - -Ð’ противном Ñлучае обновлÑет Ñвой маÑÑив `known_peers[j] = known_peers[i] \/ known_peers[j]`. Ответ Ñодержит `("discovery_resp", m, known_peers[j], guid[j])`. - -ЗдеÑÑŒ делаетÑÑ ÐµÑ‰Ñ‘ одно допущение о том, что иÑпользуемый транÑпортный протокол обладает функцией "отправки ответа". Оба TCP и UDP такой функциональноÑтью обладают. - -### **Шаг 2** (ВозвращаÑÑÑŒ к узлу _i_ - отправителю запроÑа) - -Yaroslav Dynnikov, [08/04/2022 22:18] - - -Получив ответ `("discovery_finished")` алгоритм завершает Ñвою работу - задача выполнена. `i_am_bootstrap_leader[i] = false`. - -Получив ответ `("discovery_resp", m, known_peers[j], guid[j])`, узел (_i_), как и в Ñлучае обработки `discovery_req`, обновлÑет Ñвой маÑÑив `known_peers[i] = known_peers[i] \/ known_peers[j]`. Далее полученный ответ ÑопоÑтавлÑетÑÑ Ñ Ð°Ð´Ñ€ÐµÑатом `known_peers[i][m]`. ЕÑли в маÑÑиве `known_peers[i]` оÑталиÑÑŒ ещё не ответившие адреÑаты, алгоритм приоÑтанавливаетÑÑ Ð´Ð¾ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñледующего ÑообщениÑ. - -ЕÑли ответ Ñодержит ошибку протокола транÑпортного уровнÑ, Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€ÑетÑÑ Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼ интервалом до тех пор, пока не будет получен внÑтный ответ. - -ЕÑли к концу Ñтого шага были обнаружены новые адреÑаты, алгоритм начинает новый раунд запроÑов `r+1` и возвращаетÑÑ Ðº шагу 1. - -### **Шаг 3** - -ЕÑли вдруг лидер до Ñих пор не извеÑтен, то к Ñтому моменту каждому узлу _i_ ÑтановитÑÑ Ð¸Ð·Ð²ÐµÑтна Ð¿Ð¾Ð»Ð½Ð°Ñ ÐºÐ°Ñ€Ñ‚Ð° `known_peers[i][m] -> guid[m]`. - -ЕÑли вдруг `guid[i] == min(guid)`, то узел понимает, что `i_am_bootstrap_leader[i] = true`, и Ñ Ñтих пор переÑтаёт изменÑÑ‚ÑŒ внутреннее ÑоÑтоÑние, и отвечает на вÑе запроÑÑ‹ `("discovery_finished")`. - -ЕÑли же, напротив, `guid[i] != min(guid)`, то `i_am_bootstrap_leader[i] = false`. - -### ДоказательÑтво - -КорректноÑÑ‚ÑŒ алгоритма проще вÑего доказать от противного. Предположим, что в какой-то момент узел _i_ решил, что `i_am_bootstrap_leader[i] == true`, в то Ð²Ñ€ÐµÐ¼Ñ ÐºÐ°Ðº уже ÑущеÑтвовал `i_am_bootstrap_leader[j] == true` (и при Ñтом `i != j`). - -Так как на третьем шаге оба узла вычиÑлÑÑŽÑ‚ `min(guid)` идентичным оразом, то отличатьÑÑ Ð´Ð¾Ð»Ð¶Ð½Ñ‹ были Ñами таблицы `guid`. - -При Ñтом маÑÑив `known_peers[j]` заведомо не Ñодержал Ð°Ð´Ñ€ÐµÑ _i_ в момент принÑÑ‚Ð¸Ñ Ñ€ÐµÑˆÐµÐ½Ð¸Ñ, но Ñодержал Ñвой Ð°Ð´Ñ€ÐµÑ _j_, иначе бы не выполнилоÑÑŒ уÑловие `guid[j] == min(guid)`. Ðналогично, `known_peers[i]` точно Ñодержал _i_. - -Ð’ то же Ð²Ñ€ÐµÐ¼Ñ `known_peers[i]` не мог Ñодержать _j_, иначе _i_ не Ñмог бы получить от _j_ ответ `("discovery_resp")` и не “выдать†ÑебÑ. - -Таким образом _i_ и _j_ не должны были в момент принÑÑ‚Ð¸Ñ Ñ€ÐµÑˆÐµÐ½Ð¸Ñ Ð½Ð¸Ñ‡ÐµÐ³Ð¾ знать друг о друге. - -Ðо так как у _i_ и _j_ по уÑловию должен быть как минимум один общий "ÑоÑед", назовём его _z_, он также должен был обоим _i_ и _j_ дать ответы `("discovery_resp")`. Противоречие заключаетÑÑ Ð² том, что _z_ пришлоÑÑŒ бы одному из двух узлов в ответе `("discovery_resp")` Ñообщить о ÑущеÑтвовании второго, покуда обработка запроÑов выполнÑетÑÑ Ð°Ñ‚Ð¾Ð¼Ð°Ñ€Ð½Ð¾. - -### Возможные оптимизации - -ОÑÐ½Ð¾Ð²Ð½Ð°Ñ Ñ‡Ð°ÑÑ‚ÑŒ алгоритма изложена так, чтобы быть макÑимально проÑтой. Тем не менее, Ñто не иÑключает Ð½Ð°Ð»Ð¸Ñ‡Ð¸Ñ Ð½ÐµÑкольких полезных оптимизаций, которые ниÑколько не влиÑÑŽÑ‚ на результат, Ñ…Ð¾Ñ‚Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»ÑÑŽÑ‚ Ñделать пользовательÑкий опыт приÑтнее. - -Ðачинать новый раунд на втором шаге не возбранÑетÑÑ Ñразу поÑле Ð¾Ð±Ð½Ð°Ñ€ÑƒÐ¶ÐµÐ½Ð¸Ñ Ð½Ð¾Ð²Ð¾Ð³Ð¾ адреÑата. Ðе обÑзательно Ð´Ð»Ñ Ñтого дожидатьÑÑ Ð²Ñех ожидаемых ответов. - -ПоÑле Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ алгоритма, Ñ ÑообщениÑми `("discovery_finished")` можно раÑÑылать информацию об адреÑе лидера, о `known_peers`, или любую другую необходимую, которую хотелоÑÑŒ бы Ñинхронизировать. Так как единÑтвенноÑÑ‚ÑŒ лидера доказана, оÑтальные узлы могут ему верить, еÑли конечно никто больше не возьмётÑÑ ÐµÑ‘ модифицировать, а мы договорилиÑÑŒ не раÑÑматривать византийÑкие Ñценарии. diff --git a/docs/install.md b/docs/install.md index 0a1c5db8..c532f8b1 100644 --- a/docs/install.md +++ b/docs/install.md @@ -146,7 +146,7 @@ Picodata может Ñоздать клаÑтер, ÑоÑтоÑщий вÑего picodata run ``` -Можно добавлÑÑ‚ÑŒ Ñколько угодно поÑледующих инcтанÑов — вÑе они будут подключатьÑÑ Ðº Ñтому клаÑтеру. Каждому интанÑу Ñледует задать отдельную рабочую директорию (параметр `--data-dir`), а также указать Ð°Ð´Ñ€ÐµÑ Ð¸ порт Ð´Ð»Ñ Ð¿Ñ€Ð¸ÐµÐ¼Ð° Ñоединений (параметр `--listen`) в формате `<HOST>:<PORT>`. Фактор репликации по умолчанию равен 1 — каждый инÑÑ‚Ð°Ð½Ñ Ð¾Ð±Ñ€Ð°Ð·ÑƒÐµÑ‚ отдельный репликаÑет. ЕÑли Ð´Ð»Ñ `--listen` указать только порт, то будет иÑпользован IP-Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾ умолчанию (127.0.0.1): +Можно добавлÑÑ‚ÑŒ Ñколько угодно поÑледующих инcтанÑов — вÑе они будут подключатьÑÑ Ðº Ñтому клаÑтеру. Каждому инÑтанÑу Ñледует задать отдельную рабочую директорию (параметр `--data-dir`), а также указать Ð°Ð´Ñ€ÐµÑ Ð¸ порт Ð´Ð»Ñ Ð¿Ñ€Ð¸ÐµÐ¼Ð° Ñоединений (параметр `--listen`) в формате `<HOST>:<PORT>`. Фактор репликации по умолчанию равен 1 — каждый инÑÑ‚Ð°Ð½Ñ Ð¾Ð±Ñ€Ð°Ð·ÑƒÐµÑ‚ отдельный репликаÑет. ЕÑли Ð´Ð»Ñ `--listen` указать только порт, то будет иÑпользован IP-Ð°Ð´Ñ€ÐµÑ Ð¿Ð¾ умолчанию (127.0.0.1): ``` picodata run --data-dir i1 --listen :3301 -- GitLab