Ders 08 / 30
Servis Nesneleri
Küme içi kararlı adreslemenin iki ölçüsü: on bir kapsül gelip giderken adın kaç kez değiştiği ve listenin kaç kez değiştiği, hazır olma denetimi olan ve olmayan koşumda hazır olmayan uca giden istek sayısı, ve ad çözümleme ömrünün eklediği tur ile bayat uca giden istek arasındaki takas.
İçindekiler
Önceki ders altı kopyayı ayakta tutmayı ölçtü ve ölçerken bir şeyi görünür kıldı: kopya kümesi altı kapsül olacağını garanti eder, hangi altı olacağını garanti etmez. On dört turluk koşumda on kapsül oluşturuldu, geçişte altısı silinip altısı kuruldu. Her yeni kapsül yeni bir kapsüldür; öncekinin adresi onunla birlikte gitmiştir. Doğrulayıcı, okuma toplayıcıya istek göndermek istediğinde kime bağlanacaktır?
Bu boşluğu dolduran nesne servis nesnesidir. Tuttuğu şey bir yazılım değildir; bir ad ve o adın
arkasındaki uç nokta listesidir. Liste kopya kümesinden türer ve kapsüller geldikçe gittikçe
kendiliğinden güncellenir. M16/K06’da servis, ayrı dağıtılan ve ayrı sahiplenilen bir yazılım
parçasıydı; buradaki servis nesnesi o yazılımın kopyalarının önünde duran bir addır — aynı sözcük,
başka bir nesne. Bu ders adı ve listeyi node ile modelleyip ikisini de sayar; gerçek bir küme
koşturulmaz.
TN13 — servis nesnesi bir ada bağlı uç nokta listesi tutar ve liste kopya kümesindeki kapsüllerden türer. TN14 — adın listeye çözümlenmesi isteğe bir tur ekler, sonuç bir ömür boyunca önbellekte tutulabilir. TN15 — istekler uç nokta listesi üzerinde dönüşümlü dağıtılır. TN16 — yeni kapsül iki tur sonra hazır olur; hazır olma denetimi yoksa oluşturulduğu turda listeye girer. TN17 — hazır olmayan ya da bildirimden düşmüş bir uca giden istek başarısız olur. TN18 — koşum yirmi dört tur sürer, her turda on iki istek gelir, kapsül devri tohumlu bir üreteçle üretilir.
Değişen Liste, Değişmeyen Ad
Aşağıdaki koşum aynı devir çizelgesini iki kez uygular. Değişen tek şey uç nokta listesinin nereden türediğidir: bütün kapsüllerden mi, yoksa yalnız hazır olanlardan mı.
// servis.mjs — servis nesnesi: ad sabit kalirken uc nokta listesi degisir (MODEL). export const TOHUM = 20260803, TUR = 24, ISTEK = 12, N = 6, HAZIR = 2, DEVIR = 0.45; // Uretec kendi yazildi; 32 bitlik tam sayi islemleri, tohum gorunur. export const uret = (t) => () => { t ^= t << 13; t ^= t >>> 17; t ^= t << 5; return (t >>> 0) / 2 ** 32; }; // Devir cizelgesi bir kez uretilir; iki kosum da ayni kapsulleri ayni turlarda kaybeder. const rnd = uret(TOHUM); export const CIZELGE = Array.from({ length: TUR }, () => (rnd() < DEVIR ? Math.floor(rnd() * N) : null)); export const SERVIS_ADI = 'okuma-toplayici.olcum'; // degismeyen tek sey // Kopya kumesi her turda N kapsul tutar; devir olan yuvaya yeni kapsul konur (TN13). export function kosum(denetim) { let sayac = N, ad = SERVIS_ADI; const yuva = Array.from({ length: N }, (_, i) => ({ ad: `kapsul-${i}`, hazirAn: 0 })); let istek = 0, basarisiz = 0, devir = 0, adDegisimi = 0, listeDegisimi = 0, sira = 0; let onceki = ''; const ucSayisi = [], yuk = []; for (let t = 0; t < TUR; t++) { const j = CIZELGE[t]; if (j !== null) { yuva[j] = { ad: `kapsul-${sayac++}`, hazirAn: t + HAZIR }; devir++; } // Hazir olma denetimi varsa liste yalniz hazir kapsullerden turer; yoksa hepsinden. const uclar = denetim ? yuva.filter((k) => k.hazirAn <= t) : [...yuva]; const imza = uclar.map((k) => k.ad).sort().join(','); if (t && imza !== onceki) listeDegisimi++; if (ad !== SERVIS_ADI) adDegisimi++; // ada dokunan hicbir yol yok onceki = imza; ucSayisi.push(uclar.length); yuk.push(uclar.length ? Math.ceil(ISTEK / uclar.length) : ISTEK); for (let i = 0; i < ISTEK; i++) { istek++; if (!uclar.length) { basarisiz++; continue; } const hedef = uclar[sira++ % uclar.length]; // TN15: donusumlu dagitim if (hedef.hazirAn > t) basarisiz++; // TN17 } } return { istek, basarisiz, devir, adDegisimi, listeDegisimi, ucEnAz: Math.min(...ucSayisi), ucEnCok: Math.max(...ucSayisi), yukEnCok: Math.max(...yuk) }; } if (import.meta.url === `file://${process.argv[1]}`) { const s = (x, n) => String(x).padStart(n); console.log(`tohum ${TOHUM}, ${TUR} tur, tur basina ${ISTEK} istek, ${N} kopya,` + ` hazir olma ${HAZIR} tur, servis adi '${SERVIS_ADI}'`); console.log(`${'denetim'.padEnd(12)}${s('istek', 7)}${s('basarisiz', 11)}${s('oran', 8)}` + `${s('uc sayisi', 11)}${s('uc basina en cok', 18)}${s('liste degisimi', 16)}` + `${s('ad degisimi', 13)}`); for (const [etiket, d] of [['yok', false], ['hazir olma', true]]) { const r = kosum(d); console.log(`${etiket.padEnd(12)}${s(r.istek, 7)}${s(r.basarisiz, 11)}` + `${s(`%${(100 * r.basarisiz / r.istek).toFixed(1)}`, 8)}` + `${s(`${r.ucEnAz}-${r.ucEnCok}`, 11)}${s(r.yukEnCok, 18)}${s(r.listeDegisimi, 16)}` + `${s(r.adDegisimi, 13)}`); } console.log(`\n${TUR} turda ${kosum(true).devir} kapsul gelip gitti;` + ` cagiran taraf hep ayni adi kullandi`); }
tohum 20260803, 24 tur, tur basina 12 istek, 6 kopya, hazir olma 2 tur, servis adi 'okuma-toplayici.olcum' denetim istek basarisiz oran uc sayisi uc basina en cok liste degisimi ad degisimi yok 288 44 %15.3 6-6 2 10 0 hazir olma 288 0 %0.0 4-6 3 13 0 24 turda 11 kapsul gelip gitti; cagiran taraf hep ayni adi kullandi
Son satır bu dersin bütün gerekçesidir. Yirmi dört turda on bir kapsül gelip gitti; uç nokta
listesi on üç kez değişti; ad sıfır kez değişti. Değişim sayısı ile sabitlik sayısı yan yana
durduğunda servis nesnesinin ne yaptığı görünür hâle gelir: bir değişkenlik kaynağını, çağıran
tarafın hiç görmediği bir yere taşır. Doğrulayıcının kodunda yazılı olan tek şey okuma-toplayici.olcum
adıdır ve o ad, kopya kümesindeki hiçbir olaydan etkilenmez.
Listenin kendisi de bildirilmez, türetilir. Servis nesnesine yazılan tek şey hangi kapsüllerin bu ada ait sayılacağıdır; hangi kapsüllerin o an var olduğu bir ölçümden gelir. Bu ayrım, önceki iki dersin bilgi kalemleri arasındaki farkın aynısıdır: istenen kopya sayısı bildirimdir ve eskimez, uç nokta listesi ölçümdür ve her turda yeniden üretilmesi gerekir. Bir nesnenin bildirim mi ölçüm mü taşıdığı, onun ne sıklıkta yanlış olabileceğini belirler.
Başarısız istek sütunu ise adın yeterli olmadığını söylüyor. Hazır olma denetimi yokken uç nokta listesi her zaman altı kapsüllüktür — sayı doğru, içerik yanlıştır. Yeni oluşturulan kapsül iki tur boyunca hizmet veremediği hâlde listede durur ve dönüşümlü dağıtım ona sırayla istek gönderir. Sonuç iki yüz seksen sekiz isteğin kırk dördü, yani her yedi istekten biridir. Hazır olma denetimi açıldığında bu sayı sıfıra iner; liste yalnız hizmet verebilen kapsülleri gösterir.
Bedel, hemen yanındaki iki sütunda. Denetimli koşumda uç sayısı zaman zaman dörde iner ve bir uca düşen istek en çok ikiden üçe çıkar. Denetim istekleri kurtarmaz, yeniden dağıtır: hazır olmayan kapsüle gidecek olan istek, hazır olan kapsüllere eklenir. Liste değişim sayısının onda üç artması da aynı nedendendir — kapsül artık listeye iki kez girer çıkar: oluşturulduğunda değil, hazır olduğunda girer, düştüğünde çıkar. Kararlı ad, altındaki listenin daha sık değişmesi pahasına elde edilir.
Sıfır sayısının kaynağı bir şans değil, bir ayrımdır. Ad, kopya kümesinden ayrı bir nesnede durur; kapsül oluşturan, silen ve hazır sayan hiçbir yol o nesneye dokunmaz. Servis nesnesi olmasaydı bu sıfırın yerine on üç gelirdi: uç nokta listesinin her değişimi, çağıran tarafın elindeki adres listesinin de değişmesi gerektiği anlamına gelirdi ve o listeyi güncel tutma işi doğrulayıcının kendi kodunda bir bileşen olurdu. Ad, tam olarak bu bileşeni ortadan kaldırmak için vardır.
Adı Çözmenin Bedeli
Ad sabit, liste değişken. Çağıran taraf isteği göndermeden önce adı bir listeye çevirmek zorundadır ve TN14 bunun bir tur ettiğini söyler. Bu turu her istekte ödemek de, bir kez ödeyip sonucu saklamak da mümkündür; ikisinin arasındaki alan aşağıda ölçülüyor.
// cozumleme.mjs — adin coze coze mi yoksa onbellekten mi okunacagi (MODEL). import { CIZELGE, N, HAZIR, TUR, ISTEK } from './servis.mjs'; // Ayni devir cizelgesi; her turun canli kumesi ve hazir uc listesi bir kez cikarilir. function zamanCizgisi() { let sayac = N; const yuva = Array.from({ length: N }, (_, i) => ({ ad: `kapsul-${i}`, hazirAn: 0 })); const canli = [], hazirListe = []; for (let t = 0; t < TUR; t++) { const j = CIZELGE[t]; if (j !== null) yuva[j] = { ad: `kapsul-${sayac++}`, hazirAn: t + HAZIR }; canli.push(new Set(yuva.map((k) => k.ad))); hazirListe.push(yuva.filter((k) => k.hazirAn <= t).map((k) => k.ad)); } return { canli, hazirListe }; } // TN14: her cozumleme isteme bir tur ekler; sonuc omur boyunca onbellekte tutulur. function onbellek(omur) { const { canli, hazirListe } = zamanCizgisi(); let cozumleme = 0, istek = 0, bayat = 0, sira = 0, liste = [], son = -Infinity; for (let t = 0; t < TUR; t++) { for (let i = 0; i < ISTEK; i++) { if (omur === 0 || t - son >= omur) { liste = hazirListe[t]; son = t; cozumleme++; } istek++; const hedef = liste[sira++ % liste.length]; if (!canli[t].has(hedef)) bayat++; // bildirimden dusmus uca giden istek } } return { cozumleme, istek, bayat }; } const s = (x, n) => String(x).padStart(n); console.log(`${TUR} tur x ${ISTEK} istek = ${TUR * ISTEK} istek`); console.log(`${s('onbellek omru', 14)}${s('cozumleme', 11)}${s('ek tur', 8)}` + `${s('istek basina ek tur', 21)}${s('bayat uca istek', 17)}${s('oran', 8)}`); for (const omur of [0, 2, 4, 8, TUR]) { const r = onbellek(omur); console.log(`${s(omur === 0 ? 'yok' : `${omur} tur`, 14)}${s(r.cozumleme, 11)}` + `${s(r.cozumleme, 8)}${s((r.cozumleme / r.istek).toFixed(2), 21)}${s(r.bayat, 17)}` + `${s(`%${(100 * r.bayat / r.istek).toFixed(1)}`, 8)}`); }
24 tur x 12 istek = 288 istek
onbellek omru cozumleme ek tur istek basina ek tur bayat uca istek oran
yok 288 288 1.00 0 %0.0
2 tur 12 12 0.04 12 %4.2
4 tur 6 6 0.02 35 %12.2
8 tur 3 3 0.01 72 %25.0
24 tur 1 1 0.00 216 %75.0
Tablo iki uçtan okunmalıdır. Üstte hiç önbellekleme yoktur: her istek adını yeniden çözer, iki yüz seksen sekiz istek iki yüz seksen sekiz ek tur öder ve bayat uca giden istek sıfırdır. Altta ad bir kez çözülür: ek tur bire iner, karşılığında iki yüz on altı istek — dörtte üçü — artık var olmayan kapsüllere gider. Aradaki üç satır bu iki ucun arasındaki eğridir ve eğri diktir: ömür ikiden dörde çıktığında ek tur altıya iner, bayat istek on ikiden otuz beşe çıkar.
Bu tablonun söylediği şey, bu kursun ölçü ekseninin kendisidir. Uç nokta listesi bir bilgi kalemidir ve her bilgi kaleminin iki fiyatı vardır: onu almanın maliyeti ile eskimesinin maliyeti. Sıfır ömürde birinci fiyat ödenir, sonuncu satırda ikinci fiyat. Bayat uca giden yüzde yetmiş beşlik pay, hiçbir bileşenin arızalanmadığı bir kümede doğar — yalnızca çağıran tarafın elindeki liste, kümenin gerçek durumundan yirmi dört tur geridedir.
Eğrinin ortası da bir şey söylüyor. İki turluk ömür, çözümleme yükünü iki yüz seksen sekizden on ikiye, yani yirmi dörtte birine indirirken bayat isteği yüzde dört buçukta tutar. Dört turluk ömür çözümlemeyi yalnızca ikiye böler, bayat isteği ise üç katına çıkarır. İki uçta da kazanç ve kayıp aynı hızda büyümez: birinci adımda çok kazanılır az ödenir, sonraki adımlarda az kazanılır çok ödenir. Bu asimetri ömrün seçilecek bir sayı olduğunu, iki uçtan birinin doğru olmadığını gösteriyor.
Devredilen Karar ve Bilmediği Şey
Devredilen karar burada açıktır: isteğin hangi kapsüle gideceği. Bu karar daha önce çağıranın yapılandırmasında yazılıydı; şimdi servis nesnesinin listesinden okunur. Kararın dayandığı bilgi üç kalemdir: hangi kapsüllerin var olduğu, hangilerinin hazır olduğu, listenin ne zaman okunduğu. Birincisi kopya kümesinden bedava gelir. İkincisi bir denetim gerektirir ve bedeli birinci tabloda yazılıdır: uç başına düşen en yüksek istek ikiden üçe çıkar. Üçüncüsü de bir tur eder ve ikinci tablonun ilk sütununda durur.
Sistemin bilmediği şey, listenin ne zaman eskidiğidir. Model bunu bir ömür sayısıyla yaklaşık olarak çözüyor; ömür, kapsül devrinin ne sıklıkta olduğuna dair bir tahmindir. Devir tahminden sıksa bayat uca giden istekler artar, seyrekse gereksiz çözümleme turları ödenir. Yirmi dört turda on bir devir olan bu koşumda iki turluk ömür bile on iki bayat istek üretir; devrin sıklığı yarıya inseydi aynı ömür daha ucuz olurdu. Yanlış kararın kaynağı burada bir hesap değil, bir sayının ne kadar süre doğru kaldığına dair bilgisizliktir.
Üç sonuç bir arada sayıldığında tablo şöyle çıkıyor. Denetimli ve önbelleksiz koşumda iki yüz seksen sekiz yönlendirme kararının tamamı doğrudur. Denetimsiz koşumda kırk dördü yanlıştır ve yanlışın kaynağı tek bir eksik bilgi kalemidir: kapsülün hazır olup olmadığı. Karar verememe durumu bu koşumda hiç görülmedi, çünkü hazır uç sayısı en az dörde indi, sıfıra hiç inmedi. Devir sıklığı artıp bütün kapsüller aynı anda hazır olmayı beklerse liste boşalır ve servis nesnesi elinde ad olduğu hâlde yönlendirecek yer bulamaz; o durumda karar ne doğru ne yanlıştır, verilememiştir.
Özet
- Servis nesnesi bir yazılım değil, bir ad ile onun arkasındaki uç nokta listesidir; liste kopya kümesinden türer. M16/K06’nın servis’i ayrı dağıtılan bir yazılım parçasıydı, buradaki nesne o parçanın kopyalarının önündeki addır.
- Yirmi dört turda on bir kapsül gelip gitti ve uç nokta listesi on üç kez değişti; ad sıfır kez değişti. Çağıran tarafın kodunda yazılı olan tek şey addır.
- Hazır olma denetimi olmadan iki yüz seksen sekiz isteğin kırk dördü hazır olmayan bir kapsüle gitti; denetim açıldığında bu sayı sıfıra indi.
- Denetimin bedeli istek kaybı değil yük kaymasıdır: uç sayısı dörde iner, bir uca düşen en yüksek istek ikiden üçe çıkar ve liste on yerine on üç kez değişir.
- Ad çözümlemesi isteğe bir tur ekler; hiç önbelleklenmezse iki yüz seksen sekiz ek tur ödenir, bir kez çözülüp saklanırsa ek tur bire iner ama isteklerin yüzde yetmiş beşi artık var olmayan uçlara gider.
- Bu iki tablo bir bilgi kaleminin iki fiyatını gösterir: onu almanın maliyeti ile eskimesinin maliyeti; ömür seçimi, kapsül devri sıklığına dair bir tahmindir.
Sonraki Adım
Bu dersin bütün istekleri kümenin içinden geldi: doğrulayıcı, aynı kümedeki okuma toplayıcıyı çağırdı. Ad çözümlemesi de dönüşümlü dağıtım da o sınırın içinde çalışır. Oysa bölgesel ölçüm ağının faturalama arayüzüne dışarıdan, kümeyi hiç bilmeyen bir istemciden istek gelir. O isteğin bir servis nesnesine ulaşması için kaç katmandan geçmesi ve her katmanda kaç kural yazılması gerekir? Sonraki ders dışarıdan gelen tek bir isteğin katmanlarını sayar: her katmanın eklediği tur, yol tabanlı ve ad tabanlı yönlendirmenin kural sayısı ile servis sayısı ilişkisi, ve dışarı açılan yüzeyin kaç uç ile kaç yoldan oluştuğu.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.