136 lines
7.2 KiB
Markdown
136 lines
7.2 KiB
Markdown
# Error Log: 65KB+ Payload Timeout — 2026-04-11
|
||
|
||
## Update — 2026-04-12
|
||
|
||
После дополнительного расследования в кластере инцидент переклассифицирован.
|
||
|
||
### Финальный статус
|
||
- shared-sqs backend **не является** первичной причиной зависания;
|
||
- проблема локализована на стороне **platform ingress path**;
|
||
- конкретно: ingress controller штурвала **не применяет** `nginx.ingress.kubernetes.io/proxy-request-buffering: "off"`, хотя upstream ingress-nginx эту аннотацию поддерживает;
|
||
- часть других аннотаций при этом применяется корректно, значит речь не о полном игноре ingress-ресурса, а о selective handling/bug/platform override.
|
||
|
||
### Дополнительные подтверждения
|
||
1. Для host `qu.kube5s.ru` существует только один ingress — `shared-sqs-ingress`, значит это не конфликт нескольких ingress-объектов.
|
||
2. В объекте ingress аннотация `proxy-request-buffering: "off"` присутствует.
|
||
3. В итоговом `nginx.conf` для `qu.kube5s.ru` остаётся `proxy_request_buffering on;`.
|
||
4. В шаблоне контроллера `/etc/nginx/template/nginx.tmpl` директива не захардкожена; там используется значение `location.Proxy.RequestBuffering`, то есть проблема происходит до фазы рендеринга финального location config.
|
||
5. `server-snippet`/`configuration-snippet` нельзя считать рабочим обходным путём без platform-level изменений, так как snippet-аннотации контролируются `allow-snippet-annotations`, а по умолчанию этот режим отключён.
|
||
|
||
### Операционный вывод
|
||
Это **известное ограничение инфраструктуры**, а не дефект бизнес-логики shared-sqs.
|
||
|
||
### Итоговое решение
|
||
- hard-limit 32KB в код shared-sqs **не внедряется**;
|
||
- 32KB остаётся **практической рекомендацией** для AWS CLI/botocore-клиентов в текущей инфраструктуре;
|
||
- приоритет дальнейших работ по этой теме переносится с shared-sqs на platform ingress controller.
|
||
|
||
## Симптом
|
||
|
||
SendMessage с телом ≥64740 байт зависает на 10-52 секунды и возвращает ошибку (ConnectionClosedError / exit=254).
|
||
|
||
**Воспроизведение:**
|
||
```bash
|
||
# Генерим payload 65KB
|
||
python3 -c "print('A'*65536)" > /tmp/big.txt
|
||
|
||
# Отправляем через AWS CLI — зависает на ~52 секунды
|
||
aws --endpoint-url https://qu.kube5s.ru sqs send-message \
|
||
--queue-url "https://qu.kube5s.ru/TENANT_ID/QUEUE_NAME" \
|
||
--message-body "file:///tmp/big.txt"
|
||
```
|
||
|
||
## Диагностика
|
||
|
||
### 1. Сервер — OK
|
||
Port-forward (обход nginx): 65KB за 831ms. Сервер не виноват.
|
||
|
||
### 2. nginx ingress — частично виноват
|
||
`client_body_timeout: 10s` — nginx закрывает соединение если тело не пришло за 10 секунд.
|
||
|
||
### 3. Root Cause — botocore + urllib3 2.0 + TLS + Nagle
|
||
|
||
**urllib3 2.0** посылает headers и body двумя отдельными `send()`:
|
||
```
|
||
send#1: len=774 (headers)
|
||
send#2: len=65629 (body)
|
||
```
|
||
|
||
**botocore** ставит `socket_options=[]` → убирает `TCP_NODELAY` → Nagle ON.
|
||
|
||
**Body** шифруется TLS в 4 записи по ~16KB. Первые 3 уходят, 4-я **застревает** из-за Nagle + delayed ACK deadlock.
|
||
|
||
**nginx access.log:**
|
||
```
|
||
POST status=408 req_len=49926 bytes_sent=0 time=10.001s
|
||
```
|
||
Получено 49926 байт = headers(774) + 3 × TLS(~16384). Не хватает ровно 1 TLS-записи.
|
||
|
||
### 4. Порог
|
||
|
||
| Размер | Время | Статус |
|
||
|--------|-------|--------|
|
||
| 64000B | 825ms | ✅ |
|
||
| 64720B | 799ms | ✅ |
|
||
| 64740B | 30806ms | ❌ intermittent |
|
||
| 65536B | 51843ms | ❌ всегда |
|
||
|
||
### 5. Версии ПО
|
||
|
||
| Компонент | Версия |
|
||
|-----------|--------|
|
||
| nginx ingress | shturval-ingress-controller v1.12.6 |
|
||
| AWS CLI | v2.34.27 |
|
||
| AWS CLI Python | 3.14.3 (bundled) |
|
||
| System Python | 3.12.3 |
|
||
| System urllib3 | 2.0.7 |
|
||
| System botocore | 1.42.86 |
|
||
|
||
## Что пробовали
|
||
|
||
### Помогло частично:
|
||
- **ConfigMap `client-body-timeout: "120"`** — pip boto3 (Python 3.12) стал работать (84ms → 13ms)
|
||
- **ConfigMap `client-body-buffer-size: "2m"`** — применилось глобально
|
||
|
||
### Не помогло:
|
||
- **Аннотация `proxy-request-buffering: "off"`** — shturval controller не применяет
|
||
- **`server-snippet: client_body_timeout 120s;`** — применилось но AWS CLI всё равно зависает
|
||
- **TCP_NODELAY patch через monkey-patch** — нестабильно (1-й запрос fails)
|
||
|
||
## Решение
|
||
|
||
Кодовый hard-limit не вводим.
|
||
|
||
Практическое правило эксплуатации:
|
||
- для AWS CLI / botocore в текущей ingress-инфраструктуре безопасно ориентироваться на 32KB;
|
||
- протокольный лимит SQS остаётся 256KB;
|
||
- проблема 64KB+ описывается как platform ingress limitation.
|
||
|
||
См. [решение](../decisions/message-size-limit-2026-04-11.md).
|
||
|
||
## Статус
|
||
✅ Исследование завершено. Root cause локализован до 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 options:
|
||
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
|
||
|
||
- parser `proxy-request-buffering` в upstream ingress-nginx:
|
||
https://github.com/kubernetes/ingress-nginx/blob/main/internal/ingress/annotations/proxy/main.go
|
||
|
||
- e2e test `should turn off proxy-request-buffering`:
|
||
https://github.com/kubernetes/ingress-nginx/blob/main/test/e2e/annotations/proxy.go
|
||
|
||
Краткий смысл ссылок:
|
||
- Штурвал: подтверждает, что Nginx Ingress Controller является частью platform stack;
|
||
- ingress-nginx docs/source: подтверждают, что `proxy-request-buffering` — штатная поддерживаемая фича upstream, а значит текущее поведение похоже именно на platform-specific limitation/bug.
|