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

Кластерные швы

ОСНОВНОЙ план ↔ LB API (docs/superpowers/specs/2026-09-21-main-lb-api-communication-design.md) заменяет прямой доступ узла к MySQL и Redis в MAIN на подписанный API. Фаза 0 подготавливает код без изменения какого-либо поведения. В каждом месте, где узел достигает главного состояние, и каждое место, где MAIN достигает узла, проходит через один класс. У каждого класса есть один современный сервер, устаревший, который делает именно то, что раньше делали сайты вызовов. На более поздних этапах замените этот сервер и оставьте сайты вызовов в покое.

Каждый шов снабжен крючком для проверки и последующей транспортировки (useSink(), useLoader() или useTransport()). Передача null восстанавливает устаревшую серверную часть.

Узел → ГЛАВНЫЙ

Шов Обертывания Устаревший сервер Серверная часть API (фаза)
Core\Cluster\SignalDispatcher 47 INSERT INTO signals сайтов (удаление, задания кэширования, действия root) LegacySqlSignalSink команды и события (4/5)
Domain\Stream\StreamStateWriter состояние выполнения узла в streams_servers; отклоняет любой столбец за пределами STATE_FIELDS StreamRowMerge::apply() stream.state событие (5), хранящееся в собственном хранилище узла (Core\Cluster\StreamRuntime, 7)
Domain\Stream\StreamSource строка потока, строка этого узла streams_servers, параметры потока и запись, считываемые перед запуском потока или записи; поток со строкой этого узла и его состоянием во время выполнения (nodeRow(), workerRow(), plainRow(), createdRow(), builtServerRow(), channelRow(), movieRow()) SQL кэширование потоков узла, созданное cluster:apply из раздела R2 streams, как только поток запущен (ReplicaStreamCache, 7), с состоянием выполнения из собственного хранилища узла, как только оно заполнено (StreamRuntime, 7); stream_bundle при ошибке (не создано)
Domain\Stream\NodeStreams списки потоков этого узла выбираются его администраторами и демонами в зависимости от их состояния во время выполнения (cron:streams, cron:vod, cron:cleanup, демон по требованию) SQL кэширование потока и собственное хранилище узла или весь раздел R2 (ReplicaStreams) для списков cron:cleanup сокращает файлы на (7)
Core\Cluster\LogSink записи о клиенте, потоке, ошибке потока, ошибке панели управления и повторном обнаружении потока; строки системного журнала root (syslog()) одна многострочная ВСТАВКА в пакет (по 1000 фрагментов); собственная ВСТАВКА вызывающего устройства mysql_syslog log.* события, отредактированные первыми (5); log.syslog (7)

ОСНОВНАЯ сторона

Шов Роль
Domain\Stream\StreamRowMerge Объединяет состояние выполнения узла только в строке этого узла. eventFields() сохраняет только столбцы времени выполнения и редактирует URL-адрес источника.
Domain\Stream\StreamCacheBuilder Запись в кэше stream_<id>: столбцы, строки для каждого сервера и правило, согласно которому URL-адреса источника потока не попадают в кэш, если только это не прямой источник. cron:cache_engine, который запускается только в MAIN, создает его с помощью этого класса.
Core\Cluster\Redactor Удаляет значения password=, token= и username=, сегменты /user/pass/ URL-адресов Xtream и user:pass@ из текста перед его записью в журнал.

ГЛАВНАЯ → узел

Шов Обертывания Каталог Форма API (фаза 4)
Core\Cluster\NodeRpc ApiClient::systemRequest() / asyncRequest(): запросы/ответы на запросы узла /api NodeRpc::ACTIONS node.rpc{action}, ответ через ack / rpc_result
Core\Cluster\NodeActions действия root для RootSignalsCronJob: перезагрузка, службы, обновление/откат, порты, sysctl, certbot, модули, очистка списка блокировок, OPENSSL_EXTRA, а также действия с учетными данными, ключами и pin-кодом, которые выполняются только через cluster API NodeActions::ROOT_ACTIONS node.root{action} для cluster:root, с предоставлением артефакта, когда для действия требуется файл MAIN's

Оба оператора отказываются выполнять действие, которого нет в их каталоге, поэтому новый вызов - это намеренное изменение. NodeRpcActionsTest проверяет, использует ли каждый узел вызова каталогизированное действие RPC и что RootSignalsCronJob обрабатывает каждый каталогизированный корень действие.

Правила для нового кода

  • Не записывайте INSERT INTO signals, UPDATE streams_servers (для состояния выполнения), или ВСТАВЬТЕ непосредственно в таблицу журнала; используйте шов.
  • Не вызывайте ApiClient::systemRequest() / asyncRequest() или SignalDispatcher::rootAction() за пределами Core\Cluster; добавьте действие в внесите в каталог и используйте NodeRpc / NodeActions.
  • Код на стороне узла считывает определения потоков через StreamSource, а не с помощью его собственные запросы к streams, streams_options или recordings. Как только узел будет реплика владеет потоками (ПОТОКИ продолжаются), ее ответы поступают из потока созданные кэши cluster:apply, но никогда из базы данных MAIN. Поток, считанный с состояние выполнения этого узла (объединенная строка streams ⨝ streams_servers или список, отфильтрованный по pid или stream_status) проходит через StreamSource или NodeStreams тоже: с StreamSource::local() (реплика владеет потоки и заполняется собственное хранилище узла StreamRuntime) во время выполнения колонки поступают из этого хранилища, в котором авторы ведут стримы, и в seam сохраняется инструкция MAIN для всего остального. Не подключайте повторно MAIN's database in a daemon where StreamSource::local() holds. A столбец времени выполнения MAIN записывает сам себя для этого узла, который попадает только в это хранилище где код узла также сохраняет его (диктофон сохраняет основной VOD, подключенный к узел для законченной записи).
  • Код на стороне узла считывает настройки через SettingsManager получатели и серверы через ServerRepository. Узел в режиме 2 или в режиме 1 с конфигурацией поток продолжается, загружается из своей реплики (ReplicaStage), как только приложение построит свою кэши: они поступают из кэшей реплики, и открывается любой другой запрос База данных MAIN загружается лениво, при первом использовании. Режим 1 открывает ее, подсчитанный на сайт запроса; режим 2 отклоняет его. Точки входа в потоковую передачу используются те же отложенный дескриптор (LegacyInitializer::initStreaming). На узле в режиме 1 или 2, клавиша настройки, расположенная за пределами lb_settings_keys.php, засчитывается как пропущенная (SettingsAudit) и отображается в меню Серверы → Узлы кластера.
  • Не открывайте базу данных MAIN до того, как это потребуется для запроса. Подключение при загрузке или при вершина точки входа засчитывается в семидневный нулевой показатель узла режима 1. когда запрос завершается без запроса. Когда реплика может не ответить (ReplicaBoot::hybrid(): режим 1, в котором никогда не происходит отказа в подключении), прочитайте База данных MAIN работает с отложенным дескриптором, а не с новым. Чтобы узнать, работает ли База данных MAIN отвечает на запрос: значение ленивого дескриптора connected остается ложным до его первого запроса (StatusCommand::mainDatabaseAnswers()).
  • Не записывайте new DatabaseHandler(). Возьмите дескриптор процесса (DatabaseAware, DatabaseFactory::get()), или DatabaseFactory::connect(), connectLazy() или open(). Каждое подключение к MySQL или Redis в MAIN проходит ConnectAudit::guard(): на узле в режиме 1 или 2 он подсчитывается с учетом его вызывающий и отображается на Серверах → Узлах кластера, а в режиме 2 он выдает LbDatabaseAccessException. Не открывайте соединения PDO, \Redis или mysqli ваш собственный код, который запускает подсистема балансировки нагрузки.
  • Узел в режиме 2 (NodeRole::refusesConnects()) никогда не возвращается к ОСНОВНОМУ база данных. Запись с использованием пути к агенту сначала проходит через свой шов (LogSink, LogSink::syslog() для строк системного журнала root, NodeStateSink), и корневое действие выполняется после своей строки журнала, что бы ни случилось с этой строкой (строка, которую не выполнил агент, остается в журнале ошибок панели). Действие которым все еще нужна база данных MAIN, в режиме 2 отказано заранее (RootSignalsCronJob::updatesHere() для update и rollback). Работа, для которой требуются данные MAIN, но которые еще не перенесены ни в один раздел реплики, пропускается в режим 2 за именованным швом (CleanupCronJob::streamChecks(), который содержит как только реплика и собственное хранилище узла ответят), никогда не сталкивайтесь с пустой или неполный ответ. Запись о состоянии потока, которую агент не выполнял, остается в собственном хранилище узла в режиме 2 (StreamStateWriter::resend() отправляет его позже) вместо возврата к основному ряду; в режимах 0 и 1 он возвращается обратно, и хранилище перестает работать, как только оно появляется в строке MAIN (StreamRuntime::lapse()).
  • Файл, который требуется узлу от MAIN (пользовательское видео вне эфира, архив модуля) является артефактом: MAIN называет его в Domain\Cluster\ArtefactRegistry и предоставляет его с помощью подписанной команды (ArtefactGrants), и узел использует его только один раз Core\Cluster\ArtefactStage проверил его размер и SHA-256 на соответствие grant, так как он копирует его туда, где он находится. используется (собственный этап root для действия root). Не добавляйте извлечение из MAIN с помощью путь, URL-адрес или пароль.
  • Работа MAIN для узла проходит через SignalDispatcher и NodeActions, никогда строка signals, написанная от руки: узел в режиме 2 не считывает ни одного. Там ОСНОВНОЕ отправляет задания кэширования в виде команд node.cache в форме CacheJobs::job(), узел сразу запускает задания, которые он ставит в очередь для себя, и значение, считанное узлом обратно из своей собственной строки в базе данных MAIN поступает из копии NodeStateSink сохраняет то, о чем он сообщал (NodeStateSink::reported()).
  • Файлы аудита узла (storage/cluster/, config/cluster/audit.json) хранятся в где xc_vm может записывать. Корневой процесс записывает их только внутри SettingsAudit::asAgentUser(), который выполняет работу как xc_vm, никогда с собственные права root.

Тесты, подтверждающие эти правила: SignalDispatcherParityTest, StreamStateWriterTest, StreamRowMergeTest, StreamCacheBuilderSourceTest, LogSinkTest, NodeRpcActionsTest, ArchitectureTest, DbConnectRefusalTest, ReplicaBootTest, ModeTwoPathsTest, ArtefactHashRefusalTest, StreamRuntimeTest и StreamRuntimeReadersTest.