Перейти к содержанию

Это многостраничная версия текущего раздела для печати. .

Вернуться к обычному виду страницы.

Внутренности

Соглашения по обнаружению, ведению журнала и модулям Go для участников etcd.

1 - Протокол службы обнаружения

Обнаружение других участников etcd на этапе начальной инициализации кластера

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

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

Один новый токен обнаружения предназначен для инициализации одного уникального кластера etcd. Один токен может представлять только один кластер. После запуска протокола для токена его нельзя использовать для инициализации другого кластера etcd, даже если первый процесс завершился с ошибкой на полпути.

Далее процесс обнаружения рассматривается на примере самостоятельно размещённого кластера обнаружения.

Этот документ относится только к обнаружению v3. Обнаружение v2 подробнее описано в предыдущем документе .

Рабочий процесс протокола

Протокол использует внутренний кластер etcd для координации начальной инициализации нового кластера. Сначала все новые участники взаимодействуют со службой обнаружения и совместно формируют ожидаемый список участников. Затем каждый участник запускает свой сервер с этим списком, что выполняет ту же функцию, что и флаг -initial-cluster.

В примере ниже каждый шаг показан с помощью команды etcdctl. Предполагается, что на http://example.com:2379 работает кластер etcd, обслуживающий службу обнаружения.

По соглашению протокол обнаружения etcd использует префикс ключей /_etcd/registry.

Создание нового токена обнаружения

Создайте уникальный токен, идентифицирующий новый кластер. На следующих шагах он будет уникальным префиксом в пространстве ключей обнаружения. Простой способ создать токен — использовать uuidgen:

UUID=$(uuidgen)

Указание ожидаемого размера кластера

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

etcdctl --endpoints=http://example.com:2379 put /_etcd/registry/${UUID}/_config/size ${cluster_size}

Обычно размер кластера равен 3, 5 или 7. Подробнее см. в разделе оптимального размера кластера .

Запуск процессов etcd

Передайте токен обнаружения ${UUID} флагу --discovery-token, а конечные точки кластера etcd, обслуживающего службу обнаружения, — флагу --discovery-endpoints. Это включает обнаружение v3 для начальной инициализации кластера etcd.

Если заданы флаги --discovery-token и --discovery-endpoints, каждый процесс etcd выполняет следующие шаги автоматически.

Если служба обнаружения использует аутентификацию по клиентским сертификатам, настройте следующие флаги. Они применяются так же, как при обращении etcdctl к кластеру etcd.

--discovery-insecure-transport
--discovery-insecure-skip-tls-verify
--discovery-cert
--discovery-key
--discovery-cacert

Если служба обнаружения использует ролевую аутентификацию, настройте следующие флаги. Они применяются так же, как при обращении etcdctl к кластеру etcd.

--discovery-user
--discovery-password

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

--discovery-dial-timeout
--discovery-request-timeout
--discovery-keepalive-time
--discovery-keepalive-timeout

Саморегистрация

Сначала каждый процесс etcd регистрирует себя как участника нового кластера. Для этого ID участника создаётся как ключ в полном ключе реестра.

etcdctl --endpoints=http://example.com:2379 put /_etcd/registry/${UUID}/members/${member_id} ${member_name}=${member_peer_url_1}&${member_name}=${member_peer_url_2}

Проверка состояния

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

etcdctl --endpoints=http://example.com:2379 get /_etcd/registry/${UUID}/_config/size
etcdctl --endpoints=http://example.com:2379 get /_etcd/registry/${UUID}/members

Если зарегистрированных участников пока недостаточно, процесс ожидает появления остальных.

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

Участник может проверить состояние кластера ещё до саморегистрации, поэтому при заполненном кластере отказ произойдёт быстро.

Ожидание всех участников

Процесс продолжает наблюдать за префиксом ключей /_etcd/registry/${UUID}/members, пока не найдёт всех участников.

etcdctl --endpoints=http://example.com:2379 watch /_etcd/registry/${UUID}/members --prefix

2 - Соглашения по ведению журнала

Категории уровней ведения журнала

etcd использует библиотеку zap для ведения журнала вывода приложения, категоризированного по уровням. Уровень сообщения в журнале определяется в соответствии со следующими соглашениями:

  • Логи DebugLevel обычно объёмные и обычно отключены в рабочей среде.

    • Примеры:
      • Отправка обычного сообщения удалённому узлу
      • Запись записи журнала на диск
  • Уровень InfoLevel является уровнем ведения журнала по умолчанию.

    • Примеры:
      • Конфигурация при запуске
      • Начало создания снимка
      • Добавление нового узла в кластер
      • Добавление нового пользователя в подсистему аутентификации
  • Журналы уровня Warn более важны, чем Info, но не требуют индивидуального человеческого контроля.

    • Примеры:
      • Неудача при отправке сообщения Raft удалённому узлу
      • Неудача при получении сообщения heartbeat в течение заданного тайм-аута выборов
  • Журналы уровня ошибок имеют высокий приоритет. Если приложение работает без сбоев, оно не должно генерировать журналы уровня ошибок.

    • Примеры:
      • Неудача выделения дискового пространства для WAL
  • PanicLevel записывает сообщение, а затем вызывает панику.

    • Примеры:
      • Сбой при кодировании сообщений Raft
  • FatalLevel записывает сообщение, а затем вызывает os.Exit(1).

    • Примеры:
      • Неудача при сохранении снимка Raft

3 - Модули Golang

Организация модулей Golang проекта etcd

Начиная с версии 3.5 проект etcd организован как несколько модулей Golang , размещённых в одном репозитории .

Граф модулей

Проект включает следующие модули:

  • go.etcd.io/etcd/api/v3 — определения API, например protos и созданные из proto библиотеки, которые задают протокол взаимодействия между клиентами и сервером etcd.

  • go.etcd.io/etcd/pkg/v3 — набор вспомогательных пакетов, используемых etcd, но не зависящих от его специфики. Пакет следует размещать здесь только в том случае, если в будущем его можно будет вынести в отдельный репозиторий. Не добавляйте сюда код с большим числом собственных зависимостей: они автоматически станут зависимостями клиентской библиотеки, которую важно сохранять легковесной.

  • go.etcd.io/etcd/client/v3 — клиентская библиотека для сетевого обращения к etcd по grpc. Рекомендуется для всех новых применений etcd.

  • go.etcd.io/etcd/client/v2 — устаревшая клиентская библиотека для обращения к etcd по протоколу HTTP. Новые проекты должны зависеть от библиотеки /v3.

  • go.etcd.io/etcd/raft/v3 — реализация протокола распределённого консенсуса. Не должна содержать код, специфичный для etcd.

  • go.etcd.io/etcd/server/v3 — реализация etcd. Код этого пакета является внутренним и не предназначен для внешних проектов. Структура пакета и API могут меняться между минорными версиями.

  • go.etcd.io/etcd/etcdctl/v3 — инструмент командной строки для доступа к etcd и управления им.

  • go.etcd.io/etcd/tests/v3 — модуль со всеми интеграционными тестами etcd. Обратите внимание: все модульные тесты — быстрые и не требующие межмодульных зависимостей — должны храниться в локальном модуле рядом с тестируемым кодом.

  • go.etcd.io/bbolt — реализация постоянного b-tree. Размещается в отдельном репозитории: https://github.com/etcd-io/bbolt .

Операции

  1. Все модули etcd должны выпускаться с одинаковыми версиями; например, go.etcd.io/etcd/client/v3@v3.5.10 должен зависеть от go.etcd.io/etcd/api/v3@v3.5.10.

    Согласованно обновить версии можно командой:

    % DRY_RUN=false TARGET_VERSION="v3.5.10" ./scripts/release_mod.sh update_versions
  2. Выпущенные модули должны получать теги по правилам https://golang.org/ref/mod#vcs-version , то есть каждому модулю требуется собственный тег. Создать теги можно командой:

    % DRY_RUN=false REMOTE_REPO="origin" ./scripts/release_mod.sh push_mod_tags
  3. Все модули etcd должны зависеть от одинаковых версий базовых зависимостей. Это проверяется командой:

    % PASSES="dep" ./test.sh
  4. Файлы go.mod не должны содержать неиспользуемых зависимостей и должны соответствовать формату go mod tidy. Проверка выполняется командой:

    % PASSES="mod_tidy" ./test.sh
  5. Для запуска действий во всех модулях, например автоматического форматирования всех файлов, используйте или расширьте следующий скрипт:

    % ./scripts/fix.sh

Будущее

В качестве целевой модели предлагается развивать модули etcd следующим образом:

Будущий граф модулей

Предполагается:

  • Вынести etcdmigrate/etcdadm из бинарного файла etcdctl. Тогда etcdctl станет однозначной оболочкой командной строки над сетевым клиентским API, а etcdmigrate/etcdadm будет выполнять прямые физические операции с файлами хранилища etcd.
  • Вынести etcd-proxy из бинарного файла ./etcd: он содержит больше экспериментального кода, а значит несёт дополнительные риски и зависимости.
  • Прекратить поддержку протокола v2.