- почему схему 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) и открытые вопросы.
10 KiB
Применимость обхода из 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 мс, таймаутов нет.
Технические условия (важные, иначе не заработает):
- SigV4 подписывает заголовок
Host. nginx обязан передавать внешний хост:proxy_set_header Host $host;. Сервис берёт хост именно из запроса —auth_middleware.go:315-317(canonicalHeaderValue:name == "host"→r.Host). Подменять Host на внутренний (например, на служебное имя сервиса) нельзя — подпись перестанет сходиться, клиент получитSignatureDoesNotMatch. - URL очередей сейчас жёстко внутренние и без TLS.
tenantQueueURL(tenant_helpers.go:29-37) формируетhttp://{region}.{host}:{port}/{tenantID}/{queue}. Хост и порт читаются только изgoaws.yaml(conf/config.go:87-90; вapplyEnvironmentDefaultsenv-переменных для Host нет). Следствия:- клиенты, которые сами задают
endpoint_url(все наши тесты), берут изQueueUrlтолько путь — они не пострадают; - клиенты без
endpoint_urlпойдут на хост изQueueUrl→ обязаны получить внешний адрес. Значит: либо (а) подставляем внешний хост/схему в конфиг, либо (б) nginx переписываетQueueUrlв ответах (хрупко), либо (в) требуем от клиентов явныйendpoint_url.
- клиенты, которые сами задают
- Транспорт. Схема
http://в URL — при переносе на ВМ либо оставляемhttp(нежелательно для интернета), либо переводим наhttpsи правим формирование URL. Для TLS нужен сертификат на ВМ-домен. - Доступ ВМ → кластер. ВМ вне кластера; понадобится NodePort/VIP (или опубликованный внутренний адрес). Путь ВМ→кластер нужно замерить (см. раздел 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. Что обязательно замерить ДО решения
Правило проекта: рекомендация без замера — догадка. Замеры на том же хосте и тем же инструментом:
- С ВМ → внешний endpoint кластера: тела 1 КБ / 10 КБ / 100 КБ / 256 КБ — есть ли ~51 с? (Малые тела с ВМ проверены: 6–8 мс, таймаутов нет; большие, судя по всему, отдельно не мерили.)
- ВМ → кластер (NodePort/VIP): те же размеры — сколько занимает.
- Явление B с ВМ: сохраняется ли период 31–33 с.
- После варианта 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. Открытые вопросы (нужны твои решения)
- Внешний домен и сертификат для ВМ-прокси — какой брать?
- Клиенты без явного
endpoint_url— есть ли такие (иначе вопрос №3 в разделе 3 отпадает)? - Делать ли сначала замеры (раздел 5) — я готов.