From ff62d393070c24fd37d169956c8f3ce1f223d199 Mon Sep 17 00:00:00 2001 From: Yaroslav Dynnikov <yaroslav.dynnikov@gmail.com> Date: Wed, 15 Nov 2023 14:55:48 +0300 Subject: [PATCH] instance_lifecycle.md: major edits --- docs/architecture/instance_lifecycle.md | 189 ++++++++++++------------ 1 file changed, 97 insertions(+), 92 deletions(-) diff --git a/docs/architecture/instance_lifecycle.md b/docs/architecture/instance_lifecycle.md index 0a4cb35b..56044882 100644 --- a/docs/architecture/instance_lifecycle.md +++ b/docs/architecture/instance_lifecycle.md @@ -1,39 +1,33 @@ # Жизненный цикл инÑтанÑа Ð’ контекÑте операционных ÑиÑтем каждый инÑÑ‚Ð°Ð½Ñ ÑоответÑтвует группе из -двух процеÑÑов — родительÑкого (supervisor) и дочернего (именно он -выполнÑет tarantool runtime). +двух процеÑÑов. Данный раздел выÑокоуровнево опиÑывает оÑновные Ñтапы +инициализации инÑтанÑа. Они изображены на Ñледующей Ñхеме. + + КраÑным показан родительÑкий процеÑÑ, который запущен на вÑем протÑжении -жизненного цикла инÑтанÑа. Ð’ÑÑ Ð»Ð¾Ð³Ð¸ÐºÐ°, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Ð¿Ñ€Ð¸ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ðº -клаÑтеру, и Ð·Ð°ÐºÐ°Ð½Ñ‡Ð¸Ð²Ð°Ñ Ð¾Ð±Ñлуживанием клиентÑких запроÑов, проиÑходит в +жизненного цикла инÑтанÑа. Ð’ÑÑ Ð»Ð¾Ð³Ð¸ÐºÐ°, Ð½Ð°Ñ‡Ð¸Ð½Ð°Ñ Ñ Ð¿Ñ€Ð¸ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ (joining) +к клаÑтеру, и Ð·Ð°ÐºÐ°Ð½Ñ‡Ð¸Ð²Ð°Ñ Ð¾Ð±Ñлуживанием клиентÑких запроÑов, проиÑходит в дочернем процеÑÑе (голубой цвет). ЕдинÑтвенное предназначение родительÑкого процеÑÑа — иметь возможноÑÑ‚ÑŒ ÑброÑить ÑоÑтоÑние дочернего -(выполнить rebootstrap) и инициализировать его повторно (Ñиреневый -цвет). +и инициализировать его повторно (Ñиреневый цвет). -Ð”Ð°Ð½Ð½Ð°Ñ Ñхема наиболее полно отражает логику кода в файле `main.rs`. Ðиже -опиÑаны детали Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ñтапа и ÑоответÑтвующей программной -функции. +Ðиже опиÑаны детали Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ñтапа и ÑоответÑтвующей +программной функции. -### fn main() +### fn main() {: #fn_main } -Ðа Ñтом Ñтапе проиÑходит ветвление (форк) процеÑÑа `picodata`. -РодительÑкий процеÑÑ (supervisor) ожидает от дочернего процеÑÑа -ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ механизму IPC и при необходимоÑти перезапуÑкает дочерний -процеÑÑ. +Ðа Ñтом Ñтапе проиÑходит ветвление (форк) процеÑÑа. РодительÑкий +процеÑÑ, именуемый в дальнейшем "supervisor", ожидает от дочернего +процеÑÑа ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ механизму IPC и при необходимоÑти перезапуÑкает +его. Выполнение дочернего процеÑÑа начинаетÑÑ Ñ Ð²Ñ‹Ð·Ð¾Ð²Ð° функции -[`start_discover()`](#fn-start_discover) и далее Ñледует алгоритму. При +[`start_discover()`](#fn_start_discover) и далее Ñледует алгоритму. При необходимоÑти дочерний процеÑÑ Ð¼Ð¾Ð¶ÐµÑ‚ попроÑить Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ ÑƒÐ´Ð°Ð»Ð¸Ñ‚ÑŒ вÑе -файлы БД (Ñм. раздел [РебутÑтрап](#rebootstrap)). Ðто иÑпользуетÑÑ Ð´Ð»Ñ -повторной инициализации инÑтанÑа Ñ Ð½Ð¾Ñ€Ð¼Ð°Ð»ÑŒÐ½Ñ‹Ð¼ `replicaset_uuid` вмеÑто -рандомного. - -### РебутÑтрап {: #rebootstrap } - -Ð’ СУБД Tarantool имеютÑÑ Ð´Ð²Ðµ оÑобенноÑти, из-за которых процеÑÑ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ -выглÑдит Ñледующим образом: +файлы БД. Ðто иÑпользуетÑÑ Ð´Ð»Ñ Ñ‚Ð¾Ð³Ð¾ чтобы корректно учеÑÑ‚ÑŒ две +оÑобенноÑти Tarantool: 1. ПринадлежноÑÑ‚ÑŒ инÑтанÑа тому или иному репликаÑету определÑетÑÑ Ð² момент первого вызова `box.cfg()`, когда ÑоздаетÑÑ Ð¿ÐµÑ€Ð²Ñ‹Ð¹ Ñнапшот. @@ -47,67 +41,73 @@ репликаÑету; - принадлежноÑÑ‚ÑŒ репликаÑету невозможно узнать без Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¿Ð¾ Ñети. -Чтобы Ñту проблему решить, Picodata инициализируетÑÑ Ñо Ñлучайно -Ñгенерированными идентификаторами, а позже перезапуÑкает процеÑÑ, -попутно Ð¾Ñ‡Ð¸Ñ‰Ð°Ñ Ñ€Ð°Ð±Ð¾Ñ‡ÑƒÑŽ директорию. +Чтобы Ñту проблему решить, Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð½Ð° Ñтапе `start_discover()` +проиÑходит Ñо Ñлучайно Ñгенерированными идентификаторами, поÑле чего +supervisor очищает рабочую директорию и перезапуÑкает дочерний процеÑÑ Ñ +функций `start_boot()` или `start_join()`. -### fn start_discover() +### fn start_discover() {: #fn_start_discover } Дочерний процеÑÑ Ð½Ð°Ñ‡Ð¸Ð½Ð°ÐµÑ‚ Ñвое ÑущеÑтвование Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ -[`init_common()`](#fn-init_common), в рамках которой в Ñ‚.ч. -инициализируетÑÑ Ð¼Ð¾Ð´ÑƒÐ»ÑŒ `box`. Возможно, что при Ñтом из БД будет ÑÑно, -что bootstrap данного инÑтанÑа уже был произведен ранее и что raft уже -знает о вхождении Ñтого инÑтанÑа в клаÑтер — в таком Ñлучае никакого -discovery не будет, инÑÑ‚Ð°Ð½Ñ Ñразу перейдет к Ñтапу `postjoin()`. Ð’ -противном Ñлучае, еÑли меÑто инÑтанÑа в клаÑтере еще не извеÑтно, -алгоритм discovery определÑет значение флага `i_am_bootstrap_leader` и -Ð°Ð´Ñ€ÐµÑ Ð»Ð¸Ð´ÐµÑ€Ð° raft-группы. Далее инÑÑ‚Ð°Ð½Ñ ÑбраÑывает Ñвое ÑоÑтоÑние (Ñм. -[РебутÑтрап](#rebootstrap)), чтобы повторно провеÑти инициализацию -`box.cfg()`, теперь уже Ñ Ð¸Ð·Ð²ÐµÑтными параметрами. Сам лидер -(единÑтвенный Ñ `i_am_bootstrap_leader == true`) выполнÑет функцию -`start_boot()`. ОÑтальные инÑтанÑÑ‹ переходÑÑ‚ к функции `start_join()`. - -### fn start_boot() - -Ð’ функции `start_boot` проиÑходит Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ raft-группы — лидер -генерирует и ÑохранÑет в БД первые запиÑи в журнале. Ðти запиÑи -опиÑывают добавление первого инÑтанÑа в пуÑтую raft-группу и Ñоздание -начальной clusterwide-конфигурации. Таким образом доÑтигаетÑÑ -однообразие кода, обрабатывающего Ñти запиÑи. +[`init_common()`](#fn_init_common), в рамках которой в Ñ‚.ч. +инициализируетÑÑ Ð´Ð²Ð¸Ð¶Ð¾Ðº базы данных `box.cfg()`. -Сам raft-узел на данном Ñтапе еще не ÑоздаетÑÑ. Ðто произойдет позже, на -Ñтадии `postjoin()`. +Возможно, что при Ñтом из БД Ñтанет ÑÑно, что данный инÑтанÑа уже был +добавлен в клаÑтер — в таком Ñлучае Ñтап discovery пропуÑкаетÑÑ Ð¸ +инÑÑ‚Ð°Ð½Ñ Ñразу переходит к Ñтапу [`postjoin()`](#fn_postjoin). -### fn start_join() +Ð’ противном Ñлучае, еÑли меÑто инÑтанÑа в клаÑтере еще не извеÑтно, +[алгоритм discovery](../architecture/discovery.md) позволÑет найти Ð°Ð´Ñ€ÐµÑ +лидера или же определить, что им должен Ñтать данный инÑÑ‚Ð°Ð½Ñ +(`i_am_bootstrap_leader`). -Вызову функции `start_join()` вÑегда предшеÑтвует -[ребутÑтрап](#rebootstrap) (удаление вÑех данных и перезапуÑк процеÑÑа), -поÑтому на данном Ñтапе в БД нет ни Ð¼Ð¾Ð´ÑƒÐ»Ñ `box`, ни проÑтранÑтва -хранениÑ. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ `start_join()` имеет проÑтое уÑтройÑтво: +Ð’ контекÑте инициализации клаÑтера важно лишь то, что Ñтот алгоритм +позволÑет выполнить инициализацию не более чем одному инÑтанÑу. ЕÑли +таких инÑтанÑов было бы неÑколько, то и клаÑтеров Picodata получилоÑÑŒ бы +неÑколько. -ИнÑÑ‚Ð°Ð½Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»Ñет Ð·Ð°Ð¿Ñ€Ð¾Ñ `rpc::join` лидеру raft-группы (он -извеÑтен поÑле discovery), который в ответе приÑылает вÑÑŽ необходимую -Ð´Ð»Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ информацию: +ПоÑле discovery при отÑутÑтвии ошибок инÑÑ‚Ð°Ð½Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½Ñет процедуру +"rebootstrap" — ÑбраÑывает Ñвое ÑоÑтоÑние, чтобы повторно провеÑти +инициализацию `box.cfg()`, теперь уже Ñ Ð¸Ð·Ð²ÐµÑтными параметрами. +Bootstrap-лидер выполнÑет [`start_boot()`](#fn_start_boot). +ОÑтальные инÑтанÑÑ‹ переходÑÑ‚ к [`start_join()`](#fn_start_join). -Ð”Ð»Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ raft-узла: +### fn start_boot() {: #fn_start_boot } -- идентификатор `raft_id`; -- данные таблицы `_picodata_peer_address`. +Ð’ функции `start_boot()` проиÑходит Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ ÑиÑтемных глобальных +таблиц Picodata — лидер генерирует и ÑохранÑет в БД первые запиÑи в +raft-журнале. Ðти запиÑи опиÑывают добавление первого инÑтанÑа в пуÑтую +raft-группу и Ñоздание начальной конфигурации клаÑтера. + +Сам raft-узел на данном Ñтапе еще не ÑоздаетÑÑ. Ðто произойдет позже, на +Ñтадии [`postjoin()`](#fn_postjoin). -Ð”Ð»Ñ Ð¿ÐµÑ€Ð²Ð¸Ñ‡Ð½Ð¾Ð³Ð¾ вызова `box.cfg()`: -- идентификаторы `instance_uuid`, `replicaset_uuid`, +### fn start_join() {: #fn_start_join } + +Вызову функции `start_join()` вÑегда предшеÑтвует rebootstrap (удаление +вÑех данных и перезапуÑк процеÑÑа), поÑтому на данном Ñтапе в БД нет ни +Ð¼Ð¾Ð´ÑƒÐ»Ñ `box`, ни проÑтранÑтва хранениÑ. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ `start_join()` имеет +проÑтое уÑтройÑтво: + +ИнÑÑ‚Ð°Ð½Ñ Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»Ñет join-Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð»Ð¸Ð´ÐµÑ€Ñƒ raft-группы (он извеÑтен поÑле +discovery), который в ответе приÑылает вÑÑŽ необходимую Ð´Ð»Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ +информацию: + +- идентификатор `raft_id`; +- данные ÑиÑтемной таблицы + [`_pico_peer_address`](../architecture/system_tables.md#_pico_peer_address); +- идентификаторы `instance_uuid`, `replicaset_uuid`; - `box.cfg.replication` — ÑпиÑок [адреÑов](../overview/glossary.md#address) Ð´Ð»Ñ Ñ€ÐµÐ¿Ð»Ð¸ÐºÐ°Ñ†Ð¸Ð¸. Получив вÑе наÑтройки, инÑÑ‚Ð°Ð½Ñ Ð¸Ñпользует их в `box.cfg()` (Ñм. -[`init_common()`](#fn-init_common)), и затем Ñоздает в БД группу -`_picodata_peer_address` Ñ Ð°ÐºÑ‚ÑƒÐ°Ð»ÑŒÐ½Ñ‹Ð¼Ð¸ адреÑами других инÑтанÑов. Без -Ñтого инÑÑ‚Ð°Ð½Ñ Ð½Ðµ Ñможет отвечать на ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚ других членов -raft-группы. +[`init_common()`](#fn_init_common)), и затем заполнÑет таблицу +`_pico_peer_address` актуальными адреÑами других инÑтанÑов. Без Ñтого +инÑÑ‚Ð°Ð½Ñ Ð½Ðµ Ñможет отвечать на ÑÐ¾Ð¾Ð±Ñ‰ÐµÐ½Ð¸Ñ Ð¾Ñ‚ других членов raft-группы. По завершении Ñтих манипулÑций инÑÑ‚Ð°Ð½Ñ Ñ‚Ð°ÐºÐ¶Ðµ переходит к Ñтапу `postjoin()`. -### fn postjoin() +### fn postjoin() {: #fn_postjoin } Логика функции `postjoin()` одинакова Ð´Ð»Ñ Ð²Ñех инÑтанÑов. К Ñтому моменту Ð´Ð»Ñ Ð¸Ð½ÑтанÑа уже инициализированы корректные проÑтранÑтва @@ -115,47 +115,52 @@ raft-группы. Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ `postjoin()` выполнÑет Ñледующие дейÑтвиÑ: -- инициализирует HTTP-Ñервер в ÑоответÑтвии Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ `--http-listen`. +- инициализирует HTTP-Ñервер в ÑоответÑтвии Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð¾Ð¼ `--http-listen`; - запуÑкает Lua-Ñкрипт, указанный в аргументе `--script`; - инициализирует узел Raft, который начинает взаимодейÑтвовать Ñ - raft-группой; -- в Ñлучае, еÑли других кандидатов нет, инÑÑ‚Ð°Ð½Ñ Ñ‚ÑƒÑ‚ же - избирает ÑÐµÐ±Ñ Ð»Ð¸Ð´ÐµÑ€Ð¾Ð¼ группы; -- уÑтанавливает триггер `on_shutdown`, который обеÑпечит - [корректное завершение работы инÑтанÑа](#graceful-shutdown). + другими инÑтанÑами клаÑтера; +- в Ñлучае, еÑли инÑÑ‚Ð°Ð½Ñ Ð² клаÑтере вÑего один, он тут же избирает ÑÐµÐ±Ñ + лидером группы; +- уÑтанавливает триггер `on_shutdown`, который обеÑпечит корректное + завершение работы инÑтанÑа. ПоÑледним шагом инÑÑ‚Ð°Ð½Ñ Ð¾Ð¿Ð¾Ð²ÐµÑ‰Ð°ÐµÑ‚ клаÑтер о том, что он готов проходить наÑтройку необходимых подÑиÑтем (репликации, шардинга, и Ñ‚.д.). Ð”Ð»Ñ Ñтого лидеру отправлÑетÑÑ Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° обновление `target_grade` текущего инÑтанÑа до ÑƒÑ€Ð¾Ð²Ð½Ñ `Online`, поÑле чего за дальнейшие дейÑÑ‚Ð²Ð¸Ñ Ð±ÑƒÐ´ÐµÑ‚ -отвечать Ñпециальный поток ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ [topology governor](#topology-governor). +отвечать Ñпециальный поток ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ [topology +governor](../overview/glossary.md#governor). -Как только запиÑÑŒ Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ‹Ð¼ грейдом будет зафикÑирована в Raft, узел -готов к иÑпользованию. +Как только запиÑÑŒ Ñ Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ‹Ð¼ `target_grade` будет применена, Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ +`postjoin` завершаетÑÑ. Сам процеÑÑ Ð¿Ñ€Ð¸ Ñтом оÑтаетÑÑ Ð·Ð°Ð¿ÑƒÑ‰ÐµÐ½ и +продолжает иÑполнÑÑ‚ÑŒ файберы и обÑлуживать Ñетевые запроÑÑ‹. -### fn init_common() +### fn init_common() {: #fn_init_common } Ð¤ÑƒÐ½ÐºÑ†Ð¸Ñ `init_common` обобщает дейÑтвиÑ, необходимые Ð´Ð»Ñ Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ð¸ -инÑтанÑа во вÑех трех вышеопиÑанных ÑценариÑÑ… — `start_discover`, -`start_boot`, `start_join`. +инÑтанÑа во вÑех трех вышеопиÑанных ÑценариÑÑ… — +[`start_discover()`](#fn_start_discover), +[`start_boot()`](#fn_start_boot), [`start_join()`](#fn_start_join). Ð˜Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¸Ð½ÑтанÑа подразумевает Ñледующие шаги: -- Ñоздание `data_dir`; +- Ñоздание директории Ñ Ð´Ð°Ð½Ð½Ñ‹Ð¼Ð¸ инÑтанÑа (из аргумента `picodata run + --data-dir`); - первичный вызов `box.cfg`; -- Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ `package.preload.vshard`; +- Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ð¶ÑƒÑ€Ð½Ð°Ð»Ð° Ñобытий безопаÑноÑти; +- Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Lua модулей `vshard` и `http`; +- Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ€Ð°Ñпределенного SQL; - Ð¸Ð½Ð¸Ñ†Ð¸Ð°Ð»Ð¸Ð·Ð°Ñ†Ð¸Ñ Ñ…Ñ€Ð°Ð½Ð¸Ð¼Ñ‹Ñ… процедур (`box.schema.func.create`); -- Ñоздание ÑиÑтемных таблиц (`_picodata_raft_log` и Ñ‚.д). +- Ñоздание локальных ÑпейÑов `_raft_log` и `_raft_state`; +- Ñоздание [ÑиÑтемных таблиц](../architecture/system_tables.md). Параметры первичного вызова `box.cfg` завиÑÑÑ‚ от конкретного ÑценариÑ: -| param | `start_discover` | `start_boot` | `start_join` | -|-------------|------------------|--------------|-------------------------------| -| listen | None | None | _from args_ | -| read_only | false | false | from `rpc::join` response | -| uuids | _random_ | _given_ | from `rpc::join` response | -| replication | None | None | from `rpc::join` response | -| data_dir | _from args_ | ... | ... | -| log_level | _from args_ | ... | ... | - - +| param | `start_discover` | `start_boot` | `start_join` | +|-------------|------------------|--------------|----------------------| +| listen | None | None | _from args_ | +| read_only | false | false | from `join` response | +| uuids | _random_ | _given_ | from `join` response | +| replication | None | None | from `join` response | +| data_dir | _from args_ | _from args_ | _from args_ | +| log_level | _from args_ | _from args_ | _from args_ | -- GitLab