Кластерный API (MAIN ↔ LB)¶
Балансировщик нагрузки, используемый для прямого доступа к MariaDB и Redis в MAIN: его crons, демонам и
конечные точки потоковой передачи хранили учетные данные панели управления в базе данных и записывали таблицы MAIN. То
cluster API заменяет его одним подписанным зашифрованным HTTP-каналом, который узел открывает для MAIN.
На этой странице представлен протокол и его взгляд на него оператора; проектная документация с каждым
решение и его история - docs/adr/0004-cluster-api.md,
и кодовые швы, через которые проходит каждый вызов, находятся в кластерных швах.
По умолчанию используется обычный HTTP
Для канала не требуется TLS. Каждый запрос подписывается, а его текст шифруется с помощью ключей
производный от токена узла, поэтому панель без сертификата ничего не теряет, общаясь
через http://. HTTPS является необязательным и предпочтительным при проверке сертификата — см.
Транспортировка.
Какие путешествия¶
Узел всегда набирает номер MAIN; MAIN никогда не подключается к узлу (его инструкции ожидают, пока
узел, чтобы запросить их). Каждый вызов равен POST /cluster/v1/<op> на HTTP-широковещательном порту MAIN,
или на cluster_api_port, если он установлен.
| Направление | Переносится как | Примеры |
|---|---|---|
| Узел → ГЛАВНЫЙ, требуется ответ | операция на контрольной полосе | hello, heartbeat, token_refresh, conn_admit, commands, ack |
| Узел → ГЛАВНЫЙ, отчет | операция на линии захвата | events, streams, conn_snapshot, queue_claim, queue_update, queue_enqueue, config, recording_complete, vod_analysis, artefact |
| ГЛАВНАЯ → узел | подписанная команда, которую собирает следующий вызов узла commands |
node.rpc, node.root, node.cache, conn.kill_worker, conn.drop, conn.close, config.changed, artefact.fetch |
Two ops the plan lists are deliberately never served: rpc_result (a command's result comes
back inline with its ack, which takes 64 KiB) and stream_bundle (the replica's streams
раздел содержит всю запись потока, и ошибка кэширования считывает ее с диска). Они остаются в
список операций, потому что из него выводится полоса приема nginx, а API отказывает в операции.
не служит.
Переулки¶
События помещаются в очередь по приоритету и удаляются агентом:
| Переулок | Что | Темп |
|---|---|---|
| Р0 | открытие или закрытие программы просмотра, состояние потока | сразу |
| Р1 | журналы, инвентаризация узла, его аудит | дозированный |
| Р2 | Прикосновения к здоровью | пакетно, только пока MAIN принимает их |
MAIN обслуживает операции управления в пуле cluster_ctl FPM и операции приема в
cluster_ingest, размер которого равен cluster_ingest_concurrency; половина его разрешений зарезервирована для
P0, чтобы поток журналов никогда не задерживал просмотр. Узел, который поступает во время запуска MAIN
отклоняется с STARTING и отсрочкой, но никогда не с 500.
Идентификация¶
В файле нет общего секрета, а в проводнике нет учетных данных на предъявителя.
- Зачисление. MAIN присваивает узлу идентификатор (
node_uuid, пара ключей Ed25519 для узла генерирует сам, закрепленный открытый ключ MAIN) по SSH при установке или с помощью одноразового код, который считывает оператор (cluster:enrol-code, согласован сcluster:enrol-approve). - Жетон отчеканено внутри расширения
xcvm_coreиз корневого секретного файла панели и лицензия, привязанная к uuid узла, поколению и эпохе. Она никогда не существует в PHP как открытый текст: узел получает его, запечатанный своим собственным ключом. - Каждый запрос содержит временную метку, одноразовый номер и HMAC поверх канонического представление запроса с зашифрованным текстом (AES-256-GCM). MAIN отвечает на запрос таким же образом. Хранилище одноразовых данных отклоняет повторный запрос; запрос, время которого отключено отклонение более чем на допустимое отклонение отклоняется.
- Вращение. Время жизни токена равно
lb_token_rotation_min(5-1440, по умолчанию 60). агент обновляется через половину срока службы; отклоненный токен повторно вводит ключ, а не останавливает узел. Отзыв лицензии вообще прекращает чеканку новых токенов, что и является причиной появления флота. огороженный забором.
Транспортировка и конечные точки¶
cluster_transport:
| Ценность | Значение |
|---|---|
auto (по умолчанию) |
Сначала используется HTTPS, когда проверяется собственный сертификат MAIN, в противном случае используется обычный HTTP |
http |
только обычный HTTP |
https_preferred |
Сначала HTTPS, простой HTTP в качестве запасного варианта |
https_required |
Только HTTPS; отказано, если сертификат MAIN не подтвердит, что и каждый активный узел уже подключился к MAIN по протоколу HTTPS (его агент сообщает об этой функции https). |
URL-адреса, которые набирает узел, их порядок и способ передачи - это политика MAIN, версия которой
cluster_policy_ver. Узел принимает политику, которая не старше той, которая у него есть, и
запоминает простые HTTP-URL-адреса каждой политики, которую он видел: под https_required с
сломанный сертификат, вызов подписи по обычному протоколу HTTP - это обратный путь.
При изменении адреса MAIN, его HTTPS-порта или cluster_api_port старая конечная точка продолжает обслуживаться
for seven days so no node is lost; cluster:endpoint list shows what is kept and
cron:cluster освобождает порт, как только каждый узел покидает его.
Политика также учитывает частоту сердечных сокращений флота (lb_telemetry_interval_sec, 1-3 секунды), так что
его изменение распространяется на каждый узел со следующей политикой без перезапуска агента.
Потоки и режимы¶
То, что узел выполняет через API, переключается для каждого узла на странице "Узлы кластера". Поток переносит часть своей работы на агента и отменяет устаревший путь.
| Немного | Поток | Движется |
|---|---|---|
| 1 | ТЕЛЕМЕТРИЯ | статистика сервера: MAIN записывает строку servers из числа ударов сердца |
| 2 | команды | операции удаления, задания кэширования и действия root поступают в виде подписанных команд |
| 4 | бревна | записи о клиенте, потоке, ошибке, действии и по требованию становятся событиями log.* |
| 8 | потоки | потоки узла поступают из его реплики, а его состояние выполнения - из его собственного хранилища |
| 16 | содержание | записи, анализ VOD и очередь кодирования проходят через ОСНОВНЫЕ |
| 32 | конфигурация | кэши узла создаются на основе реплики, а не базы данных MAIN |
| 64 | связи | средства просмотра узла хранятся в реестре его агента |
| 128 | ПЛОСКОСТЬ ДАННЫХ | ретрансляторы и файлы других серверов передаются через петлевой прокси-сервер агента с тикетами вместо секрета потока |
mode - это независимость узла:
| Режим | Имя | Значение |
|---|---|---|
| 0 | наследие | считывает базу данных MAIN, как это было всегда |
| 1 | гибридный | загружается с его копии, все еще может попасть в базу данных MAIN |
| 2 | интерфейс прикладного программирования | каждое подключение к MariaDB или Redis от MAIN отклоняется в коде (LbDatabaseAccessException) |
Перемещение узла вверх ограничено (ClusterAdmin::modeGate()): режим 1 требует настройки; режим 2 требует
every flow, the data plane included, and the node's own connect audit clean — zero MySQL and
нулевое повторное подключение выполняется в течение семи дней. Перемещение вниз всегда разрешено, потому что это способ
back. A crontab row whose role is legacy (today cron:users) is not sent to a node in
режим 2 вообще отсутствует.
Реплика узла¶
Пока включена настройка, кэши узла создаются на основе того, что сохранил агент, а не на основе
запрос. MAIN обслуживает разделы; cluster:apply превращает их в кэши, которые хранятся в узле.
читатели используют (теневое различие перед включением потока, чтобы оператор видел, что изменилось бы):
| Раздел | Носит |
|---|---|
settings |
настройки, которые считывает узел, никогда не являются секретом |
servers |
каждая строка сервера, без учета живучести или телеметрии |
node |
собственная строка узла и настройки его узла |
crontab |
включенные строки, роль которых соответствует режиму узла |
cluster |
ОСНОВНЫЕ URL-адреса, транспорт, сердцебиение, клавиши панели, min_proto |
secrets |
секретный токен просмотра и OPENSSL_EXTRA, каждый со значением, которое он заменил, и как долго это все еще принимается |
bouquets, categories |
как cron:cache строит их |
streams (R2) |
по одной записи на каждый поток, хранящийся на узле, которые сохраняются с помощью дельт и повторной синхронизации; при включенном DATAPLANE его ретрансляционные и файловые запросы также сохраняются |
Ссылка на настройки¶
| Установка | Границы | Что это значит |
|---|---|---|
cluster_api_enabled |
0/1 | весь API; требуется cluster:init и расширение |
cluster_api_port |
0 или 1024-65535 | 0 обслуживает API на HTTP-широковещательном порту MAIN |
cluster_main_host |
имя хоста | DNS-имя MAIN в наборе URL-адресов узлов |
cluster_transport |
смотрите выше | политика |
lb_token_rotation_min |
5–1440 (60) | срок службы токена; благодать равна clamp(L/4, 5, 60) |
lb_revocation_mode |
изящный |трудный | как быстро автопарк останавливается после отзыва лицензии |
lb_telemetry_interval_sec |
1–3 (2) | сердцебиение флота, поддерживаемое политикой |
cluster_offline_after_sec |
10–300 (30) | тишина перед включением MAIN означает, что узел отключен |
cluster_orphan_conn_ttl_sec |
30–3600 (120) | тишина перед тем, как MAIN удалит зрителей узла |
lb_offline_admission |
местный |позволять |отрицать | допуск зрителей, в то время как ГЛАВНАЯ страница недоступна |
cluster_kill_on_line_disable |
0/1 (1) | отключенная, заблокированная или с истекшим сроком действия линия теряет свои сеансы |
cluster_ingest_concurrency |
1–64 (6) | Разрешения MAIN на прием; половина зарезервирована для P0 |
lb_new_node_mode |
наследие |интерфейс прикладного программирования | режим, в котором регистрируется недавно установленный LB |
servers_stats_retention_days |
1–365 (30) | cron:cleanup чернослив servers_stats |
cluster_audit_retention_days |
1–365 (30) | cron:cleanup чернослив cluster_audit |
cluster_db_allowlist (+_extra) |
0/1 | брандмауэры 3306/6379 подключены к сети интернет |
lb_scan_roots |
пути | каталоги, которые может перечислять RPC-сервер сканирования узла |
lb_partition_tolerance_h, lb_fence_drain_min |
0–24 (12), 0–60 (10) | окно аренды после истечения срока действия токена и слив после него |
lb_lease_fence |
0/1 (0) | узел перестает обслуживаться, когда заканчивается срок его аренды |
Управляя им¶
# MAIN, once: create the cluster root and record the panel keys
console.php cluster:init
# Enrol a load balancer over SSH (or at install time, automatically)
console.php server:enrol <serverID>
# Without SSH: a one-time code the operator reads out, then approves by its SAS
console.php cluster:enrol-code <serverID>
console.php cluster:enrol-approve <serverID> <SAS>
# The node's own side, run by its agent after every change
console.php cluster:apply # --from-disk at boot
console.php cluster:exec # one signed command
# MAIN's endpoint and pools
console.php cluster:nginx # render and reload the API's nginx config
console.php cluster:pools # start or resize the API's FPM pools
console.php cluster:endpoint list # old ports and URLs still served
console.php cluster:maintain-stats # servers_stats indexes, built online (cron:cleanup starts it)
# Before switching CONNECTIONS on: load the node's viewers into its agent
console.php cluster:seed-connections <serverID>
# Every node (MAIN too, any mode) keeps the agent, the fanout daemon and xcvm_core
# current from GitHub itself, hourly from cron:root_signals; by hand, as root:
console.php fanout_binary [fanout|agent] [force]
console.php xcvm_core [force]
# Firewall MariaDB and Redis to the fleet (check first)
console.php cluster:db-allowlist status | apply | undo
# Phase 9: a mode-2 node gives up MAIN's credentials (asks first; --wait=<s> waits for the revoke)
console.php cluster:strip-credentials <serverID> [--yes] [--wait=<seconds>]
# MAIN reads other servers' files and relays through its own agent (on | off | rekey | status)
console.php cluster:main-dataplane on
# Rotate the panel's DB password (MAIN), and set it on a node MAIN cannot reach (node, root)
console.php cluster:rotate-db-password [--yes] [--password-stdin]
echo "$NEW_PASSWORD" | console.php cluster:set-db-password
# Disaster recovery of the cluster root
console.php cluster:export-keys /path/bundle
console.php cluster:import-keys /path/bundle
Страница "Узлы кластера" - это место, где узел утверждается, его потоки переключаются, его режим перемещается и
его состояние указано (эпоха, истечение срока действия токена, окно ограждения, которое следует за ним — истечение срока действия токена плюс
lb_partition_tolerance_h, затем lb_fence_drain_min — его команды в очереди, которые были просмотрены в последний раз, агент
версия и архитектура, сбои в настройках, проверка подключения). Предупреждает о завершении действия лицензии.
приостановлено (и, при включенном lb_lease_fence, не позднее, чем к моменту остановки автопарка) и когда
Срок действия сертификата MAIN истекает в течение 14 дней, пока узлы могут подключаться к протоколу HTTPS. На рисунке показаны цифры
ОСНОВНЫЕ записи: выполнение команд и задержка подтверждения (p50/p99 за последний час), глубина очереди, количество
разрешения на использование для каждой полосы, очередь прослушивания пула cluster_ctl и недавний аудит.
* Теперь поменяйте местами все токены * отправляет token.rotate_now каждому активному узлу, который принимает команды.
Сохранение другого ключа активации на панели управления приводит к тому же результату, как только расширение принимает его.
В меню "Строка" списка "Серверы" выполняются те же действия для каждого узла (переключение режимов вверх/вниз, поворот,
регистрационный код, ссылка на потоки узла) и показывает команду cluster:reenrol для запуска
для повторной регистрации по SSH. Каждое решение записывается в cluster_audit, что
cron:cluster чернослив.
Сокращение, для того чтобы¶
cluster:initна ГЛАВНОМ,cluster_api_enabledна,cluster:nginx,cluster:pools.- Зарегистрируйте узел; подтвердите его, если он пришел по коду.
- Переключите ТЕЛЕМЕТРИЮ, затем КОМАНДЫ, затем ЖУРНАЛЫ — все это обратимо и отображается на странице.
- Переключайте ПОТОКИ и КОНТЕНТ; следите за сбоями в настройках узла и его аудитом.
- Измените конфигурацию, затем
mode_upна 1: теперь узел загружается из своей реплики. cluster:seed-connections, затем СОЕДИНЕНИЯ.- ПЛОСКОСТЬ ДАННЫХ, как только родительские узлы и серверы, файлы которых он считывает, являются основными или активные узлы, и его агент запускает ретрансляционный прокси-сервер (страница отказывается от переключения в противном случае): ретрансляция и чтение файлов проходят через его агент при следующем запуске каждого потока.
- Оставьте это на неделю. Когда проверка подключения узла покажет ноль MySQL и ноль Redis
подключается в течение семи дней, с
mode_upпо 2. cluster:db-allowlist applyкак только каждый узел перейдет в режим 2.- Удалить учетные данные базы данных на узле (или
cluster:strip-credentials): имя узлаconfig.encтеряются учетные данные MAIN для DB и Redis, после чего MAIN отзывает свое разрешение. Есть отмена со страницы невозможна: для отката требуется конфигурация с учетными данными и новое разрешение.
Пределы¶
- Уровень данных (фаза 8) охватывает то, что узел извлекает с другого сервера, и только
пока его поток данных включен. Дочерний элемент, передающий поток, выборку VOD или субтитров и
элементы созданного канала проходят через закольцованный прокси-сервер агента (
127.0.0.1:31290), который подписывает каждое восходящее соединение с помощью подписанного панелью тикета из раздела потоков R2 (ретранслятор билет действителен 24 часа, файловый билет - 6 часов, оба чеканятся заново каждые 3 часа и никогда не перемещаются ETag или версию записи) и проверяет каждый фрагмент файла размером 4 МБ на соответствие его владельцу. подписанный дайджест. О чем он не распространяется: - Родитель или владелец, который не может проверить билет (устаревший сервер, не зарегистрирован или нет активен) по-прежнему доступен с помощью устаревшего URL-адреса и пароля к нему, даже при включенном потоке.
- Потоки, запущенные до переключения потока, сохраняют свой URL-адрес до тех пор, пока не будут перезапущены.
- Ретрансляционные байты аутентифицируются только при подключении, а не в рамке: по обычному протоколу HTTP они не имеют целостность (plan, D11). Файлы работают.
- Секрет по-прежнему отображается в собственном цикле обратной связи узла: локальный вывод RTMP
(
rtmp://127.0.0.1/live/<id>?password=) и подключение самописца к своему собственному/admin/liveи/admin/timeshift. - MAIN проходит через это только после того, как оператор запускает
cluster:main-dataplane on: MAIN, затем получает собственный ключ уровня данных и запись в списке подписанных узлов, а также его источник зонд, журнал certbot узла, а также ретрансляторы и файлы потоков, которые он запускает, проходят черезxc_agent run -role main. Выключено (по умолчанию), MAIN сохраняет устаревшие URL-адреса. Ключ MAIN находится в вconfig/cluster/main_agent.json(0600), внеxcvm_core, как это делает узел;cluster:main-dataplane rekeyзаменяет его и поднимает его поколение. - В файловом билете ключ от ячейки владельца указан таким, каким он был при чеканке: владелец повторно зарегистрировался так как не могу открыть его до получения билета следующей эпохи (самое большее через 3 часа).
- Собственное наследие узла
/apiпродолжает обслуживаться при включенном потоке.api_legacy.conf(Фаза второе приращение 8) удаляет его только после того, как ничто не считывает файлы узла с помощью устаревший URL-адресgetFileбольше не используется: его собственный поток, и каждый сервер кластера является основным включен активный узел с включенной плоскостью данных. Значение MAIN засчитывается один раз установлен параметрcluster:main-dataplane on. Прокси-сервер никогда не является узлом, поэтому кластер с прокси-сервером сохраняет значение/apiдля каждого узла. - Поток может быть включен только для узла, агент которого запускает прокси-сервер обратной связи
(при приветствии появляется сообщение
relay): сначала обновитеxc_agent. Агент публикует обратную связь ключ (relay.key) только в том случае, если он содержит127.0.0.1:31290, а PHP узла проверяет что прослушиватель принадлежит владельцу ключа. В то время как порт не принадлежит агенту (удерживается другим пользователем или агент остановлен), сбой ретрансляции узла и чтения файлов и повторяются: они никогда не возвращаются к секрету потока. Агент, который не может связать порт сообщает MAIN при каждом нажатии кнопки: на странице узлов кластера отображается отключенный порт ретрансляции с указывает на ошибку и указывает на нее как наserver:diagnose. Порт для нее не освобожден: оператор находит держатель на узле. /xfileимеет свой собственный лимит скорости (50 запросов в секунду на сервер, пакет 100, на который отвечает 429 повторных попыток агента), не считая 20 запросов зрителей в секунду.cluster:rotate-stream-secretне существует: отмена пароля относится к этапу 9.- Лицензионный договор выдается, проверяется и исполняется только после переключения (фаза 9).
Каждый токен MAIN передает узлу (регистрация по SSH или с помощью кода,
token_refresh,token_rekey) содержит договор аренды, подписанныйxcvm_core, с ограничением вmin(token_exp + lb_partition_tolerance_h, iat + 26 часов); когда расширение отказывает в выдаче лицензии (нет лицензии, ее clock gate, отмененная генерация) токен выходит без него, и происходит отказ для отправка лицензииClusterLicenceLapsedEvent.xc_agentпроверяет каждый полученный договор аренды (подпись панели, ее узел, сервер и генерация, окно для оценки производительности MAIN time), сохраняет самое свежее значение в своем файле состояния и выводит его сxc_agent lease. Ограждение, которое воздействует на него, встроено в PHP узла (Core\Cluster\NodeLease) заlb_lease_fence, что равно по умолчанию выключен: если он включен, то после истечения срока арендыexpновых просмотр начинается с узла (stream/auth.php), а послеlb_fence_drain_minдалее продолжающиеся сеансы останавливаются (segment.php,key.php,live.php), и агент удаляется каждый зритель, которого обслуживает fanout, сам оценивает ту же аренду, часы и настройки. Он оценивает состояние аренды следующим образом: агент записывает данные вconfig/cluster/lease_state.jsonс каждым интервалом времени, независимо от того, not MAIN answers: the lease'sexp, and MAIN's clock carried forward on the node's монотонные часы из последнего аутентифицированного оператора MAIN, поэтому перемещение настенных часов узла не перемещает время MAIN, как считает fence, и перезапуск агента возобновляет его. Каждый причины неопределенности: отключение, устаревший узел, отсутствие файла или файл, который был остановлен агентом обновление, нет аренды, нет привязки к часам MAIN. Переключатель должен быть включен перед получением лицензии сбои — он достигает узла в секции репликиsettings, в которой панель без лицензия не может быть подписана. Если номер узлаxcvm_coreпредлагает ее (cluster_lease_state), то продление срока аренды определяется само по себе — по собственному штифту на панели управления и по якорю на Часы MAIN, которые работают в монотонном режиме и никогда не возвращаются назад, и файл агента это запасной вариант. Тот же вердикт делаетlicense_valid()истинным для узла, так чтоLicenseGateпозволяет использовать разветвление. Вердикт расширения должен соответствовать вердикту узлаcore.pin: установка по SSH закрепляет его за свой собственный сеанс и за любой другой узел, который получает root команды закрепляются символомcron:clusterсо знакомnode.root pin_core(значок core на странице Узлов кластера или Закрепите ядро, чтобы отправить его сейчас). - Частично построена система блокировки учетных данных (фаза 9). Узел в режиме 2 отказывается от основного
учетные данные с подписью
node.root strip_db_credentials(или без учетных данныхnode.root install_config), запускаемыйxcvm_coreот имени пользователя root; когда его ack сообщает о конфигурации без учетных данных MAIN аннулирует разрешение узла (XC_VM::db_revoke) и записываетcluster_nodes.db_revoked_at(Domain\Cluster\DbCredentials). Только оператор отправляет блокировка (Удалить учетные данные базы данных,cluster:strip-credentials) иlb_new_node_mode=apiпо-прежнему отклонено (api_mode_allowedравно false): переход остается решение оператора. Главный узел уже не содержит учетных данных (режим 2 или отозванный грант) остается таким: при переустановке по SSH он получает конфигурацию без учетных данных, повторно регистрируется в режим 2 и не предоставляет ему ничего, и путь к нему не указан (Повторная авторизация MySQL,tools mysql) достигает своего хоста.cluster:rotate-db-passwordизменяет пароль панели управления базой данных черезXC_VM::db_set_passwordи отправляет каждый узел ниже режима 2, который получает root отправляет команду с подписьюnode.root rotate_dbи новым паролем, прикрепленным к ее ячейковому ключу, который открывается его корневой стороной и переходит вXC_VM::config_set_db(меняется толькоdb.pass). Любой другой балансировщик нагрузки, который все еще использует свой грант, сохраняет старый пароль до тех пор, пока оператор запускает на немcluster:set-db-password. Пароль никогда не используется в качестве команды в понятно.cluster:rotate-credentialsтаким же образом изменяет пароль Redis, и также существует руководствоcluster:lockdown(ADR 0004, пятый и седьмой этапы фазы 9). - Секретный токен просмотра может быть * заменен* корректно (значение, которое он заменяет, остается читаемым в течение десяти минут по всему флоту), но полный оборот — повторное шифрование того, что хранится под ним — это фаза 9.
- Имя узла
whitelist_ipsпринадлежит администратору: узел больше не публикует свои собственные адреса, потому что этот столбец предоставляет устаревший список разрешений/api.