“Load balancer var, ölçekleniriz” cümlesi doğru başlar; ama state devreye girince hikâye değişir. WebSocket, uzun TCP bağlantıları, in-memory session veya yerel disk bağımlılığı olan uygulamalarda sticky session (session affinity) bir “kolay çözüm” gibi görünür. Üretimde ise sticky; doğru kullanılırsa istikrar, yanlış kullanılırsa incident hızlandırıcı olur.
Bu yazıda sticky session’ın hangi durumda makul olduğunu, hangi durumda teknik borç ürettiğini ve en önemlisi operasyonel yönetilebilirlik açısından karar matrisini anlatıyorum.
Sticky session neden ortaya çıkar?
En yaygın sebepler:
- Uygulama state’i node üzerinde tutulur (memory cache, session store, local file)
- WebSocket/streaming gibi uzun bağlantılar vardır
- Bazı dependency’ler connection-level davranışa hassastır (ör. stateful upstream, legacy middleware)
- “Hızlı olsun” diye dış session store yerine local state seçilmiştir
Sticky session’ın görünmeyen maliyeti
Sticky genelde şu maliyetleri üretir:
- Dengesiz yük: bazı node’lar dolu, bazıları boş
- Canary/blue-green sürtünmesi: kullanıcıların bir kısmı eski node’a “takılı kalır”
- Failover şoku: bir node düşünce o node’a bağlı kullanıcılar aynı anda kopar
- Debug zorlaşması: “hangi kullanıcı hangi node’da?” sorusu incident anında zaman yer
Karar matrisi: Sticky mi, stateless mı?
Sahada pratik bir karar sorusu:
1) State’i taşımak mümkün mü?
- Evet → stateless hedefle:
- session’ı dış store’a al (Redis gibi)
- cache’i paylaştır veya yeniden üretilebilir kıl
- dosya bağımlılığını object storage’a taşı
- Hayır (kısa vadede) → sticky geçici olabilir; ama çıkış planı şart
2) Bağlantı süresi uzun mu?
- WebSocket / streaming → sticky yerine çoğu zaman connection draining + graceful shutdown kritik olur
- Kısa HTTP request’leri → sticky genellikle daha az gerekçelidir
3) Failure budget var mı?
- “Node düşebilir” gerçeğini kabul edip kullanıcı etkisini sınırlayabiliyor musun?
- Sticky kullanıyorsan, node kaybında etkilenme toplu olur; bu riski taşıyacak mısın?
Sticky’nin “doğru” kullanıldığı senaryolar
Sticky bazen gerçekten pragmatiktir:
- Legacy uygulama state’i çok karmaşıktır ve kısa vadede refactor gerçekçi değildir
- Kullanıcı oturum kaybı toleranslıdır (ör. iç admin paneli)
- Scale hedefi “çok büyük” değil, daha çok “süreklilik”tir
- İyi bir drain + deploy disiplini vardır
Alternatif desenler (sticky’ye göre daha sürdürülebilir)
1) Stateless + dış session store
En yaygın ve sürdürülebilir yol. Ama iki kritik not:
- Session store, artık “kritik state” olur → HA/latency/backup planı şart
- Network gecikmesi ve serialization maliyetini ölçmeden geçme
2) Consistent hashing (kontrollü affinity)
Sticky’nin “rastgele” değil “tahmin edilebilir” versiyonu. Özellikle cache shard’larında işe yarar. Fakat node sayısı değişince yeniden dağılım olur; bunu planla.
3) Read/write ayrımı ve state sınırı
Her request stateful olmak zorunda değil. Örneğin:
- read path stateless
- write path daha kontrollü, dar kapsam
Bu ayrım, blast radius’u dramatik düşürür.
4) Graceful shutdown + connection draining
WebSocket/uzun bağlantılarda sticky tek başına yetmez. Operasyonel başarı çoğu zaman şunlara bağlıdır:
- drain başladığında yeni bağlantıyı kes, eskileri tamamlat
- LB health check’ini “trafik alabilir mi?” ile eşleştir
- deploy sırasında eşzamanlı restart sayısını sınırla
Operasyonel kontrol listesi
Sticky olsun ya da olmasın, şu soruların cevabı yazılı olmalı:
- Node düşerse kullanıcı etkisi nasıl dağılır?
- Hangi metrikler “state sorunu” sinyali verir? (disconnect rate, session error, uneven CPU/mem)
- Deploy sırasında kaç node aynı anda çıkabilir?
- Rollback kriteri nedir? (SLO, error rate, disconnect spike)
Sonuç
Sticky session, doğru bağlamda kullanılınca iyi bir geçiş stratejisi olabilir; ama çoğu zaman state tasarımındaki borcu görünmez kılar. Üretimde sürdürülebilir hedef; state’i dışarı taşımak, connection draining ile deploy riskini yönetmek ve failure senaryosunda kullanıcı etkisini dağıtmaktır. “Çalışıyor” yetmez; bozulduğunda nasıl davranıyor sorusunu tasarımın merkezine koymak gerekir.