İçeriğe geç
academia.sh

Ders 09 / 22

Sunucu Durumu Yönetimi

Uzak verinin istemcideki kopyası; önbellek anahtarı, tazelik penceresi, uçuşta birleşme, bayat sunup arkada yenileme, yazma sonrası geçersizleştirme, saklama süresi ve yeniden getirme tetikleyicileri.

İçindekiler

Merkezî depo ve atom çizgesi aynı varsayımı paylaşıyor: durumun sahibi uygulamadır, yazılan değer doğrudur. Kuzey Yamaç Ölçüm İstasyonu uygulamasının en büyük durum kütlesi bu varsayımı karşılamıyor. İstasyon listesi ve ölçüm kayıtları uzaktaki bir kaynağın kopyası; başka bir kullanıcı yeni istasyon eklemiş, biri bir ölçümü düzeltmiş olabilir.

Durum Türleri dersinde bu türün dört ayrı soru doğurduğu söylenmişti: kopya ne kadar süre güncel sayılır, eskiyince ne zaman yenilenir, aynı veriyi iki bileşen isterse kaç istek yapılır, yerel değişiklik yazılırken ekranda ne görünür. İlk üçü bu dersin, dördüncüsü bir sonrakinin konusudur.

Anahtar

Sunucu durumu katmanının birinci kararı, bir kopyanın neyle anılacağıdır. Önbellek anahtarı, isteği tümüyle belirleyen değerlerden üretilir: kaynağın yolu ve isteği farklılaştıran her parametre.

Anahtarın eksik olması iki kopyayı birbirine karıştırır: süzgeci hesaba katmayan bir anahtar, sıcaklık ölçümleriyle nem ölçümlerini aynı girdide tutar. Anahtarın gereğinden geniş olması ise paylaşımı engeller; isteği etkilemeyen bir değer anahtara girerse her görünüm kendi kopyasını indirir.

Rota Parametreleri ve Sorgu dersindeki kanonik biçim burada karşılığını bulur. Aynı görünüm tek bir adresle anıldığı için, adresten türetilen anahtar da tektir; parametre sırası değiştiğinde ikinci bir önbellek girdisi oluşmaz.

Tazelik ve Saklama

İkinci karar, kopyanın ne kadar süre sorgusuz kullanılacağıdır. İki ayrı süre gerekir ve karıştırılmaları sık görülen bir kusurdur.

Tazelik penceresi, kopyanın yeniden istenmeden kullanılabileceği süredir. Pencere içindeki bir okuma ağa hiç çıkmaz. Saklama süresi ise kopyanın bellekte tutulacağı süredir; bu süre dolduğunda kayıt düşürülür.

İkisinin arasında kalan aralıkta kopya bayattır: kullanıcıya hemen gösterilir, aynı anda arka planda yenilenir. Ekran boş kalmaz, veri de eskimiş kalmaz.

// sunucu-durumu.mjs — tazelik penceresi, ucusta birlesme, gecersizlestirme, saklama suresi
const TAZELIK = 30;      // saniye: bu sure icinde kopya taze sayilir
const SAKLAMA = 120;     // saniye: bu sureden sonra kayit dusurulur

const onbellek = new Map();   // anahtar -> { veri, alindi, gecersiz }
const ucusta = new Map();     // anahtar -> istek numarasi
let istekNo = 0;

function iste(anahtar, saat) {                 // saat: disaridan verilen sanal zaman
  const kayit = onbellek.get(anahtar);
  const yas = kayit ? saat - kayit.alindi : null;
  if (kayit && yas > SAKLAMA) { onbellek.delete(anahtar); }
  const gecerliKayit = onbellek.get(anahtar);

  if (gecerliKayit && !gecerliKayit.gecersiz && saat - gecerliKayit.alindi <= TAZELIK)
    return { sonuc: "onbellek isabeti", yas: saat - gecerliKayit.alindi, istek: "-" };

  if (ucusta.has(anahtar))
    return { sonuc: "ucusta birlestirildi", yas, istek: `#${ucusta.get(anahtar)}` };

  ucusta.set(anahtar, ++istekNo);
  const sonuc = gecerliKayit
    ? "bayat sunuldu + yenileniyor"
    : (kayit ? "kayit dusuruldu, bekleme" : "veri yok, bekleme");
  return { sonuc, yas, istek: `#${istekNo}` };
}

function tamamla(anahtar, saat, veri) {
  onbellek.set(anahtar, { veri, alindi: saat, gecersiz: false });
  const n = ucusta.get(anahtar);
  ucusta.delete(anahtar);
  return { sonuc: "yanit yazildi", yas: 0, istek: `#${n}` };
}

function gecersizlestir(onEk) {                // yazma isleminden sonra cagrilir
  let sayi = 0;
  for (const [anahtar, kayit] of onbellek)
    if (anahtar.startsWith(onEk)) { kayit.gecersiz = true; sayi += 1; }
  return { sonuc: `${sayi} kayit gecersizlestirildi`, yas: null, istek: "-" };
}

const LISTE = ["kuzey-yamac", "dogu-sirt"];
const ADIMLAR = [
  [0, "Liste acildi", "istasyon/liste", (t, a) => iste(a, t)],
  [1, "OzetKarti ayni veriyi istedi", "istasyon/liste", (t, a) => iste(a, t)],
  [3, "yanit geldi", "istasyon/liste", (t, a) => tamamla(a, t, LISTE)],
  [5, "sekmeye geri donuldu", "istasyon/liste", (t, a) => iste(a, t)],
  [40, "sekmeye geri donuldu", "istasyon/liste", (t, a) => iste(a, t)],
  [42, "yanit geldi", "istasyon/liste", (t, a) => tamamla(a, t, LISTE)],
  [45, "istasyon ayrintisi acildi", "istasyon/kuzey-yamac", (t, a) => iste(a, t)],
  [47, "yanit geldi", "istasyon/kuzey-yamac", (t, a) => tamamla(a, t, { ad: "Kuzey Yamac" })],
  [50, "yeni istasyon kaydedildi", "istasyon/ (on ek)", (t) => gecersizlestir("istasyon/", t)],
  [51, "listeye donuldu", "istasyon/liste", (t, a) => iste(a, t)],
  [53, "yanit geldi", "istasyon/liste", (t, a) => tamamla(a, t, [...LISTE, "bati-vadi"])],
  [200, "ayrintiya geri donuldu", "istasyon/kuzey-yamac", (t, a) => iste(a, t)],
];

console.log("t".padStart(4), "olay".padEnd(30), "anahtar".padEnd(22), "sonuc".padEnd(28), "yas", "istek");
for (const [t, olay, anahtar, calistir] of ADIMLAR) {
  const r = calistir(t, anahtar);
  console.log(String(t).padStart(4), olay.padEnd(30), anahtar.padEnd(22),
    r.sonuc.padEnd(28), String(r.yas ?? "-").padStart(3), r.istek);
}

console.log("-- toplam ag istegi --", istekNo);
   t olay                           anahtar                sonuc                        yas istek
   0 Liste acildi                   istasyon/liste         veri yok, bekleme              - #1
   1 OzetKarti ayni veriyi istedi   istasyon/liste         ucusta birlestirildi           - #1
   3 yanit geldi                    istasyon/liste         yanit yazildi                  0 #1
   5 sekmeye geri donuldu           istasyon/liste         onbellek isabeti               2 -
  40 sekmeye geri donuldu           istasyon/liste         bayat sunuldu + yenileniyor   37 #2
  42 yanit geldi                    istasyon/liste         yanit yazildi                  0 #2
  45 istasyon ayrintisi acildi      istasyon/kuzey-yamac   veri yok, bekleme              - #3
  47 yanit geldi                    istasyon/kuzey-yamac   yanit yazildi                  0 #3
  50 yeni istasyon kaydedildi       istasyon/ (on ek)      2 kayit gecersizlestirildi     - -
  51 listeye donuldu                istasyon/liste         bayat sunuldu + yenileniyor    9 #4
  53 yanit geldi                    istasyon/liste         yanit yazildi                  0 #4
 200 ayrintiya geri donuldu         istasyon/kuzey-yamac   kayit dusuruldu, bekleme     153 #5
-- toplam ag istegi -- 5

Zaman dışarıdan verildiği için çıktı belirlenimcidir; aynı betik her çalıştırmada aynı satırları üretir. Gerçek uygulamada bu değerin kaynağı sistem saatidir, ama katmanın kendisi saati bir bağımlılık olarak alırsa sınanabilir kalır.

Uçuşta Birleşme

İkinci satır, katmanın en görünmez kazancını gösterir. Liste ile özet kartı aynı veriyi bir saniye arayla ister; ağa yalnız bir istek çıkar.

Bu davranış olmadan aynı ekrandaki her bileşen kendi isteğini yapar. Ağ Panelinde Tanı dersinde tanımlanan şelale görünümünde bu, aynı adrese giden yan yana isteklerle görünür. Çözüm bileşenleri değiştirmek — veriyi yukarı taşımak, tek bir yerden dağıtmak — değil, aynı anahtara giden istekleri katmanda birleştirmektir. Bileşenler birbirinden habersiz kalır ve yine tek istek yapılır.

Birleşmenin işleyebilmesi için anahtarın dizgi eşitliğiyle karşılaştırılabilir olması gerekir. Anahtar üretimi kanonik değilse, aynı isteği tanımlayan iki anahtar farklı görünür ve birleşme kaçırılır.

Geçersizleştirme

Ellinci saniyedeki adım, tazelik penceresinin çözemediği durumu gösterir. Kullanıcı yeni bir istasyon kaydetmiştir; listenin kopyası artık yanlıştır, ama yaşı henüz dokuz saniyedir. Süre bu bilgiyi veremez.

Verebilecek olan yazma işleminin kendisidir. Bir yazma başarıyla tamamlandığında, ondan etkilenen anahtarlar geçersizleştirilir: yaşları ne olursa olsun bayat sayılırlar. Çıktıda geçersizleştirme ön ekle yapılmış ve iki kaydı birden etkilemiştir.

Etkilenen anahtarların belirlenmesi bir tasarım kararıdır. Dar bir geçersizleştirme — yalnız değişen kaydın anahtarı — hızlıdır ama listeyi eski bırakır. Geniş bir geçersizleştirme — tüm ön ek — güvenlidir ama gereksiz istek üretir. Ölçüt, yazmanın hangi görünümleri gerçekten etkilediğidir; yeni bir istasyon listeyi de özetleri de değiştirir.

Geçersizleştirmenin bir kardeşi vardır: yanıtın doğrudan yazılması. Sunucu, yazma isteğine güncel kaydı geri döndürüyorsa, o kayıt önbelleğe konur ve ek bir istek hiç yapılmaz. Bu, sözleşmenin sunucu tarafını da ilgilendirir ve Veri Erişimi konusunda ele alınır.

Saklama Süresi

Son satır iki yüzüncü saniyede yaşanır. İstasyon ayrıntısının kopyası saklama süresini aştığı için düşürülmüştür; kullanıcı geri döndüğünde bayat veri bile gösterilemez ve bekleme görünür.

Saklama süresinin varlık nedeni bellektir. Kullanıcının bir kez açıp bir daha dönmediği her kayıt bellekte kalırsa, uzun süre açık duran bir sekme büyümeye devam eder. Eşzamansız JavaScript ve Çalışma Zamanı kursundaki bellek sızıntısı tanısında görülen tabloyu üreten nedenlerden biri budur.

İki süre birlikte ayarlanır. Tazelik penceresi verinin ne sıklıkta değiştiğine göre seçilir: nadiren değişen bir istasyon künyesi uzun, sürekli akan bir ölçüm listesi kısa pencere ister. Saklama süresi ise kullanıcının o görünüme dönme olasılığına göre seçilir.

Yeniden Getirme Tetikleyicileri

Bayat bir kaydın ne zaman yenileneceği yalnız okumaya bağlı değildir. Katman birkaç dış işareti de dinler.

Sekmeye geri dönülmesi bunların en etkilisidir: kullanıcı başka bir uygulamada dakikalarca kalıp geri döndüğünde ekrandaki her şey eskimiştir. Ağ bağlantısının yeniden kurulması ikinci işarettir. Belirli aralıklarla yenileme ise yalnız gerçekten değişen veriler için kullanılır ve sekme görünmediğinde durdurulur.

Her tetikleyici bir maliyet üretir. Ölçüt, kullanıcının eski veri görmesinin maliyetiyle ek isteğin maliyetini karşılaştırmaktır; ölçüm listesinde eskilik pahalıdır, istasyon künyesinde değildir.

Özet

  • Sunucu durumu kendi katmanında tutulur ve her kopya, isteği tümüyle belirleyen kanonik bir anahtarla anılır.
  • Tazelik penceresi kopyanın sorgusuz kullanılacağı süredir; saklama süresi bellekte kalacağı süredir. Arada kalan kopya bayattır: gösterilir ve arkada yenilenir.
  • Aynı anahtara giden eşzamanlı istekler uçuşta birleştirilir; bileşenler birbirinden habersizken bile tek istek yapılır.
  • Süre tabanlı tazelik, yerel bir yazmanın kopyayı yanlışladığını bilemez; yazma sonrası geçersizleştirme etkilenen anahtarları yaşlarına bakmadan bayatlatır.
  • Saklama süresi dolan kayıt düşürülür ve dönüşte bayat veri bile gösterilemez; bu süre belleği sınırlar.
  • Yeniden getirme okuma dışında sekmeye dönüş, bağlantının kurulması ve aralıklı yenileme ile de tetiklenir; her tetikleyici eskilik maliyetiyle istek maliyeti karşılaştırılarak seçilir.

Sonraki Adım

Bu katman okumayı çözdü. Yazma tarafında ise ekranda görünen şey hâlâ ağın hızına bağlı: kullanıcı bir ölçümü siler, düğme beklemeye geçer, satır ancak sunucu yanıt verince kaybolur. Oysa isteğin başarılı olacağı çoğu durumda bellidir ve sonuç zaten önceden bilinmektedir. Sonraki ders değişikliği yanıtı beklemeden ekrana yansıtmayı, başarısızlıkta önceki hâle dönmeyi ve bu dönüşün arada gelen başka değişikliklerle nasıl çakışabileceğini ele alır.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat