From 39b162439ffb6cd20971692a443d55873acb8d71 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Thu, 8 Oct 2026 17:09:21 +0300 Subject: [PATCH] =?UTF-8?q?doc:=20=D0=B0=D1=80=D1=85=D0=B8=D1=82=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D1=83=D1=80=D0=BD=D1=8B=D0=B9=20=D0=B0=D0=BD=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B7=20=E2=80=94=20=D0=BF=D1=83=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=BD=D1=8B=D0=B9=20SQS,=20=D0=BE=D0=B1=D1=85=D0=BE?= =?UTF-8?q?=D0=B4=20=D1=87=D0=B5=D1=80=D0=B5=D0=B7=20=D0=92=D0=9C,=20?= =?UTF-8?q?=D0=BC=D0=BE=D0=B4=D1=83=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BC?= =?UTF-8?q?=D0=BE=D0=BD=D0=BE=D0=BB=D0=B8=D1=82=20(data-plane/control-plan?= =?UTF-8?q?e)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SQS должен быть публичным (как AWS SQS/YMQ) -> внешний доступ обязателен; - стратегия сети: сейчас публичная точка на ВМ (обход managed-шлюза), позже — девопсам чинить шлюз с доказательствами; - 'без монолитов' уточнено: модульный монолит, критерии разбиения, data-plane vs control-plane, billing/metrics/UI — модули; - ограничение: in-memory stateful-ядро = одиночка, вынос хранилища важнее; - IoT: внешний MQTT-канал неизбежен, крупные тела мимо шлюза; - открытые вопросы. --- .../architecture-analysis-2026-10-08.md | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 doc/thinking/architecture-analysis-2026-10-08.md diff --git a/doc/thinking/architecture-analysis-2026-10-08.md b/doc/thinking/architecture-analysis-2026-10-08.md new file mode 100644 index 0000000..d3d7201 --- /dev/null +++ b/doc/thinking/architecture-analysis-2026-10-08.md @@ -0,0 +1,89 @@ +# Архитектурный анализ размещения и разбиения shared-sqs (2026-10-08) + +**Роль:** архитектор. **Статус:** решения согласованы с владельцем, записаны для исполнения. + +--- + +## 1. Исходные требования (согласовано) + +1. **SQS должен быть полноценным публичным сервисом** — как AWS SQS и Yandex YMQ. + Клиенты ходят к нему снаружи по HTTPS через AWS SDK. Внешний доступ — обязателен, + а не опция. +2. **Без монолитов** — но с уточнением (раздел 3): не «микросервисы ради микросервисов», + а «разные процессы там, где разные требования». +3. **Девопсов не дёргать сейчас** — у них и так заботы. + +## 2. Сетевая стратегия (две беды платформы, обход) + +См. `nubes-large-body-workaround-findings-2026-10-08.md` и +`nubes-workaround-applicability-to-sqs-2026-10-08.md`. + +**Две независимые беды managed-шлюза:** +- A. Большие пакеты/тела не проходят (MSS 1448 при underlay 1450, PMTUD мёртв) — ~51 с; +- B. Таймауты/RST на ЛЮБЫХ телах из-за таймеров шлюза (период 31–33 с; keep-alive 10 в drhider). + +Обе — на стороне платформы, тикет не решает (доказано опытом drhider). + +**Принятая стратегия:** +1. Сейчас — публичная точка входа на **ВМ** (наш nginx, TLS, MTU, keep-alive), минуя + managed-шлюз. Полный контроль, девопсы не нужны. +2. Когда сервис отлажен и появились реальные клиенты — к девопсам с накопленными + доказательствами (tcpdump, период 31–33 с, MSS 1448, опыт drhider), просить чинить + managed-шлюз уже предметно. + +**Уточнение про «в кубере та же хуйня»:** она есть только на пути через managed +ingress извне. Внутри кластера сеть чистая (6–8 мс, без таймаутов). + +## 3. Разбиение: «модульный монолит», а не микросервисы + +Вывод обсуждения: монолит плох там, где смешивает разное; микросервисы — плата +(сеть, распределённые транзакции, оркестрация, дебаг), которая для стадии +«никто не использует, один человек» преждевременна. + +**Критерии, по которым решаем, выносить ли в отдельный процесс:** +1. разный профиль нагрузки/масштабирования; +2. разный жизненный цикл / частота релизов; +3. stateful vs stateless. + +**Целевое разбиение SQS:** + +| Компонент | Отдельный процесс? | Обоснование | +|---|---|---| +| SQS **data-plane** (очереди, сообщения, SigV4) | **да** | горячий путь, stateful, свой профиль | +| **control-plane** (тенанты, креды, очереди, админ) | **да** | редкие операции, другой жизненный цикл и периметр | +| биллинг | модуль внутри | выносить = сеть ради одной горутины, пишущей в PG | +| метрики (Prometheus) | модуль внутри | это эндпоинт, не сервис | +| UI | статика | не сервис | + +## 4. Ограничение, которое разбиение НЕ снимает + +Ядро SQS держит очередь в памяти одного пода (`globals.go` `SyncQueues`, +`redis.go` `LoadAllQueues`). «Не монолит» ≠ «масштабируется»: пока хранилище не +вынесено наружу (чтение тоже из Redis, либо иной сторедж, либо шардирование), +data-plane всё равно одиночка. Это отдельный, более важный вопрос — решать до +набора тенантов. + +## 5. Размещение IoT (для полноты картины) + +- К IoT внешний доступ нужен по определению (устройства). Managed-шлюз в цепочке + IoT неизбежен. +- Но: телеметрия — мелкие MQTT-сообщения, для них критичен только разрыв wss ~150 с + (лечится переподключением — уже реализовано в IoT). +- Большие payload'ы от устройств через MQTT-шлюз **не пускать**: лимит размера, + дробление на уровне протокола, либо приём крупных данных на ВМ с вытягиванием + кластером (схема drhider). +- IoT переделывается с нуля — не монолитом: bridge (MQTT), consumer (→storage), + API отдельными сервисами. + +## 6. Открытые вопросы (ждут решений) + +1. Домен и сертификат для публичной точки SQS на ВМ. +2. Есть ли клиенты без явного `endpoint_url` (влияет на внешние `QueueUrl`). +3. Вынос хранилища data-plane (главный стратегический вопрос) — когда начинаем. +4. Крупные тела у IoT-устройств нужны или только мелкая телеметрия. + +## 7. Следующий шаг + +Подготовить развёртывание SQS на ВМ: разбиение на data-plane и control-plane, +nginx с правильным MTU/keep-alive/TLS, внешние `QueueUrl`. Старт — по команде +владельца.