İçeriğe geç
academia.sh

Ders 14 / 18

Tutarlılık ve Bayat Veri

Bayatlık penceresinin verinin değişme hızından hesaplanması: 48 saatlik yol süresi ve V4 ile tepe saatte 8228,57 saniyelik olay aralığının çıkarılması, pencerenin 60 saniyede doyup isabeti 0,8968'e ve depoya ulaşan isteği 140,23'e getirmesi, bayat yanıtın hep tam bir olay geride kalması ve önceki derslerin geçersizleştirme üst sınırının 0,0010'luk gerçek payla değiştirilmesi.

İçindekiler

Önceki ders önbelleğin gerekli olduğu örüntüleri ayırdı ama bir soru açık kaldı. Önbellekten dönen değer, deponun o andaki değeriyle aynı olmak zorunda değil. Bu konunun ikinci dersi ayrılmayı bir kez ölçtü — geçersizleştirme kapatıldığında 105.794 bayat okuma — ve dördüncü dersi bir parametreye bağladı: beş saniyelik üst sınır süresi keyfi seçilmişti ve gerekçesi yazılmamıştı.

Bu ders o gerekçeyi kurar. Bayatlığın ne kadarının kabul edilebilir olduğu bir tercih değil, verinin kendisinden çıkan bir sayıdır: bir gönderinin durumu ne sıklıkla değişiyorsa, o değişimden çok daha kısa bir pencere neredeyse hiç bayat yanıt üretmez.

İki Pencere, Aynı Yanıt

Sistem Tasarımına Giriş kursu eskilik penceresini tanımlamıştı: bir yazma onaylandıktan sonra kopyaların hepsinin o değeri görmesine kadar geçen süre. Buradaki pencere başkadır ve adı bayatlık penceresidir (staleness window): önbellekteki bir kopyanın kaynaktan geri kalabileceği en uzun süre; o süre içinde sunulan kopya bayat veridir (stale data). Kaynakları farklıdır — biri çoğaltmanın yayılımından, öteki girdiye verilen ömürden doğar — ama ürettikleri şey aynıdır ve aynı adla anılır: bayat yanıt. Bir sistemde ikisi birden bulunur ve toplanır.

Tutarlılık modelleri o kursta tanımlandı; burada tekrarlanmaz. Yalnız bir bağ kurulur: önbelleğin sonunda tutarlılık güvencesi, girdiye verilen ömürdür. Ömür yoksa ve yalnız geçersizleştirmeye güveniliyorsa yakınsama güvencesi de yoktur — bu konunun ikinci dersi kaybolan bir silmenin hiçbir sayaçta görünmeden bayat bir girdi bıraktığını ölçmüştü. Ömür, o girdinin er geç düzeleceğini söyleyen tek mekanizmadır ve bayatlık penceresi tam olarak o güvencenin genişliğidir.

Pencere Nereden Gelir

Bir gönderi V4’e göre yedi durum olayı üretir. Bu olayların ne kadar süreye yayıldığı K01’in tablosunda yok; oradaki tek süre 730 günlük saklamadır ve o başka bir şeydir.

B1 (bu dersin varsayımı): bir gönderi ilk olayından teslimine kadar 48 saat yolda kalır. Gerekçe: V4’ün yedi durumu (kabul, aktarma, dağıtıma çıkış, teslim ve ara durumlar) bir yol süresine yayılır ve iki günlük bir yol süresi bu durumların hepsinin gerçekleşmesine yeter. V8’in tepe çarpanı olayları da hızlandırdığına göre tepe saatte gönderi başına olay aralığı 483600/7/348 \cdot 3600 / 7 / 3 saniyedir. Duyarlılığı son ölçümde yazılıdır. Varsayım K01’in tablosuna eklenmez.

// onbellek/bayat.mjs — bayatlik penceresinin surec ici modeli. Saat bir sayactir; olay
// araligi, pencere ve kapasite parametredir. Sure olculmez, olay ve okuma sayilir.
export const K01 = {
  tepeOkuma: (2_000_000 * 6 / 86_400) * 3,   // 416,67 istek/s
  tepeYazma: (400_000 * 7 / 86_400) * 3,     // 97,22 istek/s
  gonderiBasinaOlay: 7,                      // V4
  tepeCarpani: 3,                            // V8
};

// B1: bir gonderi ilk olayindan teslimine kadar 48 saat yolda kalir. Tepe saatte olay
// araligi V4 ve V8 ile birlikte buradan cikar.
export const YOL_SAAT = 48;
export const olayAraligi = (yolSaat) => (yolSaat * 3600) / K01.gonderiBasinaOlay / K01.tepeCarpani;

// Okuma akisi ve olay takvimi birlikte uretilir: her gonderi, olusturuldugunda kendi olay
// zamanini alir. Saat okuma sayacidir; bir tik = 1/tepeOkuma saniye.
export function kosum({ okuma, calismaKumesi, obek, kapasite, pencereSn, yolSaat = YOL_SAAT }) {
  let tohum = 20260730;
  const rast = () => ((tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648);
  const pencere = pencereSn * K01.tepeOkuma;             // tik
  const aralikTik = olayAraligi(yolSaat) * K01.tepeOkuma;
  const kutu = new Map();                                // anahtar -> { surum, biter }
  const gercek = new Map();                              // anahtar -> { surum, sonrakiOlay }
  let saat = 0, sonraki = 1;
  const s = { isabet: 0, depoOkuma: 0, bayat: 0, gerilikToplam: 0, enBuyukGerilik: 0, olay: 0 };
  const yeniGonderi = () => {
    const no = sonraki++;
    gercek.set(`takip:${no}`, { surum: 0, sonrakiOlay: saat + rast() * aralikTik });
    return { no, kalan: obek };
  };
  const etkin = Array.from({ length: calismaKumesi }, () => yeniGonderi());

  for (let i = 0; i < okuma; i++) {
    saat += 1;
    const j = Math.floor(rast() * etkin.length);
    const anahtar = `takip:${etkin[j].no}`;
    if ((etkin[j].kalan -= 1) === 0) etkin[j] = yeniGonderi();

    const g = gercek.get(anahtar);                       // vadesi gelen olaylar islenir
    while (saat >= g.sonrakiOlay) { g.surum += 1; s.olay += 1; g.sonrakiOlay += aralikTik; }

    const c = kutu.get(anahtar);
    if (c !== undefined && c.biter > saat) {
      s.isabet += 1;
      const gerilik = g.surum - c.surum;
      if (gerilik > 0) {
        s.bayat += 1; s.gerilikToplam += gerilik;
        s.enBuyukGerilik = Math.max(s.enBuyukGerilik, gerilik);
      }
      continue;
    }
    s.depoOkuma += 1;
    kutu.delete(anahtar);
    kutu.set(anahtar, { surum: g.surum, biter: saat + pencere });
    if (kutu.size > kapasite) kutu.delete(kutu.keys().next().value);
  }
  return s;
}

Gerilik, bayat bir yanıtın kaç olay geride kaldığıdır. Bayat okuma sayısı pencerenin ne sıklıkla ihlal edildiğini söyler; gerilik, ihlal edildiğinde kullanıcının ne gördüğünü söyler. İkisi ayrı sorulardır ve tasarım kararı ikisine birden bakar.

// onbellek/pencere.mjs — pencere buyudukce isabet, bayat yanit ve depo yuku
import { K01, YOL_SAAT, olayAraligi, kosum } from "./bayat.mjs";

const OKUMA = 200_000, KAPASITE = 2000, CALISMA = 1000, OBEK = 10;
const PENCERE_SN = 480;

console.log(`B1: yol suresi ${YOL_SAAT} saat, V4 = ${K01.gonderiBasinaOlay} olay, V8 = ${K01.tepeCarpani}`);
const ARALIK = olayAraligi(YOL_SAAT);
console.log(`-> tepe saatte gonderi basina olay araligi = ${ARALIK.toFixed(2)} s`);
console.log(`okuma ${OKUMA} (${PENCERE_SN} s), kapasite ${KAPASITE}, es zamanli gonderi ${CALISMA}\n`);

console.log("pencere (s)  isabet  bayat okuma  bayat orani  bayat yanit/s  ort. gerilik  en buyuk  depoya ulasan/s");
console.log("----------- ------- ------------ ------------ -------------- ------------- --------- ----------------");
for (const p of [1, 5, 30, 60, 300, 1800]) {
  const r = kosum({ okuma: OKUMA, calismaKumesi: CALISMA, obek: OBEK, kapasite: KAPASITE, pencereSn: p });
  const h = r.isabet / OKUMA;
  const bayatOran = r.bayat / OKUMA;
  const arka = K01.tepeOkuma * (1 - h);
  console.log(`${String(p).padStart(11)} ${h.toFixed(4).padStart(7)} ${String(r.bayat).padStart(12)} ` +
    `${bayatOran.toFixed(6).padStart(12)} ${(bayatOran * K01.tepeOkuma).toFixed(3).padStart(14)} ` +
    `${(r.bayat === 0 ? 0 : r.gerilikToplam / r.bayat).toFixed(2).padStart(13)} ${String(r.enBuyukGerilik).padStart(9)} ` +
    `${(arka + K01.tepeYazma).toFixed(2).padStart(16)}`);
}

const r5 = kosum({ okuma: OKUMA, calismaKumesi: CALISMA, obek: OBEK, kapasite: KAPASITE, pencereSn: 5 });
console.log(`\npencere 5 s: onbellekteyken olay alan anahtar sayisi = ${r5.olay}`);
console.log(`K01 tepe yazma ${K01.tepeYazma.toFixed(2)}/s -> pencerede toplam olay = ${Math.round(K01.tepeYazma * PENCERE_SN)}`);
console.log(`onbellekteki anahtara dusen olay payi = ${(r5.olay / (K01.tepeYazma * PENCERE_SN)).toFixed(4)}`);

console.log(`\nbayatlik butcesi -> pencere (kuram: pencere = olay araligi x butce)`);
console.log("butce (bayat yanit orani)  kuramsal pencere (s)  olculen bayat orani");
for (const butce of [0.0001, 0.001, 0.01]) {
  const p = ARALIK * butce;
  const r = kosum({ okuma: OKUMA, calismaKumesi: CALISMA, obek: OBEK, kapasite: KAPASITE, pencereSn: p });
  console.log(`${butce.toFixed(4).padStart(25)} ${p.toFixed(2).padStart(21)} ${(r.bayat / OKUMA).toFixed(6).padStart(20)}`);
}

console.log(`\nB1'in duyarliligi (pencere 60 s):`);
console.log("yol suresi (saat)  olay araligi (s)  bayat orani  bayat yanit/s  isabet");
for (const yol of [48, 12, 2]) {
  const r = kosum({ okuma: OKUMA, calismaKumesi: CALISMA, obek: OBEK, kapasite: KAPASITE, pencereSn: 60, yolSaat: yol });
  const o = r.bayat / OKUMA;
  console.log(`${String(yol).padStart(17)} ${olayAraligi(yol).toFixed(2).padStart(17)} ${o.toFixed(6).padStart(12)} ` +
    `${(o * K01.tepeOkuma).toFixed(3).padStart(14)} ${(r.isabet / OKUMA).toFixed(4).padStart(7)}`);
}
B1: yol suresi 48 saat, V4 = 7 olay, V8 = 3
-> tepe saatte gonderi basina olay araligi = 8228.57 s
okuma 200000 (480 s), kapasite 2000, es zamanli gonderi 1000

pencere (s)  isabet  bayat okuma  bayat orani  bayat yanit/s  ort. gerilik  en buyuk  depoya ulasan/s
----------- ------- ------------ ------------ -------------- ------------- --------- ----------------
          1  0.2700            3     0.000015          0.006          1.00         1           401.40
          5  0.6313           32     0.000160          0.067          1.00         1           250.85
         30  0.8866          221     0.001105          0.460          1.00         1           144.46
         60  0.8968          239     0.001195          0.498          1.00         1           140.23
        300  0.8968          239     0.001195          0.498          1.00         1           140.23
       1800  0.8968          239     0.001195          0.498          1.00         1           140.23

pencere 5 s: onbellekteyken olay alan anahtar sayisi = 46
K01 tepe yazma 97.22/s -> pencerede toplam olay = 46667
onbellekteki anahtara dusen olay payi = 0.0010

bayatlik butcesi -> pencere (kuram: pencere = olay araligi x butce)
butce (bayat yanit orani)  kuramsal pencere (s)  olculen bayat orani
                   0.0001                  0.82             0.000005
                   0.0010                  8.23             0.000290
                   0.0100                 82.29             0.001195

B1'in duyarliligi (pencere 60 s):
yol suresi (saat)  olay araligi (s)  bayat orani  bayat yanit/s  isabet
               48           8228.57     0.001195          0.498  0.8968
               12           2057.14     0.004180          1.742  0.8968
                2            342.86     0.032020         13.342  0.8968

Bütün sayılar hesap sınıfındadır: belirlenimli bir akış üzerinde sayılmışlardır.

Pencerenin Doyması

İlk tablo beklenmedik bir yerde duruyor. Pencere 60 saniyeden sonra hiçbir şeyi değiştirmiyor: isabet 0,8968, bayat oranı 0,001195, depoya ulasan istek/s 140,23 — üç satır aynı. Nedeni, girdinin ömrünü dolduramadan tahliye edilmesidir. Bir gönderinin on sorgusu yaklaşık yirmi dört saniyeye yayılır; o bittiğinde gönderi çalışma kümesinden çıkar ve girdisi kapasite baskısıyla düşer. Altmış saniyeden uzun bir pencere bir daha okunmayacak bir girdiye verilmiş demektir.

Bu, dördüncü dersin beş saniyelik varsayımını kötü bir seçim yapıyor. Beş saniyede isabet 0,6313 ve depoya ulasan istek/s 250,85; altmış saniyede 0,8968 ve 140,23. Beş saniyelik pencere depoya saniyede 110,62 fazladan istek bindiriyor ve karşılığında bayat oranını 0,001195’ten 0,000160’a indiriyor: saniyede 0,43 bayat yanıt kazanmak için 110,62 istek ödeniyor.

İkinci tablo pencerenin nasıl seçileceğini veriyor. Bir bayatlık bütçesi — kabul edilen bayat yanıt oranı — konur ve pencere, olay aralığı ile bütçenin çarpımı olur. Yüzde birlik bir bütçe 82,29 saniyelik bir pencereye karşılık geliyor; ölçülen oran ise 0,001195, bütçenin sekizde biri. Kuram üst sınırı verir, tahliye onu daha da aşağı çeker.

Bayatlığın Büyüklüğü

Bayat okuma sayısı tek başına yeterli değildir. Ortalama gerilik ve en büyük gerilik sütunları altı satırın hepsinde 1,00 ve 1: bayat bir yanıt hiçbir zaman birden fazla olay geride kalmıyor. Kullanıcı açısından bu, gönderinin bir durum adımı önceki hâlini görmesi demektir — “dağıtıma çıktı” yerine “aktarma merkezinde” gibi. Durum hiçbir zaman iki adım geri gitmiyor ve sayfayı yenilediğinde doğrusunu görüyor.

Bu sayı pencereyi kabul edilebilir kılan asıl gerekçedir. Saniyede 0,498 bayat yanıt, sekiz dakikalık pencerede 239 yanıt eder ve her biri tam bir adım geridedir. Aynı bütçe, gerilik iki ya da üç olsaydı başka bir karar gerektirirdi.

Kabul kararının bir de katman boyutu var. Bu konunun ilk dersi isabetin 0,7002’sinin istemci katmanında karşılandığını ölçmüştü ve o katmanda konan kopya, süresi dolana kadar geri alınamaz. Bayat yanıtların çoğunluğu bu yüzden geri alınamaz katmandan gelir: pencere orada bir tahmin değil, bir taahhüttür.

Bir Varsayımın Yerine Bir Hesap

Son iki çıktı bloğu bu konunun en önemli düzeltmesini taşıyor.

Bu konunun ikinci dersi bir üst sınır kullanmıştı: durum olaylarının tamamının o anda sorgulanan gönderilere düştüğünü varsaydı ve bunun geçersizleştirmenin en güçlü olduğu yön olduğunu yazdı. B1 o üst sınırın yerine bir hesap koyuyor. Pencerede 46.667 durum olayı var ve bunların yalnız 46’sı önbellekte duran bir anahtara düşüyor: pay 0,0010. Olayların geri kalanı ya sorgulanmayan gönderilere ya da o anda önbellekte bulunmayan anahtarlara gidiyor ve hiçbir girdiyi düşürmüyor.

Bu, ikinci ve üçüncü derslerin sayılarını üst sınır hâline getirir. Yanında okumanın ölçtüğü 0,7287 isabet, olayların hepsi sıcak anahtara düşseydi geçerli olurdu; gerçek payla isabet 0,8968’de kalır ve yanında okuma ile içinden yazma arasındaki fark okuma tarafında kaybolur. Üçüncü dersin yazma yolu çözümlemesi bundan etkilenmez: yazma yolunun uzunluğu, birleşme oranı ve kayıp penceresi olayların nereye düştüğünden bağımsızdır.

Son tablo B1’in duyarlılığını veriyor ve kararın sınırını çiziyor. Yol süresi 48 saatten 2 saate indiğinde olay aralığı 8228,57 saniyeden 342,86 saniyeye iner ve aynı altmış saniyelik pencere bayat oranını 0,001195’ten 0,032020‘ye, bayat yanıtı saniyede 13,342’ye çıkarır. İsabet değişmez. Aynı önbellek tasarımı, aynı ölçülerle, aynı gün içinde teslim edilen bir gönderi akışında yirmi yedi kat daha fazla bayat yanıt üretir. Pencere veriye bağlıdır, sisteme değil.

Özet

  • Bayatlık penceresi önbellekteki kopyanın kaynaktan geri kalabileceği süredir; eskilik penceresinden kaynağıyla ayrılır ama aynı bayat yanıtı üretir ve önbelleğin sonunda tutarlılık güvencesi tam olarak bu penceredir.
  • Pencere verinin değişme hızından çıkar: B1 ve V4 ile tepe saatte olay aralığı 8228,57 saniye, pencere ise bu aralık ile bayatlık bütçesinin çarpımıdır — yüzde birlik bütçe 82,29 saniye.
  • Pencere 60 saniyede doyuyor: isabet 0,8968, depoya ulasan istek/s 140,23 ve bayat oranı 0,001195. Dördüncü dersin beş saniyelik penceresi saniyede 0,43 bayat yanıt kazanmak için depoya 110,62 fazladan istek bindiriyordu.
  • Bayat yanıt hiçbir koşumda birden fazla olay geride kalmadı; ortalama ve en büyük gerilik 1. Kabul kararı bayat yanıt sayısına değil, bu iki sayıya birden bakar.
  • Pencerede 46.667 olayın yalnız 46’sı önbellekteki bir anahtara düşüyor (pay 0,0010); bu, ikinci dersin geçersizleştirme varsayımını üst sınır hâline getirir. Yol süresi 2 saate inerse aynı pencere bayat oranını 0,032020’ye çıkarır.

Sonraki Adım

Bu konu okumayı deponun önünde karşıladı ve bayatlığı bir pencereyle sınırladı. depoya ulasan istek/s satırı 513,89’dan 140,23’e indi ve V9’un 0,90’ı bir varsayım olmaktan çıkıp bir yerleşim, bir strateji ve bir pencere kararının sonucu oldu. Ama bütün bu tasarım tek bir şeyi hiç sorgulamadı: önbelleğe konan değerin biçimini. Önbellek okuma yolunu hafifletti; okuduğu şey hâlâ yazma için tasarlanmış modeldir. Gönderi kaydı, taşıyıcının durum olayını yazabilmesi için düzenlenmiştir ve takip sorgusu o modeli okumak zorunda kaldığı için önce birleştirir, sonra biçimlendirir, sonra saklar. Önbellek bu ödüncü ortadan kaldırmaz, yalnız ıskalanmayan isteklerden gizler; ıskalanan her istek yine aynı modele gider. Sıradaki konu ödüncü kaldırır ve okuma ile yazma yollarını kendi modelleriyle ölçekler. İlk sorusu şudur: aynı veriyi iki ayrı yapıda tutmak okuma ve yazma yollarının ayrı ölçeklenmesini sağlar mı, sağlıyorsa hangi orandan sonra.

İ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