telemt/docs/model/MODEL.ru.md

17 KiB
Raw Blame History

Runtime-модель Telemt

Область описания

Документ фиксирует ключевые runtime-понятия пайплайна Middle-End (ME) и оркестрации вокруг него.

Фокус:

  • ME Pool / Reader / Writer / Refill / Registry
  • Adaptive Floor
  • Trio-State
  • Generation Lifecycle

Базовые сущности

ME Pool

ME Pool — центральный оркестратор всех Middle-End writer-ов.

Зона ответственности:

  • хранит инвентарь writer-ов по DC/family/endpoint;
  • управляет выбором writer-а и маршрутизацией;
  • ведёт состояние поколений (active, warm, draining контекст);
  • применяет runtime-политики (floor, refill, reconnect, reinit, fallback);
  • отдаёт сигналы готовности для admission-логики (conditional accept/cast).

Что не делает:

  • не декодирует клиентский протокол;
  • не реализует бизнес-политику пользователя (квоты/лимиты).

ME Writer

ME Writer — долгоживущий ME RPC-канал к конкретному endpoint (ip:port), у которого есть:

  • канал команд на отправку;
  • связанный reader loop для входящего потока;
  • флаги состояния/деградации;
  • метаданные contour/state и generation.

Writer — это фактический data-plane носитель клиентских сессий после бинда.

ME Reader

ME Reader — входной parser/dispatcher одного writer-а:

  • читает и расшифровывает ME RPC-фреймы;
  • проверяет sequence/checksum;
  • маршрутизирует payload в client-каналы через Registry;
  • обрабатывает close/ack/data и обновляет телеметрию.

Инженерный принцип:

  • Reader должен оставаться неблокирующим.
  • Backpressure одной клиентской сессии не должен останавливать весь поток writer-а.

Refill

Refill — механизм восстановления покрытия writer-ов при просадке:

  • восстановление на том же endpoint в первую очередь;
  • восстановление по DC до требуемого floor;
  • опциональные outage/shadow-режимы для хрупких single-endpoint DC.

Refill работает асинхронно и не должен блокировать hotpath.

Registry

Registry — маршрутизационный индекс между ME и клиентскими сессиями:

  • conn_id -> канал ответа клиенту;
  • map биндов conn_id <-> writer_id;
  • снимки активности writer-ов и idle-трекинг.

Ключевые инварианты:

  • один conn_id маршрутизируется максимум в один активный канал ответа;
  • потеря writer-а приводит к безопасному unbind/cleanup и отправке close;
  • именно Registry является источником истины по активным ME-биндам.

Adaptive Floor

Что это

Adaptive Floor — runtime-политика, которая динамически меняет целевое число writer-ов на DC в зависимости от активности, а не держит всегда фиксированный статический floor.

Зачем

Цели:

  • уменьшить churn на idle-трафике;
  • сохранить достаточную прогретую ёмкость для быстрых всплесков;
  • снизить лишние reconnect-штормы на нестабильных endpoint.

Модель поведения

  • при активности floor стремится к статическому требованию;
  • при длительном idle floor может снижаться до безопасного минимума;
  • grace/recovery окна не дают системе "флапать" слишком резко.

Ограничения безопасности

  • нельзя нарушать минимальный floor выживаемости DC-группы;
  • refill обязан быстро нарастить покрытие по запросу;
  • адаптация не должна принудительно ронять уже привязанные healthy-сессии.

Trio-State

Trio-State — контурная роль writer-а:

  • Warm
  • Active
  • Draining

Семантика состояний

  • Warm: writer подключён и валиден, но не основной для новых биндов.
  • Active: приоритетный для новых биндов и обычного трафика.
  • Draining: новые обычные бинды не назначаются; текущие сессии живут до правил graceful-вывода.

Логика переходов

  • Warm -> Active: когда достигнуты условия покрытия/готовности.
  • Active -> Draining: при swap поколения, замене endpoint или контролируемом выводе.
  • Draining -> removed: после drain TTL/force-close политики (или естественного опустошения).

Такое разделение снижает SPOF-риски и делает cutover предсказуемым.

Generation Lifecycle

Generation изолирует эпохи пула при reinit/reconfiguration.

Фазы жизненного цикла

  1. Bootstrap: поднимается начальный набор writer-ов.
  2. Warmup: создаётся и валидируется новое поколение.
  3. Activation: новое поколение становится active после прохождения coverage-gate.
  4. Drain: предыдущее поколение переводится в draining, текущим сессиям дают завершиться.
  5. Retire: старое поколение удаляется по graceful-правилам.

Операционные гарантии

  • нельзя активировать поколение частично без минимального покрытия;
  • healthy-клиенты не должны теряться только из-за появления нового поколения;
  • draining-поколение служит буфером для in-flight трафика во время swap.

Готовность и приём клиентов

Готовность пула не равна "все endpoint полностью насыщены". Типичная стратегия:

  • открыть admission при минимально достаточном alive-покрытии по DC;
  • параллельно продолжать saturation для multi-endpoint DC.

Это уменьшает startup latency и сохраняет выход на полную ёмкость.

Как понятия связаны между собой

  • Generation задаёт эпохи пула.
  • Trio-State задаёт роль каждого writer-а внутри/между эпохами.
  • Adaptive Floor задаёт, сколько ёмкости нужно сейчас.
  • Refill — исполнитель, который закрывает разницу между desired и current capacity.
  • Registry гарантирует корректную маршрутизацию сессий, пока всё выше меняется.

Архитектурный подход

Слоистая модель

Runtime специально разделён на две плоскости:

  • Control Plane: принимает решения о целевой топологии и политиках (floor, generation swap, refill, fallback).
  • Data Plane: исполняет транспорт сессий и пакетов (reader, writer, маршрутизация, ack, close).

Ключевое правило:

  • Control Plane может менять состав writer-ов и policy.
  • Data Plane должен оставаться стабильным и низколатентным в момент этих изменений.

Модель владения состоянием

Владение разделено по доменам:

  • MePool владеет жизненным циклом writer-ов и policy-state.
  • Registry владеет routing-биндами клиентских сессий.
  • Writer task владеет исходящей прогрессией ME-сокета.
  • Reader task владеет входящим парсингом и dispatch-событиями.

Это ограничивает побочные мутации и локализует инварианты.

Обязанности Control Plane

Control Plane работает событийно и policy-ориентированно:

  • стартовая инициализация и readiness-gate;
  • runtime reinit (периодический и/или по изменению конфигурации);
  • проверки покрытия по DC/family/endpoint group;
  • применение floor-политики (static/adaptive);
  • планирование refill и orchestration retry;
  • переходы поколений (warm -> active, прежний active -> draining).

Для него важнее детерминизм, чем агрессивная краткосрочная реакция.

Обязанности Data Plane

Data Plane ориентирован на пропускную способность и предсказуемую задержку:

  • bind клиентской сессии к writer-у;
  • per-frame parsing/validation/dispatch;
  • распространение ack/close;
  • корректная реакция на missing conn/closed channel;
  • минимальный лог-шум в hotpath.

Data Plane не должен ждать операций, не критичных для корректности текущего фрейма.

Конкурентность и синхронизация

Принципы конкурентности

  • Изоляция по writer-у: у каждого writer-а независимые send/read loop.
  • Изоляция по сессии: состояние канала локально для conn_id.
  • Асинхронное восстановление: refill/reconnect выполняются вне пакетного hotpath.

Стратегия синхронизации

  • Для shared map используются короткие и узкие lock-секции.
  • Read-heavy пути избегают длительных write-lock окон.
  • Решения по backpressure локализованы на границе route/channel.

Цель:

  • медленный consumer должен деградировать локально, не останавливая глобальный прогресс writer-а.

Cancellation и shutdown

Reader/Writer loop должны быть cancellation-aware:

  • явные cancel token / close command;
  • безопасный unbind/cleanup через registry;
  • детерминированный порядок: stop admission -> drain/close -> release resources.

Модель согласованности

Согласованность сессии

Для одного conn_id:

  • одновременно ровно один активный route-target;
  • close/unbind операции идемпотентны;
  • потеря writer-а не оставляет dangling-бинды.

Согласованность поколения

Гарантии generation:

  • новое поколение не активируется до прохождения минимального coverage-gate;
  • предыдущее поколение остаётся в draining на время handover;
  • принудительный вывод writer-ов ограничен policy (drain ttl, optional force-close), а не мгновенный.

Согласованность политик

Изменение policy (adaptive/static floor, fallback mode, retries) не должно ломать инварианты маршрутизации уже активных сессий.

Backpressure и управление потоком

Route-level backpressure

Route-каналы намеренно bounded. При росте нагрузки:

  • кратковременный burst поглощается;
  • длительная перегрузка переходит в контролируемую drop-семантику;
  • все drop-сценарии должны быть прозрачно видны в метриках.

Приоритет неблокирующего Reader

Входящий ME-reader path не должен сериализоваться из-за одной перегруженной клиентской сессии. Практически это означает:

  • использовать неблокирующую попытку route в parser loop;
  • выносить тяжёлое восстановление в асинхронные side-path.

Стратегия доменов отказа

Отказ отдельного endpoint

Сначала применяется endpoint-local recovery:

  • reconnect в тот же endpoint;
  • затем замена endpoint внутри той же DC-группы (если доступно).

Деградация уровня DC

Если DC-группа не набирает floor:

  • сервис сохраняется на остаточном покрытии (если policy разрешает);
  • saturation refill продолжается асинхронно в фоне.

Потеря готовности всего пула

Если достаточного ME-покрытия нет:

  • admission gate может временно закрыть приём новых подключений (conditional policy);
  • уже активные сессии продолжают работать, пока их маршрут остаётся healthy.

Архитектурные заметки по производительности

Дисциплина hotpath

Допустимо в hotpath:

  • фиксированный и дешёвый parsing/validation;
  • bounded channel operations;
  • precomputed/low-allocation доступ к данным.

Нежелательно в hotpath:

  • повторные дорогие decode;
  • широкие lock-секции с await внутри;
  • высокочастотный подробный logging.

Стабильность важнее пиков

Архитектура приоритетно выбирает стабильную пропускную способность и предсказуемую latency, а не краткосрочные пики ценой churn и long-tail reconnect.

Правила эволюции модели

Чтобы расширять модель безопасно:

  • новые policy knobs сначала внедрять в Control Plane;
  • контракты Data Plane (conn_id, route/close семантика) держать стабильными;
  • перед дефолтным включением проверять generation/registry инварианты;
  • новые recovery/retry стратегии вводить через явный config-флаг.

Нюансы отказов и восстановления

  • падение single-endpoint DC — штатный деградированный сценарий; приоритет: быстрый reconnect и, при необходимости, shadow/probing;
  • idle-close со стороны peer должен считаться нормальным событием при upstream idle-timeout;
  • backoff reconnect-логики должен ограничивать синхронный churn, но сохранять быстрые первые попытки;
  • fallback (ME -> direct DC) — это переключаемая policy-ветка, а не автоматический признак бага транспорта.

Краткий словарь

  • Coverage: достаточное число живых writer-ов для политики приёма по DC.
  • Floor: целевая минимальная ёмкость writer-ов.
  • Churn: частые циклы reconnect/remove writer-ов.
  • Hotpath: пер-пакетный/пер-коннектный путь, где любые лишние ожидания и аллокации особенно дороги.