# Динамическое изменение конфигурации

> Поддержка поэтапного изменения конфигурации etcd во время работы

---

Индекс LLMS: [llms.txt](/ru/llms.txt)

---

etcd поддерживает поэтапное изменение конфигурации во время работы, позволяя
обновлять состав кластера без остановки.

Запросы изменения конфигурации обрабатываются только при работающем большинстве
участников. В производственной среде **настоятельно рекомендуется** кластер
размером более двух. Удалять участника из кластера из двух участников небезопасно:
его большинство также равно двум, поэтому ошибка во время удаления может
остановить кластер и потребовать [перезапуска после потери большинства][majority failure].

Архитектура описана в [документе о динамическом изменении конфигурации][runtime-reconf].

## Сценарии реконфигурации {#reconfiguration-use-cases}

В этом разделе рассмотрены распространённые причины изменения конфигурации.
Обычно это сочетания добавления и удаления участников, описанные в разделе
[Операции изменения конфигурации кластера][cluster-reconf].

### Поочерёдная замена или обновление машин {#cycle-or-upgrade-multiple-machines}

Если несколько участников кластера необходимо переместить из-за запланированного обслуживания (обновления аппаратного обеспечения, простоя сети и т. д.), рекомендуется изменять их по одному.

Лидера можно безопасно удалить, но во время выборов возникнет краткий простой.
Если кластер содержит более 50MB данных v2, рекомендуется
[перенести каталог данных участника][member migration].

### Изменение размера кластера {#change-the-cluster-size}

Увеличение размера кластера может повысить [устойчивость к отказам участников][fault tolerance table] и обеспечить лучшую производительность чтения. Поскольку клиенты могут читать из любого участника, увеличение числа участников увеличивает общую серийную пропускную способность чтения.

Уменьшение размера может ускорить запись ценой отказоустойчивости. До фиксации
запись реплицируется большинству участников; меньшее большинство подтверждает её быстрее.

### Заменить сбойную машину {#replace-a-failed-machine}

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

Для замены [удалите участника][remove member], затем [добавьте нового][add member].
Если кластер содержит более 50MB и каталог отказавшего участника доступен,
рекомендуется [перенести его][member migration].

### Перезапуск кластера после потери большинства {#restart-cluster-from-majority-failure}

При потере большинства или изменении IP-адресов всех узлов требуется ручное
восстановление: [создать новый кластер из старых данных][disaster recovery],
принудительно назначить одного участника лидером, затем по одному
[добавить новых участников][add member].

### Восстановить кластер после миноритарной ошибки {#recover-cluster-from-minority-failure}

Потеря отдельного участника эквивалентна замене отказавшей машины; см.
[Замена отказавшей машины](/ru/docs/etcd/op-guide/runtime-configuration/#replace-a-failed-machine).

## Операции перенастройки кластера {#cluster-reconfiguration-operations}

Для этих сценариев используются следующие операции.

Перед внесением любых изменений должно быть доступно простое большинство (кворум) участников etcd. Это в сущности то же самое требование для любого вида записи в etcd.

Все изменения в кластере должны выполняться последовательно:

* Чтобы обновить peerURLs одного участника, выполните операцию обновления.
* Чтобы заменить одного исправного участника, удалите старого и добавьте нового.
* Для увеличения с 3 до 5 участников выполните две операции добавления.
* Для уменьшения с 5 до 3 выполните две операции удаления.

Во всех примерах используется поставляемая с etcd утилита `etcdctl`. Чтобы
изменить состав без `etcdctl`, используйте [HTTP API участников v2][member-api] или
[gRPC API участников v3][member-api-grpc].

### Обновление участника {#update-a-member}

#### Обновление адресов клиентов для обмена {#update-advertise-client-urls}

Для обновления адресов advertise клиентских URL-ов участника достаточно перезапустить этот участник с флагом (`--advertise-client-urls`) или переменной окружения (`ETCD_ADVERTISE_CLIENT_URLS`) обновленными клиентскими URL-ами. Перезапущенный участник сам опубликует обновленные URL-ы. Неправильно обновленный клиент (URL) не повлияет на состояние здоровья кластера etcd.

#### Обновление анонсируемых адресов пеерконтроллеров {#update-advertise-peer-urls}

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

Для обновления объявляемых URL сначала найдите ID участника. Список выводится командой `etcdctl`:

```sh
$ etcdctl member list
6e3bd23ae5f1eae0: name=node2 peerURLs=http://localhost:23802 clientURLs=http://127.0.0.1:23792
924e2e83e93f2560: name=node3 peerURLs=http://localhost:23803 clientURLs=http://127.0.0.1:23793
a8266ecf031671f3: name=node1 peerURLs=http://localhost:23801 clientURLs=http://127.0.0.1:23791
```

Пример выполняет `update` участника с ID a8266ecf031671f3 и задаёт peerURLs
`http://10.0.1.10:2380`:

```sh
$ etcdctl member update a8266ecf031671f3 --peer-urls=http://10.0.1.10:2380
Updated member with ID a8266ecf031671f3 in cluster
```

### Удалить участника {#remove-a-member}

Предположим, что идентификатор участника для удаления — a8266ecf031671f3. Используйте команду `remove` для выполнения удаления:

```sh
$ etcdctl member remove a8266ecf031671f3
Removed member a8266ecf031671f3 from cluster
```

Целевой участник остановит себя на этом этапе и выведет удаление в лог:

```
etcd: this member has been permanently removed from the cluster. Exiting.
```

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

### Добавление нового участника {#add-a-new-member}

Добавление участника является двухэтапным процессом:

 * Добавьте участника через [HTTP API участников][member-api], [gRPC API участников][member-api-grpc] или `etcdctl member add`.
 * Запустите его с новой конфигурацией кластера и обновлённым списком участников (существующие + новый).

`etcdctl` добавляет участника по его [имени][conf-name] и
[объявляемым URL однорангового узла][conf-adv-peer]:

```sh
$ etcdctl member add infra3 --peer-urls=http://10.0.1.13:2380
added member 9bf1b35fc7761a23 to cluster

ETCD_NAME="infra3"
ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
ETCD_INITIAL_CLUSTER_STATE=existing
```

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

```sh
$ export ETCD_NAME="infra3"
$ export ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
$ export ETCD_INITIAL_CLUSTER_STATE=existing
$ etcd --listen-client-urls http://10.0.1.13:2379 --advertise-client-urls http://10.0.1.13:2379 --listen-peer-urls http://10.0.1.13:2380 --initial-advertise-peer-urls http://10.0.1.13:2380 --data-dir %data_dir%
```

Новый участник будет функционировать как часть кластера и немедленно начнет синхронизироваться с остальными участниками кластера.

При добавлении нескольких участников настраивайте их по одному и проверяйте
запуск. После добавления участника в кластер из 1 узла кластер не продвигается,
пока новый участник не запустится: для консенсуса теперь нужно большинство из
двух. Пауза длится от `etcdctl member add` до успешного соединения нового участника.

#### Добавление нового участника как обучающегося {#add-a-new-member-as-learner}

Начиная с v3.4 etcd поддерживает добавление обучающегося участника без права голоса.
Мотивация и дизайн можно найти в [документе по дизайну][design-learner].
Чтобы сделать процесс добавления нового участника безопаснее,
и снизить время простоя кластера при добавлении нового участника, рекомендуется добавлять новый участник в кластер
как обучающийся до тех пор, пока он не синхронизируется. Это можно описать как трехступенчатый процесс:

 * Добавьте новый участник как обучающийся участника через gRPC members [ API][member-api-grpc] или команду `etcdctl member add --learner`.

 * Запустите нового участника с новой конфигурацией и обновлённым списком участников (существующие + новый).
 Этот шаг не отличается от описанного выше.

 * Промотировать новый добавленный обучающийся до участника с правом голоса через [gRPC members API][member-api-grpc] или командой `etcdctl member promote`.
сервер etcd проверяет запрос на промотацию для обеспечения его оперативной безопасности.
Только после того как лог raft обучающегося участника захватит лог лидера, он может быть промовирован до участника с правом голоса.
Если обучающийся участник не захватил лог лидера, запрос на промотацию участника завершится неудачей
(см. раздел об ошибках при промотации участника для получения дополнительной информации).
В этом случае пользователь должен подождать и повторить попытку позже.

В v3.4 сервер etcd ограничивает количество обучающихся участников, которые может иметь кластер, одним. Основное соображение заключается в ограничении дополнительной нагрузки на лидера при распространении данных от лидера к обучающемуся участнику.

Используйте `etcdctl member add` с флагом `--learner` для добавления нового участника в кластер как обучающегося участника.

```sh
$ etcdctl member add infra3 --peer-urls=http://10.0.1.13:2380 --learner
Member 9bf1b35fc7761a23 added to cluster a7ef944b95711739

ETCD_NAME="infra3"
ETCD_INITIAL_CLUSTER="infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra3=http://10.0.1.13:2380"
ETCD_INITIAL_CLUSTER_STATE=existing
```

После запуска нового процесса etcd для нового добавленного обучающегося участника используйте `etcdctl member promote` для повышения обучающегося участника до голосующего участника.
```
$ etcdctl member promote 9bf1b35fc7761a23
Member 9e29bbaa45d74461 promoted in cluster a7ef944b95711739
```

#### Случаи ошибок при добавлении участников {#error-cases-when-adding-members}

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

```sh
$ etcd --name infra3 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380 \
  --initial-cluster-state existing
etcdserver: assign ids error: the member count is unequal
exit 1
```

В этом случае используйте другую адресацию (10.0.1.14:2380), отличную от той, которая была использована для присоединения к кластеру (10.0.1.13:2380):

```sh
$ etcd --name infra4 \
  --initial-cluster infra0=http://10.0.1.10:2380,infra1=http://10.0.1.11:2380,infra2=http://10.0.1.12:2380,infra4=http://10.0.1.14:2380 \
  --initial-cluster-state existing
etcdserver: assign ids error: unmatched member while checking PeerURLs
exit 1
```

Если etcd начинает использовать данные из директории данных удаленного участника, etcd автоматически завершает работу, если он подключается к любому активному участнику в кластере:

```sh
$ etcd
etcd: this member has been permanently removed from the cluster. Exiting.
exit 1
```

#### Ошибки при добавлении обучающегося участника {#error-cases-when-adding-a-learner-member}

Нельзя добавить обучающегося участника в кластер, если кластер уже имеет 1 обучающегося участника (v3.4).
```
$ etcdctl member add infra4 --peer-urls=http://10.0.1.14:2380 --learner
Error: etcdserver: too many learner members in cluster
```

#### Ошибки при повышении обучающегося участника до участника {#error-cases-when-promoting-a-learner-member}

Обучающегося можно повысить до голосующего участника только после синхронизации с лидером.
```
$ etcdctl member promote 9bf1b35fc7761a23
Error: etcdserver: can only promote a learner member which is in sync with leader
```

Повышение участника, который не является обучающимся, завершится ошибкой.
```
$ etcdctl member promote 9bf1b35fc7761a23
Error: etcdserver: can only promote a learner member
```

Повышение отсутствующего в кластере участника завершится ошибкой.
```
$ etcdctl member promote 12345abcde
Error: etcdserver: member not found
```


### Тщательный режим проверки строгой реконфигурации (`-strict-reconfig-check`) {#strict-reconfiguration-check-mode--strict-reconfig-check}

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

Для предотвращения проблемы etcd предоставляет `-strict-reconfig-check`.
С этим параметром etcd отклоняет изменение конфигурации, если число запущенных
участников станет меньше кворума нового состава.

По умолчанию включено.

[add member]: #add-a-new-member
[cluster-reconf]: #cluster-reconfiguration-operations
[conf-adv-peer]: /ru/docs/etcd/op-guide/configuration#clustering
[conf-name]: /ru/docs/etcd/op-guide/configuration#member
[design-learner]: /ru/docs/etcd/learning/design-learner
[disaster recovery]: /ru/docs/etcd/op-guide/recovery
[error cases when promoting a member]: #error-cases-when-promoting-a-learner-member
[fault tolerance table]: https://etcd.io/docs/v2.3/admin_guide/#fault-tolerance-table
[majority failure]: #restart-cluster-from-majority-failure
[member migration]: https://etcd.io/docs/v2.3/admin_guide/#member-migration
[member-api]: https://etcd.io/docs/v2.3/members_api/
[member-api-grpc]: /ru/docs/etcd/dev-guide/api_reference_v3/
[remove member]: #remove-a-member
[runtime-reconf]: /ru/docs/etcd/op-guide/runtime-reconf-design/
