125 lines
7.6 KiB
Markdown
125 lines
7.6 KiB
Markdown
# 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.
|
||
|
||
## Ссылки для повторного разбора
|
||
|
||
- Штурвал Community Edition, архитектура платформы:
|
||
https://docs.k8s.ngcloud.ru/2.12/docs/common/structure/
|
||
|
||
- ingress-nginx annotations:
|
||
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
|
||
|
||
- ingress-nginx configmap:
|
||
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
|
||
|
||
- upstream parser `proxy-request-buffering`:
|
||
https://github.com/kubernetes/ingress-nginx/blob/main/internal/ingress/annotations/proxy/main.go
|
||
|
||
- upstream e2e tests for proxy annotations:
|
||
https://github.com/kubernetes/ingress-nginx/blob/main/test/e2e/annotations/proxy.go
|
||
|
||
Если к вопросу 64KB+ возвращаться позже, эти ссылки нужны для быстрого подтверждения двух вещей:
|
||
- ingress controller у нас platform-managed со стороны Штурвала;
|
||
- аннотация `proxy-request-buffering` в upstream ingress-nginx поддерживается официально.
|