14 puan yazan GN⁺ 2025-01-09 | 5 yorum | WhatsApp'ta paylaş
  • Node.js/TypeScript tabanlı bir backend'de büyük ölçekli gerçek zamanlı güncellemeleri işlemek gereken bir durum söz konusuydu
  • Backend olarak PostgreSQL kullanılıyordu; yüzlerce worker node'un yeni işleri sürekli kontrol etmesi ve agent'ların çalıştırma ile sohbet durumu güncellemelerini alması gerekiyordu
  • Araştırma WebSocket ile başladı, ancak şaşırtıcı derecede etkili bir "eski usul" çözüme ulaştı
    → "Postgres ile HTTP Long Polling"

Sorun: büyük ölçekli gerçek zamanlı güncellemeler

  • Worker node güncellemeleri :
    • Node.js/Golang/C# SDK'larını çalıştıran yüzlerce worker node vardı
    • Yeni bir iş gelir gelmez bunu öğrenmeleri gerekiyordu; bu yüzden Postgres veritabanını zorlamayacak bir sorgu stratejisine ihtiyaç vardı
  • Agent durum senkronizasyonu :
    • Agent'ların çalıştırma ve sohbet durumu için gerçek zamanlı güncellemelere ihtiyacı vardı ve bunların verimli şekilde akış olarak iletilmesi gerekiyordu

Long polling ile WebSocket karşılaştırması

  • Short polling, yolcu olup olmadığına bakmadan belirli aralıklarla hareket eden, tarifeye sıkı sıkıya bağlı bir tren gibidir
  • Long polling'de sunucu yanıt vermek için bekler; veri oluştuğunda hemen döner, belirli bir süre geçerse timeout ile yanıt verir
    • Yani, "bekleyip veri gelince hareket eden" bir tren gibidir. Yalnızca belirli bir süre (TTL) içinde yolcu çıkmazsa boş olarak hareket eder
    • Veri (yolcu) varsa hemen hareket etme ve yoksa kaynakları verimli kullanma avantajlarını birlikte sunar
  • WebSocket, bağlantının sürekli açık tutulduğu ve verinin çift yönlü aktarıldığı bir yöntemdir
    • Kurumsal ortam, altyapı ve firewall sorunları nedeniyle long polling, WebSocket kurulumuna göre daha basit ve daha uyumludur

Long polling uygulamasının ayrıntıları

  • getJobStatusSync fonksiyonu kritik rol oynar
    • jobId, owner, ttl gibi parametreleri alır ve belirli bir işin durumunu belli bir süre boyunca tekrar tekrar sorgular
  • Aşağıdaki koşullardan biri sağlanana kadar tekrar sorgulama yapılır
    • İş durumu success veya failure olur
    • ttl (timeout) süresi dolar
  • Veritabanı 500ms aralıklarla sorgulanır; sonuç kesinleşmemişse beklenir ve yeniden sorgulanır
  • Timeout aşılırsa hata fırlatılır, başarılıysa sonuç döndürülür

Veritabanı optimizasyonu

  • Sorgu maliyetini en aza indirmek için Postgres üzerinde uygun indeksler kullanılır
  • Örnek: CREATE INDEX idx_jobs_status ON jobs(id, cluster_id);

Long polling'in faydaları

  • İzleme sürdürülebilirliği : mevcut HTTP tabanlı loglama ve izleme yığını aynen kullanılabilir
  • Kimlik doğrulama basitliği : yeni bir kimlik doğrulama yöntemi uygulamaya gerek kalmadan mevcut HTTP kimlik doğrulaması kullanılabilir
  • Altyapı uyumluluğu : firewall veya load balancer için ek ayar gerekmez; normal HTTP trafiği olarak ele alınır
  • Operasyonel basitlik : sunucu yeniden başlatıldığında bağlantı durumunu ayrıca ele almak gerekmez ve debug daha kolaydır
  • İstemci uygulamasının kolaylığı : standart HTTP istek-yanıt yapısına yalnızca yeniden deneme mantığı eklenmesi yeterlidir

ElectricSQL ile karşılaştırma

  • ElectricSQL, Postgres verisini frontend ile senkronize eden bir çözümdür
  • WebSocket yerine HTTP kullanırken de gerçek zamanlılığı garanti eden bir yapıya sahiptir
  • Gerçek zamanlı güncellemeleri işlemek için aşırı kontrol veya düşük seviyeli bir yapı gerekmiyorsa pratikte ElectricSQL önerilir

Neden raw long polling seçtik

  • Mesaj iletim mekanizması basit bir uygulama ayrıntısı değil, ürünün çekirdeği
  • Bu temel özelliği üçüncü taraf bir kütüphaneye bağımlı kılamayız (kütüphane ne kadar iyi olursa olsun)
  • Gereksinimler
    • Çekirdek ürün kontrolü : mesaj iletim mekanizması üzerinde tam denetime sahip olmak gerekiyor. Bu bir altyapı meselesi değil, doğrudan ürünün kendisi
    • Harici bağımlılıkları kaldırma : self-hosting'i basitleştirmek için dış bağımlılıkları en aza indirmek
    • Düşük seviyeli kontrol : polling mekanizması ve bağlantı yönetimi üzerinde doğrudan kontrol
    • Maksimum denetlenebilirlik : dinamik polling aralığı uygulamak gibi ayrıntıların ince ayarının yapılabilmesi
    • Kod basitliği : kullanıcıların kod tabanını kolayca anlayıp değiştirebilmesi için sade bir tasarım
  • Sonuç olarak basit bir HTTP Long Polling uygulaması seçilerek doğrudan kontrol ve basitlik sağlandı

Long polling uygularken dikkat edilmesi gerekenler

  • TTL ayarı : sunucu tarafında mutlaka bir maksimum TTL zorunlu kılınmalı ve istemcinin istediği TTL bunun üstüne çıkmamalıdır
  • Altyapı timeout'larını dikkate alma : TTL, load balancer, edge sunucu ve proxy gibi bileşenlerin timeout ayarlarından yeterince kısa olmalıdır
  • DB polling aralığı : veritabanı yükünü azaltmak için yaklaşık 500ms gecikme verilmelidir
  • Backoff stratejisi (isteğe bağlı) : polling aralığını kademeli artırarak sistem kaynakları daha verimli kullanılabilir

WebSocket düşünülmesi gereken durumlar

  • WebSocket'in kendisi yanlış bir tercih değildir; başka açılardan faydalı olabilir
    • Çok sayıda durum bilgili bağlantının izlenmesi ve karmaşık olayların sürekli çift yönlü aktarılması gerekiyorsa
    • Kimlik doğrulama, altyapı ve gözlemlenebilirlik sorunlarını çözmek için yeterli kaynak ve zaman varsa
  • Ancak operasyon, loglama, yeniden bağlanma yönetimi ve kimlik doğrulama mekanizmalarının doğrudan kurulmasını gerektiren bir karmaşıklık vardır

WebSockets: başka bir seçeneğe dair notlar

  • Long Polling bizim ihtiyaçlarımıza uydu, ancak WebSockets de kesinlikle değerlendirmeye değerdir
  • WebSockets kendi başına kötü değildir; sadece ciddi özen ve yönetim gerektirir
  • WebSockets'in temel zorlukları ve çözüm yönleri
    • Görünürlük : WebSockets durum temelli olduğundan, kalıcı bağlantılar için ek loglama ve izleme gerekir
    • Kimlik doğrulama : WebSocket bağlantıları için yeni bir kimlik doğrulama mekanizması uygulanmalıdır
    • Altyapı : WebSocket desteği için load balancer, firewall gibi altyapı bileşenleri uygun şekilde yapılandırılmalıdır
    • Operasyon yönetimi : WebSocket bağlantılarının ve yeniden bağlantıların yönetimi; bağlantı timeout'ları ve hata işleme
    • İstemci uygulaması : istemci tarafı WebSocket kütüphanesinin uygulanması; yeniden bağlanma ve durum yönetimi özellikleri dahil

5 yorum

 
jhj0517 2025-01-10

ML model serving için burada bahsedilen short polling yapısını kullanıyoruz; hangi seçeneğin daha verimli olacağı konusunda epey düşünüyorum. Kendi çapımda biraz araştırdığım kadarıyla, WebSocket veya SSE gibi yöntemlerde yeniden bağlanma işlemlerinin maliyeti yüksek olduğu için short pollingin genel olarak daha güvenli olduğu söyleniyordu; ben de bu yüzden short pollingi seçtim.. 😭

 
bbulbum 2025-01-10

Long polling biraz hacky hissettirdiği için insanlar bundan kaçınıyor gibi görünüyor. Tarayıcıda muhtemelen istek sürekli tamamlanmamış olarak görünecektir. Bazen yüklemesi hiç bitmeyen siteler oluyor; ben de "acaba içerik tamamen yüklenemedi mi?" diye düşündüğüm için pek hoşuma gitmiyor.
Uygulama tarafında da sonuçta bir yerde hang verip yanıt bekleyen bir duruma geçilecek; bu da biraz tuhaf görünüyor.

 
joyfui 2025-01-09

"Ajanın çalıştırma ve sohbet durumu güncellemelerini alması gerekiyor"
Bunu görünce aklıma hemen SSE geldi; gerçekten de Hacker News yorumlarında SSE'den çokça bahsedilmiş.

 
GN⁺ 2025-01-09
Hacker News yorumu
  • Long polling'in kendine özgü sorunları var

    • Second Life, istemci ile sunucu arasında HTTPS long polling kanalı kullanıyor
    • İstemci tarafında libcurl kullanılıyor ve timeout oluşabiliyor
    • Sunucu timeout ile sonraki istek arasında mesaj göndermeye çalışırsa yarış durumu oluşup mesaj kaybolabiliyor
    • Önde Apache sunucusu bulunduğundan gereksiz istekleri engelliyor ama timeout yaşanabiliyor
    • Ara kutular ve proxy sunucular long polling'den hoşlanmayabiliyor
    • HTTP bağlantısını uzun süre açık tutmaktan hoşlanmayan pek çok unsur var
    • Sonuç olarak güvenilir olmayan bir mesaj kanalına dönüşüyor; tekrarları tespit etmek için sıra numarası gerekiyor ve mesaj kaybı yaşanabiliyor
    • Orijinal makalede "loop" olarak işaretlenen grafik bölümü timeout işleminden bahsetmiyor
    • Long polling kullanıldığında bağlantıyı canlı tutmak için birkaç saniyede bir veri göndermek gerekiyor
  • Phoenix ve LiveView'ı her gün kullanmak keyifli

    • WebSockets kullandığı için bunlarla uğraşmak gerekmiyor
  • Server-Sent Events (SSE) kullanmaya kıyasla teknik bir avantaj olup olmadığını merak ediyorum

    • İkisi de HTTP bağlantısını açık tutuyor ve basit HTTP olma avantajına sahip
    • SSE, güncellemeleri veya sonuçları stream etmek mümkün olduğunda daha uygun görünüyor
    • Uygun bir kullanım senaryosu, belirli bir istemci adına tüm iş kimliklerini izlemek olabilir
  • Bu makale "Websocket" ile "Long-polling"i birbirinden bağımsız kararlar gibi bağlıyor

    • Long-polling sunucusu, biraz ek çalışmayla websocket istemcilerini de işleyebilir
    • Mevcut mimari websocket ise long-polling istemcilerini desteklemek için iki sunucu katmanı gerekiyor
  • Node.js'te setTimeout kullanmanın daha kolay bir yolu

    • import { setTimeout } from "node:timers/promises"; await setTimeout(500); kullanın
  • Long polling'i seviyorum; anlaması kolay ve istemci açısından çok yavaş bir bağlantı gibi çalışıyor

    • Yeniden denemeleri ve istemci tarafında iptal edilen bağlantıları takip etmek gerekiyor
    • Kod örneğinde veriyi tekrar tekrar sorgulayan döngü biraz tuhaf görünüyor
  • Server-Sent Events veya WebSockets, long polling'in tüm kullanım senaryolarının yerini alamaz

    • SSE'nin bağlantı sınırı sık sık sorun oluyor
    • WebSockets çoğu ortamda güvenilir değil
    • Arka uçta değişiklikleri tespit edip uygun istemcilere iletme sorunu hâlâ çözülmüş değil
  • Postgres'in asenkron bildirim özelliğini kullanmak iyi olur

    • Sunucu kanalı LISTEN edebilir ve veri değiştiğinde PG, TRIGGER ve NOTIFY çalıştırabilir
  • Kısa timeout'lar ve zarifçe sonlandırılan isteklerle long polling'in hâlâ anlamlı olup olmadığından emin değilim

    • HTTP/2 veya QUIC kullanılmıyorsa bu yöntem hâlâ anlamlı olabilir
  • WebSockets'e görece basit bir alternatifin hatırlatılması ferahlatıcı

    • WebSockets'i seçen bir startup'ta çalışmıştım ve otel ile restoran Wi‑Fi'ında test etmek zordu
 
luminance 2025-01-10

Elixir, Phoenix framework ve LiveView üzerinden WebSockets kullanmayı denemek istiyorum.