Ders 06 / 16
Katman 4 Dengeleme
Kararın bağlantı kurulurken bir kez verilmesi ve bunun bedeli: aynı toplam yükün eşit ve eşitsiz istemci paylarıyla ölçülmesi, kusursuz bağlantı dağıtımının dört kat istek sapması üretmesi, kararı vermek için okunan bilginin sayılması ve ölçülen dengesizliğin giriş kursundaki tepe hızda kaç kopyaya karşılık geldiğinin hesaplanması.
İçindekiler
Önceki dersin dengeleyicisi kararını her istek için verdi ve kararı verebilmek için isteğin yolunu okudu. Okumak bir seçimdir, zorunluluk değildir. Bir dengeleyici isteğin içine hiç bakmadan da çalışabilir: kararı bağlantı kurulurken bir kez verir, sonra o bağlantıdan akan her şeyi aynı kopyaya geçirir.
Bu düzeyin adı katman 4 dengelemedir. Katman modeli Ağ Modelleri ve Protokoller kursunda kuruldu: katman 4 taşıma katmanıdır ve orada görülen şey adres, bağlantı noktası ve bayt akışıdır; yol, başlık ve gövde bir katman yukarıdadır. Bu ders o düzeyi kurar, ne bilemediğini sayar ve bilmemenin dağıtıma ne yaptığını ölçer.
Bağlantı Başına Bir Karar
Katman 4 dengeleyici bir bağlantı kabul eder, bir kopya seçer, o kopyaya kendi bağlantısını açar ve iki yön arasında baytları oldukça aktarır. Seçim bir kez yapılır; bağlantı kapanana kadar geçerlidir.
// k4/dengeleyici.mjs — katman 4 dengeleyici: karar baglanti kurulurken bir kez verilir, sonra // iki yon oldugu gibi aktarilir. Kullanim: node k4/dengeleyici.mjs <nokta> <sayac.json> <kopyalar...> import { createServer, connect } from "node:net"; import { writeFileSync } from "node:fs"; const nokta = Number(process.argv[2]); const sayacYolu = process.argv[3]; const kopya = process.argv.slice(4).map(Number); const sayac = { karar: 0, baglanti: Object.fromEntries(kopya.map((p) => [p, 0])), bayt: 0 }; let sira = 0; if (Number.isInteger(nokta) === false || kopya.length === 0) { console.log("kullanim: node k4/dengeleyici.mjs <nokta> <sayac.json> <kopyalar...>"); } else { const s = createServer((disi) => { const hedef = kopya[sira++ % kopya.length]; // tek karar: bu baglanti hangi kopyaya ait sayac.karar += 1; sayac.baglanti[hedef] += 1; const ici = connect(hedef, "127.0.0.1"); disi.on("data", (p) => { sayac.bayt += p.length; }); // gecen bayt sayilir, icerigi okunmaz disi.pipe(ici); ici.pipe(disi); for (const [a, b] of [[disi, ici], [ici, disi]]) { a.on("error", () => b.destroy()); a.on("close", () => b.destroy()); } }); s.listen(nokta, "127.0.0.1"); process.on("SIGTERM", () => { writeFileSync(sayacYolu, JSON.stringify(sayac)); process.exit(0); }); }
Kodun taşıdığı ayrım node:net ile node:http arasındaki ayrımdır. Bu dosyada bir HTTP isteği
nesnesi yoktur, dolayısıyla bir yol, bir başlık ya da bir takip numarası da yoktur. Sayaçta
tutulabilen tek içerik ölçüsü geçen bayt sayısıdır — ve o bile ne olduğu bilinmeyen baytların
sayısıdır.
Kopyalar bir katman yukarıda çalışır ve gördükleri isteği yola göre sayar. Sayaçlarını /sayac
yolundan bildirirler; bu yol dengeleyiciden değil doğrudan sorulur, bu yüzden ölçüme karışmaz.
// k4/kopya.mjs — uygulama kopyasi: gordugu istekleri yola gore sayar, /sayac ile bildirir import { createServer } from "node:http"; const [port, ad] = [Number(process.argv[2]), process.argv[3]]; const sayac = { ad, istek: 0, yol: {} }; if (Number.isInteger(port) === false) console.log("kullanim: node k4/kopya.mjs <nokta> <ad>"); else createServer((istek, yanit) => { yanit.sendDate = false; const yol = new URL(istek.url, "http://yerel").pathname; if (yol === "/sayac") { yanit.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(sayac)); return; } sayac.istek += 1; sayac.yol[yol] = (sayac.yol[yol] ?? 0) + 1; yanit.writeHead(200, { "content-type": "application/json", "x-kopya": ad }); yanit.end(JSON.stringify({ durum: "aktarma merkezinde", bolge: "35", adim: 4 })); }).listen(port, "127.0.0.1");
İstemci düzeneğin asıl parametresini taşır: her istemci tek bir kalıcı bağlantı açar ve payındaki istekleri o bağlantıdan gönderir. Payların eşit olup olmaması ölçümün girdisidir. İstemciler sırayla koşar; böylece bağlantı kurulma sırası, dolayısıyla sıralı dağıtımın verdiği eşleme belirlenimli olur.
// k4/istemci.mjs — her istemci tek kalici baglanti acar ve payindaki istekleri sirayla gonderir import { Agent, request } from "node:http"; const nokta = Number(process.argv[2]); const PAY = (process.argv[3] ?? "1").split(",").map(Number); // istemci basina istek sayisi function bir(agent, no, yol) { return new Promise((coz, sap) => { const r = request({ port: nokta, path: `${yol}?no=${no}`, agent }, (y) => { y.resume(); y.on("end", () => coz(y.headers["x-kopya"] ?? "-")); }); r.on("error", sap); r.end(); }); } if (Number.isInteger(nokta) === false) console.log("kullanim: node k4/istemci.mjs <nokta> <pay,pay,...>"); else { let toplam = 0; for (let i = 0; i < PAY.length; i += 1) { // istemciler sirayla kosar: baglanti sirasi belirlenimli const agent = new Agent({ keepAlive: true, maxSockets: 1 }); for (let j = 0; j < PAY[i]; j += 1) { await bir(agent, `I${i}-${j}`, j % 2 === 0 ? "/takip" : "/olay"); toplam += 1; } agent.destroy(); } console.log(`${PAY.length} istemci, ${toplam} istek gonderildi (pay: ${PAY.join(",")})`); }
Rapor betiği iki kaynağı birleştirir: dengeleyicinin bağlantı sayaçları ile kopyaların istek sayaçları.
// k4/rapor.mjs — dengeleyicinin sayac dosyasi ile kopyalarin /sayac ciktisini tek tabloda birlestirir import { existsSync, readFileSync } from "node:fs"; const [sayacYolu, ...noktalar] = process.argv.slice(2); if (sayacYolu === undefined || existsSync(sayacYolu) === false) { console.log("kullanim: node k4/rapor.mjs <sayac.json> <kopya-noktalari...>"); process.exit(0); } const d = JSON.parse(readFileSync(sayacYolu, "utf8")); const satir = []; for (const p of noktalar) { const y = await fetch(`http://127.0.0.1:${p}/sayac`).then((r) => r.json()); satir.push({ ad: y.ad, nokta: p, baglanti: d.baglanti[p], istek: y.istek, yol: Object.entries(y.yol).sort().map(([a, n]) => `${a.slice(1)}=${n}`).join(" ") }); } const istek = satir.map((s) => s.istek); console.log("kopya baglanti istek yol dagilimi"); for (const s of satir) { console.log(`${s.ad.padEnd(5)} ${String(s.baglanti).padStart(8)} ${String(s.istek).padStart(5)} ${s.yol}`); } console.log(`karar sayisi = ${d.karar} (baglanti basina 1), istek basina karar = ` + `${(d.karar / istek.reduce((a, b) => a + b, 0)).toFixed(3)}`); console.log(`baglanti sapmasi = ${(Math.max(...satir.map((s) => s.baglanti)) / Math.min(...satir.map((s) => s.baglanti))).toFixed(2)}, ` + `istek sapmasi = ${(Math.max(...istek) / Math.min(...istek)).toFixed(2)}`); console.log(`dengeleyiciden gecen istek bayti = ${d.bayt}`);
Düzenek iki kez koşar. İkisinde de altı istemci ve üç kopya vardır; değişen tek şey isteklerin istemcilere nasıl dağıldığıdır. Bağlantı noktaları ortama bağlıdır.
# olc.sh — ayni toplam yuk iki istemci karisimiyla: esit paylar ve esitsiz paylar for karisim in "10,10,10,10,10,10" "1,2,4,8,16,32"; do node k4/kopya.mjs 8871 k1 & K1=$! node k4/kopya.mjs 8872 k2 & K2=$! node k4/kopya.mjs 8873 k3 & K3=$! node k4/dengeleyici.mjs 8841 sayac.json 8871 8872 8873 & D=$! sleep 1 node k4/istemci.mjs 8841 "$karisim" kill -TERM $D; sleep 0.3 node k4/rapor.mjs sayac.json 8871 8872 8873 kill $K1 $K2 $K3; sleep 0.3 echo done
6 istemci, 60 istek gonderildi (pay: 10,10,10,10,10,10) kopya baglanti istek yol dagilimi k1 2 20 olay=10 takip=10 k2 2 20 olay=10 takip=10 k3 2 20 olay=10 takip=10 karar sayisi = 6 (baglanti basina 1), istek basina karar = 0.100 baglanti sapmasi = 1.00, istek sapmasi = 1.00 dengeleyiciden gecen istek bayti = 4590 6 istemci, 63 istek gonderildi (pay: 1,2,4,8,16,32) kopya baglanti istek yol dagilimi k1 2 9 olay=4 takip=5 k2 2 18 olay=9 takip=9 k3 2 36 olay=18 takip=18 karar sayisi = 6 (baglanti basina 1), istek basina karar = 0.095 baglanti sapmasi = 1.00, istek sapmasi = 4.00 dengeleyiciden gecen istek bayti = 4848
İki Sapma Aynı Tabloda
Bu sayılar ölçüm sınıfındadır ve belirlenimlidir; istemciler sırayla koştuğu ve dağıtım kuralı sıralı olduğu için başka bir makinede de aynı bölünme çıkar.
İki koşumda da bağlantı sapması 1,00’dır: dengeleyici altı bağlantıyı üç kopyaya ikişer ikişer paylaştırdı ve bu paylaşımda hiçbir kusur yok. Kendisine verilen işi kusursuz yapıyor. Birinci koşumda istek sapması da 1,00: paylar eşit olduğu için bağlantı dengesi istek dengesine çeviriyor.
İkinci koşumda aynı kusursuz bağlantı dağıtımı 4,00 kat istek sapması üretiyor. Kopyalar 9, 18 ve 36 istek gördü; en yüklü kopya en az yüklü olanın dört katını taşıdı. Değişen tek şey isteklerin bağlantılara nasıl dağıldığıdır. Katman 4 dengeleyici bağlantıları dengeler, isteği dengelemez; ikisi aynı şey olmadığı için ölçüm iki ayrı sapma sütunu gerektirir.
Sapmanın kaynağı kalıcı bağlantıdır. Bir bağlantı bir istek taşıyorsa iki sayı aynıdır; bir bağlantı otuz iki istek taşıyorsa dengeleyicinin bir kararı otuz iki isteği birden bağlar. Karar bir kez verildiği için de düzeltilemez: dengeleyici 36 isteğin aynı kopyaya gittiğini fark etmez, çünkü onları hiç saymaz.
Ne Bilinmiyor
Karar sütunu bilmemenin ölçüsüdür: 63 istek için 6 karar, istek başına 0,095 karar. Katman 4 dengeleyicinin işi bu orandan ucuzdur — bir bağlantı için bir kez seçim yapıp sonra baytları geçirmek, her isteği ayrıştırıp yeniden yazmaktan daha az iştir.
Ödenen bedel yol dağılımı sütununda görünüyor. Her kopya hem takip hem olay isteği aldı ve
oranlar bağlantı paylarının aynısı. Kopyaların bir kısmını okumaya, bir kısmını yazmaya
ayırmak bu düzeyde olanaksızdır: karar bağlantı kurulurken verilir ve o anda henüz bir yol
gönderilmemiştir. Aynı kısıt daha ince ayrımlar için de geçerlidir — takip numarasına, istemci
türüne ya da bir başlığa bakan bir kural yazılamaz, çünkü bunların hiçbiri katman 4’te
görünmez. Dengeleyicinin gördüğü 4848 bayt, içeriği bilinmeyen bir akıştır.
Bilinmemenin bir de olumlu yüzü var. Katman 4 dengeleyici HTTP bilmediği için HTTP’ye bağlı değildir: aynı kod başka bir bağlantı tabanlı protokol için de çalışır ve gövdeyi tamponlamadığı için akış hâlinde giden veri araya girmeden geçer.
Hesaba Geri Dönüş
Önceki ders 513,89 istek/s tepe hızı üç kopyaya bölmüş ve kopya başına 171,30 istek/s bulmuştu. O bölme, dağıtımın kusursuz olduğunu varsayıyordu. Ölçülen sapma varsayımı bozar. Aşağıdaki hesap ölçülen paylardan bir dengesizlik çarpanı çıkarır: en yüklü kopyanın payı ile kopya sayısının çarpımı, kusursuz dengede 1’dir.
Bir varsayım daha gerekir. Y4 — kalıcı bağlantı başına ortalama istek: 10. Gerekçe: bir kullanıcı takip sayfasını açtığında aynı bağlantıdan birkaç sorgu geçer; sayı bu konunun kendi varsayımıdır, K01’in tablosuna eklenmez.
// k4/kapasite.mjs — olculen dengesizligin K01 tepe hizindaki karsiligi ve gereken kopya sayisi const TEPE_UC = 513.89; // K01 Kabaca Buyukluk Hesabi: tepe ucta istek/s const GUVENLI = 200; // 01. ders: Y1 x Y2 = 400 x 0.50 const ISTEK_BAGLANTI = 10; // varsayim Y4: kalici baglanti basina ortalama istek const OLCUM = { esit: [20, 20, 20], esitsiz: [9, 18, 36] }; // 02. dersin olcumu const dengesizlik = (d) => (Math.max(...d) / d.reduce((a, b) => a + b, 0)) * d.length; const gereken = (d) => Math.ceil((dengesizlik(d) * TEPE_UC) / GUVENLI); console.log("karisim paylar en yuklu pay dengesizlik en yuklu kopya istek/s doluluk gereken kopya"); for (const [ad, d] of Object.entries(OLCUM)) { const enYuklu = Math.max(...d) / d.reduce((a, b) => a + b, 0); const hiz = enYuklu * TEPE_UC; console.log(`${ad.padEnd(9)} ${d.join("/").padEnd(13)} ${enYuklu.toFixed(4).padStart(12)} ` + `${dengesizlik(d).toFixed(3).padStart(13)} ${hiz.toFixed(2).padStart(24)} ` + `${(hiz / 400).toFixed(3).padStart(9)} ${String(gereken(d)).padStart(15)}`); } console.log(`\nkusursuz dengede kopya = ${gereken(OLCUM.esit)}, olculen dengesizlikte = ` + `${gereken(OLCUM.esitsiz)}: fark ${gereken(OLCUM.esitsiz) - gereken(OLCUM.esit)} kopya, ` + `yalnizca dagilim sapmasi icin`); console.log(`\nkarar hizi (baglanti basina 1 karar, Y4 = ${ISTEK_BAGLANTI}): ` + `${(TEPE_UC / ISTEK_BAGLANTI).toFixed(2)} karar/s`); console.log(`istek basina karar verilse: ${TEPE_UC} karar/s, ${ISTEK_BAGLANTI} kat`); console.log(`duyarlilik: Y4 = 1 ise iki hiz esitlenir, Y4 = 100 ise oran 100 kat olur`);
karisim paylar en yuklu pay dengesizlik en yuklu kopya istek/s doluluk gereken kopya esit 20/20/20 0.3333 1.000 171.30 0.428 3 esitsiz 9/18/36 0.5714 1.714 293.65 0.734 5 kusursuz dengede kopya = 3, olculen dengesizlikte = 5: fark 2 kopya, yalnizca dagilim sapmasi icin karar hizi (baglanti basina 1 karar, Y4 = 10): 51.39 karar/s istek basina karar verilse: 513.89 karar/s, 10 kat duyarlilik: Y4 = 1 ise iki hiz esitlenir, Y4 = 100 ise oran 100 kat olur
Hesap sınıfındaki bu sayılar önceki dersin sonucunu düzeltiyor. Kusursuz dengede en yüklü kopya 171,30 istek/s ve 0,428 doluluk taşır; ölçülen dengesizlikte 293,65 istek/s ve 0,734 doluluk taşır. İkinci sayı Y2 ile konan 0,50 hedefinin üstündedir, yani üç kopyalı tasarım tepe yükte hedefi tutmaz. Hedefi tutmak için gereken kopya sayısı 3 yerine 5’tir ve fazladan iki kopya yükün büyümesi için değil, yalnızca dağılım sapması için ödenir.
Karar hızı satırı bir sonraki dersin fiyat etiketini de veriyor. Bağlantı başına karar verildiğinde dengeleyici saniyede 51,39 karar üretir; istek başına karar verilse 513,89 karar üretir, on kat fazla. Sapmayı düzeltmenin yolu bu on katı ödemekten geçiyor.
Özet
- Katman 4 dengeleme kararı bağlantı kurulurken bir kez verir; o bağlantıdan akan bütün istekler aynı kopyaya gider ve karar sonradan düzeltilmez.
- Aynı toplam yük eşit paylarla 20–20–20, eşitsiz paylarla 9–18–36 bölündü: bağlantı sapması iki koşumda da 1,00, istek sapması 1,00’a karşı 4,00.
- Bağlantıyı dengelemek isteği dengelemek değildir; sapmanın kaynağı kalıcı bağlantıların eşit sayıda istek taşımamasıdır ve dengeleyici bunu ölçemez, çünkü istekleri saymaz.
- Karar sayısı 63 istek için 6’dır (istek başına 0,095); bu ucuzluk yol, başlık ve takip numarasının görünmemesiyle satın alınır — okuma ile yazmayı ayrı kopyalara ayırmak bu düzeyde olanaksızdır.
- Ölçülen dengesizlik çarpanı 1,714 tepe hızda en yüklü kopyayı 293,65 istek/s ve 0,734 dolulukla hedefin üstüne çıkarıyor; hedefi tutmak 3 yerine 5 kopya gerektiriyor.
- İstek başına karar vermenin bedeli Y4 = 10 varsayımıyla 51,39 karar/s yerine 513,89 karar/s, yani on kattır.
Sonraki Adım
Ölçülen 4,00 kat sapma ve ayrılamayan iki akış aynı nedenden geliyor: karar, karar için gereken bilgi ortaya çıkmadan önce veriliyor. Bilgi bir katman yukarıda vardır — yol, başlık, yöntem ve sorgu dizgisi bağlantı kurulduktan hemen sonra akmaya başlar. Bir dengeleyici bunları okumayı seçerse her istek için yeniden karar verebilir, isteği içeriğine göre başka bir kopya kümesine gönderebilir ve on kat karar üretmenin faturasını öder. Sonraki ders bu düzeyi kurar: aynı istemci karışımının içerik farkındalıklı bir dengeleyiciden geçirilmesiyle sapmanın ne olduğunu, okuma ile yazmanın ayrı havuzlara bölünmesinin kopya sayısını nasıl değiştirdiğini ve dengeleyicinin isteği ayrıştırmasının hangi yeni sorumlulukları getirdiğini ölçer.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.