- WebSocket gerçek zamanlı iletişim için yararlıdır, ancak her zaman gerekli değildir; HTTP tabanlı alternatifler daha basit ve daha kararlı olabilir
- İşlem yönetimi, bağlantı yönetimi ve sunucu karmaşıklığı açısından WebSocket gereğinden fazla ek yük yaratabilir
- HTTP Streaming ve
eventkit kütüphanesi kullanılarak WebSocket olmadan da gerçek zamanlı senkronizasyon ve olay işleme mümkün olabilir
WebSocket nedir
- WebSocket, istemci ile sunucu arasında kalıcı çift yönlü bir iletişim kanalı açan bir teknolojidir
- Bağlantı HTTP üzerinden başlatılır, ancak sonrasında iletişim ayrı bir protokol üzerinden gerçekleşir
- Gerçek zamanlı uygulamalar geliştirmede sık kullanılır ve çift yönlü iletişim sağlayabildiği için faydalıdır
WebSocket mesajları işlemsel değildir
- WebSocket, istek ile yanıt arasında doğrudan bir ilişkiyi garanti etmez
- Durum değiştirme komutları ile bunların sonuç mesajları aynı akış içinde karışık şekilde gelebilir
- Örneğin bir istemci durumu değiştirip hata alsa bile, bu hatanın hangi komuta ait olduğunu anlamak zor olabilir
- Çözüm olarak komut ile yanıtı bağlamak için
requestId eklenebilir, ancak bu da karmaşıklığı ve yönetim maliyetini artırır
- Komutları HTTP kullanan işlemsel bir yöntemle gönderip, WebSocket’i yalnızca durum değişikliklerini yayınlamak için kullanmak daha basittir
- Gönderim tarafı HTTP isteğiyle, alım tarafı ise WebSocket veya başka bir streaming yöntemiyle ayrılabilir
WebSocket bağlantı yaşam döngüsünü yönetmenin zorlukları
- WebSocket kullanıldığında bağlantının başlatılması, sonlandırılması, hata durumu ve yeniden bağlanma gibi konuların doğrudan ele alınması gerekir
- Tarayıcıdaki temel işleyiş örnekleri; bağlantının açılması, mesaj alınması, hata oluşması ve bağlantının kapanması olaylarının işlenmesini içerir
- Yeniden bağlanma mantığı, mesaj arabelleğe alma ve exponential backoff gibi ek mantık gerekir
- Buna karşılık HTTP’de her isteğin başlangıcı ve sonu nettir, bu da uygulamayı basitleştirir
- Karmaşık yaşam döngüsü yönetimi, ancak WebSocket kullanmak için güçlü bir gerekçe olduğunda haklı çıkarılabilir
Sunucu kodunda artan karmaşıklık
- WebSocket, HTTP upgrade isteklerini işlemek zorundadır; bu da ek handshake mantığı gerektirir
Sec-WebSocket-Key gibi özel header’ların doğrulanması ve uygun yanıt header’larının döndürülmesi gerekir
- WebSocket bağlantısı kurulduktan sonra mesaj alma ve gönderme durumunu sürekli korumak gerekir; parçalı frame işleme gibi sorunlar da ortaya çıkabilir
- Yalnızca HTTP kullanmaya kıyasla debug etme ve hata işleme daha zordur
- Framework’ler bazı süreçleri soyutlasa da temel karmaşıklık ortadan kalkmaz
Alternatif: HTTP Streaming
- HTTP, doğası gereği streaming destekleyen bir protokoldür; tüm dosyayı değil, veri akışını gerçek zamanlı olarak iletebilir
- Mevcut WebSocket’in yalnızca alım tarafındaki işlevi HTTP streaming ile değiştirilebilir
- Asenkron generator’lar kullanılarak durum güncellemeleri akış biçiminde işlenebilir
- Sunucu tarafı akışı
- Durum güncellemeleri komut işleme işlevinde yapılır
- Bağlı istemciler, generator aracılığıyla her yeni değer geldiğinde bunu alır
- Durum değiştirme komutları HTTP POST ile gönderilir, gerçek zamanlı akış ise GET isteğiyle abone olunarak alınır
- İstemci tarafı akışı
- Fetch API ve Stream Reader üzerinden gerçek zamanlı veri alınır
- Metin decode edildikten sonra UI güncellenir
- Bu yapıyla WebSocket olmadan da gerçek zamanlı durum senkronizasyonu uygulanabilir
Bonus: eventkit kütüphanesine kısa bir giriş
eventkit, asenkron akışları kolayca kurup gözlemlemeyi sağlayan bir kütüphanedir
- RxJS’e benzer, ancak yan etki yönetimi iyileştirilmiştir ve generator tabanlı tasarlanmıştır
- Durum güncellemeleri akışa push edildiğinde, istemci bunları gerçek zamanlı olarak alabilir
Stream ve AsyncObservable ile hem sunucu hem istemci tarafında basit uygulamalar kurulabilir
- Sunucu tarafında
eventkit kullanımı
- Durum değişiklikleri Stream’e push edilir ve istemciler bu akışa abone olur
- İstemci tarafında
eventkit kullanımı
- Akış verisi alınır, decode edilir ve ardından UI güncellenir
- Resmî GitHub deposu ve HTTP Streaming rehberi de sunulmaktadır
GitHub: https://github.com/hntrl/eventkit
3 yorum
Hacker News görüşleri
HTTP streaming’in bu kullanım kalıbı düşünülerek tasarlandığını sanmıyorum. HTTP streaming, büyük veriyi parçalara bölmek içindir. Streaming’i bir pub/sub mekanizması gibi kullanırsanız pişman olabilirsiniz. HTTP aracılar bu trafik kalıbını beklemez (NGINX, CloudFlare vb.). WiFi bağlantısı her koptuğunda fetch API muhtemelen isteği başarısız sayıp hata üretecektir
İstek/yanıt döngüsü elde etmek için sunucuya RequestID göndermek garip ya da aşırı bir şey değil. Ciddi uygulamalarda
send(message).then(res => ...)gibi bir API’ye sahip olmak her zaman değerlidirheaders['authorization']okuyan middleware’i yeniden kullanmak yerine, istek başlığıymış gibi davrananconnectionParamsnesnesine erişmek gerekiyorVideo streaming’de istemci chunk’ları range ile ister; bu tek bir HTTP bağlantısı değildir
EventKit yerine SSE kullanmak daha iyi
POC’de geleneksel HTTP form gönderimini kullanacağım. Başka bir şeye gerek yok
HTTP2 ile ilgili sorun, server push’ın mevcut protokolün üstüne eklenmiş olması. HTTP bir kaynak aktarım protokolüdür ve gereksiz ek yük getirir. HTTP2’nin ana amacı, sunucunun dosyaları/kaynakları istemciye önceden iterek gidiş-dönüş gecikmesini azaltmasıdır
WebSockets akış olarak değil, datagram (paket) olarak gönderir. JavaScript kütüphanelerindeki WebSockets API’si backpressure’ı yönetemez ve tüm hataları ele alamaz. Onu TCP stream gibi kullanacaksanız dikkatli olmanız gerekir
WebSockets’i production’a aldıktan sonra pişman oldum. NGINX’in 4/8 saat sonra bağlantıyı kapatması, tarayıcının uykudan sonra yeniden bağlanmaması gibi sorunlar vardı. Mümkünse WebSockets’ten ve uzun süreli bağlantılardan kaçınmak gerekir
WebSockets hakkında idealize edilmiş bir algı var. Streaming/gerçek zamanlı kullanım senaryolarında WebSockets kullanma eğilimi bulunuyor. WebSockets, HTTP araçlarının sadeliğini ve avantajlarını kaybettiriyor. Streaming sunucu değişiklikleri için çözüm h2/h3 ve SSE’dir. İstemci başına en fazla 0.5 req/s olacak şekilde batch edebiliyorsanız WebSockets’e ihtiyacınız yok
HTTP streaming ile ilgilenenler Braid-HTTP’ye bakmalı. HTTP’yi event streaming için zarif biçimde genişleterek güçlü bir durum senkronizasyon protokolü sunuyor