Ders 13 / 18
Servis Keşfi
Adres çözümlemenin bir gerçekleştirme olarak kurulması: kira süreli kayıt defteri süreci, kopyaların kendini kaydetmesi ve sağlık bilgisinin yönlendirmeye bağlanması; sabit yapılandırmayla dağıtımda dokunulan dosya ve ölü adrese giden istek üzerinden karşılaştırma.
İçindekiler
Önceki iki dersin de sessiz bir ortak kabulü vardı: karşı tarafın adresi kodun içinde sabit bir
dizedir. Ödünç servisi ücret servisine 127.0.0.1:8751 diye gitti; ondan önceki toplama
katmanları katalog servisine 127.0.0.1:8741 diye gitti. Tek kopyalı bir düzenekte bu doğrudur.
Kütüphane ödünç sisteminin katalog servisi ise tek kopya değildir: yük arttıkça kopya eklenir,
bir kopya çöker, bir kopya bakıma alınır. Sabit dizenin karşılığı olmayan bir adres, çağrının
kendisi kadar kesin bir arızadır.
Bu dersin işi adres çözümlemeyi bir gerçekleştirme olarak kurmaktır. Servis keşfi ile kayıt defterinin ne olduğu Uygulama Katmanı ve Servis Etkileşimi kursunda tanımlandı; burada kayıt defteri gerçekten bir süreç olarak koşar, kayıtlara bir kira süresi verilir, sağlık bilgisi yönlendirmeye bağlanır ve sonuç sabit yapılandırmayla iki sayı üzerinden karşılaştırılır: bir kopya eklendiğinde dağıtımda dokunulan dosya, bir kopya öldüğünde ölü adrese giden istek.
Varsayımlar: SS16 katalog servisinin üç kopyası vardır ve üçü de aynı veriyi sunar. SS17 kayıt defterinde kira süresi 900 ms, kopyaların yenileme aralığı 300 ms’dir; bu oranlar gerçek bir sistemdekinden küçüktür, ölçüm süresini kısaltmak içindir. SS18 katalog servisini çağıran üç istemci vardır (ödünç, bildirim, ücret) ve sabit yapılandırmada her biri kendi adres dosyasını taşır.
Kayıt Defteri Süreci
Kayıt defteri, adres ile kayıt zamanını tutan tek bir süreçtir. Kaydın geçerliliği süreye bağlıdır: son yenilemesinin üzerinden kira süresi geçmiş bir kayıt listeden düşer. Çözümleme yanıtı iki sayı döndürür — diri kayıt sayısı ve yönlendirilebilir adresler. İkisinin ayrı olmasının nedeni sağlık bilgisidir.
// kesif/kayit-defteri.mjs — kayit defteri 8761: kira sureli kayit ve saglik bilgisi import { createServer } from "node:http"; const KIRA = 900; // ms: yenilenmeyen kayit bu surenin sonunda listeden duser const kayit = new Map(); // adres -> { ad, saglik, son yenileme } createServer((q, y) => { const [kok, deger] = q.url.split("/").filter(Boolean); if (kok === "kayit") { // /kayit/<ad>|<adres>|<saglik> const [ad, adres, saglik] = decodeURIComponent(deger).split("|"); kayit.set(adres, { ad, saglik: saglik === "1", son: Date.now() }); } const ad = kok === "cozumle" ? deger : "katalog"; const diri = [...kayit.entries()] .filter(([, k]) => k.ad === ad && Date.now() - k.son < KIRA); y.writeHead(200, { "Content-Type": "application/json" }); y.end(JSON.stringify({ kira: KIRA, kayit: diri.length, adres: diri.filter(([, k]) => k.saglik).map(([a]) => a) })); }).listen(8761, "127.0.0.1", () => console.log("kayit-defteri 127.0.0.1:8761"));
Kayıt defterinde silme ucu yoktur. Bir kopya düzgün kapanırken kaydını sildirebilirdi, ama çöken bir kopya bunu yapamaz; bu yüzden kaydın geçerliliği kopyanın iyi niyetine değil, süreye bağlanır. Kayıt defteri hiçbir kopyaya kendisi soru sormaz.
Kaydolan Kopya
Her kopya ayağa kalkarken kendini kaydeder ve kira süresinin üçte biri kadar bir aralıkla
kaydını yeniler. Yenileme çağrısı sağlık bilgisini de taşır. /bozul ucu, sürecin yaşadığı ama
iş göremediği durumu üretmek içindir: süreç yenilemeyi sürdürür, bildirdiği sağlık bilgisi
değişir.
// kesif/katalog.mjs — katalog kopyasi: node kesif/katalog.mjs 8762 import { createServer } from "node:http"; const port = Number(process.argv[2] ?? 8762); const YENILEME = 300; // ms: kira suresinin ucte biri let saglik = true; const kaydol = () => fetch("http://127.0.0.1:8761/kayit/" + encodeURIComponent(`katalog|127.0.0.1:${port}|${saglik ? "1" : "0"}`)).catch(() => {}); createServer((q, y) => { if (q.url === "/bozul") saglik = false; // surec yasiyor ve kaydini yeniliyor, is goremiyor const kod = saglik ? 200 : 503; y.writeHead(kod, { "Content-Type": "application/json" }); y.end(JSON.stringify({ port, saglik })); }).listen(port, "127.0.0.1", () => { kaydol(); setInterval(kaydol, YENILEME).unref(); });
Yenileme aralığının kira süresinden küçük olması zorunludur; oran, bir kopyanın kaç yenileme kaçırdıktan sonra listeden düşeceğini belirler. Burada oran üçtür: iki yenileme kaçıran kopya hâlâ listededir, üçüncüsünü de kaçıran düşer.
İki Çözümleme Yolu, Aynı İş
Ölçüm betiği kayıt defterini ve üç kopyayı kendisi başlatır, sabit yapılandırma dosyasını kendisi yazar ve beş aşamanın her birinde aynı altı isteği iki yolla dağıtır. Sabit yolda adresler dosyadan okunur; keşif yolunda her aşamanın başında kayıt defterine sorulur.
// kesif/olc.mjs — sabit yapilandirma ile kayit defteri ayni is uzerinde kosturulur import { spawn } from "node:child_process"; import { writeFileSync, readFileSync } from "node:fs"; const bekle = (ms) => new Promise((c) => setTimeout(c, ms)); const surec = {}; const baslat = (p) => (surec[p] = spawn("node", ["kesif/katalog.mjs", String(p)], { stdio: "ignore" })); const ISTEK = 6; // asama basina istek; adresler arasinda sirayla dagitilir const ISTEMCI = 3; // katalogu cagiran servis: odunc, bildirim, ucret const defter = spawn("node", ["kesif/kayit-defteri.mjs"], { stdio: "ignore" }); await bekle(400); [8762, 8763, 8764].forEach(baslat); writeFileSync("kesif/adresler.json", // dagitim sirasinda elle yazilan yapilandirma dosyasi JSON.stringify([8762, 8763, 8764].map((p) => `127.0.0.1:${p}`))); await bekle(500); const cagir = async (adres) => { try { return (await fetch(`http://${adres}/kitap/978-0`)).status === 200; } catch { return false; } }; const dagit = async (adres) => { let ok = 0; for (let i = 0; i < ISTEK && adres.length; i += 1) if (await cagir(adres[i % adres.length])) ok += 1; return ok; }; const sabit = async () => { const a = JSON.parse(readFileSync("kesif/adresler.json", "utf8")); return { ok: await dagit(a), kayit: a.length, adres: a.length }; }; const kesif = async () => { const d = await (await fetch("http://127.0.0.1:8761/cozumle/katalog")).json(); return { ok: await dagit(d.adres), kayit: d.kayit, adres: d.adres.length }; }; const asama = []; const olc = async (ad) => asama.push({ ad, s: await sabit(), k: await kesif() }); await olc("hepsi diri"); surec[8764].kill(); await olc("kopya olduruldu (hemen)"); await bekle(1200); await olc("kira suresi doldu"); await fetch("http://127.0.0.1:8763/bozul").catch(() => {}); await bekle(400); await olc("kopya bozuk bildirdi"); baslat(8765); await bekle(600); await olc("yeni kopya eklendi"); const B = ["sabit b/i", "sabit adres", "defter b/i", "defter kayit", "defter adres"]; console.log(`${"asama".padEnd(26)}${B.map((b) => b.padStart(14)).join("")}`); for (const a of asama) { console.log(`${a.ad.padEnd(26)}${[`${a.s.ok}/${ISTEK}`, a.s.adres, `${a.k.ok}/${ISTEK}`, a.k.kayit, a.k.adres].map((v) => String(v).padStart(14)).join("")}`); } console.log(`\nkira suresi 900 ms, yenileme araligi 300 ms; kesif penceresinde olu adrese ` + `giden istek = ${ISTEK - asama[1].k.ok}/${ISTEK}`); console.log(`yeni kopya eklendiginde dokunulan yapilandirma dosyasi: sabit ${ISTEMCI}, defter 0; ` + `yeniden baslatilan istemci: sabit ${ISTEMCI}, defter 0`); console.log(`kayit defteri = 1 ek surec, her cagri oncesi 1 ek cozumleme istegi`); Object.values(surec).forEach((s) => s.kill()); defter.kill();
asama sabit b/i sabit adres defter b/i defter kayit defter adres hepsi diri 6/6 3 6/6 3 3 kopya olduruldu (hemen) 4/6 3 4/6 3 3 kira suresi doldu 4/6 3 6/6 2 2 kopya bozuk bildirdi 2/6 3 6/6 2 1 yeni kopya eklendi 2/6 3 6/6 3 2 kira suresi 900 ms, yenileme araligi 300 ms; kesif penceresinde olu adrese giden istek = 2/6 yeni kopya eklendiginde dokunulan yapilandirma dosyasi: sabit 3, defter 0; yeniden baslatilan istemci: sabit 3, defter 0 kayit defteri = 1 ek surec, her cagri oncesi 1 ek cozumleme istegi
Sayıların Okunması
İlk aşamada iki yol da aynı sonucu veriyor: altı istek, altı başarı, üç adres. Keşfin hiçbir katkısı görünmüyor ve bu doğrudur — her şey yolundayken sabit yapılandırma da doğru çalışır. Keşfin ölçüsü ancak yerleşim değiştiğinde ortaya çıkar.
İkinci aşama, bir kopya öldürüldükten hemen sonra ölçülüyor. İki yol da 4/6 veriyor. Kayıt defteri henüz üç adres döndürüyor, çünkü ölen kopyanın son yenilemesinin üzerinden kira süresi geçmedi. Bu aralığa keşif penceresi denir ve ölçümdeki karşılığı 2/6’dır: pencerede giden her altı istekten ikisi ölü bir adrese gitmiştir. Kayıt defteri, ölümü öğrenme süresini sıfıra indirmez; yalnız sınırlar.
Üçüncü aşama pencerenin kapanmasını gösteriyor. Kira süresi dolduktan sonra kayıt defteri iki adres döndürüyor ve altı istek iki adrese üçer dağılıyor: 6/6. Sabit yapılandırma ise hâlâ üç adres taşıyor ve 4/6 vermeye devam ediyor. Bu fark keşfin bütün karşılığıdır: sabit yapılandırmanın yanlışı, bir kişi dosyayı düzeltene kadar sürer.
Dördüncü aşama, sağlık bilgisinin neden ayrı bir bilgi olduğunu gösteriyor. 8763 kopyası
/bozul çağrısından sonra yaşamayı ve kaydını yenilemeyi sürdürüyor; kayıt defterindeki diri
kayıt sayısı 2 kalıyor, ama yönlendirilebilir adres 1’e düşüyor. Sürecin ayakta olması, işi
yapabildiği anlamına gelmez. Sabit yapılandırma bu ayrımı hiç yapamaz ve 2/6’ya iner: iki istek
ölü adrese, iki istek de 503 döndüren kopyaya gider.
Beşinci aşama dağıtım tarafını ölçüyor. Dördüncü bir kopya başlatıldığında kayıt defteri tarafında hiçbir dosyaya dokunulmuyor; kopya kendini kaydediyor ve bir sonraki çözümlemede yönlendirilebilir adres 2’ye çıkıyor. Sabit yapılandırma tarafında ise sonuç değişmiyor: yeni kopya hiçbir isteği karşılamıyor, çünkü üç istemcinin adres dosyası hâlâ eski üçlüyü taşıyor. Değişikliğin bedeli çıktının son satırlarındadır: dokunulan yapılandırma dosyası 3’e karşı 0, yeniden başlatılan istemci 3’e karşı 0.
Kayıt Defterinin Bedeli ve Doğan Arıza Kipleri
Ödenen bedel üç kalemdir. Birincisi bir ek süreçtir ve bu süreç sıradan bir servis değildir: kayıt defteri düştüğünde hiçbir istemci adres çözemez. Sabit yapılandırmanın tek üstünlüğü tam buradadır — dosya, hiçbir şeye bağlı olmadan okunur. Bu yüzden kayıt defterine yaslanan istemciler genellikle son çözümlemenin sonucunu ellerinde tutar; o zaman da elde tutulan liste eskiyebilir ve keşif penceresi yeniden büyür.
İkincisi çözümleme isteğidir. Ölçümde her aşama başında bir çözümleme yapıldı; her çağrı öncesi çözümleme yapılsaydı katalog servisine giden her istek iki isteğe dönüşecekti. Bu, bir önceki dersteki yerel durak ölçüsünün keşif tarafındaki karşılığıdır ve çözümlemenin önbelleğe alınmasını zorunlu kılar.
Üçüncüsü kira süresinin kendisidir ve iki yönü de arıza doğurur. Süre uzatılırsa keşif penceresi büyür, yani ölü adrese giden istek artar. Süre kısaltılırsa kopyalar daha sık yenileme yapar; kayıt defterine gelen yazma yükü kopya sayısıyla çarpılır ve ağdaki kısa bir kesinti diri kopyaların listeden düşmesine yol açar. Listeden düşen kopya geri döndüğünde istekler yeniden dağılır; bu salınım, kayıt defteri gerçekleştirmelerinin en tanıdık arızasıdır.
Doğan arıza kiplerinin ortak kaynağı şudur: kayıt defteri gerçeği değil, gerçeğin gecikmeli bir kopyasını tutar. Sabit yapılandırmada gecikme sınırsızdır ve bir insanın dosyayı düzeltmesine bağlıdır; kayıt defterinde gecikme kira süresiyle sınırlıdır. Keşfin sattığı şey doğruluk değil, yanlışın ömrüne konan üst sınırdır.
Özet
- Kayıt defteri kira süreli kayıt tutar; silme ucu yoktur, çünkü çöken bir kopya kaydını sildiremez. Kopyalar kira süresinin üçte biri aralıkla kaydını yeniler.
- Her şey yolundayken iki yol da 6/6 verir; fark yalnız yerleşim değiştiğinde ortaya çıkar.
- Bir kopya öldürüldükten hemen sonra iki yol da 4/6 verir: keşif penceresinde altı istekten ikisi ölü adrese gider. Kira süresi dolduktan sonra kayıt defteri 6/6’ya döner, sabit yapılandırma 4/6’da kalır.
- Sağlık bilgisi diri kayıttan ayrıdır: bozuk bildiren kopya kayıtta kalır (kayıt 2) ama yönlendirmeden düşer (adres 1); sabit yapılandırma bu ayrımı yapamaz ve 2/6’ya iner.
- Yeni kopya eklendiğinde dokunulan yapılandırma dosyası 3’e karşı 0, yeniden başlatılan istemci 3’e karşı 0’dır.
- Ödenen bedel: 1 ek süreç ve tek arıza noktası, çağrı başına 1 ek çözümleme isteği, kira süresinin iki yönlü arızası (uzun süre keşif penceresini, kısa süre yenileme yükünü ve salınımı büyütür).
Sonraki Adım
Bu konu sınırın nereden geçeceğiyle başladı, sınırın iki yanının nasıl konuşacağıyla sürdü ve adresin nasıl çözüleceğiyle bitti. Sınır çizildi, eşzamanlı ve eşzamansız iletişim kuruldu, kenar sorumlulukları toplandı, istemciye özel katman eklendi, ağ ilgileri uygulamadan çıkarıldı ve adres kodun dışından çözüldü. Yedi dersin ölçtüğü her şeyin altında duran bir kabul ise hiç sınanmadı: bir işin ortasında sınırın iki yanındaki veri, sanki tek bir işlemin güvencesi altındaymış gibi ele alındı. Ödünç servisi kaydı yazdı ve ücret servisi cezayı tahsil etti; ikisi ayrı süreçlerde, ayrı veriler üzerinde ve ayrı zamanlarda oldu. Bir önceki dersin çift tahsilat ölçümü bu kabulün ilk çatlağıydı. Sonraki konu tam olarak bunu ele alır: bir iş akışı birden çok servisin verisine dokunduğunda, hepsinin birlikte olması ya da hiçbirinin olmaması nasıl sağlanır, sağlanamadığında ne olur ve bunun bedeli hangi birimlerle ölçülür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.