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ığı 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/s140,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.