Files
SQS-service/doc/decisions/message-size-limit-2026-04-11.md
T

7.6 KiB
Raw Blame History

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.

Ссылки для повторного разбора

Если к вопросу 64KB+ возвращаться позже, эти ссылки нужны для быстрого подтверждения двух вещей:

  • ingress controller у нас platform-managed со стороны Штурвала;
  • аннотация proxy-request-buffering в upstream ingress-nginx поддерживается официально.