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

10 KiB
Raw Blame History

Применимость обхода из 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) — я готов.