WebSockets ile Gerçek Zamanlı İletişimin Derinlikleri: Anlık Mesajlaşma Uygulamaları Nasıl Tasarlanır?

Günümüz dijital dünyasında anlık etkileşim ve gerçek zamanlı veri akışı vazgeçilmez bir ihtiyaç haline geldi. Canlı sohbetler, oyunlar, borsa uygulamaları veya anlık bildirimler… Tüm bunlar, istemci ile sunucu arasında kesintisiz ve hızlı bir iletişimi gerektirir. Peki, bu dinamik etkileşimin arkasındaki sihir nedir? İşte burada WebSockets devreye giriyor.

Geleneksel HTTP istek-yanıt modelinin ötesine geçerek çift yönlü ve kalıcı bir bağlantı sunan WebSockets, modern web uygulamalarının temel taşlarından biridir. Bu makalede, WebSockets’in nasıl çalıştığını, diğer istemci-sunucu iletişim yöntemlerinden farklarını ve gerçek zamanlı mesajlaşma uygulamalarını tasarlarken nelere dikkat etmeniz gerektiğini derinlemesine inceleyeceğiz. Böylece, karşılaşılan yaygın hatalardan kaçınarak daha sağlam sistemler kurabilirsiniz.

İstemci-Sunucu İletişim Yöntemlerine Genel Bakış

İstemci-sunucu iletişimi, bir istemcinin (örneğin web tarayıcısı veya mobil uygulama) veri talebinde bulunması ve sunucunun bu talepleri işleyerek yanıt döndürmesi esasına dayanır. Ancak gerçek zamanlı ihtiyaçlar, bu iletişimin farklı yöntemlerle ele alınmasını gerektirir. WebSockets’e geçmeden önce, diğer önemli iletişim modellerini hatırlayalım.

Kısa Yoklama (Short Polling)

En basit yöntem olan kısa yoklamada, istemci düzenli aralıklarla (örneğin her birkaç saniyede bir) sunucuya yeni veri olup olmadığını sormak için HTTP istekleri gönderir. Her istek bağımsız ve tek yönlüdür (istemci → sunucu).

Bu yöntem kurulumu kolay olsa da, sunucuda nadiren yeni veri varsa gereksiz kaynak tüketimine yol açabilir. Daha az zaman hassasiyetine sahip uygulamalar için uygun olabilir.

Uzun Yoklama (Long Polling)

Uzun yoklama, kısa yoklamanın bir geliştirilmiş versiyonudur ve gereksiz istek sayısını azaltmayı hedefler. Sunucu, istemci isteğine hemen yanıt vermek yerine, yeni veri gelene kadar bağlantıyı açık tutar. Veri geldiğinde yanıtı gönderir ve istemci hemen yeni bir bağlantı kurar.

Uzun yoklama da durumsuz ve tek yönlüdür (istemci → sunucu). Bir araç çağırma uygulamasında, istemcinin bir eşleşme veya rezervasyon güncellemesi beklemesi tipik bir örnektir.

Webhooks

Webhooks, sunucunun inisiyatifi ele almasını sağlar. Sunucu, belirli olaylar meydana geldiğinde önceden tanımlanmış bir istemci uç noktasına HTTP POST istekleri gönderir. Her istek bağımsızdır ve kalıcı bir bağlantıya dayanmaz.

Webhooks da tek yönlüdür (sunucu → istemci) ve genellikle üçüncü taraf hizmetlerle entegrasyonlarda asenkron bildirimler için kullanılır. Örneğin, ödeme sistemleri işlem durumu değiştiğinde istemcileri bilgilendirmek için webhooks kullanır.

Sunucu Tarafından Gönderilen Olaylar (Server-Sent Events – SSE)

SSE, sunucuların tek, kalıcı bir bağlantı üzerinden istemcilere gerçek zamanlı güncellemeler göndermesine olanak tanıyan HTTP tabanlı bir olay akışı protokolüdür. EventSource API’si kullanılarak kolayca uygulanabilir.

SSE de tek yönlüdür (sunucu → istemci) ve istemcinin sadece güncelleme alması gereken durumlar için idealdir. Borsa platformları veya canlı spor güncellemeleri gibi sunucunun sürekli veri akışı sağladığı uygulamalar için uygundur. Bu senaryolarda istemcinin sunucuya veri göndermesine gerek yoktur.

Yukarıdaki yöntemlerin hepsi tek yönlü veri akışına odaklanırken, gerçek çift yönlü ve anlık alışverişler için farklı bir yaklaşıma ihtiyaç duyarız. İşte tam da bu noktada WebSockets devreye girer.

WebSockets Nasıl Çalışır?

WebSockets, gerçek zamanlı, çift yönlü iletişim sağlayarak sohbet uygulamaları, canlı bildirimler ve çevrimiçi oyunlar gibi uygulamalar için mükemmel bir çözüm sunar. Geleneksel HTTP istek-yanıt modelinin aksine, WebSockets kalıcı bir bağlantı oluşturur; böylece hem istemci hem de sunucu, bir istek beklemeksizin bağımsız olarak mesaj gönderebilir.

Bu bağlantı, normal bir HTTP isteği olarak başlar ve bir el sıkışma (handshake) süreciyle WebSocket bağlantısına yükseltilir. Kurulduktan sonra, HTTP ile aynı portlar (80 ve 443) üzerinden tek bir TCP bağlantısı kullanır. WebSockets üzerinden gönderilen mesajlar küçük ve hafiftir, bu da onları düşük gecikmeli, yüksek etkileşimli kullanım durumları için verimli kılar.

WebSocket El Sıkışma (Handshake) Süreci

El sıkışma, iki sistem arasında bir bağlantının başlatılması sürecidir. WebSockets için bu süreç, istemciden bir protokol yükseltme talebi içeren bir HTTP GET isteğiyle başlar. Bu, kalıcı bir WebSocket bağlantısına geçmeden önce HTTP altyapısıyla uyumluluğu sağlar.

1. İstemci İsteği

İstemci, sunucuya şu başlıklara benzer bir HTTP GET isteği gönderir:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

Burada Upgrade: websocket protokol değiştirme isteğini işaret ederken, Sec-WebSocket-Key el sıkışma doğrulaması için kullanılan rastgele oluşturulmuş bir anahtardır.

2. Sunucu Yanıtı

Sunucu WebSockets’i destekliyorsa ve yükseltmeyi kabul ediyorsa, 101 Switching Protocols durum koduyla yanıt verir. Örnek başlıklar şunlara benzer:

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat

Sec-WebSocket-Accept, istemcinin Sec-WebSocket-Key‘inin ve belirli bir GUID’nin Base64 kodlu karma değeridir. Bu, el sıkışmanın güvenli ve geçerli olmasını sağlar.

3. El Sıkışma Doğrulaması ve Bağlantı Kurulumu

101 Switching Protocols yanıtıyla birlikte, WebSocket bağlantısı başarıyla kurulur ve hem istemci hem de sunucu gerçek zamanlı olarak mesaj alışverişine başlayabilir. Bu bağlantı, taraflardan biri tarafından açıkça kapatılana kadar açık kalır. 101 dışında herhangi bir kod döndürülürse, istemcinin bağlantıyı sonlandırması gerekir ve WebSocket el sıkışması başarısız olur.

WebSocket Kullanım Alanları

WebSockets’in gerçek zamanlı, çift yönlü iletişimi nasıl sağladığını konuştuk, ancak bu hala soyut bir terim. Şimdi bazı somut örneklere bakalım.

WebSockets, Excalidraw, Telegram, WhatsApp, Google Docs, Google Haritalar gibi gerçek zamanlı işbirliği araçlarında ve sohbet uygulamalarında yaygın olarak kullanılır. Ayrıca YouTube veya TikTok canlı yayınlarındaki canlı sohbet bölümleri de WebSockets teknolojisini kullanarak anlık etkileşim imkanı sunar.

WebSockets’in Dezavantajları ve Dikkat Edilmesi Gerekenler

Her güçlü teknoloji gibi, WebSockets’in de bazı dezavantajları ve dikkat edilmesi gereken noktaları vardır.

Bağlantı Sonlandığında Yedek Strateji İhtiyacı

Ağ sorunları, sunucu çökmeleri veya diğer hatalar nedeniyle bağlantı kesilirse, WebSockets otomatik olarak kurtarma yapmaz. İstemcinin bağlantı kesilmesini açıkça tespit etmesi ve bağlantıyı yeniden kurmaya çalışması gerekir. Genellikle bir WebSocket bağlantısı yeniden kurulmaya çalışılırken uzun yoklama bir yedek olarak kullanılır.

Ses ve Video Akışı İçin Optimize Edilmemiş

WebSocket mesajları, küçük, yapılandırılmış mesajlar göndermek için tasarlanmıştır. Büyük medya verilerini akışla iletmek için WebRTC gibi teknolojiler bu senaryolar için daha uygun çözümler sunar.

Durum Bilgisi Olan Yapı ve Yatay Ölçeklemenin Zorluğu

WebSockets durum bilgisi olan (stateful) bir yapıya sahiptir, yani sunucunun her istemci için aktif bir bağlantıyı sürdürmesi gerekir. Bu durum, durumsuz (stateless) HTTP’ye kıyasla yatay ölçeklemeyi daha karmaşık hale getirir. Geniş ölçekli sistemlerde, bu karmaşıklığı yönetmek için ek bir yayınla-abone ol (pub/sub) mekanizması katmanına ihtiyaç duyulabilir.

Gerçek Zamanlı Bir Mesajlaşma Uygulaması Tasarımı

Şimdi WebSockets’in sistem tasarımında nasıl uygulandığını inceleyelim. Hem basit (ölçeklenemeyen) çözümü hem de yatay olarak ölçeklenmiş bir sistemi ele alacağız.

Ölçeklenemeyen Tek Sunuculu Uygulama

İki kullanıcı gerçek zamanlı olarak nasıl sohbet eder?

Tüm kullanıcılar WebSocket üzerinden tek bir sunucuya bağlanır. Sunucu, kullanıcıID : WebSocket bağlantısı şeklinde bellek içi bir eşleme tutar. Kullanıcı1, mesajı WebSocket bağlantısı üzerinden sunucuya gönderir. Sunucu, mesajı Mesaj Veritabanına (önce kalıcılık) yazar. Ardından sunucu, Kullanıcı2’nin WebSocket bağlantısını bellek içi haritasında arar. Kullanıcı2 çevrimiçiyse, mesajı gerçek zamanlı olarak teslim eder. Kullanıcı2 çevrimdışıysa, sunucu mesajı Gelen Kutusu Veritabanına (teslim edilmemiş mesajların deposu) yazar. Kullanıcı2 çevrimiçi olduğunda, sunucu tüm çevrimdışı mesajları Gelen Kutusu Veritabanından alır.

Yatay Olarak Ölçeklenmiş Sistem

Tek bir sunucu belirli sayıda eşzamanlı WebSocket bağlantısını kaldırabilir. Daha fazla kullanıcıya hizmet vermek için WebSocket bağlantılarınızı yatay olarak ölçeklendirmeniz gerekir. Temel zorluk şudur: Kullanıcı1 sunucu1’e bağlıysa ancak Kullanıcı2 sunucu2’ye bağlıysa, sistem mesajı nereye göndereceğini nasıl bilir?

Redis, aktif WebSocket oturumları için kullanıcıID : sunucuID eşlemesini tutan global bir veri deposu olarak kullanılabilir. Her sunucu, bir kullanıcı bağlandığında (çevrimiçi olduğunda) veya bağlantısı kesildiğinde (çevrimdışı olduğunda) Redis’i günceller.

Örneğin: Kullanıcı1 sunucu1’e bağlanır. Sunucu1’in bellek içi haritası: kullanıcı1 : WebSocket bağlantısı. Sunucu1 ayrıca Redis’e yazar: kullanıcı1 : sunucu1. Kullanıcı2 sunucu2’ye bağlanır. Sunucu2’nin bellek içi haritası: kullanıcı2 : WebSocket bağlantısı. Sunucu2 ayrıca Redis’e yazar: kullanıcı2 : sunucu2.

Uçtan Uca Sohbet Akışı: Kullanıcı1 Kullanıcı2’ye Mesaj Gönderir

Kullanıcı1, mesajı sunucu1 üzerindeki WebSocket’i aracılığıyla gönderir. Sunucu1, mesajı bir Sohbet Servisine iletir. Sohbet Servisi, önce mesajı kalıcılık için Mesaj Veritabanına yazar. Sohbet Servisi, ardından Kullanıcı2’nin çevrimiçi/çevrimdışı durumunu almak için Redis’i kontrol eder.

Kullanıcı2 çevrimiçiyse, Sohbet Servisi mesajı bir mesaj broker’ına yayınlar ve mesajı "kullanıcı2: sunucu2" etiketiyle işaretler. Broker, mesajı sunucu2’ye yönlendirir. Sunucu2, Kullanıcı2’nin WebSocket bağlantısını bulmak için yerel bellek içi eşlemesini arar ve mesajı o WebSocket üzerinden gerçek zamanlı olarak iletir.

Kullanıcı2 çevrimdışıysa (Redis’te giriş yoksa), Sohbet Servisi mesajı Gelen Kutusu Veritabanına yazar. Kullanıcı2 çevrimiçi olduğunda, Sohbet Servisi teslim edilmemiş tüm mesajları getirir. Yeni bir WebSocket bağlantısı açıldığında veya kapatıldığında sunucular Redis’i günceller. Bir kullanıcı uygulamayı ilk yüklediğinde veya bir sohbeti açtığında, Sohbet Servisi Mesaj Veritabanından geçmiş mesajları (örneğin son 10 günden) getirir. Bir önbellek katmanı tekrarlanan veritabanı sorgularını azaltabilir.

Önemli Tasarım Hususları

Önce Kalıcılık

Tüm mesajlar teslim edilmeden önce veritabanına kaydedilir. Bir WebSocket’e gönderme başarısız olsa bile, mesaj veritabanında güvende kalır.

Redis Kullanımı

Redis sadece aktif bağlantıları saklayarak ek yükü en aza indirir. Tek bir hata noktasını önlemek için bir replika eklenebilir. Gelen Kutusu Veritabanı, çevrimdışı durumları sorunsuz bir şekilde yönetmeye yardımcı olur.

Sohbet Servisi Soyutlaması

WebSocket sunucuları gerçek zamanlı bağlantıları ve yönlendirmeyi yönetirken, Sohbet Servisi katmanı HTTP isteklerini ve tüm veritabanı yazma işlemlerini ele alır. Bu sorumluluk ayrımı, her bir parçayı ölçeklemeyi veya geliştirmeyi kolaylaştırır.

Mesajların Sıralı Teslimini Sağlama

Tipik “gerçek zamanlı itme” iş akışları, ağ varyasyonları nedeniyle mesajların sırasız gelmesine neden olabilir. Birçok mesaj broker’ı da kesin sıralama garantisi vermez. Bunu ele almak için, her mesaja oluşturulduğunda bir zaman damgası atanır. Mesajlar sırasız gelse bile, istemci bunları zaman damgasına göre yeniden sıralayabilir.

Yük Dengeleyiciler

Kalıcı WebSocket bağlantıları için L4 Yük Dengeleyici (TCP) ve normal istekler (CRUD, giriş vb.) için L7 Yük Dengeleyici (HTTP) kullanmak performansı ve istikrarı artırır. Doğru yük dengeleme stratejisi, sisteminizin yüksek trafik altında bile sorunsuz çalışmasını sağlar.

WebSockets, modern gerçek zamanlı uygulamaların temelini oluşturur ve doğru tasarlandığında muazzam bir esneklik ve performans sunar. Bu derinlemesine inceleme, WebSockets’in gücünü anlamanıza ve kendi sistemlerinizi tasarlarken karşılaşabileceğiniz zorlukları aşmanıza yardımcı olmayı amaçlamaktadır. Anlık mesajlaşma veya diğer gerçek zamanlı ihtiyaçlarınız için bu bilgileri kullanarak daha sağlam, ölçeklenebilir ve kullanıcı dostu uygulamalar geliştirebilirsiniz.

Yorum yapın