Ders 21 / 25
Yoklama Yaklaşımları
İstemcinin sunucudaki değişiklikten haberdar olmasının en yalın yolu: kısa yoklamanın istek ve boş yanıt maliyeti, uzun yoklamanın bağlantı tutma karşılığı, ikisinin aynı olay üzerinde ölçülmesi ve sürüm numarasıyla kapatılan olay boşluğu.
İçindekiler
Bir önceki konu işin sunucu tarafındaki dayanıklılığını tamamladı: iş bir işçiye düşer, zamanında tetiklenir, ilerlemesi kaydedilir, kuyruk taşmaz, aşırı yükte denetimli olarak reddedilir. Zincirin bir ucu hâlâ açık kaldı. İşi başlatan istemci, işin kabul edildiğini biliyor ama sonucun ne zaman hazır olduğunu bilmiyor.
Uzun süren raporun ilerleme yüzdesi, rezervasyon sırasındaki konumun değişmesi, şube stok sayacının güncellenmesi — bunların hepsi sunucu tarafında hazır ama istemci tarafında görünmez. HTTP’nin varsayılan yönü bunu zorlaştırır: bağlantıyı istemci açar, isteği istemci gönderir. Sunucunun kendiliğinden konuşma imkânı yoktur.
Bu konu, bilginin istemciye ulaşmasının dört yolunu kurar. En yalınından başlıyoruz: istemcinin tekrar tekrar sorması.
Yoklama
Yoklama (polling), istemcinin durumu öğrenmek için sunucuya düzenli aralıklarla istek göndermesidir. Hiçbir ek protokol gerektirmez; sunucu tarafında ek durum tutulmaz; her ara katman, güvenlik duvarı ve önbellek onu olağan bir HTTP isteği olarak görür. Bu yüzden yoklama, gerçek zamanlı veri sorununun varsayılan yanıtıdır ve pek çok durumda doğru yanıttır.
İki biçimi vardır ve aralarındaki fark tek bir karardır: sunucu, verecek bir şeyi yoksa ne yapar.
Kısa yoklama (short polling) biçiminde sunucu hemen cevap verir. Değişiklik yoksa “değişiklik yok” der ve bağlantı kapanır; istemci bir süre bekleyip yeniden sorar.
Uzun yoklama (long polling) biçiminde sunucu cevabı geciktirir. Bir değişiklik olana kadar bağlantıyı açık tutar; değişiklik gelirse cevabı o anda yazar. Belirli bir süre boyunca hiçbir şey olmazsa boş cevap verir ve istemci yeniden bağlanır.
İki Yaklaşımı Tek Sunucuda Kurmak
Aşağıdaki sunucu, önceki konuda is_durumu tablosuna yazılan ilerlemeyi sunuyor. Durumun
bir sürüm numarası var; istemci en son gördüğü sürümü isteğe iliştiriyor.
// yoklama.mjs — rapor isinin durumunu iki bicimde sunar: kisa yoklama ve uzun yoklama import { createServer } from "node:http"; const TUTMA_SINIRI = 1000; // uzun yoklamanin baglantiyi tutma suresi (ms) let surum = 0, ilerleme = 0; // rapor-2026-01 isinin durumu const sayac = { durum_istegi: 0, bekle_istegi: 0, bos_yanit: 0 }; const bekleyen = new Set(); // acik tutulan uzun yoklama yanitlari const govde = () => JSON.stringify({ surum, ilerleme }) + "\n"; const yaz = (yanit, metin, kod = 200) => { yanit.writeHead(kod, { "content-type": "application/json; charset=utf-8" }); yanit.end(metin); }; const bos = (yanit) => { sayac.bos_yanit++; yanit.writeHead(204).end(); }; createServer((istek, yanit) => { yanit.sendDate = false; const adres = new URL(istek.url, "http://yerel"); const gorulen = Number(adres.searchParams.get("surum") ?? 0); if (adres.pathname === "/durum") { // kisa yoklama: hemen cevap ver sayac.durum_istegi++; return surum > gorulen ? yaz(yanit, govde()) : bos(yanit); } if (adres.pathname === "/bekle") { // uzun yoklama: degisene kadar tut sayac.bekle_istegi++; if (surum > gorulen) return yaz(yanit, govde()); const kayit = { yanit }; kayit.zamanlayici = setTimeout(() => { bekleyen.delete(kayit); bos(yanit); }, TUTMA_SINIRI); return void bekleyen.add(kayit); } if (adres.pathname === "/ilerlet") { // isci ilerlemeyi bildirdi surum++; ilerleme += 10; for (const b of bekleyen) { clearTimeout(b.zamanlayici); yaz(b.yanit, govde()); } bekleyen.clear(); return yaz(yanit, govde()); } if (adres.pathname === "/olcum") return yaz(yanit, JSON.stringify(sayac) + "\n"); yaz(yanit, JSON.stringify({ hata: "yol yok" }) + "\n", 404); }).listen(8361, "127.0.0.1", () => console.log("dinleniyor: 127.0.0.1:8361"));
İki uç arasındaki tek yapısal fark bekleyen kümesidir. Kısa yoklamada sunucu isteği
işleyip unutur; uzun yoklamada yanıt nesnesini saklar ve /ilerlet geldiğinde o saklanan
nesnelere yazar. Yani uzun yoklama, sunucuya durum ekler.
Ölçüm
Aşağıdaki betik aynı tek olayı — raporun bir adım ilerlemesini — iki yaklaşımla karşılar ve sayar. Bağlantı noktası 8361 keyfîdir ve boş olmalıdır.
#!/usr/bin/env bash # yoklama.mjs'yi baslatir, ayni tek olayi iki yaklasimla olcer, durdurur. A=http://127.0.0.1:8361 B='%{http_code} %{size_download} B\n' node yoklama.mjs > /dev/null & sunucu=$! sleep 1 echo "--- kisa yoklama: alti istek ---" for i in 1 2 3 4 5; do curl -sS -w "$B" "$A/durum?surum=0"; done curl -sS -o /dev/null -X POST "$A/ilerlet" # is bu anda ilerledi curl -sS -w "$B" "$A/durum?surum=0" curl -sS "$A/olcum" kill "$sunucu"; sleep 0.3 node yoklama.mjs > /dev/null & sunucu=$! sleep 1 echo "--- uzun yoklama: iki istek ---" curl -sS -w "$B" "$A/bekle?surum=0" & bekleyen=$! sleep 0.3 curl -sS -o /dev/null -X POST "$A/ilerlet" # is bu anda ilerledi wait $bekleyen curl -sS -w "$B" "$A/bekle?surum=1" # degisim yok: sure dolar curl -sS "$A/olcum" kill "$sunucu"
--- kisa yoklama: alti istek ---
204 0 B
204 0 B
204 0 B
204 0 B
204 0 B
{"surum":1,"ilerleme":10}
200 26 B
{"durum_istegi":6,"bekle_istegi":0,"bos_yanit":5}
--- uzun yoklama: iki istek ---
{"surum":1,"ilerleme":10}
200 26 B
204 0 B
{"durum_istegi":0,"bekle_istegi":2,"bos_yanit":1}
Aynı olay, kısa yoklamada altı istekle, uzun yoklamada iki istekle karşılandı. Kısa yoklamada beş yanıt boştu; boş yanıtların gövdesi sıfır bayt olduğu için taşınan veri küçük, ama istek sayısı aynı kaldı. Her istek bir bağlantı kurulumu, bir yönlendirme kararı, bir kimlik doğrulama ve bir kütük satırı demektir; gövdenin boş olması bunların hiçbirini ucuzlatmaz.
Uzun yoklamada ikinci istek bir saniye açık kaldı ve değişiklik olmadığı için 204 ile kapandı. Bu, uzun yoklamanın kaçınılmaz maliyetidir: bağlantı sonsuza kadar tutulamaz, çünkü ara katmanların ve yük dağıtıcıların kendi zaman aşımları vardır.
Maliyetin Hesabı
İki yaklaşımın maliyeti, gözlem penceresi ve olay sıklığıyla hesaplanabilir. Aşağıdaki tablo altmış saniyelik bir pencerede tek bir olay olduğu varsayımıyla çıkarılmıştır.
| Yaklaşım | İstek | Boş yanıt | En kötü gecikme |
|---|---|---|---|
| Kısa yoklama, 1 s arayla | 60 | 59 | 1 s |
| Kısa yoklama, 5 s arayla | 12 | 11 | 5 s |
| Uzun yoklama, 30 s tutma | 3 | 1 | ağ gecikmesi |
Kısa yoklamada istek sayısı pencere / aralık ile, en kötü gecikme ise doğrudan aralıkla
belirlenir. İkisi ters orantılıdır ve bu, kısa yoklamanın tek gerçek ödünleşimidir:
gecikmeyi yarıya indirmek istek sayısını iki katına çıkarır.
Uzun yoklamada istek sayısı pencere / tutma süresi + olay sayısı ile belirlenir ve
gecikme aralığa bağlı değildir. Bu yüzden uzun yoklama, seyrek ama gecikmeye duyarlı
olaylar için kısa yoklamadan belirgin ölçüde ucuzdur.
Hesabın yönü olay sıklığı arttıkça tersine döner. Saniyede birden çok olay üreten bir kaynakta uzun yoklama her olayda bir bağlantı kurar; kısa yoklama ise bir istekte birden çok değişikliği toplu olarak taşır. Sık değişen ve her ara değeri önemsenmeyen veriler — şube stok sayacı gibi — kısa yoklamayla daha ucuza sunulur.
Sunucu Tarafındaki Bedel
Uzun yoklama sunucuya durum ekler ve bu durumun bir sınırı vardır. Açık tutulan her istemci bir yuva (socket), bir dosya tanıtıcısı ve bir yanıt nesnesi tutar. Bin istemci bin açık bağlantı demektir; bunlar iş yapmıyor olsa da kaynak tüketirler.
Üç sonuç doğar. Sunucunun eşzamanlı bağlantı sınırı, artık eşzamanlı istek sınırından farklı bir büyüklüktür ve ona göre ayarlanmalıdır. Önceki dersteki kabul denetimi bu bağlantıları saymamalıdır; bekleyen bir uzun yoklama işlemci kullanmaz, dolayısıyla onu “çalışan iş” olarak saymak sunucuyu gereksiz yere doygun gösterir. Ve tutma süresi, ara katmanların zaman aşımından kısa seçilmelidir; aksi hâlde bağlantıyı sunucu değil aradaki bir katman keser ve istemci nedenini anlayamaz.
Olay Boşluğu
Uzun yoklamanın gözden kaçan kusuru şurasıdır: yanıt yazıldıktan sonra istemci yeniden bağlanana kadar geçen sürede sunucu dinlenmez. O aralıkta olan bir olay, hiçbir açık bağlantıya yazılamaz.
Kodda bu boşluğu kapatan şey sürüm numarasıdır. İstemci en son gördüğü sürümü isteğe
ekler; sunucu surum > gorulen koşulunu bağlantıyı tutmadan önce sınar ve geride kalmış
bir istemciye hemen cevap verir. Ölçümdeki ikinci uzun yoklamanın surum=1 ile
gönderilmesinin nedeni budur.
Bu, gerçek zamanlı veri sunan her yaklaşımın ortak gereksinimidir: istemcinin nerede
kaldığını söyleyebilmesi. Sürüm numarası, olay kimliği ya da damga — adı değişir, işlevi
değişmez. Sonraki derste aynı işi Last-Event-ID başlığının yaptığını göreceğiz.
Özet
- Yoklama, istemcinin durumu öğrenmek için düzenli aralıklarla istek göndermesidir; ek protokol gerektirmediği için varsayılan yaklaşımdır.
- Kısa yoklamada sunucu hemen cevap verir ve boş yanıtlar üretir; istek sayısı
pencere / aralıkile artar, en kötü gecikme aralığın kendisidir. - Uzun yoklamada sunucu değişiklik olana kadar bağlantıyı tutar; ölçümde aynı olay altı istek yerine iki istekle karşılandı ve gecikme aralığa bağlı olmaktan çıktı.
- Uzun yoklamanın bedeli sunucuya eklenen durumdur: açık tutulan her bağlantı kaynak tüketir, tutma süresi ara katman zaman aşımlarından kısa seçilmelidir.
- İki yoklama arasındaki olay boşluğu, istemcinin en son gördüğü sürümü isteğe iliştirmesiyle kapatılır.
Sonraki Adım
Uzun yoklama, bağlantıyı tutup tek bir yanıt yazdıktan sonra kapatıyor. Her olay için yeni bir bağlantı kurulması, olaylar sıklaştığında saçma bir düzene dönüşür: aynı istemciye arka arkaya yazılacak on olay için on ayrı bağlantı. Oysa bağlantı zaten açıkken üzerine birden çok olay yazılabilir. Sonraki ders bunu standartlaştıran biçimi kurar: sunucunun tek bir açık yanıt gövdesine olayları peş peşe yazdığı, tarayıcı tarafında yeniden bağlanmayı kendi üstlenen tek yönlü akış.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.