Ders 10 / 16
Oturum Yapışkanlığı
Seçimin bir kısıt hâline gelmesi ve bunun ölçekleme faturası: yapışkan bağlamanın dağılımı ne kadar bozduğunun ölçülmesi, bir kopya düştüğünde kaybolan oturumun ve kopya eklendiğinde bağı kopan oturumun sayılması, en yüklü kopyanın kopya eklenmesine rağmen düşmemesi ve bölünemeyen payın giriş kursundaki seri pay bağıntısıyla bir üst sınıra çevrilmesi.
İçindekiler
Buraya kadarki beş ders bir şeyi hiç sorgulamadı: dengeleyicinin seçimi serbestti. Bir istek herhangi bir kopyaya gönderilebiliyordu, çünkü kopyalar birbirinin eşiydi. Tutarlı karma bile seçimi kararlı tutmayı isterken zorunlu kılmıyordu — anahtar başka bir kopyaya düşse yanıt yine doğru olurdu, yalnız önbellek soğuk kalırdı.
Bir istemcinin önceki isteğinden kalan durum belirli bir kopyanın belleğinde duruyorsa durum değişir. O istemcinin sonraki isteği artık herhangi bir kopyaya gidemez; seçim bir tercih olmaktan çıkıp bir kısıt hâline gelir. Bu bağa oturum yapışkanlığı (session stickiness) denir. Eşzamansız İşleme kursunda geçen yapışkan yönlendirme aynı şeydir: istemci hep aynı örneğe yönlendirilir. Oturum durumunun kendisi ve yönetimi Sunucu Tarafı Temelleri kursunun konusudur ve burada yeniden anlatılmaz; bu dersin işi yapışkanlığın ölçekleme faturasını ölçmektir.
Bağın Ölçülmesi
Model bir istemci karışımı alır ve üç kuralı aynı karışımda karşılaştırır. Yapışkansız kuralda karar istek başına verilir. Yapışkan-kalan kuralda istemci kimliğinin karması kopya sayısına bölünür. Yapışkan-tutarlı kuralda bağ, önceki dersteki tutarlı karma halkasından okunur.
İstemci karışımı gönderi takip servisinin gerçek biçimini taşır: bir büyük satıcı entegrasyonu tek bir oturumdan çok sayıda sorgu gönderir, dokuz orta satıcı daha az, doksan küçük satıcı çok az. Sayılar model parametresidir.
// otur/model.mjs — yapiskanligin dagilim, oturum kaybi ve olcek artisi uzerindeki etkisi. // Bu bir MODELDIR: istemci karisimi ve istek sayilari model parametreleridir. const ISTEMCI = [ // [ad oneki, istemci sayisi, istemci basina istek] ["buyuk", 1, 2000], ["orta", 9, 400], ["kucuk", 90, 50], ]; const SANAL = 200; // tutarli karma sanal dugum sayisi function karma(metin) { // FNV-1a + son karistirma adimi; cig etkisi Karma Tablolari let h = 2166136261; // dersinde tanimlandi: benzer anahtarlar uzak degerler vermeli for (let i = 0; i < metin.length; i += 1) h = Math.imul(h ^ metin.charCodeAt(i), 16777619) >>> 0; h ^= h >>> 15; h = Math.imul(h, 2246822507) >>> 0; h ^= h >>> 13; return h >>> 0; } const istemciler = ISTEMCI.flatMap(([ad, adet, istek]) => Array.from({ length: adet }, (_, i) => ({ ad: `${ad}-${i}`, istek }))); const TOPLAM = istemciler.reduce((a, c) => a + c.istek, 0); function halka(kopya) { const h = []; for (const k of kopya) for (let v = 0; v < SANAL; v += 1) h.push([karma(`${k}#${v}`), k]); return h.sort((x, y) => x[0] - y[0]); } function halkada(a, h) { const c = karma(a); if (c > h[h.length - 1][0]) return h[0][1]; let alt = 0, ust = h.length - 1; while (alt < ust) { const o = (alt + ust) >> 1; if (h[o][0] < c) alt = o + 1; else ust = o; } return h[alt][1]; } function baglama(kural, kopya) { // istemci -> kopya eslemesi (yapiskansizda esleme yok) if (kural === "yapiskan-kalan") return new Map(istemciler.map((c) => [c.ad, kopya[karma(c.ad) % kopya.length]])); if (kural === "yapiskan-tutarli") { const h = halka(kopya); return new Map(istemciler.map((c) => [c.ad, halkada(c.ad, h)])); } return null; } function yuk(kural, kopya) { // kopya basina istek sayisi const y = new Map(kopya.map((k) => [k, 0])); const b = baglama(kural, kopya); if (b === null) { // istek basina sirali: her istek ayri karar let s = 0; for (const c of istemciler) for (let i = 0; i < c.istek; i += 1) { const k = kopya[s++ % kopya.length]; y.set(k, y.get(k) + 1); } } else for (const c of istemciler) y.set(b.get(c.ad), y.get(b.get(c.ad)) + c.istek); return y; } const dengesizlik = (y, n) => (Math.max(...y.values()) / TOPLAM) * n; const UC = ["k1", "k2", "k3"], DORT = [...UC, "k4"]; console.log(`${istemciler.length} istemci, ${TOPLAM} istek; en buyuk istemcinin payi = ` + `${(Math.max(...istemciler.map((c) => c.istek)) / TOPLAM).toFixed(4)}\n`); console.log("kural 3 kopya yuku dengesizlik 4 kopya yuku dengesizlik en yuklu kopya dususu"); for (const kural of ["yapiskansiz", "yapiskan-kalan", "yapiskan-tutarli"]) { const u = yuk(kural, UC), d = yuk(kural, DORT); const pu = Math.max(...u.values()) / TOPLAM, pd = Math.max(...d.values()) / TOPLAM; console.log(`${kural.padEnd(18)} ${[...u.values()].join("/").padEnd(20)} ${dengesizlik(u, 3).toFixed(3).padStart(11)} ` + `${[...d.values()].join("/").padEnd(25)} ${dengesizlik(d, 4).toFixed(3).padStart(11)} ` + `${(1 - pd / pu).toFixed(4).padStart(21)}`); } console.log("\nkopya eklendiginde bagi degisen istemci ve onlarin istek payi:"); for (const kural of ["yapiskan-kalan", "yapiskan-tutarli"]) { const bu = baglama(kural, UC), bd = baglama(kural, DORT); const oynayan = istemciler.filter((c) => bu.get(c.ad) !== bd.get(c.ad)); console.log(` ${kural.padEnd(18)} istemci ${String(oynayan.length).padStart(3)}/${istemciler.length} ` + `istek payi ${(oynayan.reduce((a, c) => a + c.istek, 0) / TOPLAM).toFixed(4)}`); } console.log("\nbir kopya dustugunde kaybolan oturum ve o kopyaya bagli istek payi (3 kopya):"); for (const kural of ["yapiskansiz", "yapiskan-kalan", "yapiskan-tutarli"]) { const b = baglama(kural, UC); if (b === null) { console.log(` ${"yapiskansiz".padEnd(18)} oturum 0/${istemciler.length} istek payi 0.0000 (durum kopyada durmuyor)`); continue; } const dusen = istemciler.filter((c) => b.get(c.ad) === "k1"); console.log(` ${kural.padEnd(18)} oturum ${String(dusen.length).padStart(3)}/${istemciler.length} ` + `istek payi ${(dusen.reduce((a, c) => a + c.istek, 0) / TOPLAM).toFixed(4)}`); }
100 istemci, 10100 istek; en buyuk istemcinin payi = 0.1980 kural 3 kopya yuku dengesizlik 4 kopya yuku dengesizlik en yuklu kopya dususu yapiskansiz 3367/3367/3366 1.000 2525/2525/2525/2525 1.000 0.2501 yapiskan-kalan 2500/2500/5100 1.515 1650/1850/2000/4600 1.822 0.0980 yapiskan-tutarli 3950/2500/3650 1.173 1450/2100/2750/3800 1.505 0.0380 kopya eklendiginde bagi degisen istemci ve onlarin istek payi: yapiskan-kalan istemci 77/100 istek payi 0.8515 yapiskan-tutarli istemci 30/100 istek payi 0.3762 bir kopya dustugunde kaybolan oturum ve o kopyaya bagli istek payi (3 kopya): yapiskansiz oturum 0/100 istek payi 0.0000 (durum kopyada durmuyor) yapiskan-kalan oturum 36/100 istek payi 0.2475 yapiskan-tutarli oturum 33/100 istek payi 0.3911
Üç Ayrı Fatura
Tablolar yapışkanlığın üç ayrı kalemde ödendiğini gösteriyor.
Dağılım. Yapışkansız kuralda dengesizlik 1,000 — istekler sayıya göre bölünüyor ve istemci kimliği hiç rol oynamıyor. Yapışkan-kalan kuralda 1,515, yapışkan-tutarlı kuralda 1,173. Sapmanın kaynağı istemcilerin eşit sayıda istek göndermemesidir: büyük satıcının 2000 isteği tek bir kopyaya düşüyor ve dengeleyicinin bunu düzeltme yetkisi yok. Bu, ikinci dersteki bağlantı sapmasının aynısıdır, yalnız orada bağ bağlantı ömrüydü, burada oturum.
Kopya düşmesi. Yapışkansız kuralda düşen kopyanın taşıdığı hiçbir oturum yoktur; istekler kalan kopyalara yönlenir ve kaybolan bir şey olmaz. Yapışkan kurallarda düşen kopyaya bağlı oturumlar da düşer: yapışkan-tutarlı kuralda 100 oturumun 33’ü ve isteklerin yüzde 39,11’i. Birinci dersteki sağlık denetimi bu kaybı azaltmaz — kopyayı havuzdan düşürmek isteklerin yanıtlanmasını sağlar, ama o kopyanın belleğindeki oturumu geri getirmez. Sağlık denetiminin 34,26 isteklik penceresi burada geçerli değildir; kayıp pencereyle değil, oturumla ölçülür.
Kopya ekleme. Üçüncü tablo yapışkanlığın en sinsi kalemidir. Yapışkan-kalan kuralda dördüncü kopya eklendiğinde 100 istemcinin 77’si başka bir kopyaya bağlanıyor ve bu istemciler toplam isteğin yüzde 85,15’ini taşıyor; yani ölçek artışı oturumların neredeyse tamamını koparıyor. Yapışkan-tutarlı kuralda oran 30 istemci ve yüzde 37,62’ye iniyor — önceki dersin taşıma sonucu burada oturum cinsinden tekrarlanıyor.
Aynı satırın sonundaki sütun asıl sonucu veriyor. Dördüncü kopya eklendiğinde en yüklü kopyanın yükü yapışkansız kuralda yüzde 25,01 düşüyor; bu, kusursuz bölünmenin verdiği rakamdır. Yapışkan kurallarda düşüş yüzde 9,80 ve yüzde 3,80. Kopya eklemek tepe yükü düşürmüyor, çünkü en yüklü kopyanın yükünü yaratan büyük oturum yerinde kalıyor. Yapışkan-tutarlı kuralın oturum korumada daha iyi olması burada aleyhine işliyor: bağı korumak, yükü taşımamak demektir.
Hesaba Geri Dönüş
Bu davranışın adı K01’de konmuştu. Yatay ve Dikey Ölçekleme dersi işin bölünemeyen kısmını seri pay olarak adlandırmış ve birimle en iyi hızlanmayı şöyle yazmıştı:
Yapışkanlıkta seri payın karşılığı doğrudandır: tek bir oturum bölünemez. En büyük oturumun toplam yüke oranı, kaç kopya eklenirse eklensin en yüklü kopyada kalır.
// otur/olcek.mjs — yapiskanligin seri paya cevrilmesi ve K01 tepe hizindaki karsiligi const ISTEMCI = [["buyuk", 1, 2000], ["orta", 9, 400], ["kucuk", 90, 50]]; // model.mjs ile ayni const TEPE_UC = 513.89; // K01 Kabaca Buyukluk Hesabi: tepe ucta istek/s const DOYUM = 400; // 01. ders varsayim Y1 const GUVENLI = 200; // 01. ders: Y1 x Y2 const OLCUM = { 3: 1.173, 4: 1.505 }; // model.mjs ciktisi: yapiskan-tutarli dengesizlik const toplam = ISTEMCI.reduce((a, [, adet, istek]) => a + adet * istek, 0); const s = Math.max(...ISTEMCI.map(([, , istek]) => istek)) / toplam; // bolunemeyen pay const amdahl = (n) => 1 / (s + (1 - s) / n); // K01 Yatay ve Dikey Olcekleme dersinin bagintisi console.log(`toplam istek = ${toplam}, en buyuk oturumun payi (seri pay s) = ${s.toFixed(4)}`); console.log(`ust sinir 1/s = ${(1 / s).toFixed(2)}: kopya sayisi ne olursa olsun tepe yuk bu kattan fazla bolunemez\n`); console.log("kopya yapiskansiz hizlanma yapiskan hizlanma en yuklu kopya alt siniri istek/s o an doluluk"); for (const n of [3, 4, 8, 16, 64]) { const alt = TEPE_UC / amdahl(n); console.log(`${String(n).padStart(5)} ${String(n).padStart(19)} ${amdahl(n).toFixed(2).padStart(17)} ` + `${alt.toFixed(2).padStart(33)} ${(alt / DOYUM).toFixed(3).padStart(12)}`); } console.log(`${"sonsuz".padStart(5)} ${"sonsuz".padStart(19)} ${(1 / s).toFixed(2).padStart(17)} ` + `${(TEPE_UC * s).toFixed(2).padStart(33)} ${((TEPE_UC * s) / DOYUM).toFixed(3).padStart(12)}\n`); console.log("kopya olculen dengesizlik en yuklu kopya istek/s doluluk gereken kopya"); for (const [n, d] of Object.entries(OLCUM)) { const hiz = (d * TEPE_UC) / n; console.log(`${n.padStart(5)} ${d.toFixed(3).padStart(18)} ${hiz.toFixed(2).padStart(22)} ` + `${(hiz / DOYUM).toFixed(3).padStart(7)} ${String(Math.ceil((d * TEPE_UC) / GUVENLI)).padStart(13)}`); } console.log(`\nduyarlilik: en buyuk oturum toplamin %10'u olsa ust sinir ${(1 / 0.10).toFixed(2)}, ` + `%30'u olsa ${(1 / 0.30).toFixed(2)} olurdu`);
toplam istek = 10100, en buyuk oturumun payi (seri pay s) = 0.1980
ust sinir 1/s = 5.05: kopya sayisi ne olursa olsun tepe yuk bu kattan fazla bolunemez
kopya yapiskansiz hizlanma yapiskan hizlanma en yuklu kopya alt siniri istek/s o an doluluk
3 3 2.15 239.14 0.598
4 4 2.51 204.79 0.512
8 8 3.35 153.28 0.383
16 16 4.03 127.52 0.319
64 64 4.75 108.20 0.270
sonsuz sonsuz 5.05 101.76 0.254
kopya olculen dengesizlik en yuklu kopya istek/s doluluk gereken kopya
3 1.173 200.93 0.502 4
4 1.505 193.35 0.483 4
duyarlilik: en buyuk oturum toplamin %10'u olsa ust sinir 10.00, %30'u olsa 3.33 olurdu
Bu sayılar hesap sınıfındadır. Seri pay 0,1980 ve üst sınır 5,05: kopya sayısı sonsuza gitse bile tepe yük beş kattan fazla bölünemez. Yapışkansız sütunla karşılaştırıldığında fark büyüyor — 16 kopyada yapışkansız kural 16 kat böler, yapışkan kural 4,03 kat. Fazladan konan kopyaların çoğu en yüklü kopyaya hiçbir şey yapmıyor.
Doluluk sütunu bunu bir eşiğe bağlıyor. Birinci ders kopya başına hedef doluluğu 0,50 olarak seçmişti (Y2). Yapışkan düzende üç kopya bu hedefi tutmuyor: en yüklü kopya en az 239,14 istek/s ve 0,598 doluluk taşır. Dört kopyada 204,79 ve 0,512 — hâlâ hedefin üstünde. Hedefin altına inmek için sekiz kopya gerekiyor ve o noktada üç kopyanın işini sekiz kopya yapıyor. Yapışkanlık kopya sayısını iki kattan fazla artırıyor ve artışın karşılığında kapasite gelmiyor.
İkinci tablo ölçülen dengesizlikle aynı hesabı yapıyor. Üç kopyada en yüklü kopya 200,93 istek/s ve 0,502 doluluk; dört kopyada 193,35 ve 0,483. Bir kopya eklemek en yüklü kopyanın yükünü yalnız yüzde 3,8 düşürüyor ve gereken kopya sayısı iki durumda da 4 çıkıyor. Karşılaştırma noktası birinci dersin sayısıdır: yapışkanlık olmadan 3 kopya yetiyordu, ikinci dersin bağlantı sapmasıyla 5 çıkmıştı; buradaki 4, oturum bağının kendi payıdır.
Sonuç, K01’in yatay ölçekleme kuralının bu katmandaki karşılığıdır. O ders “yatay ölçekleme birim sayısını artırmakla olmaz, işin paylaşılan durum gerektirmeyecek biçimde bölünebilmesiyle olur” demişti ve indis bölümlemesinin seri payını yüzde 28,0 ölçmüştü. Oturum yapışkanlığı aynı cümlenin trafik katmanındaki hâlidir: durum kopyanın belleğinde kaldığı sürece dengeleyici ne kadar akıllı olursa olsun yükü bölemez. Yapışkanlığı kaldırmak bir dengeleme kararı değil, durumu süreç dışına taşıma kararıdır.
Özet
- Oturum yapışkanlığı, istemcinin isteklerini belirli bir kopyaya bağlayarak dağıtım seçimini bir kısıta çevirir; Eşzamansız İşleme kursundaki yapışkan yönlendirme aynı bağdır.
- Aynı istemci karışımında dengesizlik yapışkansız kuralda 1,000, yapışkan-kalan kuralda 1,515, yapışkan-tutarlı kuralda 1,173 çıktı; sapmanın kaynağı istemcilerin eşit sayıda istek göndermemesidir.
- Bir kopya düştüğünde yapışkan-tutarlı düzende 100 oturumun 33’ü ve isteklerin yüzde 39,11’i kayboluyor; sağlık denetimi isteği kurtarır, oturumu kurtarmaz.
- Dördüncü kopya eklendiğinde en yüklü kopyanın yükü yapışkansız kuralda yüzde 25,01, yapışkan kurallarda yüzde 9,80 ve yüzde 3,80 düşüyor; bağı korumak yükü taşımamak demektir.
- En büyük oturumun payı 0,1980 bir seri paydır ve ölçekleme üst sınırını 5,05’te tutar: 16 kopya yapışkansız kuralda 16 kat, yapışkan kuralda 4,03 kat böler.
- Y2 ile konan 0,50 doluluk hedefi yapışkan düzende üç kopyada tutmuyor (0,598) ve dört kopyada da tutmuyor (0,512); ölçülen dengesizlikle gereken kopya sayısı 4’tür, yapışkanlıksız 3 idi.
Sonraki Adım
Bu konu isteğin hangi kopyaya düştüğünü çözdü. Dengeleyici bir yönlendirme aygıtıdır: kararını bağlantı düzeyinde ya da içerik düzeyinde verir, kuralını sıraya, kuyruk uzunluğuna ya da anahtara göre seçer, düşen kopyayı denetimle havuzdan çıkarır ve durum kopyanın belleğinde kaldığında seçme yetkisini kaybeder. Kenarda biriken işler bununla bitmiyor. Aynı noktada kimlik doğrulanıyor, hız sınırı uygulanıyor, istemcinin beklediği biçime çeviri yapılıyor ve tek bir kullanıcı isteğini karşılamak için birden çok servisten gelen yanıtlar toplanıyor. Bu işlerin dengeleyiciye mi, uygulamaya mı, yoksa ayrı bir katmana mı ait olduğu açıkta kaldı — üçüncü seçeneğin bir adı vardır ve sonraki konu onunla başlar: kenar sorumluluklarının toplandığı bir ağ geçidi neyi üstlenir, neyi üstlenmemelidir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.