test: stress_http --file (реальные файлы); History: 100KB прямой POST — 83% таймаутов (шлюз рвёт >64KB), 30KB реальный — 200/200 ok
This commit is contained in:
@@ -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.
|
||||
@@ -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}")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user