Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

☂️ Separate voter role that will help to do failover #148

Closed
sharonovd opened this issue Aug 28, 2019 · 6 comments · Fixed by #604
Closed

☂️ Separate voter role that will help to do failover #148

sharonovd opened this issue Aug 28, 2019 · 6 comments · Fixed by #604

Comments

@sharonovd
Copy link
Contributor

In GitLab by @racktear on Jul 5, 2018, 20:00

There should be a separate voter role that works like this:

  • If master or replica sees that their peer has died (through membership), it asks the voter who should be leader
  • The voter then decides and replies with the decision based on what it sees
  • If master or replica looses connection to the voter, it continues to operate as before
  • If master or replica looses connection to the voter and their peer, it becomes read-only until the voter reappears
  • If cluster configuration has no voter roles, the order of master-slave is decided by lexicographically comparing live node uuids in the replicaset
  • All nodes periodically poll the voter for role changes
@sharonovd
Copy link
Contributor Author

In GitLab by @racktear on Aug 15, 2018, 13:38

removed milestone

@sharonovd
Copy link
Contributor Author

In GitLab by @filonenko-mikhail on Nov 8, 2018, 14:50

What do you think about moving this issue to entrps tracker?

@rosik rosik added the epic label Jan 28, 2020
@rosik
Copy link
Contributor

rosik commented Jan 29, 2020

RFC v1

У каждого инстанса есть две потребности:

  1. Понять, кто в каждом репликасете является лидером;
  2. Вовремя взять на себя роль лидера и переключиться в rw.

Для этого мы добавляем в картридж новую роль координатора фейловера.
Координатор хранит перистентно в спейсах локи - назначения лидеров вида
{replicaset_uuid, leader_uuid, best_before}.

При первом запуске координатор назначает лидерами те инстансы, которые
прописаны в конфиге. Таким образом мы можем предположить, что ни один
репликасет не останется без лидера. При рестарте координатора, он
обновляет таймстемпы имеющихся локов, список лидеров не меняется.

Апи координатора:

function acquire_lock(replicaset_uuid, instance_uuid)
	return true/false
end

function release_lock(replicaset_uuid, instance_uuid)
	return true/false
end

function subscribe()
	-- По пушу рассылает клиентам свежие новости
	box.session.push(active_leaders)
end

@mtrempoltsev
Copy link
Contributor

Я думаю у инстанса ровно 1 потребность - знать мастер он или реплика. Информацию об этом должен рассылать координатор (наоборот делать не надо, чтобы кластер не заспамил координатора и чтобы получать информацию асап). Отсутствие инфы от координатора может означать как проблемы сети, так и отсутствие координатора, но это ок - проявление инициативы здесь чревато, лучше инстансам ее не проявлять. Починку конфигуратора предлагаю пока делегировал админам. Я бы предложил идти инстансу к координатору на старте и регистрироваться у него с инфой следующего характера (replicaset_uuid, instance_uuid), первый подключившийся из репликасета становится мастером.

@rosik
Copy link
Contributor

rosik commented Jan 29, 2020

RFC v2

У каждого инстанса есть две потребности:

  1. Понять, кто в каждом репликасете является лидером;
  2. Вовремя взять на себя роль лидера и переключиться в rw.

Для этого мы заводим две новые сущности - консистентное хранилище
(consul / etcd / свой raft) и король фейловера. Королём может стать
любой инстанс, у которого получится захватить блокировку в хранилище.

Король, получив эксклюзивные права на запись, начинает творить
самоуправство. Он единолично принимает решения по всем репликасетам и
назначает лидеров так, как ему нравится. Свои решения он записывает в
то же самое распределённое хранилище в виде пар {replicaset_uuid, leader_uuid}.

Все остальные инстансы в это время с некоторой периодичностью продолжают
свои попытки захватить корону, на случай если с предыдущим королём
что-то случится.

В свободное от соперничества время инстансы живут своей жизнью и
вынуждены повиноваться приказам короля. После старта каждый инстанс
получает из конфига полный список лидеров и начинает лонгполлить
обновления этого списка. Роли конфигурируются в соответствии с
полученным конфигом.

Алгоритм короля

Первым делом после назначения король выкачивает список лидеров из
хранилища. Вот правила, которыми он руководствуется при принятии
решений:

  1. Для каждой записи король локально хранит её таймстемп.
  2. Первые несколько секунд каждая запись неприкасаема.
  3. Король мониторит мембершип. Если старый лидер дохнет, король
    назначает нового, выбирая наиболее подходящего по приоритету на тот
    момент.
  4. Кололь следит только за сбоями, а восстановления игнорирует.
  5. Преждевременная поломка репликации также расценивается как сбой
    (и также отслеживается через мембершип).

Дополнительно

Я предлагаю всем инстансам запрашивать обновления лидеров не из консула, а с короля. Это позволит избежать переписывания лонгполлинга под каждое хранилище, и принципиально ни на что не влияет. О текущем короле все истансы по-прежнему узнают из хранилища, и авторитарность назначений лидеров не нарушается.

@rosik

This comment has been minimized.

rosik added a commit that referenced this issue Mar 13, 2020
This patch is necessary in context of #148 for upcoming failover changes.

### Failover configuration

 Clusterwide config schema is extended (preserving backward compatibility):

```yaml
# topology.yml
failover: true # old
failover:      # new
  mode: disabled | eventual | stateful
  coordinator_uri: "kingdom.com:4401"
```

Older setting `enabled = true` corresponds to the eventual failover mode as it used to.

### Lua API:
- `cartridge.admin_enable/disable_failover` - **deprecated**, unchanged;
- `cartridge.admin_get_failover` - **deprecated**, unchanged;
- `cartridge.failover_get_params` - added, returns `{mode = ..., coordinator_uri = ...}`;
- `cartridge.failover_set_params({mode = ..., coordinator_uri = ...})` - **added**, returns `true`;

### GraphQL API
- `query {cluster {failover} }` - **deprecated**, unchanged;
- `mutation {cluster {failover(enabled: true/false)} }` - **deprecated**, unchanged;
- `query {cluster {failover_params {mode coordinator_uri} } }` - added;
- `mutation {cluster {failover_params(mode: ..., coordinator_uri: ...) {mode coordinator_uri} } }` - added;

Close #650
@rosik rosik mentioned this issue Mar 17, 2020
3 tasks
@rosik rosik added this to the 2.1.0 (stateful failover) milestone Mar 18, 2020
@rosik rosik changed the title Separate voter role that will help to do failover ☂️ Separate voter role that will help to do failover Dec 29, 2020
@rosik rosik added the epic label Dec 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants