Files
SQS-service/doc/thinking/nubes-workaround-applicability-to-sqs-2026-10-08.md
T
Repinoid d8bdea75f3 doc: разбор применимости обхода drhider к SQS (прокси на ВМ, pull вместо push)
- почему схему 1:1 скопировать нельзя (клиенты на AWS SDK, синхронный протокол) ->
  аналог: прозрачный прокси на ВМ;
- условия: сохранение Host для SigV4 (auth_middleware.go:315-317), внешние QueueUrl
  (сейчас http://region.host:port из goaws.yaml, tenant_helpers.go:29-37),
  TLS, доступ ВМ->кластер, отключение буферизации;
- 4 варианта с оценкой (прокси / настройки ingress / MTU / ретраи) и таблица
  'что какой лечит';
- обязательные замеры до решения (раздел 5) и открытые вопросы.
2026-10-08 16:51:45 +03:00

139 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Применимость обхода из drhider к shared-sqs (разбор)
**Дата:** 2026-10-08
**Основание:** `nubes-large-body-workaround-findings-2026-10-08.md` (находки из `~/nubes/drhider`).
**Статус:** анализ. **Ничего ещё не внедрено** — сначала замеры (см. раздел 5).
---
## 1. Почему нельзя скопировать схему 1:1
В drhider обе стороны протокола — свои (браузер + своё приложение на Flask),
поэтому туда встроили двухшаговый протокол: `PUT` файла на ВМ-буфер → `POST`
ссылки в кластер → исходящий `GET` (pull).
В shared-sqs **обе стороны чужие по протоколу**: клиенты — сторонние приложения
с AWS SDK (подпись SigV4), протокол SQS синхронный (запрос → ответ). Вставить
«положите тело на буфер, пришлите ссылку» нельзя без изменения клиентов и потери
совместимости с AWS SDK.
→ Прямой аналог буфера в SQS — **прозрачный обратный прокси на ВМ**, а не буфер
и не хранилище. Данные идут потоком, протокол не меняется.
## 2. Что именно болит у shared-sqs (наши факты)
| Явление | Причина по нашим документам | Источник |
|---|---|---|
| A. Большие тела (>~1.4 КБ) виснут ~51 с | MSS, анонсируемый шлюзом = 1448; MTU пода 1400, underlay 1450 → сегменты 1488 дропаются при DF; PMTUD мёртв (ICMP не доходит) | `nubes-ticket.md:11-13` |
| B. Малые тела (512 Б) — `ReadTimeout` 30 с с периодом 31–33 с | таймер на ВНЕШНЕМ шлюзе; доказано tcpdump: запросы не доходят до пода, nginx чист, Cilium 0 дропов | `nubes-ticket.md` (явление B), HANDOFF |
Что уже проверено ранее:
- **внутри кластера** — проблем нет; **с ВМ (5.172.178.213) p50 = 6–8 мс, таймаутов нет**;
- **MTU пода уже 1400** — то есть тот фикс, который помог drhider (1500→1400), у нас
**уже применён**, а явление A осталось: причина в MSS-анонсе шлюза, а это вне
нашего контроля (`nubes-ticket.md:16-17`);
- лимит SQS — тело ≤ 262144 Б (256 КБ), т.е. большие тела легальны и попадают
ровно в проблемную зону.
## 3. Варианты, применимые к SQS
### Вариант 1 (основной) — публичная точка входа на ВМ-прокси
Схема: `клиент (AWS SDK) → HTTPS на ВМ → nginx (ВМ) → под shared-sqs в кластере`.
Убираем из пути внешний шлюз платформы. Основания:
- путь «интернет → ВМ» в drhider держал тела 63 КБ и 5 МБ **успешно**
(`PROBLEM-AND-SOLUTION.md`), то есть у ВМ нет той патологии, что у шлюза кластера;
- путь «ВМ → кластер» у нас измерен: 6–8 мс, таймаутов нет.
**Технические условия (важные, иначе не заработает):**
1. **SigV4 подписывает заголовок `Host`.** nginx обязан передавать внешний хост:
`proxy_set_header Host $host;`. Сервис берёт хост именно из запроса —
`auth_middleware.go:315-317` (`canonicalHeaderValue`: `name == "host"` → `r.Host`).
Подменять Host на внутренний (например, на служебное имя сервиса) **нельзя** —
подпись перестанет сходиться, клиент получит `SignatureDoesNotMatch`.
2. **URL очередей сейчас жёстко внутренние и без TLS.** `tenantQueueURL`
(`tenant_helpers.go:29-37`) формирует `http://{region}.{host}:{port}/{tenantID}/{queue}`.
Хост и порт читаются **только из `goaws.yaml`** (`conf/config.go:87-90`; в
`applyEnvironmentDefaults` env-переменных для Host нет). Следствия:
- клиенты, которые сами задают `endpoint_url` (все наши тесты), берут из
`QueueUrl` только путь — они не пострадают;
- клиенты **без** `endpoint_url` пойдут на хост из `QueueUrl` → обязаны получить
внешний адрес. Значит: либо (а) подставляем внешний хост/схему в конфиг, либо
(б) nginx переписывает `QueueUrl` в ответах (хрупко), либо (в) требуем от
клиентов явный `endpoint_url`.
3. **Транспорт.** Схема `http://` в URL — при переносе на ВМ либо оставляем
`http` (нежелательно для интернета), либо переводим на `https` и правим
формирование URL. Для TLS нужен сертификат на ВМ-домен.
4. **Доступ ВМ → кластер.** ВМ вне кластера; понадобится NodePort/VIP (или
опубликованный внутренний адрес). Путь ВМ→кластер нужно замерить (см. раздел 5).
5. **Проксирование тел** — без буферизации на диск: `proxy_request_buffering off`,
`client_max_body_size` ≥ 256 КБ (+ запас).
### Вариант 2 — настройки ingress через `ShturvalServiceConfig`
В drhider этим вылечили RST (`keep-alive: 10` → `75`), подняли
`proxy-body-size: 1024m`, выключили HTTP/2, подняли `client-body-timeout: 60`.
Правки делаются **только через `ShturvalServiceConfig`** — kubectl откатывает ArgoCD
(`PROBLEM-AND-SOLUTION.md`).
Оценка для нас: **скорее всего не поможет**. Наш таймер (явление B) доказанно
находится **вне кластера** (tcpdump: запросы не доходят до пода; nginx чист), а
MSS-анонс делает **внешний шлюз**. Но правка дешёвая и безопасная → имеет смысл
проверить замером «до/после», прежде чем строить прокси.
### Вариант 3 — MTU-фикс
**Уже сделан** (MTU пода 1400). Явление A не убрал — так как причина в шлюзе.
Для SQS этот путь закрыт.
### Вариант 4 — клиентские ретраи (+ идемпотентность)
Маскирует явление B, **не решает** явление A (51 с ожидания при большом теле).
Для standard-очередей ретрай без идемпотентности даёт дубли (FIFO-дедуп по
`MessageDeduplicationId` у нас есть, для standard — нет). Годится как временная
мера, не как решение.
## 4. Сводка: что какой вариант лечит
| Вариант | Явление A (большие тела) | Явление B (таймер) | Стоимость/риск |
|---|---|---|---|
| 1. Прокси на ВМ | да (по аналогии с drhider) | да (шлюз вне пути) | TLS, Host, внешние URL, доступ ВМ→кластер |
| 2. Настройки ingress | вероятно нет | вероятно нет | низкая; нужен доступ к платформенному конфигу |
| 3. MTU | нет (уже 1400) | нет | — |
| 4. Ретраи клиентов | нет | частично | дубли для standard |
## 5. Что обязательно замерить ДО решения
Правило проекта: рекомендация без замера — догадка. Замеры на том же хосте и тем
же инструментом:
1. **С ВМ → внешний endpoint кластера**: тела 1 КБ / 10 КБ / 100 КБ / 256 КБ —
есть ли ~51 с? (Малые тела с ВМ проверены: 6–8 мс, таймаутов нет; большие, судя
по всему, отдельно не мерили.)
2. **ВМ → кластер (NodePort/VIP)**: те же размеры — сколько занимает.
3. **Явление B с ВМ**: сохраняется ли период 31–33 с.
4. **После варианта 2** (если включаем): те же замеры, сравнение «до/после».
Инструменты уже есть в репозитории: `tests/tcp_mtu_probe.py`,
`tests/long_compare_local.py`, `tests/compare_ymq_vs_shared.py`,
`tests/platform_probe.py`, `tests/reboot_probe.py`.
## 6. Вывод
- Тикет в поддержку — **не решение** (болезнь платформы), оставляем только как
историю; в drhider её тоже не «починили», а обошли.
- Архитектурный аналог решения drhider для SQS — **прозрачный прокси на ВМ**
(вариант 1). Ключевые камни: сохранение `Host` для SigV4, внешние `QueueUrl`
(сейчас `http://{region}.{host}:{port}` из `goaws.yaml`), TLS, доступ ВМ→кластер.
- Перед стройкой — замеры из раздела 5; возможно, вариант 2 закроет часть проблемы
за 10 минут вместо новой инфраструктуры.
## 7. Открытые вопросы (нужны твои решения)
1. Внешний домен и сертификат для ВМ-прокси — какой брать?
2. Клиенты без явного `endpoint_url` — есть ли такие (иначе вопрос №3 в разделе 3
отпадает)?
3. Делать ли сначала замеры (раздел 5) — я готов.