Canlı panolar için WebSockets ile Server-Sent Events (SSE) karşılaştırması: seçim için basit kurallar, ölçeklenme temelleri ve bağlantılar koptuğunda yapılması gerekenler.

Canlı bir pano temelde bir sözleşmedir: sayılar yenilenir, siz sayfayı yenilemezsiniz ve gördükleriniz şu anki duruma yakın olur. İnsanlar güncellemelerin hızlı hissettirmesini bekler (genellikle bir-iki saniye içinde), ama sayfanın sakin kalmasını da isterler. Titreme, zıplayan grafikler ya da her birkaç dakikada bir görünen "Bağlantı kopuk" uyarısı istemezler.
Çoğu pano sohbet uygulaması değildir. Genellikle güncellemeler sunucudan tarayıcıya doğru akar: yeni metrik noktaları, değişen bir durum, yeni satır topluları veya bir uyarı. Yaygın kullanım şekilleri tanıdık: bir metrik tablosu (CPU, kayıtlar, gelir), bir uyarılar paneli (yeşil/sarı/kırmızı), bir log kuyruğu (son olaylar) veya bir ilerleme görünümü (iş %63'te, sonra %64).
WebSockets ile Server-Sent Events (SSE) arasındaki tercih sadece teknik bir tercih değildir. Hangi yolu seçtiğiniz, yazacağınız kod miktarını, ele almanız gereken tuhaf kenar durumlarını ve 50 kullanıcıyken çalışırken 5.000 olunca maliyetin ne kadar artacağını değiştirir. Bazı seçenekler yük dengeleme açısından daha kolaydır. Bazıları yeniden bağlanma ve telafi mantığını basitleştirir.
Amaç basit: pano doğru kalmalı, duyarlı olmalı ve büyüdükçe sizin için bir nöbet kabusu haline gelmemeli.
WebSockets ve Server-Sent Events, panonun sürekli anket yapmadan güncellenebilmesi için bir bağlantıyı açık tutar. Fark, konuşmanın nasıl işlediğindedir.
WebSockets bir cümlede: tarayıcı ve sunucunun istedikleri zaman mesaj gönderebildiği tek, uzun ömürlü bir bağlantı.
SSE bir cümlede: tarayıcının aynı akış üzerinde karşı tarafa mesaj göndermediği, sunucunun tarayıcıya sürekli olay gönderdiği uzun ömürlü bir HTTP bağlantısı.
Bu fark genellikle hangi yaklaşımın doğal hissettireceğini belirler.
Somut bir örnek: sadece gelir, aktif denemeler ve hata oranlarını gösteren bir satış KPI panosu SSE ile rahatça çalışabilir. Bir kullanıcının emir verdiği, onay aldığı ve her işlem için anında geri bildirim beklediği bir işlem ekranı ise WebSocket'lere daha uygundur.
Hangi yolu seçerseniz seçin, bazı şeyler değişmez:
Taşıma son milidir. Zor kısımlar genellikle her iki durumda da aynıdır.
Ana fark kim konuşabilir ve ne zaman konuştuğudur.
Server-Sent Events ile tarayıcı bir uzun süreli bağlantı açar ve sadece sunucu güncellemeleri bu borudan aşağı gönderir. WebSockets ile bağlantı iki yönlüdür: tarayıcı ve sunucu istedikleri zaman mesaj gönderebilir.
Çoğu pano için trafiğin büyük kısmı sunucudan tarayıcıya doğrudur. "Yeni sipariş geldi", "CPU %73", "bilet sayısı değişti" gibi. SSE bu şekle iyi uyar çünkü istemci çoğunlukla dinler.
WebSockets, pano aynı zamanda bir kontrol paneli olduğunda mantıklı olur. Kullanıcının sık sık aksiyon göndermesi gerekiyorsa (uyarıları onaylama, paylaşılan filtreleri değiştirme, işbirliği), iki yönlü mesajlaşma sürekli yeni istekler yaratmaktan daha temiz olabilir.
Mesaj yükleri genellikle her iki durumda da basit JSON olaylarıdır. Yaygın bir desen, istemcinin güncellemeleri güvenle yönlendirebilmesi için küçük bir zarf (envelope) göndermektir:
{"type":"metric","name":"active_users","value":128,"ts":1737052800}
Fan-out (bir güncellemenin aynı anda birçok izleyiciye ulaşması) panoları ilginç kılar. Hem SSE hem de WebSockets aynı olayı binlerce açık bağlantıya yayınlayabilir. Fark operasyoneldir: SSE uzun bir HTTP yanıtı gibi davranırken, WebSockets yükseltme (upgrade) sonrası ayrı bir protokole geçer.
Canlı bir bağlantı olsa bile, başlangıç sayfa yüklemesi, geçmiş veriler, dışa aktarma, oluştur/sil eylemleri, kimlik yenileme ve canlı akışa ait olmayan büyük sorgular için normal HTTP isteklerini kullanırsınız.
Pratik bir kural: canlı kanal küçük, sık olaylar için olsun; her şeyin geri kalanı HTTP olsun.
Pano sadece tarayıcıya güncelleme itiyorsa, SSE genellikle basitlik açısından öne çıkar. Bu, açık kalan ve metin olayları gönderen bir HTTP yanıtıdır. Daha az hareketli parça, daha az kenar durumu demektir.
WebSockets, istemcinin sık sık geriye konuşması gerektiğinde harikadır, ama bu özgürlük, korumanız gereken ek kod anlamına gelir.
SSE ile tarayıcı bağlanır, dinler ve olayları işler. Yeniden bağlanma ve temel yeniden deneme davranışı çoğu tarayıcıda yerleşiktir, bu yüzden bağlantı durumuna daha az, olay yüklerine daha çok zaman harcarsınız.
WebSockets ile soket yaşam döngüsünü birinci sınıf özellik olarak yönetmeye başlarsınız: connect, open, close, error, reconnect ve bazen ping/pong. Birçok mesaj türünüz varsa (filtreler, komutlar, onaylar, varlık sinyalleri), hem istemci hem sunucu tarafında mesaj zarfı ve yönlendirme gerekir.
İyi bir kural:
SSE genellikle hata ayıklaması daha kolaydır çünkü normal HTTP gibi davranır. Tarayıcı geliştirici araçlarında olayları kolayca görebilir ve birçok proxy ile gözlemlenebilirlik aracı HTTP'yi zaten iyi anlar.
WebSockets daha belirgin olmayan şekillerde başarısız olabilir. Yaygın sorunlar: yük dengeleyicilerden sessiz kopmalar, boşta zaman aşımı ve bir tarafın hâlâ bağlı olduğunu düşündüğü "yarı açık" bağlantılar. Sorunları genellikle kullanıcılar eski panolar rapor edene kadar fark etmezsiniz.
Örnek: sadece canlı toplamlar ve son siparişleri gösteren bir satış panosu inşa ediyorsanız, SSE sistemi stabil ve okunabilir tutar. Aynı sayfada hızlı kullanıcı etkileşimleri (paylaşılan filtreler, işbirlikçi düzenleme) olması gerekiyorsa, WebSockets ek karmaşıklığa değer olabilir.
Bir pano birkaç izleyiciden binlerce izleyiciye geçtiğinde, ana sorun ham bant genişliği değildir. Açık tutmanız gereken bağlantı sayısı ve bu istemcilerden bazılarının yavaş veya dengesiz olması durumunda ne olacağıdır.
100 izleyiciyle her iki seçenek de benzer hisseder. 1.000'de bağlantı limitleri, zaman aşımı ve istemcilerin ne sıklıkla yeniden bağlandığı önem kazanmaya başlar. 50.000'de ise bağlantı ağırlıklı bir sistem işletiyorsunuz: istemci başına tamponlanan her ekstra kilobayt gerçek bellek basıncına dönüşebilir.
Ölçek farkları genellikle yük dengeleyicide gösterir.
WebSockets uzun ömürlü, iki yönlü bağlantılar olduğu için birçok kurulum yapışkan oturum (sticky sessions) gerektirir; yoksa paylaşılan bir pub/sub katmanı ve herhangi bir sunucunun herhangi bir kullanıcıyı işleyebilmesi gerekir.
SSE de uzun ömürlüdür, ama düz HTTP olduğu için mevcut proxylerle daha sorunsuz çalışma eğilimindedir ve fan-out yapmak daha kolay olabilir.
Sunucuları stateless (durumsuz) tutmak genellikle panolar için SSE ile daha basittir: sunucu paylaşılan bir akıştan olayları itebilir ve istemci başına fazla şey hatırlamak zorunda kalmaz. WebSockets ile ekipler genellikle bağlantı başına durum (abonelikler, son görülen ID'ler, auth bağlamı) saklamaya başlar; bu da yatay ölçeklendirmeyi zorlaştırır, erken tasarlamazsanız.
Yavaş istemciler her iki yaklaşımda da sizi sessizce zorlayabilir. Bu hata modlarına dikkat edin:
Popüler panolar için basit bir kural: mesajları küçük tutun, düşündüğünüzden daha az sık gönderin ve güncellemeleri düşürmeye veya birleştirmeye istekli olun (örneğin yalnızca en son metrik değerini gönderin) ki bir yavaş istemci tüm sistemi yavaşlatmasın.
Canlı panolar sıkıcı şekillerde başarısız olur: bir dizüstü uykuya geçer, Wi‑Fi ağ değiştirir, mobil cihaz tünele girer veya tarayıcı arka plan sekmesini askıya alır. Taşıma seçiminiz, bağlantı koptuğunda nasıl kurtaracağınızdan daha az önemlidir.
SSE ile tarayıcının yeniden bağlanması yerleşiktir. Akış koparsa, kısa bir gecikme sonrası tekrar dener. Birçok sunucu Last-Event-ID tarzı başlık kullanarak yeniden oynatma (replay) desteği sunar. Bu, istemcinin "son gördüğüm olay 1042 idi, bana kaçırdıklarımı gönder" demesine izin vererek dayanıklılığa basit bir yol sağlar.
WebSockets genellikle daha fazla istemci mantığı gerektirir. Soket kapandığında istemci backoff ve jitter ile yeniden denemeli (böylece binlerce istemci aynı anda bağlanmaz). Yeniden bağlandıktan sonra temiz bir yeniden-abone akışı gerekir: gerekirse tekrar doğrula, doğru kanallara katıl, sonra kaçırılan güncellemeleri iste.
Daha büyük risk sessiz veri boşluklarıdır: UI normal görünür ama eskidir. Panonun güncel olduğunu kanıtlaması için şu desenlerden birini kullanın:
Örnek: "dakika başına sipariş" gösteren bir satış panosu, toplamları her 30 saniyede bir yenilerse kısa bir boşluğu tolere edebilir. Bir işlem panosu tolere edemez; her yeniden bağlanmada sıra numaraları ve snapshot gerekir.
Canlı panolar uzun süreli bağlantılar açtığı için küçük kimlik doğrulama hataları dakikalar veya saatler boyunca sürebilir. Güvenlik taşıma yönteminden çok kimlik doğrulama, yetkilendirme ve erişimi nasıl sonlandırdığınızla ilgilidir.
Temelden başlayın: HTTPS kullanın ve her bağlantıyı süresi dolması gereken bir oturum gibi muamele edin. Oturum çerezlerine güveniyorsanız, doğru kapsamlandırıldıklarından ve girişte döndürüldüklerinden emin olun. JWT gibi token kullanıyorsanız, bunları kısa ömürlü tutun ve istemcinin bunları nasıl yenileyeceğini planlayın.
Pratik bir tuzak: tarayıcı SSE (EventSource) özel başlık ayarlamanıza izin vermez. Bu durum genellikle ekipleri çerez tabanlı kimlik doğrulamaya iter veya token'ı URL'ye koymaya zorlar. URL token'ları loglar ve kopyala-yapıştır ile sızabileceğinden, eğer kullanmanız gerekiyorsa kısa ömürlü tutun ve tam sorgu dizelerini kaydetmekten kaçının. WebSockets tipik olarak daha fazla esneklik verir: el sıkışma sırasında (handshake) cookie veya sorgu dizesiyle doğrulama yapabilir veya bağlandıktan hemen sonra bir auth mesajı gönderebilirsiniz.
Çok kiracılı (multi-tenant) panolarda iki kez yetkilendirme yapın: bağlanırken ve her abone isteğinde. Bir kullanıcı yalnızca kendi stream'lerine abone olabilmeli (ör. org_id=123) ve sunucu istemci daha fazlasını istemiş olsa bile bunu zorunlu kılmalıdır.
Kötüye kullanımı azaltmak için bağlantı kullanımını sınırlandırın ve izleyin:
Bu loglar sizin denetim iziğinizdir ve birinin neden boş bir pano veya başkasının verilerini gördüğünü açıklamanın en hızlı yoludur.
Bir soru ile başlayın: panonuz çoğunlukla izliyor mu yoksa sürekli geri konuşuyor mu? Tarayıcı ağırlıklı olarak güncellemeleri alıyor (grafikler, sayaçlar, durum ışıkları) ve kullanıcı eylemleri nadir ise (filtre değişikliği, uyarı onayı), gerçek zamanlı kanalınızı tek yönlü tutun.
Sonra 6 ay sonrası için bakın. Eğer etkileşimli özelliklerin (satır içi düzenlemeler, sohbet benzeri kontroller, sürükle-bırak işlemleri) bolca olmasını bekliyorsanız ve çoklu olay türleri olacaksa, her iki yönü de temizce ele alabilen bir kanal planlayın.
Ardından görünümün ne kadar doğru olması gerektiğine karar verin. Birkaç ara güncellemeyi kaçırmak sorun değilse (çünkü bir sonraki güncelleme eski durumu yerine koyuyor), basitliği tercih edebilirsiniz. Her olayın önemli olduğu durumlar (denetimler, finansal tikler) için güçlü sıra numaralandırma, tamponlama ve yeniden senkronizasyon mantığına her durumda ihtiyacınız olacaktır.
Son olarak, eşzamanlılık ve büyümeyi tahmin edin. Binlerce pasif izleyici genellikle HTTP altyapısıyla iyi oynayan ve yatay ölçeklemeyi kolaylaştıran seçeneğe yönlendirir.
SSE'yi seçin quando:
WebSockets'i seçin quando:
Eğer kararsızsanız, tipik okuma-ağırlıklı panolar için önce SSE'yi seçin ve iki yönlü ihtiyaçlar gerçek ve sürekli hale geldiğinde geçiş yapın.
En yaygın hata, panonuzun ihtiyaç duyduğundan daha karmaşık bir aracı seçmekle başlar. UI sadece sunucudan istemciye güncellemelere ihtiyaç duyuyorsa, WebSockets fazla hareketli parça ekleyebilir. Ekipler bağlantı durumu ve mesaj yönlendirmesini debug etmekle uğraşır, panoya değil.
Yeniden bağlanma başka bir tuzaktır. Yeniden bağlanma genellikle bağlantıyı geri getirir, ama kaçırılan veriyi geri getirmez. Bir kullanıcının dizüstü bilgisayarı 30 saniye uykuya geçerse, olayları kaçırabilir ve pano yanlış toplamlar gösterebilir; bunun için yakalama adımı (ör. son görülen olay id'si veya zaman damgasına göre yeniden fetch) tasarlanmalıdır.
Yüksek frekanslı yayın sessizce sistemi çökertir. Her küçük değişikliği (her satır güncellemesi, her CPU tick) anında göndermek yükü, ağ trafiğini ve UI titreşimini artırır. Batching ve throttling panonun daha hızlı hissetmesini sağlar çünkü güncellemeler temiz parçalar halinde gelir.
Üretimde dikkat edilmesi gereken tuzaklar:
Örnek: bir destek ekibi panosu canlı bilet sayımlarını gösteriyor. Her bilet değişikliğini anında iterseniz, ajanlar sayıları görsel olarak titreyen ve bazen yeniden bağlandıktan sonra geriye kayan değerler olarak görür. Daha iyi bir yaklaşım güncellemeleri her 1-2 saniyede bir göndermek ve yeniden bağlandığında mevcut toplamları çekmektir.
Bir SaaS yönetici panosunu düşünün: faturalama metrikleri (yeni abonelikler, churn, MRR) ve olay uyarıları (API hataları, kuyruk birikimi). Çoğu izleyici sadece sayıları izler ve sayfanın yenilenmeden güncellenmesini ister. Yalnızca birkaç yönetici işlem yapar.
Erken aşamada ihtiyacı karşılayan en basit akışla başlayın. SSE çoğu zaman yeterlidir: metrik güncellemelerini ve uyarı mesajlarını sunucudan tarayıcıya tek yönlü itmek. Yönetilecek durum daha az, kenar durumları daha az ve yeniden bağlanma davranışı öngörülebilirdir. Bir güncelleme kaçırılırsa, bir sonraki mesaj en son toplamları içerebilir ve UI hızlıca düzelir.
Birkaç ay sonra kullanım büyür ve pano etkileşimli hale gelir. Yönetici birkaç canlı filtre değiştirmek (zaman penceresi, bölgeleri açık/kapat) ve belki işbirliği (iki yönetici aynı uyarıyı onaylayıp anında görmek) isteyebilir. İşte seçim değişebilir. İki yönlü mesajlaşma, kullanıcı eylemlerini aynı kanal üzerinde göndermeyi ve paylaşılan UI durumunu senkronize etmeyi kolaylaştırır.
Geçiş yapmanız gerekirse, gece yarısı ani bir kesinti yerine güvenli bir şekilde taşıyın:
Gerçek kullanıcılara canlı bir pano sunmadan önce ağın bozuk olacağını ve bazı istemcilerin yavaş olacağını varsay.
Her güncellemeye benzersiz bir olay ID'si ve zaman damgası verin, ve sıralama kuralınızı yazın. İki güncelleme ters sıra ile gelirse hangisi kazanır? Bu, yeniden bağlanma sırasında eski olayların oynatılması veya birden fazla hizmetin güncelleme yayınlaması durumunda önemlidir.
Yeniden bağlanma otomatik ve kibar olmalı. Backoff kullanın (ilk başta hızlı, sonra daha yavaş) ve kullanıcı oturumu kapattığında sonsuza kadar denemeyi bırakın.
Ayrıca verinin bayat olduğu durumda UI'nin ne yaptığına karar verin. Örneğin: 30 saniye boyunca güncelleme gelmezse grafikleri griye çevirin, animasyonları durdurun ve "bayat" bir durum gösterin; eski rakamları sessizce göstermek yerine kullanıcıya net bilgi verin.
Kullanıcı başına limitler koyun (bağlantılar, mesajlar/dakika, payload boyutu) ki bir sekme fırtınası herkesi düşürmesin.
Bağlantı başına bellek izleyin ve yavaş istemcileri yönetin. Bir tarayıcı yetişemiyorsa, tamponların sınırsız büyümesine izin vermeyin. Bağlantıyı bırakın, daha küçük güncellemeler gönderin ya da periyodik snapshot'lara geçin.
Bağlanma, kopma, yeniden bağlanma ve hata nedenlerini loglayın. Açık bağlantılarda, yeniden bağlanma oranında ve mesaj kuyruk uzunluğunda olağan dışı sıçramalara alarm kurun.
Streaming'i devre dışı bırakıp polling veya manuel yenilemeye geçecek basit bir acil durum anahtarı bulundurun. Saat 02:00'de bir şeyler yanlış gittiğinde güvenli bir seçenek istiyorsunuz.
Ana rakamların yanında "Son güncelleme" gösterin ve bir manuel yenileme butonu ekleyin. Bu destek taleplerini azaltır ve kullanıcıların gördüklerine güvenmesini sağlar.
Bilinçli olarak küçük başlayın. Önce bir akış seçin (ör. sadece CPU ve istek hızı veya sadece uyarılar) ve olay sözleşmesini yazın: olay adı, alanlar, birimler ve ne sıklıkla güncellenir. Açık bir sözleşme UI ile backend'in birbirinden kopmasını engeller.
Davranışa odaklanan, gösterişten uzak bir prototip yazın. UI'ye üç durum gösterin: bağlanıyor, canlı ve yeniden bağlandıktan sonra yakalanıyor. Sonra hataları zorlayın: sekmeyi öldürün, uçak modunu açıp kapatın, sunucuyu yeniden başlatın ve panonun ne yaptığını izleyin.
Trafiği ölçeklemeden önce boşlukları nasıl kurtaracağınızı kararlaştırın. Basit bir yaklaşım, bağlanırken (veya yeniden bağlanırken) bir snapshot göndermek, sonra tekrar canlı güncellemelere geçmektir.
Genel adımlar:
Hızlı ilerliyorsanız, Koder.ai (koder.ai) uçtan uca prototip üretmenizde yardımcı olabilir: bir React pano UI'si, bir Go backend ve veri akışı sohbet isteminden başlayarak, kaynak kodu dışa aktarma ve dağıtım seçenekleriyle birlikte.
Prototipiniz çirkin ağ koşullarından sağ çıkarsa, ölçeklendirmek çoğunlukla tekrar etmektir: kapasite ekleyin, gecikmeyi ölçmeye devam edin ve yeniden bağlanma yolunu sıkıcı ve güvenilir tutun.
Use SSE when the browser mostly listens and the server mostly broadcasts. It’s a great fit for metrics, alerts, status lights, and “latest events” panels where user actions are occasional and can go over normal HTTP requests.
Pick WebSockets when the dashboard is also a control panel and the client needs to send frequent, low-latency actions. If users are constantly sending commands, acknowledgements, collaborative changes, or other real-time inputs, two-way messaging usually stays simpler with WebSockets.
SSE is a long-lived HTTP response where the server pushes events to the browser. WebSockets upgrade the connection to a separate two-way protocol so both sides can send messages any time. For read-heavy dashboards, that extra two-way flexibility is often unnecessary overhead.
Add an event ID (or sequence number) to each update and keep a clear “catch-up” path. On reconnect, the client should either replay missed events (when possible) or fetch a fresh snapshot of the current state, then resume live updates so the UI is correct again.
Treat staleness as a real UI state, not a hidden failure. Show something like “Last updated” near key numbers, and if no events arrive for a while, mark the view as stale so users don’t trust outdated data by accident.
Start by keeping messages small and avoiding sending every tiny change. Coalesce frequent updates (send the latest value instead of every intermediate value), and prefer periodic snapshots for totals. The biggest scaling pain is often open connections and slow clients, not raw bandwidth.
A slow client can cause server buffers to grow and eat memory per connection. Put a cap on queued data per client, drop or throttle updates when a client can’t keep up, and favor “latest state” messages over long backlogs to keep the system stable.
Authenticate and authorize every stream like it’s a session that must expire. SSE in browsers typically pushes you toward cookie-based auth because custom headers aren’t available, while WebSockets often require an explicit handshake or first message auth. In both cases, enforce tenant and stream permissions on the server, not in the UI.
Send small, frequent events on the live channel and keep heavy work on normal HTTP endpoints. Initial page load, historical queries, exports, and large responses are better as regular requests, while the live stream should carry lightweight updates that keep the UI current.
Run both in parallel for a while and mirror the same events into each channel. Move a small slice of users first, test reconnects and server restarts under real conditions, then gradually cut over. Keeping the old path briefly as a fallback makes rollouts much safer.