İçeriğe geç
academia.sh

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 nn birimle en iyi hızlanmayı şöyle yazmıştı:

S(n)=1s+1snS(n) = \frac{1}{s + \dfrac{1 - s}{n}}

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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat