--- title: Topology RFC (v3.1) tags: Picodata, RFC --- ## Topology RFC (v3.1) *2022-06-13* *Yaroslav Dynnikov* Мы рассмотрим несколько сценариев работы с кластером. Все они основаны на одном и том же принципе, а сложность деплоя фактически зависит только от сложности самой топологии. [TOC] --- ## Кластер с минимальными усилиями С минимальными, так с минимальными. Обязательных параметров у пикодаты нет совсем. Так что одноинстансовый кластер запускается командой ``` picodata run ``` Запускайте сколько хотите инстансов, кластер будет расти. Каждому инстансу придётся выделить рабочую директорию и `listen` адрес. Фактор репликации по умолчанию равен 1 — каждый инстанс образует отдельный репликасет. ``` picodata run --data-dir i1 --listen :3301 picodata run --data-dir i2 --listen :3302 picodata run --data-dir i3 --listen :3303 ``` > Q: Что, даже peer не надо указывать (для кластера из 3х)? > A: Да, по умолчанию `--peer=127.0.0.1:3301`, прям как дефолтный `--listen` ## Несколько серверов Когда локалхост покорён, самое время запустить пикодату на нескольких серверах. Предположим их два — `192.168.0.1` и `192.168.0.2`. Запускаем: На `192.168.0.1`: ```shell picodata run --listen 0.0.0.0 --advertise 192.168.0.1 ``` На `192.168.0.2`: ```shell picodata run --listen 0.0.0.0 --advertise 192.168.0.2 --peer 192.168.0.1 ``` Во-первых, вместо дефолтного `127.0.0.1` надо указать `--listen=0.0.0.0`. Порт указывать не обязательно (по умолчанию везде используется `:3301`), но для наглядности лучше использовать полноценный формат `<HOST>:<PORT>`. Значение `--listen` не хранится в кластерной конфигурации. Поменять его можно на рестарте. Во-вторых, надо дать инстансам возможность обнаружить друг друга. В параметре `--peer` указываем адрес одного соседа для дискавери. По дефолту `--peer=127.0.0.1:3301`. Параметр `--peer` ни на что, кроме дискавери, не влияет. Параметр `--advertise` сообщает, по какому адресу остальные инстансы должны обращаться к данному. По умолчанию он определяется автоматически как `<HOSTNAME>:<LISTEN_PORT>`. Значение `--advertise` анонсируется кластеру на старте инстанса. Его можно поменять при рестарте или в рантайме командой `picodata set-advertise`. ## Питомцы против стада Чтобы проще было отличать инстансы друг от друга, инстансам можно давать имена: ``` picodata run --instance-id barsik ``` Если имя не дать, оно будет сгенерировано автоматически в момент добавления в кластер. Имя инстанса персистится в снапшотах и не подлежит редактированию. Иметь в кластере два инстанса с одинаковым именем тоже запрещено — второй инстанс получит ошибку при добавлении. Тем не менее, имя можно переиспользовать, если предварительно выгнать инстанс командой `picodata expel barsik`. ## Репликация и зоны доступности (failure domains) Количество реплик настраивается параметром `--init-replication-factor`. Этот параметр играет роль только в момент инициализации кластера. Бутстрап лидер записывает это значение в кластерную конфигурацию (`replication-factor`). В дальнейшем значение `--init-replication-factor` игнорируется. Отредактировать фактор репликации, сохраненный в конфиге кластера, можно командой `picodata set-replication-factor`. Редактирование кластерного конфига сказывается только на новых добавляемых инстансах, но не затрагивает уже работающие. Этот параметр составляет часть конфигурации кластера и обозначает *желаемое* количество реплик в каждом репликасет.е При добавлении инстанса, фактор репликации будет записан в кластерную конфигурацию, но такой сценарий позволяет изменять аго только в сторону увеличения. Уменьшить фактор репликации можно командой `picodata set-replication-factor`, но опять же, с уже работающими инстансами ничего не произойдёт. По мере усложнения топологии встаёт ещё один вопрос — как запретить пикодате объединять в репликасет инстансы из одного датацентра. Понятие датацентра здесь используется только как пример, на самом деле пикодата позволяет использовать любые удобные понятия — регион (`eu-east`), датацентр, стойка, сервер, или придумать свои обозначения (blue, green, yellow). ``` picodata run --replication-factor 2 --failure-domain region=us,zone=us-west-1 ``` Добавление инстанса в репликасет происходит по следующим правилам: - Если в каком-то репликасете количество инстансов меньше необходимого фактора репликации, новый инстанс добавляется в него при условии, что их фейл домены отличаются. - Если подходящих репликасетов нет, пикодата создаёт новый репликасет. Параметр `--failure-domain` играет роль только в момент добавления инстанса в кластер. **Принадлежность инстанса репликасету впоследствии не меняется**. Как и параметр `--advertise`, значение `failure-domain` каждого инстанса можно редактировать - Либо перезапустив инстанс с новыми параметрами. - Либо в рантайме командой `picodata set-failure-domain`. Добавляемый инстанс должен обладать тем же набором ключей, которые уже есть в кластере. Например, инстанс `dc=msk` не сможет присоединиться к кластеру с `--failure-domain region=eu/us` и вернёт ошибку. ## Группы репликасетов Иногда бывает так, что в разных репликасетах хочется использовать разный фактор репликации или ограничить размер хранимых данных. Классический пример — разделение кластера на стораджа и роутеры. Это делается с помощью параметра `--replicaset-group`. По умолчанию инстансы добавляются в неявную группу `"default"`, но пользователь может насоздавать сколько угодно новых, перечислив их в параметре `--available-replicaset-groups`. ```bash export PICODATA_AVAILABLE_REPLICASET_GROUPS=\ "name=storage:replication-factor=3,"\ "name=router:storage-weight=0" ``` Теперь при запуске инстансов можно будет указывать ``` picodata run --replicaset-group router ``` Наличие групп не ограничивает пользователя в создании новых. Как и в случае с `--replication-factor`, новые группы можно добавлять вместе с добавлением новых инстансов. ## Кейс: два датацентра по две реплики Пикодата старается не объединять в один репликасет инстансы, у которых совпадает хотя бы один фейл домен. Но иногда это прямо таки необходимо. Чтобы ограничить пикодату в бесконечном создании репликасетов, можно воспользоваться флагом `--max-replicaset-count` (по умолчанию `inf`). Как и `--replication-factor`, параметр `--max-replicaset-count` можно назначать разным для разных групп репликасетов. Как и другие параметры, `--max-replicaset-count` редактируется в любой момент: - При добавлении нового инстанса - В рантайме командой picodata set-max-replicaset-count Единственное, `--max-replicaset-count` нельзя сделать меньше существующего количества репликасетов. ## Файлы конфигурации Пикодата позволяет передавать параметры из трёх мест (в порядке возрастания приоритета): 1. Файл конфига (yaml / toml) 2. Переменные окружения `PICODATA_<PARAM>=<VALUE>` 3. Аргументы командной строки `--param value` Мы перечислили достаточно много разнобразных параметров, некоторые из которых достаточно развесистые. Пользуйтесь конфигами: <h5 a><strong><code>c1.toml</code></strong></h5> ``` [[available-replicaset-groups]]: name = "storage" max-replicaset-count = 30 replication-factor = 4 [[available-replicaset-groups]] name = "router" storage-weight = 0 ``` ## Ползучие воутеры (raft voter failover) Все рафт ноды в кластере делятся на две роли - воутеры и лёрнеры. За консистентность отвечают только воутеры. Для коммита каждой транзакции требуется собрать кворум из `N/2 + 1` воутеров. Лернеры в кворуме не участвуют. Чтобы сохранить баланс между надёжностью кластера и беззаботностью его эксплуатации, пикодата обладает фишечкой — при смерти одного из воутеров (на которох держится кворум рафта и который терять очень не хочется) роль воутера автоматически передаётся одному из живых инстансов. Переключение происходит незаметно для пользователя. Количество воутеров в кластере не настраивается и зависит только от общего количества инстансов. Если инстансов 1 или 2, воутер один. Если инстансов 3 или 4, то воутера три. Для кластеров от 5 инстансов и больше - пять воутеров. ## Configuration reference > `--cfg <path>` : Read configuration parameters from file (toml / yaml). *env*: `PICODATA_CFG` *default*: *none* `--data-dir` : Here the instance persists all of its data. *env*: `PICODATA_DATA_DIR` *default*: `.` `--listen` : Socket bind address. *env*: `PICODATA_LISTEN` *default*: `localhost:3301` `--peer <[host][:port]>` : Address of other instance(s). *env*: `PICODATA_PEER` *default*: `localhost:3301` `--advertise <[host][:port]>` : Address the other instances should use to connect to this instance. *env*: `PICODATA_ADVERTISE` *default*: `%hostname%:%listen_port%` :hammer_and_wrench:: Если `%listen% == "0.0.0.0"`, то надо подставлять `%hostname%`. Сейчас дефолт всегда просто `%listen%`. `--cluster-id <name>` : Name of the cluster. The instance will refuse to join the cluster with a different name. *env*: `PICODATA_CLUSTER_ID` *default*: `demo` `--instance-id <name>` : Name of the instance. *env*: `PICODATA_INSTANCE_ID` *default*: `i%raft_id%`, e.g. `i1`, `i42`, etc. :hammer_and_wrench:: Надо придумать, как идентифицировать клиентов в батче, если айдишник генерится только при обработке запроса. Ответ - по адвертайзу. `--failure-domain <key=value,...>` : Comma-separated list describing physical location of the server. Each domain is a key-value pair. Until max replicaset count is reached, picodata will never put two instances with a common failure domain in the same replicaset. Instead, new replicasets will e created. They'll be filled with other instances until desired replication factor is satisfied. *env*: `PICODATA_FAILURE_DOMAIN` *default*: *none* :hammer_and_wrench:: Объяснить правила "common failure domain". `--replicaset-group <name>` : Name of the replicaset group. It's an error to run instance with a group changed. *env*: `PICODATA_REPLICASET_GROUP` *default*: `default` :hammer_and_wrench: Зачем это? Без картинки, поясняющей архитектуру кластера, объяснить сложновато . `--init-replication-factor <number>` : Total number of replicas (copies of data) for each replicaset in the current group. *env*: `PICODATA_INIT_REPLICATION_FACTOR` *default*: `1` :hammer_and_wrench: Учитывается только при создании группы. Потом игнорируется. `--init-storage-weight <number>` : Proportional capacity of current instance. Common for each instance in the current group. *env*: `PICODATA_INIT_STORAGE_WEIGHT` *default*: `1` :hammer_and_wrench: Учитывается только при создании группы. Потом игнорируется. `--max-replicaset-count` : Maximum number of replicasets in the current group. *env*: `PICODATA_MAX_REPLICASET_COUNT` *default*: don't modify :hammer_and_wrench: Если меньше текущего размера группы, то игнорируется. Если в текущей группе нет места, то ошибка. Если больше — настройка применяется к текущей группе репликасетов.