İçeriğe geç
academia.sh

Ders 04 / 20

Yeniden Deneme ve Fırtına Riski

Yeniden denemenin çağrı çarpanı altında fırtınaya dönüşmesi: zincirin her katmanı denediğinde bozuk bağımlılığa varan çağrının kaç katına çıktığının ölçülmesi, aritmetik üst sınır ile geri çekilmenin altında gözlenen çarpanın ayrılması, çarpanın kesintide izne ve bozulmada başarısızlık oranına bağlanması ve deneme bütçesinin zincire dağıtılarak fırtınanın kesilmesi.

İçindekiler

Bölme ile devre kesici bulaşmayı çevreledi ama ikisi de aynı varsayımın üstünde duruyordu: başarısız olan çağrı bir kez yapılıyor. Gerçek bir çağıran öyle davranmaz. Hataların çoğu geçicidir, ikinci deneme çoğu zaman başarılıdır ve bu yüzden hemen her katmana yeniden deneme konur. Bu dersin sorusu, o kararın bozuk bağımlılık üzerinde ne yaptığıdır.

Yeniden deneme kararı, üstel geri çekilme, tavan, tam sarsıntı ve deneme bütçesi Uygulama Mimarisi kursunda kuruldu ve ölçüldü; Eşzamansız İşleme kursu geri çekilme çizelgelerini ölçtü. Buradaki koşumların hepsinde geri çekilme ve tam sarsıntı açıktır ve tohumu sabittir — böylece karşılaştırmayı yalnız çarpan belirler. Sarsıntı aritmetiği yeniden hesaplanmaz.

Ölçülecek şey başkadır. Zincir üç katmanlıdır: ağ geçidi olay ucunu, olay ucu durum deposunu çağırır. Her katman kendi başına makul bir karar verir — “başarısız olursa üç kez dene” — ve kimse öteki katmanın da denediğini bilmez. Sonuç çarpılır: üç katman üçer kez denerse en dipteki bağımlılık tek bir dış istek için yirmi yedi çağrı görebilir. Buna yeniden deneme fırtınası denir ve tanımı gereği en kötü anda olur.

İki Arıza Profili

Aşağıdaki koşum bir modeldir: tur soyut bir adım, varışlar tohumlu bir üreteçten Poisson, bağımlılığın kapasitesi tur başına çağrı sayısı. Gerçek küme, kuyruk ya da kaos aracı kurulmaz.

AY6 — bağımlılığın olağan kapasitesi tur başına 6 çağrı (600 istek/s). Gerekçe: K01’in tepe yazma hızı 97,22 istek/s, yani tur başına 0,9722 çağrı; altı katlık pay dalgalı varışta taşmayı seyrekleştirir. Duyarlılığı aşağıda deneme bütçesiyle birlikte verilir.

Arıza iki profille koşuluyor, çünkü çarpan ikisinde başka türlü davranıyor. Kesinti: bağımlılık bir saniye boyunca hiçbir çağrıyı karşılamıyor (kapasite 0) — 01. dersin durma kipi. Bozulma: on saniye boyunca kapasitesi altıda bire iniyor (kapasite 1) — çağrıların bir bölümü hâlâ başarılı.

// firtina/kosum.mjs — cagri carpani altinda yeniden deneme firtinasi. MODELDIR: tur soyut bir adim,
// varislar tohumlu Poisson, geri cekilme ustel ve tam sarsintili (aritmetigi M14/K06'da olculdu).
const CEVRIM = 100, T = 4000, BAS = 500;        // AY1: 1 tur = 10 ms; 40 s kosum, ariza 5. saniyede
const OLAY = 97.22, OLAGAN = 6;                 // K01 tepe yazma istek/s; AY6: olagan kapasite cagri/tur
const TABAN = 2, TAVAN = 32, SEYREK = 0.025;    // geri cekilme taban/tavani (tur); AY4
const SENARYO = {                               // pencere suresi ve pencere boyunca kalan kapasite
  saglikli: { sure: 0, kapasite: OLAGAN },
  "kesinti (1 s)": { sure: 100, kapasite: 0 },
  "bozulma (10 s)": { sure: 1000, kapasite: 1 },
};

function kosum({ deneme, butce, senaryo }) {
  let s = 20260802 % 2147483647;
  const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;
  const poisson = (lam) => { const L = Math.exp(-lam); let k = 0, p = 1;
    do { k += 1; p *= rast(); } while (p > L); return k - 1; };
  const { sure, kapasite: bozuk } = SENARYO[senaryo];
  const izin = deneme.reduce((a, x) => a * x, 1);   // izin verilen deneme = katmanlarin carpimi
  const cizelge = new Map();
  const koy = (t, i) => { if (t < T) (cizelge.get(t) ?? cizelge.set(t, []).get(t)).push(i); };
  const c = { istek: 0, cagri: 0, birincil: 0, ek: 0, basarili: 0, dusen: 0, tepe: 0, pencereCagri: 0 };

  for (let t = 0; t < T; t += 1) {
    const pencerede = sure > 0 && t >= BAS && t < BAS + sure;
    const kapasite = pencerede ? bozuk : OLAGAN;
    for (let n = poisson(OLAY / CEVRIM); n > 0; n -= 1) { c.istek += 1; koy(t, { n: 0 }); }
    const bugun = cizelge.get(t) ?? [];
    c.cagri += bugun.length; c.tepe = Math.max(c.tepe, bugun.length);
    if (pencerede) c.pencereCagri += bugun.length;
    bugun.forEach((istek, i) => {
      if (istek.n === 0) c.birincil += 1; else c.ek += 1;
      if (i < kapasite && (sure > 0 || rast() >= SEYREK)) { c.basarili += 1; return; }
      const butceVar = butce === null || c.ek <= butce * c.birincil;
      if (istek.n + 1 >= izin || butceVar === false) { c.dusen += 1; return; }
      const ust = Math.min(TAVAN, TABAN * 2 ** istek.n);   // ustel geri cekilme + tam sarsinti
      koy(t + 1 + Math.floor(rast() * ust), { n: istek.n + 1 });
    });
    cizelge.delete(t);
  }
  return { ...c, izin, carpan: c.cagri / c.istek, pencereHiz: sure === 0 ? 0 : c.pencereCagri / sure };
}

const b = (x, n = 2) => x.toFixed(n);
const YAP = [                                    // zincir: ag gecidi -> olay ucu -> durum deposu
  ["denemesiz", [1, 1, 1], null],
  ["yalniz gecit (3)", [3, 1, 1], null],
  ["iki katman (3x3)", [3, 3, 1], null],
  ["uc katman (3x3x3)", [3, 3, 3], null],
  ["uc katman + butce 0,30", [3, 3, 3], 0.3],
];
console.log(`model: ${T} tur (${T / CEVRIM} s), ariza ${BAS}. turda; olagan kapasite ${OLAGAN} cagri/tur ` +
  `(${OLAGAN * CEVRIM} istek/s), olay varisi ${(OLAY / CEVRIM).toFixed(4)}/tur; tohum 20260802`);

const r = {};
for (const senaryo of Object.keys(SENARYO)) {
  const p = SENARYO[senaryo];
  console.log(`
-- ${senaryo}${p.sure === 0 ? " (AY4: 0,025 seyrek hata)"
    : `: ${p.sure} tur boyunca kapasite ${p.kapasite}`} --`);
  console.log(`${"yapilandirma".padEnd(25)}${"izin".padStart(6)}${"cagri".padStart(8)}${"carpan".padStart(9)}` +
    `${"tepe cagri/tur".padStart(16)}${"basarili".padStart(10)}${"dusen".padStart(8)}` +
    (p.sure === 0 ? "" : `${"pencerede cagri/tur".padStart(20)}${"olagan hizin kati".padStart(19)}`));
  for (const [ad, deneme, butce] of YAP) {
    const k = kosum({ deneme, butce, senaryo });
    r[`${ad}|${senaryo}`] = k;
    console.log(`${ad.padEnd(25)}${String(k.izin).padStart(6)}${String(k.cagri).padStart(8)}` +
      `${`x${b(k.carpan)}`.padStart(9)}${String(k.tepe).padStart(16)}${String(k.basarili).padStart(10)}` +
      `${String(k.dusen).padStart(8)}` + (p.sure === 0 ? ""
        : `${b(k.pencereHiz).padStart(20)}${`x${b(k.pencereHiz / (OLAY / CEVRIM), 1)}`.padStart(19)}`));
  }
}

const al = (ad, sen) => r[`${ad}|${sen}`];
const K = "kesinti (1 s)", B = "bozulma (10 s)";
const [s0, s27] = [al("denemesiz", "saglikli"), al("uc katman (3x3x3)", "saglikli")];
const [k0, k3, k9, k27, kb] = YAP.map(([ad]) => al(ad, K));
const [z0, z9, z27, zb] = [al("denemesiz", B), al("iki katman (3x3)", B),
  al("uc katman (3x3x3)", B), al("uc katman + butce 0,30", B)];
console.log(`
arizasiz gunun bedeli: cagri ${s0.cagri} -> ${s27.cagri} (carpan x${b(s27.carpan)}), ` +
  `bagimliliga varan ${b((s0.cagri / T) * CEVRIM)} -> ${b((s27.cagri / T) * CEVRIM)} istek/s; ` +
  `izin 1 ile 27 arasinda fark yok, cunku basarisizlik orani 0,025`);
console.log(`arizali gunun kazanci (kesinti): dusen istek ${k0.dusen} -> ${k3.dusen} -> ${k9.dusen} -> ` +
  `${k27.dusen}; basarili ${k0.basarili} -> ${k27.basarili}`);
console.log(`firtinanin buyumesi (kesinti): pencerede cagri/tur ${b(k0.pencereHiz)} -> ${b(k3.pencereHiz)} -> ` +
  `${b(k9.pencereHiz)} -> ${b(k27.pencereHiz)} = olagan hizin x${b(k27.pencereHiz / (OLAY / CEVRIM), 1)}'i; ` +
  `aritmetik ust sinir x${k27.izin}`);
console.log(`bozulmada carpan izne degil basarisizlik oranina bagli: izin 9 ve 27 ayni cagriyi veriyor ` +
  `(${z9.cagri} ve ${z27.cagri}), pencere hizi ${b(z27.pencereHiz)}`);
console.log(`butce 0,30 zincire dagitilinca: kesintide cagri ${k27.cagri} -> ${kb.cagri}, pencere hizi ` +
  `${b(k27.pencereHiz)} -> ${b(kb.pencereHiz)}, dusen ${k27.dusen} -> ${kb.dusen}; bozulmada cagri ` +
  `${z27.cagri} -> ${zb.cagri}, dusen ${z0.dusen} -> ${z27.dusen} -> ${zb.dusen}`);
console.log(`kosumdan bagimsiz ust sinir: d katman r kez denerse carpan r^d; r=3 icin ` +
  `${[1, 2, 3, 4].map((d) => `d=${d} -> ${3 ** d}`).join(", ")}`);
const ESIK = 20;                                 // AY2: zaman asimi 20 tur = K01'in 200 ms'lik esigi
const enKotu = Array.from({ length: 27 }, (_, n) => 1 + Math.min(TAVAN, TABAN * 2 ** n))
  .reduce((a, x) => a + x, 0);
console.log(`27 denemenin en kotu toplam beklemesi ${enKotu} tur = ${enKotu / CEVRIM} s, K01'in ` +
  `${ESIK} turluk okuma esiginin ${b(enKotu / ESIK, 1)} kati`);
const dar = kosum({ deneme: [3, 3, 3], butce: 0.1, senaryo: K });
console.log(`duyarlilik: butce 0,30 yerine 0,10 olsaydi kesintide cagri ${kb.cagri} -> ${dar.cagri}, ` +
  `pencere hizi ${b(kb.pencereHiz)} -> ${b(dar.pencereHiz)}, dusen ${kb.dusen} -> ${dar.dusen}`);
model: 4000 tur (40 s), ariza 500. turda; olagan kapasite 6 cagri/tur (600 istek/s), olay varisi 0.9722/tur; tohum 20260802

-- saglikli (AY4: 0,025 seyrek hata) --
yapilandirma               izin   cagri   carpan  tepe cagri/tur  basarili   dusen
denemesiz                     1    3832    x1.00               6      3736      96
yalniz gecit (3)              3    3953    x1.03               6      3851       0
iki katman (3x3)              9    3953    x1.03               6      3851       0
uc katman (3x3x3)            27    3953    x1.03               6      3851       0
uc katman + butce 0,30       27    3953    x1.03               6      3851       0

-- kesinti (1 s): 100 tur boyunca kapasite 0 --
yapilandirma               izin   cagri   carpan  tepe cagri/tur  basarili   dusen pencerede cagri/tur  olagan hizin kati
denemesiz                     1    3855    x1.00               5      3775      80                0.80               x0.8
yalniz gecit (3)              3    4071    x1.05               8      3782      94                2.89               x3.0
iki katman (3x3)              9    4435    x1.15              13      3850      20                5.77               x5.9
uc katman (3x3x3)            27    4523    x1.17              17      3870       0                6.24               x6.4
uc katman + butce 0,30       27    4065    x1.05              10      3777     103                2.88               x3.0

-- bozulma (10 s): 1000 tur boyunca kapasite 1 --
yapilandirma               izin   cagri   carpan  tepe cagri/tur  basarili   dusen pencerede cagri/tur  olagan hizin kati
denemesiz                     1    3855    x1.00               5      3534     321                0.95               x1.0
yalniz gecit (3)              3    4913    x1.28               8      3754      94                2.01               x2.1
iki katman (3x3)              9    5296    x1.39               9      3803       0                2.39               x2.5
uc katman (3x3x3)            27    5296    x1.39               9      3803       0                2.39               x2.5
uc katman + butce 0,30       27    4288    x1.11               7      3643     220                1.40               x1.4

arizasiz gunun bedeli: cagri 3832 -> 3953 (carpan x1.03), bagimliliga varan 95.80 -> 98.83 istek/s; izin 1 ile 27 arasinda fark yok, cunku basarisizlik orani 0,025
arizali gunun kazanci (kesinti): dusen istek 80 -> 94 -> 20 -> 0; basarili 3775 -> 3870
firtinanin buyumesi (kesinti): pencerede cagri/tur 0.80 -> 2.89 -> 5.77 -> 6.24 = olagan hizin x6.4'i; aritmetik ust sinir x27
bozulmada carpan izne degil basarisizlik oranina bagli: izin 9 ve 27 ayni cagriyi veriyor (5296 ve 5296), pencere hizi 2.39
butce 0,30 zincire dagitilinca: kesintide cagri 4523 -> 4065, pencere hizi 6.24 -> 2.88, dusen 0 -> 103; bozulmada cagri 5296 -> 4288, dusen 321 -> 0 -> 220
kosumdan bagimsiz ust sinir: d katman r kez denerse carpan r^d; r=3 icin d=1 -> 3, d=2 -> 9, d=3 -> 27, d=4 -> 81
27 denemenin en kotu toplam beklemesi 793 tur = 7.93 s, K01'in 20 turluk okuma esiginin 39.6 kati
duyarlilik: butce 0,30 yerine 0,10 olsaydi kesintide cagri 4065 -> 3926, pencere hizi 2.88 -> 1.54, dusen 103 -> 90

Bu sayılar ölçüm sınıfındadır ve tohuma bağlıdır.

Arızasız Günde Çarpan Uykudadır

İlk tablo kalıbın arızasız gündeki bedelini veriyor ve bedel küçüktür: çağrı 3832’den 3953’e çıkıyor, çarpan 1,03, bağımlılığa varan hız 95,80’den 98,83 istek/s’ye. Karşılığında düşen istek 96’dan 0’a iniyor — arızasız günde yeniden deneme, seyrek zaman aşımlarını yüzde üçlük bir bedelle tamamen soğuruyor.

Asıl önemli olan tablonun hiç değişmeyen sütunudur. İzin verilen deneme 1’den 27’ye çıkarken çağrı sayısı sabit kalıyor. Nedeni aritmetiktir: başarısızlık oranı 0,025 iken bir isteğin üçüncü denemeye ihtiyaç duyma olasılığı binde birin altındadır, dolayısıyla yirmi yedilik izin hiç kullanılmaz. Çağrı çarpanı arızasız günde uykudadır; onu uyandıran şey başarısızlık oranıdır. Bir zincirin fazla deneme hakkı taşıdığı, olağan koşulda hiçbir ölçütte görünmez.

Kesintide Fırtına Katmanla Büyüyor

İkinci tablo uyanışı gösteriyor. Bağımlılık bir saniye boyunca hiçbir çağrıyı karşılamazken pencere içindeki çağrı hızı katman eklendikçe büyüyor: denemesiz 0,80, tek katmanda 2,89, iki katmanda 5,77, üç katmanda 6,24 çağrı/tur. Son sayı olağan hızın 6,4 katıdır ve düşmüş bir bağımlılığa gidiyor.

Aritmetik üst sınır ile gözlenen çarpan ayrılmalıdır. Üç katman üçer denemeyle 27’lik izin verir; gözlenen 6,4’tür. Farkı geri çekilme yaratıyor — denemeler zamana yayıldığı için hepsi pencereye sığmaz. Üst sınır tasarımın taşıdığı risktir, gözlenen çarpan o riskin bu parametrelerde gerçekleşen payıdır. Üst sınır koşumdan bağımsızdır: derinlik dörde çıkarsa 81.

Tablo çağıran tarafındaki kazancı da veriyor ve kazanç gerçektir: düşen istek denemesiz koşumda 80, üç katmanlı koşumda 0. Geri çekilme denemeleri pencerenin ötesine yaydığı için, yeterli deneme hakkı olan her istek sonunda başarılı oluyor.

İki satır arasında ters giden bir şey de var. Tek katmanlı koşumda düşen istek 94, yani denemesiz koşumun 80’inden fazla. Nedeni tepe sütununda: fırtına pencereden sonra tur başına 8 çağrıya çıkıyor ve bu, olağan kapasite olan 6’nın üstündedir. Üç deneme hakkı, kesinti bittikten sonraki bu ikinci dalgayı atlatmaya yetmiyor. Yetersiz deneme hakkı, hiç denememekten kötü olabilir: yükü büyütür ama isteği kurtarmaz.

Bozulmada Çarpanı İzin Değil Başarısızlık Oranı Belirliyor

Üçüncü tablo aynı yapılandırmaları kapasitenin sıfıra değil bire indiği bir profilde koşuyor ve sıralama değişiyor. İki katman ile üç katman aynı sayıyı veriyor: 5296 çağrı, pencerede 2,39 çağrı/tur. İzin 9’dan 27’ye çıkmasına rağmen hiçbir şey değişmiyor.

Nedeni ikinci tablodakinin tersidir. Kapasite bir olduğu için çağrıların bir bölümü hâlâ başarılı oluyor; bir isteğin dokuz denemeyi tüketecek kadar üst üste başarısız olması ender bir olaydır. Çarpanı belirleyen şey izin değil, denemenin başarısızlık olasılığıdır. Kural şöyle yazılabilir: izin bir üst sınır koyar, gerçekleşen çarpanı arıza kipi seçer. Tam kesinti izni sonuna kadar kullandırır, kısmi bozulma kullandırmaz.

Bozulmada çarpanın 2,5 kata çıkması yine de küçük değildir: kapasitesi altıda birine düşmüş bir bağımlılık, kendisini zorlayan sistemden iki buçuk kat istek alıyor. Bozulmayı uzatan budur.

Deneme Bütçesi Zincire Dağıtılır

Son satır çözümü veriyor ve çözüm katman katman deneme sayısını kısmak değildir; her katmanın makul bir sayı seçtiği ve toplamın çarpıldığı zaten görüldü. Deneme bütçesi, ek denemelerin birincil çağrılara oranına bir tavan koyar ve o tavan zincirin tamamında geçerlidir.

Bütçe 0,30’a bağlandığında kesintide pencere hızı 6,24’ten 2,88 çağrı/tura, yani olağan hızın 3,0 katına iniyor; toplam çağrı 4523’ten 4065’e düşüyor. Bozulmada pencere hızı 2,39’dan 1,40’a, toplam çağrı 5296’dan 4288’e iniyor. Bedeli açıktır: kesintide düşen istek 0’dan 103’e, bozulmada 0’dan 220’ye çıkıyor. Bütçe, çağıranın kurtardığı isteğin bir bölümünü bağımlılığın nefes alması için geri verir.

Duyarlılık satırı bütçenin ne kadar sıkılabileceğini gösteriyor: 0,10’da kesintide pencere hızı 1,54’e iniyor ve düşen istek 103’ten 90’a düşüyor — daha sıkı bütçe burada iki tarafı birden iyileştiriyor, çünkü küçülen fırtına pencere sonrası ikinci dalgayı da küçültüyor. Bütçenin doğru değeri, arızanın kaç isteği kurtardığından çok fırtınanın kaç isteği ezdiğine bağlıdır.

Özet

  • Zincirin her katmanı kendi başına yeniden deneme koyar ve izinler çarpılır: üç katman üçer denemede 27’lik bir üst sınır verir; d katman r denemede üst sınır r^d’dir ve d=4’te 81 olur.
  • Arızasız günde çarpan uykudadır: izin 1’den 27’ye çıkarken çağrı sayısı değişmiyor, çarpan 1,03 ve düşen istek 96’dan 0’a iniyor. Fazla deneme hakkı olağan koşulda hiçbir ölçütte görünmez.
  • Tam kesintide fırtına katmanla büyüyor: pencerede çağrı hızı 0,80 → 2,89 → 5,77 → 6,24 çağrı/tur, olağan hızın 6,4 katı. Gözlenen çarpan aritmetik üst sınırın (27) altındadır, çünkü geri çekilme denemeleri zamana yayar.
  • Yetersiz deneme hakkı hiç denememekten kötü olabilir: tek katmanlı koşumda düşen istek 94, oysa denemesiz koşumda 80; fırtına pencere sonrası tepeyi olağan kapasitenin üstüne, 8 çağrı/tura taşır.
  • Kısmi bozulmada çarpanı izin değil başarısızlık oranı belirliyor: izin 9 ile 27 aynı sonucu veriyor (5296 çağrı, 2,39 çağrı/tur), çünkü hiçbir istek dokuz denemeyi tüketmiyor.
  • Deneme bütçesi zincirin tamamına konur: 0,30’da kesinti fırtınası 6,24’ten 2,88 çağrı/tura, bozulma 2,39’dan 1,40’a iner; bedeli kesintide 103, bozulmada 220 düşen istektir.

Sonraki Adım

Bütün bu ölçümler bir sayıyı sabit tuttu: denemeler arasındaki bekleme. Oysa bekleme ile deneme hakkı tek başına seçilemez, çünkü çarpımları çağıranın ne kadar bekleyeceğini belirler. Son satır bunu veriyor: yirmi yedi deneme, tavanı otuz iki tur olan bir geri çekilmeyle bir isteği en kötü durumda 793 tur, yani 7,93 saniye ayakta tutar — K01’in yirmi turluk okuma eşiğinin 39,6 katı. Yani deneme politikasının gerçek sınırı deneme sayısında değil, çağıranın elindeki süredir; ve o süre bu derste hiç bütçelenmedi. Sonraki ders onu ele alır ve zincir boyunca dağıtır: uçtan uca eşik hangi adıma ne kadar pay bırakır, kalan pay alt çağrılara nasıl bölünür ve yavaşlayan bir bağımlılıkta bütçe tükendiğinde iptal edilen iş nasıl sayılır.

İ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