docs: finalize 64kb ingress investigation

This commit is contained in:
Naeel
2026-04-12 07:59:04 +03:00
parent eba01c9580
commit a1ff9c4e52
5 changed files with 643 additions and 1 deletions
@@ -0,0 +1,103 @@
# Decision: Ограничение MaximumMessageSize — 2026-04-11
## Update — 2026-04-12
Первичное решение из этой записи было пересмотрено после дополнительного расследования ingress controller штурвала.
### Новый финальный статус решения
- **не вводить** hard-limit 32KB в код shared-sqs;
- **оставить** протокольный максимум SQS без искусственного server-side урезания;
- **документировать** 32KB как безопасный практический размер для AWS CLI/botocore при текущем ingress path.
### Почему решение изменено
На момент первоначальной записи было уже понятно, что 32KB работает стабильно, но не было окончательно доказано, где именно ломается путь 64KB+.
Дополнительное расследование 2026-04-12 показало:
1. В кластере для `qu.kube5s.ru` существует только один ingress.
2. Объект ingress у shared-sqs содержит `proxy-request-buffering: "off"`.
3. Платформенный ingress controller штурвала рендерит для этого host `proxy_request_buffering on;` несмотря на annotation override.
4. Upstream ingress-nginx такую аннотацию официально поддерживает, значит это platform-specific limitation/bug, а не ограничение shared-sqs.
Следовательно, code-level лимит 32KB был бы не корневым исправлением, а маскировкой внешней инфраструктурной проблемы внутри приложения.
## Контекст
При тестировании shared-sqs v0.1.21 обнаружено, что сообщения размером 65KB+ зависают на 10-52 секунды при отправке через AWS CLI / boto3.
## Проблема
### Root Cause (подтверждённый)
**Цепочка сбоя:** urllib3 2.0 + botocore + TLS + Nagle's algorithm + nginx.
1. **urllib3 2.0** изменил API: headers и body отправляются двумя отдельными `send()` вызовами (раньше одним через `endheaders()`)
2. **botocore** устанавливает `socket_options=[]`, что убирает `TCP_NODELAY` → включает алгоритм Nagle
3. Body (65629 байт) шифруется TLS в 4 записи по ~16KB
4. Первые 3 записи (49152 байт) отправляются сразу
5. Последняя 4-я запись (~16KB) **застревает** из-за Nagle + delayed ACK deadlock
6. nginx `client_body_timeout` срабатывает → HTTP 408 → connection reset
### Доказательство
nginx access.log при сбое:
```
POST status=408 req_len=49926 bytes_sent=0 time=10.001s
```
49926 = headers(774) + 3 × TLS_record(~16384) — ровно на 1 TLS-запись меньше чем нужно.
### Что мы НЕ контролируем
- botocore (AWS SDK) — убирает TCP_NODELAY, мы не можем повлиять
- urllib3 2.0 — split headers/body, это багфикс а не баг
- nginx ingress controller (shturval) — аннотация `proxy-request-buffering: "off"` не применяется
- AWS CLI bundled runtime (Python 3.14.3 с другим TLS-стеком)
### Что мы пробовали
1. **proxy-request-buffering: off** — аннотация не подхватывается shturval controller ❌
2. **client_body_timeout: 120s** — помогло для pip boto3, но НЕ для AWS CLI ❌
3. **client_body_buffer_size: 2m** — не помогло для AWS CLI ❌
4. **TCP_NODELAY patch** — помогает частично (1-й запрос fails, остальные OK) — не production решение ❌
## Решение
Первоначальная идея: ограничить `MaximumMessageSize` до **32768 байт (32 KB)**.
Финальное решение после дополнительного расследования: **не вводить hard-limit в коде**, а использовать 32KB как **операционную рекомендацию**.
### Обоснование
1. **32KB стабильно:** 20 из 20 запросов через AWS CLI = 805-917ms, ни одного зависания
2. **Двойной запас:** от порога сбоя (64720B) до лимита (32768B) — двойной запас
3. **Покрывает use-cases:** >99% SQS-сообщений — JSON, уведомления, команды (<10KB)
4. **Паритет с Yandex MQ:** на 32KB shared-sqs стабильнее (нет cold start penalty)
5. **Честный лимит:** лучше явный лимит чем молчаливые зависания на 52 секунды
### Бенчмарк 32KB
**shared-sqs (20 запросов):**
- Min: 805ms, Max: 917ms, Avg: ~860ms
- 0 зависаний из 20
**Yandex MQ (10 запросов):**
- Min: 869ms, Max: 3490ms (cold start), Avg: ~920ms (прогретый)
- Cold start: 2-3.5 секунды
### Альтернативы (рассмотренные и отвергнутые)
| Вариант | Почему нет |
|---------|------------|
| 256KB (как AWS SQS) | Зависает на 52 секунды, не работает |
| 64KB (ближе к порогу) | Впритык к границе, рискованно — 720 байт запас |
| Фиксить nginx controller | Мы не контролируем shturval, нет исходников |
| Monkey-patch botocore | Не production, каждое обновление AWS CLI сломает |
| Отдельный endpoint без nginx | Over-engineering для MVP |
## Статус
✅ Решение принято: **не менять код shared-sqs** ради этого кейса.
## Практический вывод
1. Для повседневного использования через AWS CLI/botocore ориентироваться на payload до 32KB.
2. Если в будущем потребуется надёжная поддержка 64KB+ для этих клиентов, исправление нужно делать в platform ingress layer, а не в shared-sqs.