From 08e8e3afece236ecd1329bafa9a62c1eb65fa585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Wed, 26 Aug 2026 20:35:48 +0300 Subject: [PATCH] =?UTF-8?q?test:=20stress=5Fhttp=20--file=20(=D1=80=D0=B5?= =?UTF-8?q?=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B5=20=D1=84=D0=B0=D0=B9=D0=BB?= =?UTF-8?q?=D1=8B);=20History:=20100KB=20=D0=BF=D1=80=D1=8F=D0=BC=D0=BE?= =?UTF-8?q?=D0=B9=20POST=20=E2=80=94=2083%=20=D1=82=D0=B0=D0=B9=D0=BC?= =?UTF-8?q?=D0=B0=D1=83=D1=82=D0=BE=D0=B2=20(=D1=88=D0=BB=D1=8E=D0=B7=20?= =?UTF-8?q?=D1=80=D0=B2=D1=91=D1=82=20>64KB),=2030KB=20=D1=80=D0=B5=D0=B0?= =?UTF-8?q?=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=E2=80=94=20200/200=20ok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- History/2026-08-26-stress-100kb-gateway.md | 22 ++++++++++++++++++++++ tests/load/stress_http.py | 18 ++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) create mode 100644 History/2026-08-26-stress-100kb-gateway.md diff --git a/History/2026-08-26-stress-100kb-gateway.md b/History/2026-08-26-stress-100kb-gateway.md new file mode 100644 index 0000000..01f5e23 --- /dev/null +++ b/History/2026-08-26-stress-100kb-gateway.md @@ -0,0 +1,22 @@ +# Стресс прод: 100KB прямой POST — 83% таймаутов (2026-08-26) + +## Прогон + +`stress_http.py --url https://contractor.pythonk8s.dev.nubes.ru --n 300 --threads 20 --size 100000` +(файл `load.docx`, невалидный, 100KB) + +Результат: `ok=51, err=249, timeouts=249, elapsed=398.5s, rps=0.8`. + +## Находка + +- **100KB прямой POST `/upload` через managed-шлюз → 83% обрывов** (таймауты ~30с). +- Подтверждает известное ограничение платформы: **шлюз рвёт тело >~64KB** + (история 2026-08-18, ingress-аннотация / client_max_body_size). +- Это НЕ деградация приложения: под почти не грузился (CPU 15m, MEM 66Mi) — обрывает внешний шлюз. +- Именно поэтому и внедрён **VM-буфер** (PUT на ВМ WebDAV → egress GET): прямой большой + POST через шлюз для прода непригоден. + +## Вывод + +- Стресс `/upload` валиден только файлами **< 64KB** (реальные документы 17–36KB). +- Большие файлы — только через VM-буфер (`/api/upload_refs`), не прямым POST. diff --git a/tests/load/stress_http.py b/tests/load/stress_http.py index 0ea0271..5b5a19b 100644 --- a/tests/load/stress_http.py +++ b/tests/load/stress_http.py @@ -24,11 +24,21 @@ def main(): ap.add_argument("--url", default="http://127.0.0.1:5000") ap.add_argument("--n", type=int, default=1000, help="число запросов") ap.add_argument("--threads", type=int, default=32, help="параллельных потоков") - ap.add_argument("--size", type=int, default=100000, help="размер файла в байтах") + ap.add_argument("--size", type=int, default=100000, help="размер файла в байтах (если не задан --file)") + ap.add_argument("--file", default=None, help="путь к реальному файлу (заменяет сгенерированный)") ap.add_argument("--health-only", action="store_true", help="только /health, без загрузки файлов") args = ap.parse_args() - payload = b"x" * args.size + if args.file: + import os as _os + fname = _os.path.basename(args.file) + with open(args.file, "rb") as _f: + payload = _f.read() + real_size = len(payload) + else: + fname = "load.docx" + payload = b"x" * args.size + real_size = args.size ok = 0 err = 0 slow = 0 @@ -43,7 +53,7 @@ def main(): else: r = c.post( f"{args.url}/upload", - files={"files": ("load.docx", payload, "application/octet-stream")}, + files={"files": (fname, payload, "application/octet-stream")}, ) if r.status_code == 200: ok += 1 @@ -60,7 +70,7 @@ def main(): elapsed = time.time() - t0 print(f"url={args.url}") - print(f"n={args.n} threads={args.threads} size={args.size}B health_only={args.health_only}") + print(f"n={args.n} threads={args.threads} size={real_size}B file={args.file or '(gen)'} health_only={args.health_only}") print(f"ok={ok} err={err} timeouts={slow} elapsed={elapsed:.1f}s rps={args.n / elapsed:.1f}")