Ders 08 / 18
Eşler Arası
Başlatan ve bekleyen rolünün tek birimde birleştiği merkezsiz düzenin ölçülmesi: altı aktarma merkezinin üç komşuluk düzeninde tanımak zorunda olduğu komşu sayısı, bir tarife güncellemesinin herkese ulaşması için gereken tur ve ileti sayısı, bir birim çekildiğinde öğrenen birim sayısı ve yeni birim eklendiğinde düzenlenen komşu listesi sayısı.
İçindekiler
Önceki düzende asimetri kasıtlıydı: bir taraf hep başlatıyor, öbürü hep bekliyor ve bekleyen taraf tekti. Teslimat operasyonu bağlamında bu tekliğin bir karşılığı var — bütün ücret sorularının tek bir yere gitmesi, o yerin herkes tarafından bilinmesi anlamına gelir. Aynı işi birden çok aktarma merkezinin yürüttüğü bir düzende soru tersine döner. Her merkez hem soran hem yanıtlayan olursa bilme yükümlülüğü tek yöne yığılmak yerine dağılır.
Eşler arası (peer-to-peer) biçemin yazılım mimarisi düzeyindeki imzası budur: rol ayrımı kalkar, iki rol aynı modülde birleşir. Bilgisayar Ağları müfredatındaki İstemci–Sunucu Modeli dersi bu düzenin talep arttıkça kapasite kazandırdığını, ama kararlı adres ve merkezî denetim gerektiren web için istemci–sunucu modelinin seçildiğini söylemişti. Adres, bağlantı ve ağ katmanı oraya aittir. Buradaki soru üç sayıdır: bir birimin tanımak zorunda olduğu komşu sayısı, bir tarife güncellemesinin bütün birimlere ulaşması için gereken ileti sayısı, bir birim çekildiğinde iş görmeye devam eden birim sayısı.
Bağlandığı kalite niteliği güvenilirliktir ve nitelik sorusu şudur: bir aktarma merkezi devre dışı kaldığında kaç merkez yeni tarifeyi öğrenemez.
İki Rolü Taşıyan Modül
Altı aktarma merkezi var ve hepsi için aynı dosya koşuyor. Modülün içinde iki şey birden durur:
gelen isteği karşılayan istekIsle ve komşulara istek gönderen yay. Önceki dersin iki
dosyası — istemci ve sunucu — burada tek dosyada birleşmiştir.
mkdir -p es
// es/es.mjs — her aktarma merkezi icin kosan tek modul: hem karsilayan hem baslatan export function es(ad) { const komsular = []; let surum = "T1", alinan = 0, gonderilen = 0; return { ad, get surum() { return surum; }, tanit: (komsu) => komsular.push(komsu), sayac: () => ({ alinan, gonderilen, komsu: komsular.length }), istekIsle(istek) { alinan += 1; if (istek.islem !== "tarife-duyur") return { durum: "bilinmeyen-islem" }; if (istek.surum === surum) return { durum: "bilinen" }; surum = istek.surum; return { durum: "yeni" }; }, yay() { for (const komsu of komsular) { gonderilen += 1; komsu.istekIsle({ islem: "tarife-duyur", surum }); } }, }; }
Bir eşin bildiği tek şey komşularıdır. Kaç komşu tanıdığı ise dışarıdan verilir; biçemin ölçülebilir yüzü buradadır.
Üç Komşuluk Düzeni
Aynı altı birim üç ayrı biçimde bağlanır. Yıldız düzeninde bir merkez herkesi, herkes yalnız merkezi tanır; bu, önceki dersin düzeninin komşuluk olarak yazılmış hâlidir. Halka düzeninde her birim iki komşu tanır. Tam ağda her birim diğer beşini tanır.
Güncelleme her üç düzende de aynı yerden girer: ANK merkezine yeni tarife sürümü bildirilir.
Sonra tur tur yayılır — her turda sürümü bilen bütün birimler komşularına duyurur.
// es/ag.mjs — ayni birimlerin uc komsuluk duzeni ve bir guncellemenin yayilim kosumu import { es } from "./es.mjs"; export const AD = ["IST", "ANK", "IZM", "BUR", "ADA", "TRA"]; export const GIRIS = "ANK"; export const yildiz = (ad) => new Map(ad.map((a, i) => [a, i === 0 ? ad.slice(1) : [ad[0]]])); export const halka = (ad) => new Map(ad.map((a, i) => [a, [ad[(i + 1) % ad.length], ad[(i - 1 + ad.length) % ad.length]]])); export const tamAg = (ad) => new Map(ad.map((a) => [a, ad.filter((b) => b !== a)])); export const DUZENLER = [["yildiz", yildiz], ["halka", halka], ["tam ag", tamAg]]; export function yayilim(harita) { const esler = new Map([...harita.keys()].map((a) => [a, es(a)])); for (const [a, komsular] of harita) for (const k of komsular) esler.get(a).tanit(esler.get(k)); esler.get(GIRIS).istekIsle({ islem: "tarife-duyur", surum: "T2" }); const hepsi = [...esler.values()]; let tur = 0; while (hepsi.some((e) => e.surum !== "T2") && tur < 20) { tur += 1; for (const e of hepsi.filter((e) => e.surum === "T2")) e.yay(); } return { tur, ileti: hepsi.reduce((t, e) => t + e.sayac().gonderilen, 0), komsu: hepsi.reduce((t, e) => t + e.sayac().komsu, 0), ogrenen: hepsi.filter((e) => e.surum === "T2").length, birim: hepsi.length, }; }
// yayilim.mjs — bilinen komsu sayisi, yayilim turu ve ileti sayisi uc duzende import { AD, DUZENLER, yayilim } from "./es/ag.mjs"; console.log("duzen birim bilinen komsu tur ileti ogrenen"); for (const [etiket, kurucu] of DUZENLER) { const s = yayilim(kurucu(AD)); console.log( `${etiket.padEnd(7)}${String(s.birim).padStart(4)}${String(s.komsu).padStart(13)}` + `${String(s.tur).padStart(6)}${String(s.ileti).padStart(7)}${`${s.ogrenen}/${s.birim}`.padStart(9)}`, ); }
node yayilim.mjs
duzen birim bilinen komsu tur ileti ogrenen yildiz 6 10 2 7 6/6 halka 6 12 3 18 6/6 tam ag 6 30 1 5 6/6
Yayılım burada bir modeldir, ağ ölçümü değil: sayılan şey ileti ve tur sayısıdır, hiçbir süre ölçülmemiştir.
Sayıların Okunması
Üç düzen de altı birimin altısına ulaştı, yani aynı işi yapıyorlar. Farklar üç sütunda toplanır.
Bilinen komşu sayısı bilme yükümlülüğünün toplamıdır. Yıldızda 10: merkez beşini, beş birim birer merkezi tanıyor. Halkada 12, tam ağda 30. Tam ağ en pahalı bilme düzenidir ve bu, birim sayısının karesiyle büyür.
İleti ve tur sayıları ters yönde hareket eder. Tam ağ en az iletiyle (5) ve tek turda bitirdi, çünkü giriş birimi herkesi tanıyordu. Halka en çok iletiyi harcadı (18) ve üç tur sürdü, çünkü haber komşudan komşuya atlamak zorunda; her turda haberi bilen bütün birimler yeniden duyurur ve duyuruların çoğu bilinen bir sürümü taşır. Yıldız ikisinin arasında kaldı: 7 ileti, 2 tur — haberin ilk turda merkeze çıkması, ikinci turda merkezden dağılması gerekti.
Bu üç sütun bir ödünleşim tablosudur: bilme yükümlülüğünü azaltmak ileti sayısını artırır.
Bir Birim Çekildiğinde
Güvenilirlik sorusunun ölçümü şu deneydir: giriş birimi dışındaki her birim sırayla ağdan çıkarılır, yayılım baştan koşturulur ve kalan birimlerden kaçının yeni sürümü öğrendiği sayılır. Aynı betik ağa yedinci bir merkez eklendiğinde kaç komşu listesinin düzenlenmek zorunda kaldığını da hesaplar.
// dayaniklilik.mjs — bir birim cekildiginde ogrenen birim, yeni birim eklemenin maliyeti, tek dosyadaki iki rol import { readFileSync } from "node:fs"; import { AD, GIRIS, DUZENLER, yayilim } from "./es/ag.mjs"; const cikar = (harita, ad) => new Map([...harita].filter(([a]) => a !== ad).map(([a, k]) => [a, k.filter((x) => x !== ad)])); console.log("duzen en kotu ogrenen kritik birim yeni birim icin duzenlenen liste"); for (const [etiket, kurucu] of DUZENLER) { const tam = kurucu(AD); let kritik = 0, enKotu = [Infinity, 0]; for (const ad of AD.filter((a) => a !== GIRIS)) { const s = yayilim(cikar(tam, ad)); if (s.ogrenen < s.birim) kritik += 1; if (s.ogrenen < enKotu[0]) enKotu = [s.ogrenen, s.birim]; } const buyuk = kurucu([...AD, "ESK"]); const degisen = AD.filter((a) => tam.get(a).join(",") !== buyuk.get(a).join(",")).length; console.log( `${etiket.padEnd(9)}${`${enKotu[0]}/${enKotu[1]}`.padStart(16)}${String(kritik).padStart(14)}` + `${String(degisen).padStart(34)}`, ); } const kaynak = readFileSync("es/es.mjs", "utf8"); const karsilayan = (kaynak.match(/istekIsle\(istek\)/g) ?? []).length; const baslatan = (kaynak.match(/\.istekIsle\(\{/g) ?? []).length; console.log(`es/es.mjs: karsilayan tanim = ${karsilayan}, baslatan cagri = ${baslatan}`);
node dayaniklilik.mjs
duzen en kotu ogrenen kritik birim yeni birim icin duzenlenen liste yildiz 1/5 1 1 halka 5/5 0 2 tam ag 5/5 0 6 es/es.mjs: karsilayan tanim = 1, baslatan cagri = 1
Yıldızda kritik birim sayısı 1’dir ve o birim merkezdir: çekildiğinde kalan beş birimden yalnız biri — haberin girdiği birim — sürümü biliyor, dördü öğrenemiyor. Halkada ve tam ağda kritik birim sayısı 0; hangi birim çekilirse çekilsin kalan beşinin beşi öğreniyor. Merkezsizliğin sayısı budur. Sözcük bir yapı betimlemesi değil, bir ölçüm sonucudur: çekildiğinde başkalarının işini durduran birim sayısı sıfır.
Son sütun bedelin öbür yarısıdır. Yedinci merkez eklendiğinde yıldızda tek bir liste — merkezin listesi — düzenlenir. Halkada iki, tam ağda altı liste düzenlenir. Tam ağın tek turda bitirme kazancı, her yeni birimde var olan bütün birimlerin bilgisini güncellemekle ödenir.
Son satır biçemin kod imzasını verir. Tek dosyada bir karşılayan tanım ve bir başlatan çağrı bulunuyor. Önceki dersin iki ayrı dosyası burada bir dosyaya indi ve bu, ölçümün nedenidir: başlatma yönü tek yöne yığılmadığı için ağdan bir birim çıkarmak kalanların konuşmasını engellemiyor.
Özet
- Eşler arası biçemin kod imzası rol ayrımının kalkmasıdır: karşılayan tanım ile başlatan çağrı aynı modülde durur, altı birim için tek dosya koşar.
- Bilinen komşu sayısı yıldızda 10, halkada 12, tam ağda 30 çıktı; bilme yükümlülüğü tam ağda birim sayısının karesiyle büyür.
- İleti ve tur sayıları ters yönde hareket etti: tam ağ 5 ileti ve 1 tur, yıldız 7 ileti ve 2 tur, halka 18 ileti ve 3 tur harcadı; üçü de altı birimin altısına ulaştı.
- Kritik birim sayısı yıldızda 1, halkada ve tam ağda 0; merkez çekildiğinde kalan beş birimden dördü yeni tarifeyi öğrenemedi.
- Merkezsizliğin bedeli yeni birim eklemenin maliyetidir: yedinci merkez için yıldızda 1, halkada 2, tam ağda 6 komşu listesi düzenlendi.
Sonraki Adım
Buraya kadarki iki biçem de aynı türden birimler arasındaki etkileşimi ele aldı: konuşan tarafların ikisi de ücret hesaplayan ya da tarife duyuran birimlerdi, aradaki fark yalnız kimin başlattığıydı. Kitaplıkta bir de türü farklı bir sınır var. Operasyon masasındaki görevli ücretin nasıl hesaplandığını değil, ekranda ne yazdığını görür: bölge adı, kademe, indirim gerekçesi ve ödenecek tutar belirli bir biçimde dizilmiş olmalıdır. Bu sınırın iki tarafı eşit değildir — biri kuralı ve veriyi taşır, öbürü onu gösterir. Sonraki ders bu sorumluluğun üç ayrı dağıtımını karşılaştırır: gösteren dosyanın alan adlarından kaç tanesini tanıdığını, biçimlendirmenin kaç ayrı yerde yapıldığını ve bir görünüm değişikliğinin kaç dosyaya dokunduğunu sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.