Kubernetes'te dağıtık yük testi: runner'lar, ölçekleme ve birden fazla lokasyon
Tek bir makine belli bir yükten sonra test ettiğiniz sistemi değil kendisini ölçmeye başlar: CPU dolar, soketler ve geçici portlar tükenir, ağ kartı doyar ve gecikmeler yük üreticisinin içinde büyür. Dağıtık yük testi yükü birden fazla makineye (runner'a) böler ve sonuçları tek bir koşu olarak birleştirir. Kubernetes bunun için doğal bir yerdir: runner'lar pod'dur, sayıları bir komutla değişir ve test edilen sisteme yakın çalışırlar.
Ne zaman dağıtık yük gerekir?
- Yük üreticisi doyduğunda: runner'ın CPU'su yüksekken ölçülen gecikmeler güvenilmez. Kural basit: yük üreten makine zorlanıyorsa sonucu değil makineyi görüyorsunuzdur.
- Çok sayıda bağlantıda: her sanal kullanıcı en az bir soket demektir; on binlerce WebSocket ya da MQTT bağlantısı tek bir makinenin dosya tanımlayıcı ve port sınırlarına dayanır.
- Farklı lokasyonlardan: kullanıcılarınız farklı şehirlerde ya da bulut bölgelerindeyse, yükü oralardan üretmek ağ gecikmesini ve CDN/yük dengeleyici davranışını sonuca katar.
Sık yapılan hatalar
- Yüzdeliklerin ortalamasını almak. İki runner'ın p95'lerinin ortalaması bütün isteklerin p95'i değildir. Doğru sonuç, bütün runner'ların ölçümleri birleştirilerek hesaplanır (p95 ve p99 rehberi).
- Test edilen sistemle aynı node'lar. Runner pod'ları uygulamanın pod'larıyla aynı node'larda çalışırsa ikisi CPU ve ağ için yarışır; test kendi sonucunu bozar. Runner'ları ayrı bir node havuzuna ya da ayrı bir cluster'a koyun.
- CPU limitinde kısılma. Limitine dayanan bir pod'u Kubernetes kısar (throttling) ve bu, isteklerin gecikmesine runner'ın içinde eklenir. Runner'lara yeterli CPU verin ve kullanımını koşu boyunca izleyin.
- Çıkış (egress) darboğazı. Cluster dışına giden trafik bir NAT ağ geçidinden ya da tek bir çıkış IP'sinden geçiyorsa, bağlantı izleme tabloları ve port sayısı yükü sınırlar; hedef tarafta da bütün yük tek bir IP'den geliyormuş gibi görünür ve hız sınırlarına takılabilir.
Spitfire ile
Spitfire'ın kurulum betiği mevcut kubectl bağlamına her şeyi kurar: PostgreSQL, controller (web arayüzü ve API) ve runner'lar, aralarında ağ politikalarıyla. Controller tek bir pod'dur; runner'lar bir Deployment'tır ve sayıları kurulumda --runners ile verilir, sonra kubectl scale ile değiştirilir (aşağıda önce 3 runner'la kurulum, sonra 8'e çıkarma). Bütün bileşenler tek bir imajdan (amd64 ve arm64) çalışır. Seçeneklerin tamamı ve güncelleme, yedekleme adımları kurulum rehberinde.
curl -fsSL https://spitfire.tr/install.sh | bash -s -- kubernetes --namespace loadtest --runners 3
kubectl -n loadtest scale deploy/spitfire-runner --replicas=8- Yük tam bölünür. Bir koşuyu başlatırken runner'ları sayıyla, etiketle, tek tek ya da lokasyona göre seçersiniz; yük seçilen runner'lar arasında bölünür ve toplam VU sayısı ve varış hızı tanımladığınız gibi kalır. Varış hızı modellerinde her iterasyon tek bir runner'a düşer, aynı iş iki kez yapılmaz.
- Sonuç tek bir koşudur. Runner'lar ölçümlerini her saniye controller'a gönderir; controller bunları birleştirir ve p95, p99 gibi yüzdelikleri bütün ölçümler üzerinden hesaplar, runner'ların değerlerinin ortalamasını almaz. Sonuç ekranı ayrıca adım ve lokasyon kırılımını gösterir.
- Koşu başına pod'lar. Runner'ları sürekli açık tutmak yerine koşu sırasında açabilirsiniz (
--runners 0 --on-demand-runners 20): koşu sayıyla seçilen runner'lardan boşta olandan fazlasını isterse eksikler aynı imajdan pod olarak açılır, koşu bunlar bağlanana kadar (genellikle 20–60 saniye) kuyrukta bekler ve pod'lar koşu bitince silinir; aynı anda en fazla N pod açılır. Koşu penceresi testin en yüksek VU sayısından bir runner sayısı önerir (1.000 VU başına bir pod). Controller yalnız kendi namespace'inde pod yetkisi alır. - Boyutlandırma. Runner pod'larının varsayılan limiti 2 CPU ve 1 GiB bellektir. Runner, dosya tanımlayıcı sınırı VU sayısına yetmeyecek kadar düşükse uyarır; koşu sonrası bulgular da yük üreticisinin doyduğunu ayrıca söyler. Pod başına VU sayısını protokole ve düşünme süresine göre ayarlayın: düşünme süresi uzun HTTP kullanıcıları ile hiç beklemeyen bir varış hızı aynı CPU'yu çok farklı tüketir.
Birden fazla lokasyon
Başka bir cluster'da, veri merkezinde ya da bulut bölgesinde çalışan runner'lar controller'a dışarıdan içeri değil, içeriden dışarı bağlanır: TLS ile, controller'ın anahtarını sabitleyerek (key pinning). Runner'ın bulunduğu ağda hiçbir port açılmaz; yalnız controller'ın gRPC portuna giden bir bağlantı gerekir. Runner'lar sayfası kayıt anahtarını ve kurulum komutunu verir; anahtar bir lokasyona bağlanabilir.
curl -fsSL https://spitfire.tr/install.sh | bash -s -- runner \
--controller spitfire.example.com:8471 --token sfrun_… --ca-pin sha256:… --runners 2Koşuyu başlatırken yükü lokasyonlara yüzdeyle dağıtırsınız (örneğin İstanbul %60, Frankfurt %40). Sonuç ekranı her lokasyonun istek sayısını, hızını, p95'ini, p99'unu ve hatalarını ayrı gösterir; bir eşik tek bir lokasyona yazılabilir ("filter": { "location": "frankfurt" }). Bir lokasyonun p95'i diğerinden belirgin biçimde yüksekse koşu sonrası bulgular bunu söyler. Bir koşuda kullanılabilecek runner ve lokasyon sayısı lisansa bağlıdır (fiyatlar).
Kubernetes'e kurulan Spitfire'da veriler kendi altyapınızda kalır: testler, sonuçlar ve bağlantı parolaları cluster'ınızdaki PostgreSQL'dedir, runner'lar test edilen sisteme doğrudan bağlanır (on-premise yük testi). Sistemin hangi yükte kırıldığını bulmak için dağıtık yükle bir kırılma noktası testi koşturabilirsiniz.
Spitfire tek komutla Docker'a ya da Kubernetes'e kurulur; ücretsiz sürümde bütün test özellikleri ve protokoller açıktır.