Ana içeriğe geç

API Yük Testi

Bu sayfa Sword API (Gezen Backend) için yapılan yük testi koşularını kaydeder. Her koşudan sonra sonuç tablosuna yeni bir satır ekleyin.


Hızlı Menü


Özet ve Ana Bulgular

1. Pratik Eşzamanlılık Sınırı: Mevcut tek işlem (proses) kurulumumuz 50 eşzamanlı sanal kullanıcıya (VU) kadar sorunsuz çalışmaktadır. 50 VU'nun ötesinde gecikme süresi önemli ölçüde artmakta ve 200 VU'da sistem veritabanı bağlantı havuzunun tükenmesi nedeniyle kısmi çöküş yaşamaktadır.

2. Yavaşlık vs. Çöküş (Önemli Bir Ayrım): API'miz üzerindeki yüksek yük, uygulamanın tamamen çökmesinden ziyade aşırı yavaşlamaya (şifre doğrulama ve veritabanı bağlantı kuyruğuna takılma) neden olur. 100 VU'da bile hata oranı %0 kalmakta, ancak gecikme süresi ~2.5 saniye p95 değerine yükselmektedir (2 saniyelik hedefimizi aşmaktadır).

3. Eşzamanlılık vs. Payload: Eşzamanlılık testleri (çok kullanıcı, küçük istekler) ve Payload testleri (az kullanıcı, ağır yükleme/indirmeler) farklı mimari soruları yanıtlar. Bunları tek bir koşuda karıştırmayın.

4. Teknik Olmayan Görünüm: Bu sonuçların iş paydaşları için hazırlanmış, teknik terimlerden arındırılmış sade bir açıklaması için lütfen Kolaylaştırılmış Yük Testi Raporu belgesine bakın.


Yığın (stack)

Katman Teknoloji Açıklama
Yük üreteci k6 (Grafana) Yüksek performanslı, geliştirici odaklı yük testi aracı
Eşzamanlılık betiği scripts/load/api-load.js Tipik mobil/web uygulama trafiğini simüle eder
Payload betikleri scripts/load/payload-upload.js, payload-read.js Ağır dosya yüklemelerini ve veri transferlerini simüle eder
Ortak yardımcılar scripts/load/lib/common.js Ortak kimlik doğrulama ve istek yardımcıları
Yükleme fixture’ları scripts/load/fixtures/ python3 scripts/load/generate_fixtures.py ile üretilir
API Çerçevesi FastAPI (main.py) Yüksek performanslı Python web çerçevesi
ASGI sunucu Uvicorn Test edilen tek işlemli ASGI sunucusu
Veritabanı PostgreSQL İlişkisel veritabanı (SQLAlchemy ORM aracılığıyla)
Test edilen kimlik doğrulama OAuth2 Password Flow POST /api/auth/token (sonraki isteklerde JWT bearer)

Eşzamanlılık testi vs payload testi

İki farklı soruya cevap verirler. Üretim öncesi ikisini de çalıştırın; ayrı betikler ve ayrı sonuç satırları kullanın — tek koşuda karıştırmak hataları yorumlamayı zorlaştırır.

Eşzamanlılık (concurrency) Payload (veri boyutu)
Soru Aynı anda kaç kullanıcı uygulamayı kullanabilir? Her istek büyük veya maliyetli olduğunda ne olur?
Betik api-load.js payload-upload.js, payload-read.js
Değişken Sanal kullanıcı (VU), ramp hızı, bekleme süresi (think time) İstek/yanıt boyutu, yükleme dosya boyutu, liste limit, PDF üretimi
Tipik VU 20–200 1–5 (az kullanıcı, ağır işlemler)
Tipik istek boyutu Küçük JSON (listeler, profil) 1–12 MiB yükleme, büyük liste yanıtları, dosya indirme
Ana darboğazlar Event loop kuyruğu, DB pool, bcrypt giriş Disk I/O, bellek, serileştirme, Graphviz/PDF CPU
Ana metrikler p95 gecikme, hata oranı, N VU’da ist/sn http_req_sending, http_req_receiving, response_bytes, yükleme süresi
Önkoşul Test kullanıcısı mevcut Test kullanıcısı + en az bir fabrika/makine; yükleme için fixture üretilmiş

Tanımlar için Sözlük — terimler ve metrikler bölümüne bakın.

Eşzamanlılık kapasiteyi yanıtlar: “50 kişi aynı anda fabrika ve görev listelerine bakabilir mi?”

Payload hacim ve ağırlığı yanıtlar: “3 kişi 12 MiB görsel yüklerken diğerleri limit=300 listeleri çekebilir mi?”

Sözlük — terimler ve metrikler

Tablolar veya k6 çıktısı tanıdık gelmiyorsa önce bu bölümü okuyun.

Temel kavramlar

Terim Anlamı
VU (Virtual User — sanal kullanıcı) Betiği döngüde çalıştıran simüle edilmiş bir istemci. 50 VU ≈ aynı anda uygulamayı kullanan 50 kişi (her biri bir işlem yapar, sonra bekler).
Iterasyon Bir VU için ana betiğin bir tam turu (bir HTTP isteği + think time). 20 VU ile 2.782 iterasyon, bu kullanıcıların koşu boyunca toplam 2.782 işlem yaptığı anlamına gelir.
Think time (düşünme süresi) İşlemler arasındaki duraklama; gerçek kullanıcının ekranı okuması gibi. Eşzamanlılık testlerinde 1 sn; payload okuma testlerinde senaryoya göre 1–5 sn. Düşük think time = API’ye daha fazla baskı.
Ramp / stages (aşamalar) VU sayısının zamanla nasıl artıp azaldığı. load-50 30 sn’de 50 VU’ya çıkar, 2 dk sabit tutar, sonra düşer — anlık sıçrama değildir.
K6_SCENARIO Adlandırılmış test profili (örn. smoke, load-50, upload-12m). VU sayısı, süre ve geçti/kaldı eşiklerini belirler.
Setup Testten önce bir kez çalışır (giriş, fabrika/makine oluşturma, 12 MiB görsel seed). Yük sayılmaz — ana döngü için veri hazırlar.

Uç nokta yüzdeleri (trafik karışımı)

“GET /api/factories — %25” gibi tablolar her uç noktanın ne sıklıkla seçildiğini gösterir; başarı oranı veya sunucu yük payı değildir.

Her sanal kullanıcı rastgele bir sayı seçer ve bir uç noktaya istek gönderir:

Aralık Uç nokta Pay
0–10% POST /api/auth/token %10
10–35% GET /api/factories?limit=300 %25
35–60% GET /api/machines?limit=100 %25
60–85% GET /api/tasks?limit=100 %25
85–100% GET /api/users/me %15

Uzun bir koşuda isteklerin kabaca %25’i fabrikalara gider — liste ekranlarının baskın olduğu mobil uygulamayı taklit eder. Payload betikleri aynı mantığı farklı ağırlıklarla kullanır (örn. read-fat’te %35 fabrika, %15 görsel indirme).

Gecikme ve verim

Metrik Ne ölçer Nasıl okunur
p95 (95. persentil) İstek süresi — isteklerin %95’i bu değerden hızlıydı; %5’i daha yavaştı. Kayıtlarımızdaki ana gecikme sayısı. p95 1,04 sn = çoğu istek saniyenin altında, yavaş kuyruk ~1 sn’ye ulaştı.
p95 (tümü) Koşudaki tüm HTTP istekleri için p95. O senaryoda genel API yanıt hızı.
p95 auth / factories / … Uç nokta bazında p95 (özel k6 trend’leri). Hangi rota yavaş — örn. giriş (bcrypt) vs liste uç noktaları.
ist/sn (Req/s) Saniyede tamamlanan HTTP isteği (verim). Daha fazla VU ve kısa think time ile artar. “Saniyede kullanıcı” ile aynı değil — her kullanıcı işlemler arasında bekler.
Koşu süresi k6 koşusunun duvar saati süresi (ramp dahil). Senaryo adındaki “tutma” süresinden biraz uzundur.

Hatalar, kontroller ve geçti/kaldı

Metrik Ne ölçer Nasıl okunur
Hata oranı Başarısız isteklerin payı (2xx dışı HTTP, zaman aşımı veya başarısız betik kontrolleri). %0,00 = hata yok. %6,05 ≈ 16 istekten 1’i başarısız — çoğunlukla ağır yük altında zaman aşımı; her zaman HTTP 500 değildir.
Eşikler (thresholds) Betikte tanımlı geçti/kaldı kuralları, örn. p95 < 2 sn ve hata < %1. k6 sonunda ✓ veya ✗ basar. Sonuç sütunumuz buna karşılık gelir.
Sonuç (Geçti / Kaldı) Koşu eşikleri karşıladı mı? Kaldı (gecikme) = istekler başarılı ama çok yavaş. Hatalı Kaldı = zaman aşımı veya HTTP hataları.
Geçen kontroller (örn. 2783/2783) Betik doğrulamaları (status 2xx, login returns token vb.). Gecikme yüksekse tüm kontroller geçebilir ama eşikler yine kaldırabilir.
İstek zaman aşımı k6 beklemeyi bıraktı (varsayılan 60 sn). 5xx gövdesi olmadan hata olarak görünür — sunucu aşırı yüklendiğinde veya DB pool tükendiğinde yaygın.

HTTP zamanlama dökümü (k6 varsayılanları)

Gövdelerin büyük olduğu payload koşularında faydalı:

Metrik Aşama
http_req_sending İstek gövdesini sunucuya gönderme süresi (yükleme).
http_req_waiting Sunucuyu bekleme süresi (DB sorguları, disk, PDF).
http_req_receiving Yanıt gövdesini indirme süresi (büyük listeler, görseller).
http_req_duration gönderme + bekleme + alma toplamı (p95 ile aynı temel).

Payload’a özel terimler

Terim Anlamı
MiB Mebibayt (1 MiB = 1.048.576 bayt). Yükleme fixture’ları 1 / 6 / 12 MiB; 12 MiB uygulamanın max yükleme boyutu.
limit=300 Liste uç noktalarındaki sorgu parametresi — en fazla 300 satır döner. Büyük limit = daha büyük JSON yanıtı.
response_bytes / upload_bytes İstek başına gönderilen/alınan baytları izleyen özel k6 trend’leri.
413 HTTP “Payload Too Large” — dosya 12 MiB sınırını aştı.

Sonuç tablosu sütunları (eşzamanlılık kaydı)

Sütun Anlamı
Max VU Koşu sırasındaki eşzamanlı sanal kullanıcı zirvesi.
Toplam istek k6’nın tamamladığı tüm HTTP istekleri (setup girişi ve iterasyon çağrıları dahil).
Ortam / Sunucu / DB API’nin nerede ve nasıl çalıştığı — farklı kurulumlar arasında sonuçlar not edilmeden karşılaştırılamaz.
Eşikler O senaryonun geçme kriterleri (betikten kopyalanır).
Notlar Serbest metin — zaman aşımları, yeniden başlatmalar, yapılandırma değişiklikleri, aykırı değerleri açıklayan her şey.

Sonuç tablosu sütunları (payload kaydı)

Sütun Anlamı
Tür upload veya read.
Payload Ne ağırdı — dosya boyutu, liste limitleri veya indirme boyutu.
p95 (tümü) Genel gecikme; localhost’ta yükleme p95’si loopback’te gerçek ağ olmadığı için yanıltıcı derecede düşük görünebilir.

k6 terminal çıktısını okuma (hızlı harita)

Koşu sonunda k6 bir özet basar. Sık satırlar:

  • http_req_duration — genel gecikme istatistikleri; p(95)=… bizim p95 (tümü) olarak kaydettiğimiz değer.
  • http_req_failed — başarısız isteklerin oranı (hata oranımız).
  • iterations — tüm VU’larda toplam döngü sayısı.
  • vus — anlık / max sanal kullanıcı.
  • Eşik adlarının yanındaki ✓ / ✗ — o kural için geçti veya kaldı.

Eşzamanlılık testleri (api-load.js)

k6 betiği tipik mobil/web uygulama trafiğini simüle eder:

  1. Setup (bir kez): K6_USERNAME / K6_PASSWORD ile giriş yapılır ve JWT alınır.
  2. Ana döngü (sanal kullanıcı başına): ağırlıklı rastgele bir uç nokta seçilir, kimlik doğrulamalı istek gönderilir, ardından 1 saniye beklenir (think time).

Uç nokta Yaklaşık pay = trafik karışımı (her rotanın ne sıklıkla vurulduğu), başarı oranı değil. Sözlük bölümüne bakın.

Uç nokta Yaklaşık pay
POST /api/auth/token %10
GET /api/factories?limit=300 %25
GET /api/machines?limit=100 %25
GET /api/tasks?limit=100 %25
GET /api/users/me %15

Senaryolar

K6_SCENARIO ile ayarlanır:

Senaryo Profil Varsayılan eşikler
smoke 5 VU, 30 sn p95 < 3 sn, hata < %5
load (varsayılan) 4 dk içinde 50 → 200 → 0 p95 < 2 sn, hata < %1
load-20 sabit 20 VU (30 sn ramp, 2 dk tut, 30 sn düş) p95 < 2 sn, hata < %1
load-50 sabit 50 VU (30 sn ramp, 2 dk tut, 30 sn düş) p95 < 2 sn, hata < %1
load-100 sabit 100 VU (30 sn ramp, 2 dk tut, 30 sn düş) p95 < 2 sn, hata < %1
stress 7 dk içinde 100 → 500 → 0 p95 < 5 sn, hata < %5

Nasıl çalıştırılır

k6 kurulumu

macOS (Homebrew)

brew install k6

Linux (Debian / Ubuntu)

curl -fsSL https://dl.k6.io/key.gpg | sudo gpg --dearmor -o /usr/share/keyrings/k6-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6

Linux (Fedora / CentOS)

sudo dnf install https://dl.k6.io/rpm/repo.rpm
sudo dnf install k6

Windows (winget)

winget install k6

Windows (Chocolatey)

choco install k6

Doğrulama: k6 version. Diğer seçenekler (Docker, tek dosya binary): k6 kurulum dokümanı.

API’yi başlatma

Bir terminalde, repo kökünden:

macOS / Linux (bash veya zsh)

cd /path/to/gezen-backend
source venv/bin/activate
uvicorn main:app --host 0.0.0.0 --port 8000

Windows (PowerShell)

cd C:\path\to\gezen-backend
.\venv\Scripts\Activate.ps1
uvicorn main:app --host 0.0.0.0 --port 8000

Değişkenleri ayarlama ve çalıştırma (smoke testi)

macOS / Linux (bash veya zsh)

export BASE_URL=http://127.0.0.1:8000
export K6_USERNAME=loadtest
export K6_PASSWORD=loadtest123
K6_SCENARIO=smoke k6 run scripts/load/api-load.js

Windows (PowerShell)

$env:BASE_URL = "http://127.0.0.1:8000"
$env:K6_USERNAME = "loadtest"
$env:K6_PASSWORD = "loadtest123"
$env:K6_SCENARIO = "smoke"
k6 run scripts/load/api-load.js

Windows (Komut İstemi)

set BASE_URL=http://127.0.0.1:8000
set K6_USERNAME=loadtest
set K6_PASSWORD=loadtest123
set K6_SCENARIO=smoke
k6 run scripts/load/api-load.js

Ayrı bir test kullanıcısı kullanın (örn. POST /api/users ile loadtest). Onay olmadan üretimde yüksek yük uygulamayın.

Aşağıdaki komut örnekleri bash / zsh sözdizimini kullanır (export, VAR=değer cmd). Windows’ta ortam değişkenleri ve senaryo seçimi için yukarıdaki PowerShell veya Komut İstemi kalıplarını kullanın.

Hızlı referans: scripts/load/README.md

Eşzamanlılık sonuç kaydı

Koşu başına bir satır doldurun. Yeni kayıt eklerken alttaki şablon satırını kopyalayın.

# Tarih Senaryo Max VU Süre Ortam Base URL Sunucu DB Test kullanıcı Toplam istek ist/sn Hata oranı p95 (tümü) p95 auth p95 factories p95 machines p95 tasks p95 users/me Eşikler Sonuç Notlar
1 2026-06-24 smoke 5 ~31 sn Yerel dev (Mac) http://127.0.0.1:8000 Uvicorn, tek süreç PostgreSQL loadtest 75 2,41 %0,00 203 ms 206 ms 24 ms 12 ms 15 ms 10 ms Geçti (p95 < 3 sn, hata < %5) Geçti 5 eşzamanlı kullanıcı sorunsuz; 74 iterasyon, 76/76 kontrol geçti, 4xx/5xx yok
2 2026-06-24 load 200 ~4 dk 30 sn Yerel dev (Mac) http://127.0.0.1:8000 Uvicorn, tek süreç PostgreSQL loadtest 5513 20,43 %6,05 2,78 sn 3,23 sn 2,95 sn 1,27 sn 3,01 sn 1,28 sn Kaldı (p95 < 2 sn, hata < %1) Kaldı 4 dk içinde 50 → 200 → 0; 5509 iterasyon, 5180/5514 kontrol geçti; zirvede 334 istek zaman aşımı
3 2026-06-24 load-20 20 ~3 dk 01 sn Yerel dev (Mac) http://127.0.0.1:8000 Uvicorn, tek süreç PostgreSQL loadtest 2782 15,38 %0,00 369 ms 389 ms 383 ms 199 ms 378 ms 194 ms Geçti (p95 < 2 sn, hata < %1) Geçti Sabit 20 VU; 2781 iterasyon, 2783/2783 kontrol geçti
4 2026-06-24 load-50 50 ~3 dk 00 sn Yerel dev (Mac) http://127.0.0.1:8000 Uvicorn, tek süreç PostgreSQL loadtest 5600 31,05 %0,00 1,04 sn 1,13 sn 1,17 sn 616 ms 1,18 sn 593 ms Geçti (p95 < 2 sn, hata < %1) Geçti Sabit 50 VU; 5599 iterasyon, 5601/5601 kontrol geçti
5 2026-06-24 load-100 100 ~3 dk 01 sn Yerel dev (Mac) http://127.0.0.1:8000 Uvicorn, tek süreç PostgreSQL loadtest 7398 40,83 %0,00 2,57 sn 2,41 sn 2,87 sn 1,39 sn 2,80 sn 1,39 sn Kaldı (p95 < 2 sn, hata < %1) Kaldı Sabit 100 VU; 7397 iterasyon, 7399/7399 kontrol geçti; HTTP hatası yok ama p95 2 sn üstü

Koşu #1 özeti

  • Sonuç: 5 sanal kullanıcı / 30 saniye hatasız tamamlandı; genel p95 203 ms (3 sn duman eşiğinin çok altında).
  • En yavaş yol: giriş (~200 ms ort.) — parola hash’i beklenen davranış.
  • Liste uç noktaları: fabrikalar, makineler, görevler ve users/me yerel donanımda çoğunlukla < 25 ms p95.
  • Kullanılan komut:
export BASE_URL=http://127.0.0.1:8000
export K6_USERNAME=loadtest
export K6_PASSWORD=loadtest123
K6_SCENARIO=smoke k6 run scripts/load/api-load.js

Koşu #2 özeti

  • Sonuç: Varsayılan yük profili (4 dk içinde 50 → 200 VU) eşikleri geçemedi — genel p95 2,78 sn (hedef < 2 sn), hata oranı %6,05 (hedef < %1).
  • Verim: 1 sn think time ile 5513 istek, ~20,4 ist/sn; 5509 tamamlanan iterasyon.
  • Hata türü: Çoğunlukla istek zaman aşımı (k6 varsayılan 60 sn) ~200 eşzamanlı VU’da tek süreç Uvicorn’da — 5xx yanıtı değil.
  • En yavaş p95 yollar: auth 3,23 sn, tasks 3,01 sn, factories 2,95 sn; machines ve users/me daha düşük (1,27–1,28 sn).
  • Kullanılan komut:
export BASE_URL=http://127.0.0.1:8000
export K6_USERNAME=loadtest
export K6_PASSWORD=loadtest123
K6_SCENARIO=load k6 run scripts/load/api-load.js

Koşu #3–#5 özeti (sabit yük: 20 / 50 / 100 VU)

Her seviyede kapasiteyi ölçmek için ayrı koşular (30 sn ramp → 2 dk sabit → 30 sn düşüş). Koşu #2 sonrası DB pool tükenmesi nedeniyle API yeniden başlatıldı.

VU Sonuç p95 (tümü) ist/sn Hata
20 Geçti 369 ms 15,4 %0
50 Geçti 1,04 sn 31,1 %0
100 Kaldı (gecikme) 2,57 sn 40,8 %0
  • 20 VU: Rahat marj — tüm uç nokta p95 400 ms altında.
  • 50 VU: Hâlâ eşikler içinde; gecikme 20 VU’ya göre kabaca 3× (p95 1,04 sn).
  • 100 VU: Başarısız istek yok ama genel p95 2,57 sn 2 sn yük eşiğini aşıyor — sert hata olmadan bozulma.
  • Kırılma noktası: Tek süreç Uvicorn + varsayılan SQLAlchemy pool (30 + 40 overflow) ile 50–100 VU arası.
  • Kullanılan komutlar:
export BASE_URL=http://127.0.0.1:8000
export K6_USERNAME=loadtest
export K6_PASSWORD=loadtest123
K6_SCENARIO=load-20 k6 run scripts/load/api-load.js
K6_SCENARIO=load-50 k6 run scripts/load/api-load.js
K6_SCENARIO=load-100 k6 run scripts/load/api-load.js

Payload testleri (payload-upload.js, payload-read.js)

Fixture oluşturma (makine başına bir kez)

Yükleme testleri 1 MiB, 6 MiB ve 12 MiB ikili dosyalar gerektirir (uygulama limiti app/services/upload_storage.py içinde dosya başına 12 MiB):

python3 scripts/load/generate_fixtures.py

Windows’ta PATH’te python3 yoksa python scripts/load/generate_fixtures.py kullanın.

Önkoşullar

  • Eşzamanlılık testlerinin gerektirdiği her şey, artı:
  • scripts/load/fixtures/ altında üretilmiş fixture’lar
  • Test kullanıcısının fabrika/makinesi yoksa setup() otomatik oluşturur (K6_FACTORY_ID / K6_MACHINE_ID ile geçersiz kılınabilir)

Yükleme betiği (payload-upload.js)

POST /api/machines/{id}/images — multipart JPEG yüklemeleri.

K6_SCENARIO Profil Dosya boyutu
upload-smoke 1 VU, 30 sn 1 MiB (hızlı kablolama kontrolü)
upload-1m 2 VU, ~3 dk 1 MiB
upload-6m 2 VU, ~3 dk 6 MiB
upload-12m 1→2 VU, ~3 dk 12 MiB (uygulama limiti)
upload-mix 3 VU, ~3 dk rastgele 1 / 6 / 12 MiB

Herhangi bir senaryoda dosya boyutunu geçersiz kılma: K6_UPLOAD_SIZE=6mb

export BASE_URL=http://127.0.0.1:8000
export K6_USERNAME=loadtest
export K6_PASSWORD=loadtest123
python3 scripts/load/generate_fixtures.py
K6_SCENARIO=upload-smoke k6 run scripts/load/payload-upload.js

Okuma / indirme betiği (payload-read.js)

Büyük giden veri yollarını test eder:

Uç nokta Pay Notlar
GET /api/factories?limit=300 ~%35 varsayılan limit: K6_FACTORY_LIMIT
GET /api/machines?limit=100 ~%25 varsayılan: K6_MACHINE_LIMIT
GET /api/tasks?limit=100 ~%20 varsayılan: K6_TASK_LIMIT
GET /api/uploads/... (makine görseli) ~%15 yüklenen görseli indirir
GET /api/factories/{id}/mindmap ~%5 yalnızca read-mindmap senaryosunda; Graphviz gerekir
K6_SCENARIO Profil Amaç
read-smoke 5 VU, 30 sn hızlı büyük okuma kontrolü (seed varsa 12 MiB görsel indirme)
read-fat 5 VU, ~3 dk sürekli büyük liste + indirme karışımı
read-mindmap 1→2 VU, ~1,5 dk Graphviz PDF üretimi stresi

Graphviz yüklü değilse: K6_SKIP_MINDMAP=1

K6_SCENARIO=read-smoke k6 run scripts/load/payload-read.js
K6_SCENARIO=read-fat k6 run scripts/load/payload-read.js

Payload koşularında izlenecekler

  • http_req_sending — yükleme bant genişliği / istemci tarafı gönderme süresi
  • http_req_receiving — listeler ve görseller için indirme bant genişliği
  • http_req_waiting — sunucu DB, disk veya PDF işi
  • response_bytes ve upload_bytes özel trend’leri
  • Yükleme senaryolarından sonra uploads/ disk kullanımı
  • Dosya 12 MiB’i aşarsa 413 yanıtları

Payload sonuç kaydı

# Tarih Tür Senaryo Max VU Süre Payload Ortam p95 (tümü) Hata oranı Sonuç Notlar
P1 2026-06-24 upload upload-smoke 1 ~31 sn 1 MiB JPEG × 10 Yerel dev (Mac) 111 ms %0,00 Geçti Yalnızca kablolama kontrolü — gerçek payload testi değil
P2 2026-06-24 read read-smoke 5 ~31 sn limit=300/100 + 1 MiB indirme Yerel dev (Mac) 36 ms %0,00 Geçti Küçük DB’de hızlı okuma kontrolü
P3 2026-06-24 upload upload-6m 2 ~3 dk 05 sn 6 MiB JPEG × 40 Yerel dev (Mac) 31 ms %0,00 Geçti ~252 MB gönderildi; yükleme p95 ~31 ms
P4 2026-06-24 upload upload-12m 2 ~3 dk 01 sn 12 MiB JPEG × 20 (uyg. max) Yerel dev (Mac) 46 ms %0,00 Geçti İzin verilen max boyutta ~252 MB gönderildi
P5 2026-06-24 upload upload-mix 3 ~3 dk 05 sn rastgele 1 / 6 / 12 MiB × 60 Yerel dev (Mac) 45 ms %0,00 Geçti ~331 MB gönderildi; karışık boyutlar
P6 2026-06-24 read read-fat 5 ~3 dk 02 sn limit=300/100 + 12 MiB indirme Yerel dev (Mac) 43 ms %0,00 Geçti 382 iterasyon; ~643 MB alındı

Payload boyut merdiveni (ne çalıştırılır)

Senaryo Dosya / yanıt boyutu Rol
upload-smoke / read-smoke 1 MiB Yalnızca hızlı kablolama kontrolü
upload-6m 6 MiB Orta boy yükleme stresi
upload-12m 12 MiB Uygulama limiti (MAX_UPLOAD_SIZE_BYTES)
upload-mix rastgele 1 / 6 / 12 MiB Gerçekçi karışık trafik
read-fat Listeler + 12 MiB görsel indirme Giden bant genişliği stresi

Payload koşuları P1–P6 özeti

  • P1–P2 (smoke): 1 MiB kasıtlı olarak küçük — betiklerin ve kimlik doğrulamanın çalıştığını doğrular.
  • P3–P5 (yükleme merdiveni): 2–3 eşzamanlı VU ile 6 MiB ve 12 MiB (izin verilen max) — hepsi geçti, localhost’ta p95 31–46 ms. P3–P5’te toplam ~835 MB yüklendi.
  • P6 (read-fat): 3 dk boyunca 5 VU, 12 MiB görsel indirmeleri — 643 MB alındı, p95 43 ms, %0 hata.
  • Not: localhost loopback gerçek ağ gecikmesini gizler; WAN/mobil benzeri sayılar için staging’de tekrar çalıştırın.
  • Kullanılan komutlar:
python3 scripts/load/generate_fixtures.py
export BASE_URL=http://127.0.0.1:8000
export K6_USERNAME=loadtest
export K6_PASSWORD=loadtest123
K6_SCENARIO=upload-6m k6 run scripts/load/payload-upload.js
K6_SCENARIO=upload-12m k6 run scripts/load/payload-upload.js
K6_SCENARIO=upload-mix k6 run scripts/load/payload-upload.js
K6_SCENARIO=read-fat k6 run scripts/load/payload-read.js

Payload şablonu (sonraki koşu için kopyala)

# Tarih upload / read senaryo Max VU Süre Boyut / limitler p95 Hata Sonuç Notlar

Bulgular — eşzamanlılık (yerel dev, 2026-06-24)

Beş eşzamanlılık koşusunun tamamı Mac geliştirme makinesinde loadtest kullanıcısı, istekler arası 1 sn think time ve tek süreç Uvicorn + PostgreSQL kullandı.

Kapasite özeti

Sabit VU Sonuç p95 (tümü) Hata oranı Not
≤20 Geçti 369 ms %0 Rahat marj
~50 Geçti 1,04 sn %0 Yük eşiklerini karşılar (p95 < 2 sn, hata < %1)
~100 Kaldı (gecikme) 2,57 sn %0 HTTP hatası yok; p95 2 sn hedefini aşıyor
ramp → 200 Kaldı 2,78 sn %6,05 334 istek zaman aşımı; API yeniden başlatılana kadar yanıt vermedi

Pratik yerel limit (mevcut kurulum): tek Uvicorn worker başına ~50 eşzamanlı kullanıcı planlayın. Bozulma 50–100 VU arasında başlar; 200+ zaman aşımı ve DB pool tükenmesine yol açar.

Sunucu çöker mi yoksa sadece çok mu yavaşlar?

Ölçülen koşular üç davranış ayırır. Yüksek yük çoğunlukla aşırı yavaşlık demektir; toplu çöküş değil. Gerçek bir kısmi çöküş (zaman aşımı, pool tükenmesi, yeniden başlatma gereksinimi) yalnızca en agresif eşzamanlılık rampasında görüldü.

Davranış Kullanıcının gördüğü HTTP / sunucu Ne zaman gördük
Sağlıklı Hızlı yanıtlar %0 hata, düşük p95 ≤20 VU okuma mix; matrix'te 1 kullanıcı, çoğu route
Yavaş ama çalışıyor Uzun beklemeler; uygulama kullanılabilir HTTP hatası %0; p95 yükselir (en kötü route'larda 1–70+ sn) ~50–100 VU okuma mix; 10–50 kullanıcıda tüm route'lara matrix yükü
Kısmi çöküş Spinner zaman aşımı; yeni istekler takılabilir Sıfır olmayan hata oranı (timeout); DB pool tükenir; yeniden başlatma gerekir Varsayılan load ramp 200 VU (~%6 hata, 334 timeout)

Önemli ayrımlar:

  • Yavaş ≠ bozuk. Mobil okuma mix'inde 100 sabit VU'da tüm istekler hâlâ 2xx döndü — p95 ~2,57 sn, %0 hata. API ayaktaydı; yalnızca 2 sn hedefi için fazla yavaştı.
  • 50 kullanıcıda matrix: users.create p95 ~67 sn'ye çıktı; koşu yine %0 HTTP hatası kaydetti — istekler bcrypt, DB pool ve tek worker kuyruğunda bekledi; toplu hata yerine sonunda tamamlandı.
  • Çöküş dar ama gerçek. Koşu #2 (50→200 VU ramp) QueuePool limit of size 30 overflow 40 reached verdi; API yeniden başlatılana kadar iş kabul etmedi. Bu kapasite tükenmesi; rastgele 500 yağmuru değil.
  • İş kuralı hatası ≠ sunucu çöküşü. 30 kullanıcıda matrix'te admin.users.delete üzerinde bir 409 (silinen kullanıcıda hâlâ bildirim) — yük altında çakışma; altyapı arızası değil.

Gözlemlenen darboğazlar

  1. Tek süreç Uvicorn — tek event loop tüm eşzamanlı istekleri işler; yük altında auth (bcrypt) ve liste uç noktaları kuyruğa girer.
  2. SQLAlchemy bağlantı havuzu — app/database.py içinde pool_size=30, max_overflow=40. Koşu #2’de QueuePool limit of size 30 overflow 40 reached ve API yeniden başlatılana kadar istek kabul etmedi.
  3. Auth uç noktası — parola hash’i yüksek VU sayılarında en yavaş yollardan biri (beklenen).
  4. Ağır liste uç noktaları — factories?limit=300, tasks?limit=100 50–100 VU’da en yüksek p95.

Önerilen sonraki adımlar

Daha ağır k6 koşularından önce:

  1. Uvicorn worker sayısını artırın — örn. uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4 (pool_size × worker ≤ PostgreSQL max_connections olduğundan emin olun).
  2. DB pool boyutunu gözden geçirin — app/database.py içindeki pool_size / max_overflow değerlerini worker sayısı ve Postgres max_connections ile hizalayın.
  3. Sabit yükü tekrar test edin — yapılandırma değişikliklerinden sonra K6_SCENARIO=load-100 tekrar çalıştırın; hedef p95 < 2 sn, %0 hata.

İsteğe bağlı takip koşuları (Koşu #6+ veya Payload P7+ olarak kaydedin):

Öncelik Senaryo Betik Amaç
Ayarlama sonrası load-100 api-load.js 100 VU’nun eşikleri geçtiğini doğrula
Baseline stress api-load.js 7 dk içinde 100 → 500 → 0
Payload upload-smoke → upload-12m payload-upload.js Yükleme boyut merdiveni (1 / 6 / 12 MiB)
Payload read-smoke → read-fat payload-read.js Büyük liste + görsel indirme
Payload read-mindmap payload-read.js Fabrika PDF üretimi (Graphviz gerekir)
Prod öncesi staging’de load-50 veya upload-mix her ikisi Gerçekçi veri hacmi ve donanım

Daha ağır koşularda ayrıca kaydedin (aşağıdaki kontrol listesine bakın): API sunucusunda CPU/bellek, PostgreSQL aktif bağlantıları ve liste payload’larının üretim satır sayılarını yansıtıp yansıtmadığı.

Şablon (sonraki koşu için kopyala)

# Tarih YYYY-AA-GG smoke / load / stress

Daha ağır koşularda kaydedilecekler

load veya stress çalıştırırken Notlar sütununa şunları da ekleyin:

  • API sunucusunda CPU / bellek
  • PostgreSQL bağlantı sayısı veya pool tükenmesi
  • p95’nin 2 sn’yi aştığı veya hataların başladığı ilk VU sayısı
  • Veri hacminin (fabrika/makine/görev satırları) gerçekçi olup olmadığı

Genel backend kapasitesi (yavaş vs çöküş)

Bu bölüm repoda kayıtlı tüm performans test türlerini birleştirir. “Çok kullanıcı olunca ne olur?” sorusuna tek yerden cevap verir.

Üç test türü — üç soru

Test Soru Araç Çöküş vs yavaşlık
Eşzamanlılık yükü Kaç kullanıcı aynı anda listelere bakabilir? scripts/load/api-load.js ~100 VU'ya kadar yavaş (%0 hata); 200 VU ramp'ta kısmi çöküş
Hacim / cardinality Tablolar büyüyünce listeler (tek kullanıcı)? scripts/volume/ Yalnızca yavaşlık — 1 istemcide T1'de %0 hata; sunucu çökmez
API matrix Her route'a çok kullanıcı vurursa? scripts/performance/ Çoğunlukla aşırı yavaş (r100/vu-50'de %0 HTTP hatası); SLO ihlali, kesinti değil

Karıştırmayın: küçük veritabanında geçen 50 VU yük testi, üretim boyutunda veriyle tüm uygulamayı 50 kullanıcının kaldıracağı anlamına gelmez.

Birleşik kapasite tablosu (yerel dev, tek Uvicorn worker)

Senaryo Yaklaşık yük Sunucu davranışı Hatalar Pratik sonuç
Tek kullanıcı, mütevazı veri 1 istemci Sağlıklı %0 Uygun
Tek kullanıcı, 6 aylık veri 1 kullanıcı Görevler 437 ms → 23 ms; fabrikalar 523 ms; makineler 351 ms %0 hata Görevler düzeltildi
~20 kullanıcı, mobil okuma mix 20 VU Sağlıklı (~370 ms p95) %0 Rahat
~50 kullanıcı, yalnızca okuma mix 50 VU Yavaş (~1 sn p95) %0 Çalışır; eşikte
~100 kullanıcı, yalnızca okuma mix 100 VU Çok yavaş (~2,6 sn p95) %0 HTTP hatası Ayakta; kabul edilemez gecikme
200 VU ramp, okuma mix 200 VU tepe Kısmi çöküş ~%6 timeout Pool tükendi; yeniden başlatma gerekti
10+ kullanıcı, tam API yüzeyi (matrix) 10–50 eşzamanlı route koşusu Yazma/auth'ta aşırı yavaş %0 HTTP (30 kullanıcıda bir 409) Ağır iş akışları için prod'a hazır değil
Büyük yükleme / yağ okuma (payload) 1–5 VU Localhost'ta sağlıklı %0 Payload boyutu ana limit değil

Trafik yönetimi için anlamı

  1. Okuma ağırlıklı iç kullanım (~20 kullanıcı, liste ekranları): backend genelde ayakta kalır ve yanıt verir; gecikme mevcut donanımda kabul edilebilir.
  2. ~50 kullanıcı yalnızca mobil yük betiğinin simüle ettiği işi yaparsa: yavaş ama çalışır — sabit load-50'de ölçülen HTTP hata oranı %0.
  3. ~50 kullanıcı gerçek yazma, kayıt, login, bildirim, teklif işlemi yaparsa: SLO'ları karşılamaz — matrix çok saniyeden dakikaya uzayan kuyruklar gösterir; istekler çoğunlukla tamamlanır, süreç çökmez.
  4. Agresif sıçramalar (200+ VU veya tükenmiş DB pool): sunucu kısmi çöküş moduna girebilir — istekler zaman aşımına uğrar, yeni bağlantılar takılır; Koşu #2'de manuel yeniden başlatma gerekti.

Ham matrix çıktıları: docs/performance-results/run-20260628-api-matrix/. Hacim ayrıntısı: Hacim Testi.

İlgili dokümanlar