WebSocket ve SSE yük testi: bağlantılar, mesajlar ve gecikme
Canlı skor ekranları, sohbet, bildirim akışları, borsa fiyatları, sipariş takibi: kullanıcıya veriyi sunucunun ittiği her ekran WebSocket ya da Server-Sent Events (SSE) kullanır. Bu ekranların yükü klasik istek/yanıt trafiğinden farklıdır: kullanıcı bir istek atıp gitmez, bağlantıyı dakikalarca, bazen saatlerce açık tutar. Sunucuyu zorlayan şey saniyedeki istek sayısından çok aynı anda açık bağlantı sayısı ve bu bağlantılara mesajın ne kadar hızlı ulaştığıdır.
WebSocket mi, SSE mi?
WebSocket iki yönlüdür: tek bir bağlantı üzerinden istemci de sunucu da istediği an mesaj gönderir. Sohbet, oyun ve ortak düzenleme gibi istemcinin de sık konuştuğu durumlarda kullanılır. SSE tek yönlüdür: istemci sıradan bir HTTP GET ile bir olay akışı (text/event-stream) açar, sunucu olayları o akıştan gönderir. Bildirim, fiyat ve durum akışları için yeterlidir ve HTTP altyapısıyla (proxy, kimlik doğrulama, sıkıştırma) doğal olarak çalışır. Testte ikisinin ölçtüğünüz şeyler de farklıdır.
Neyi ölçüyoruz?
- Eşzamanlı bağlantı sayısı. Her açık bağlantı sunucuda bellek, bir dosya tanımlayıcısı (file descriptor) ve çoğu zaman bir goroutine ya da thread tutar. Sistem 10.000 bağlantıda sorunsuzken 50.000'de bellek ya da tanımlayıcı sınırına takılabilir. Kullanıcı sayısını sanal kullanıcı (VU) sayısıyla modelleyin ve yükü dakikalara yayarak artırın.
- Bağlanma süresi. WebSocket'te el sıkışma (handshake), SSE'de akışın açılması. Bağlanma sırasında kimlik doğrulama, oturum kontrolü ve abonelik kaydı gibi işler yapılır; bu süre çoğu zaman mesaj gecikmesinden uzundur.
- Mesaj gecikmesi. WebSocket'te bir mesaj gönderip cevabını almak ya da bir olayın yayınlanmasından istemciye ulaşmasına kadar geçen süre; SSE'de akış açıldıktan sonra ilk olaya ve beklenen olaylara kadar geçen süre. Ortalama değil, p95 ve p99 (p95 ve p99 rehberi).
- Kopmalar. Bağlantı beklenmedik şekilde kapanıyor mu, mesaj gelmeden bekleme süresi doluyor mu?
Gözden kaçan üç durum
- Yeniden bağlanma dalgası. Bir deploy ya da load balancer değişikliği bütün bağlantıları aynı anda koparır ve bütün istemciler birkaç saniye içinde yeniden bağlanmaya çalışır. Sistem binlerce açık bağlantıyı taşırken bu kadar bağlantıyı aynı anda kuramayabilir. VU sayısını çok kısa sürede yükselten bir spike testi bu durumu canlandırır (test türleri).
- Proxy ve load balancer zaman aşımları. Araya giren proxy'ler boşta kalan bağlantıyı belirli bir süre sonra (çoğu zaman 60 sn) kapatır. Testin mesajsız bekleyen bir bölümü olsun ki kopma bu sürede ortaya çıksın. SSE'de proxy'nin yanıtı tamponlaması (buffering) olayları geciktirir ya da toplu gönderir; ilk olaya kadar geçen süre bunu hemen gösterir.
- Yayın (fan-out) yükü. Bir odaya ya da konuya gelen tek mesaj binlerce bağlantıya kopyalanır. Az sayıda mesaj gönderen ama çok sayıda dinleyen bir test, çok mesaj gönderen ama az dinleyen bir testten tamamen farklı bir yüktür. Oda ve konu dağılımını canlıya benzetin.
Spitfire ile
WebSocket adımı. Her VU bir URL için tek bir bağlantı tutar, bir tarayıcı sekmesi gibi: o URL'ye ihtiyaç duyan ilk adım bağlanır, sonraki adımlar ve iterasyonlar aynı bağlantıyı kullanır, sunucu bağlantıyı kapattıysa bir sonraki adım yeniden bağlanır. Böylece açık bağlantı sayısı VU sayısına eşit olur. Adımın dört işlemi vardır:
- Gönder ve yanıt bekle: mesajı gönderir, bir sonraki mesajı ya da içinde verdiğiniz metin geçen ilk mesajı bekler. Süre gönderimden yanıta kadardır; yanıt kontrollere ve değişken çıkarmaya gider.
- Gönder: yanıt beklemeden mesaj gönderir (metin ya da base64 verilen binary frame).
- Mesaj bekle: sunucunun ittiği bir sonraki mesajı bekler. Adımlar arasında gelen mesajlar bağlantı başına tamponlanır, yani iki adım arasında gelen bir bildirim kaybolmaz.
- Bağlantıyı kapat: bağlantıyı kapatır; bir sonraki WebSocket adımı yeniden bağlanır. Yeniden bağlanma davranışını test etmek için kullanışlıdır.
El sıkışma süresi ws_connecting metriği olarak ayrıca ölçülür. El sıkışmaya header ve subprotocol eklenebilir; bağlantı girişte alınan cookie'leri taşır, kurum içi servisler için İstemci sertifikası (mTLS) seçilebilir. Bekleme süresi (varsayılan 10 sn) mesaj gelmeden dolarsa ya da bağlantı beklerken kapanırsa adım başarısız olur. Mesajlar hedefte veri değiştiriyorsa adımda bunu işaretleyin; koşu başlamadan yazma onayı istenir.
SSE adımı. Akışı açar (GET, Accept: text/event-stream), beklenen sayıda olay (varsayılan 1) gelene kadar okur ve akışı kapatır. Yalnız belirli bir türdeki ya da verisinde belirli bir metin geçen olayları sayabilirsiniz. Adımın süresi son beklenen olaya kadardır; ilk olaya kadar geçen süre sse_time_to_first_event metriğidir. Son olayın verisi kontrollere gider, türü ve id'si Sse-Event ve Sse-Id header'larında okunur. Yanıt 200 değilse ya da bir olay akışı değilse, olaylar bekleme süresi (varsayılan 30 sn) dolmadan gelmezse adım başarısız olur. Akış adım boyunca açık kalır; uzun süre açık akışları canlandırmak için olay sayısını ve bekleme süresini artırın.
Bir sohbet odasına katılan, mesaj gönderip yayının kendisine dönmesini bekleyen ve bir fiyat akışından 5 olay okuyan adımlar; el sıkışma, mesaj ve ilk olay süreleri için eşikler.
"steps": [
{ "id": "join", "name": "Odaya katıl", "protocol": "ws",
"ws": { "action": "request", "url": "wss://chat.example.com/ws?token={{token}}",
"message": "{\"type\":\"join\",\"room\":\"{{room}}\"}", "match": "joined" } },
{ "id": "say", "name": "Mesaj gönder ve yayını bekle", "protocol": "ws",
"ws": { "action": "request", "url": "wss://chat.example.com/ws?token={{token}}",
"message": "{\"type\":\"say\",\"text\":\"{{$uuid}}\"}",
"match": "\"type\":\"said\"" },
"thinkTime": { "min": "2s", "max": "5s" } },
{ "id": "feed", "name": "Fiyat akışından 5 olay", "protocol": "sse",
"sse": { "url": "https://api.example.com/prices/stream",
"event": "price", "count": 5, "wait": "20s" } }
],
"thresholds": [
{ "metric": "ws_connecting", "expr": "p(95)<300" },
{ "metric": "req_duration", "filter": { "step": "say" }, "expr": "p(95)<200" },
{ "metric": "sse_time_to_first_event", "expr": "p(95)<1000" }
]Koşu sırasında her adımın istek/sn, p95, p99 ve hata oranı canlı izlenir; WebSocket ve SSE adımları aynı testte HTTP girişi ve API çağrılarıyla bir kullanıcı yolculuğu oluşturabilir.
Spitfire tek komutla Docker'a ya da Kubernetes'e kurulur; ücretsiz sürümde bütün test özellikleri ve protokoller açıktır.