Ders 08 / 20
Zarif Bozulma
Yanıtın çekirdek kümesinin ayrılması ve eksik alanlarla yanıtlanması: alan atlama ile bayat yedeğin K01'in 480 baytlık takip yanıtı üzerinde ölçülmesi, isteğe bağlı bir bağımlılık düştüğünde 15 dakikalık kesintinin sıfırlanması, çekirdek bağımlılık düştüğünde aynı kalıbın kesintiyi yalnız 14,02 dakikaya indirmesi ve yalıtımın sınırının bu farkla yazılması.
İçindekiler
Bir önceki ders kapıyı kurdu ve reddedilen isteği açıkça reddetti. Reddin bir sağlaması eksik kaldı: bir istek düştüğünde onun için o ana kadar toplanmış her şey de düşüyor. Takip sorgusunun yanıtı tek parça değildir — gönderinin durumu, rotası, tahmini teslim zamanı ve ücreti ayrı alanlardır ve ayrı bağımlılıklardan gelir. Bir bağımlılık düştüğünde isteğin tamamını düşürmek, elde olan üç alanı da atmak demektir.
Bu ders son seçeneği ele alır: yanıtın hangi parçasının çekirdek olduğuna karar vermek ve çekirdek dışındaki alanlar gelmediğinde isteği yine de yanıtlamak. Adı zarif bozulmadır (graceful degradation) ve zarif kapanma (graceful shutdown) ile karıştırılmamalıdır: zarif kapanma, bir sürecin kapanırken elindeki işi bitirip yeni iş almamasıdır ve Sunucu Tarafı Temelleri ile Önbellekleme, Kuyruklar ve Eşzamansız İşleme kurslarında kuruldu. Zarif bozulma ise ayakta kalan bir sistemin yanıtının içeriğini küçültmesidir.
Alanlar ve Çekirdek Küme
AY14 — çekirdek küme, yedek defteri ve iki arıza senaryosu. Çekirdek küme durum ve rota
alanlarıdır; tahmin ile ucret isteğe bağlıdır. Gerekçe: takip sayfası gönderinin nerede ve
hangi durumda olduğunu göstermeden anlamsızdır, tahmini teslim ile ücret ise o sayfanın yardımcı
bilgileridir. Yedek defteri son bilinen değeri 5000 gönderi için tutar ve bayat bir değer en çok 60
tur sunulur. AY14a: ücretlendirme servisi duruyor, süre 15 dakika, sıklık ayda bir kez.
AY14b: izdüşüm okuma modeli duruyor, süre 15 dakika, sıklık ayda bir kez. İki senaryonun süresi
K01’in on dakikalık kurtarma süresi varsayımının biraz üstündedir. Bu varsayımlar K01’in tablosuna
eklenmez.
Alanların bayt boyları K01’in 480 baytlık takip yanıtını bölüştürür: durum 180, rota 120, tahmin 90, ücret 90. Üç politika karşılaştırılır. Hepsi ya da hiçbiri bir alan eksikse isteği düşürür. Alan atlama çekirdeği zorunlu tutar, eksik isteğe bağlı alanı yanıttan çıkarır. Bayat yedek buna ek olarak son bilinen değeri sunar — bayat sunum da bir bozulma biçimidir ve bayatlık sınırı onun genişliğini belirler.
// bozulma/yanit.mjs — takip yanitinin MODELI: alanlar ayri bagimliliklardan toplanir. // Tur soyut bir adimdir (bir tur = bir saniye) ve her tur akistan bir ornek istegi // temsil eder. Gercek servis, ag ya da depo kurulmaz. export const K01 = { tepeOkuma: 416.67, yanitBayt: 480, arizaPayi: 28.2 }; // AY14: cekirdek kume {durum, rota}; toplam bayt K01'in 480 baytlik takip yanitini verir. export const ALAN = [ { ad: "durum", kaynak: "izdusum", cekirdek: true, bayt: 180 }, { ad: "rota", kaynak: "izdusum", cekirdek: true, bayt: 120 }, { ad: "tahmin", kaynak: "tahmin", cekirdek: false, bayt: 90 }, { ad: "ucret", kaynak: "ucretlendirme", cekirdek: false, bayt: 90 }, ]; export const ISARET_BAYT = 6; // alan basina tazelik gostergesi export const YEDEK_KAYIT = 5000; // yedek defterinde tutulan gonderi sayisi export const BAYATLIK_SINIRI = 60; // AY14: bayat deger en cok 60 tur sunulur const GECICI = 40; // saglam bagimlilikta gecici zaman asimi araligi export function kosum({ politika, kip, isinma = 120, ariza = 900 }) { const yedek = new Map(); // alan -> son taze degerin turu const s = { tam: 0, azaltilmis: 0, dusen: 0, tazeAlan: 0, bayatAlan: 0, eksikAlan: 0, yanlisBozulma: 0, toplamBayt: 0, sonYanitTuru: 0, }; for (let t = 1; t <= isinma + ariza; t += 1) { const arizada = t > isinma; const sonuc = []; ALAN.forEach((a, i) => { const durum = arizada ? kip[a.kaynak] : "saglam"; const gecici = durum === "saglam" && (t + i * 10) % GECICI === 0; if (durum === "saglam" && gecici === false) { yedek.set(a.ad, t); sonuc.push({ a, hal: "taze" }); return; } const yas = yedek.has(a.ad) ? t - yedek.get(a.ad) : Infinity; if (politika === "yedekli" && yas <= BAYATLIK_SINIRI) { sonuc.push({ a, hal: "bayat" }); if (gecici && arizada) s.yanlisBozulma += 1; // taze deger vardi, gecici asim kesti return; } sonuc.push({ a, hal: "yok" }); }); if (arizada === false) continue; // isinma turlari sayilmaz const eksikCekirdek = sonuc.some((o) => o.a.cekirdek && o.hal === "yok"); const eksikVar = sonuc.some((o) => o.hal !== "taze"); if (politika === "hepsi" ? eksikVar : eksikCekirdek) { s.dusen += 1; continue; } let bayt = 0; for (const o of sonuc) { if (o.hal === "taze") s.tazeAlan += 1; else if (o.hal === "bayat") s.bayatAlan += 1; else { s.eksikAlan += 1; continue; } bayt += o.a.bayt + ISARET_BAYT; } s.toplamBayt += bayt; s.sonYanitTuru = t - isinma; if (eksikVar) s.azaltilmis += 1; else s.tam += 1; } s.yanit = s.tam + s.azaltilmis; s.ortBayt = s.yanit === 0 ? 0 : s.toplamBayt / s.yanit; s.tur = ariza; return s; }
Isınma turları arızanın sistemin bir süre sağlam çalıştıktan sonra başladığını temsil eder. Yedek defteri ancak o sürede doldurulmuş bir değeri sunabilir; hiç görülmemiş bir alanın yedeği yoktur.
// bozulma/kosum.mjs — uc politikanin uc gunde karsilastirilmasi ve yalitimin siniri import { K01, ALAN, ISARET_BAYT, YEDEK_KAYIT, BAYATLIK_SINIRI, kosum } from "./yanit.mjs"; const ARIZA = 900; // AY14: 15 dakika = 900 tur const POLITIKA = [["hepsi ya da hicbiri", "hepsi"], ["alan atlama", "atlama"], ["+ bayat yedek", "yedekli"]]; const SAGLAM = { izdusum: "saglam", tahmin: "saglam", ucretlendirme: "saglam" }; const GUN = [ ["arizasiz", SAGLAM], ["AY14a: ucretlendirme durdu (istege bagli alan)", { ...SAGLAM, ucretlendirme: "dusuk" }], ["AY14b: izdusum durdu (cekirdek alan)", { ...SAGLAM, izdusum: "dusuk" }], ]; console.log(`${ARIZA} tur (120 tur isinmadan sonra); bayatlik siniri ${BAYATLIK_SINIRI} tur`); console.log(`alanlar: ` + ALAN.map((a) => `${a.ad}(${a.kaynak}, ${a.cekirdek ? "cekirdek" : "istege bagli"}, ${a.bayt} B)`).join(", ")); console.log(`toplam alan bayti ${ALAN.reduce((x, a) => x + a.bayt, 0)} = K01 takip yaniti ${K01.yanitBayt} B\n`); for (const [gun, kip] of GUN) { console.log(`-- ${gun} --`); console.log(`${"politika".padEnd(20)}${"yanit".padStart(6)}${"tam".padStart(5)}${"azaltilmis".padStart(11)}` + `${"dusen".padStart(6)}${"taze/bayat/eksik alan".padStart(22)}${"ort. bayt".padStart(10)}${"son yanit turu".padStart(15)}`); for (const [ad, p] of POLITIKA) { const r = kosum({ politika: p, kip, ariza: ARIZA }); console.log(`${ad.padEnd(20)}${String(r.yanit).padStart(6)}${String(r.tam).padStart(5)}` + `${String(r.azaltilmis).padStart(11)}${String(r.dusen).padStart(6)}` + `${`${r.tazeAlan}/${r.bayatAlan}/${r.eksikAlan}`.padStart(22)}${r.ortBayt.toFixed(1).padStart(10)}` + `${String(r.sonYanitTuru).padStart(15)}`); } console.log(); } const a = kosum({ politika: "hepsi", kip: SAGLAM, ariza: ARIZA }); const y = kosum({ politika: "yedekli", kip: SAGLAM, ariza: ARIZA }); console.log(`-- arizasiz gunun bedeli --`); console.log(`tazelik gostergesi ${ISARET_BAYT} B x ${ALAN.length} alan = ${ISARET_BAYT * ALAN.length} B/yanit` + ` = K01 yanitinin %${((ISARET_BAYT * ALAN.length) / K01.yanitBayt * 100).toFixed(1)}'i,` + ` tepe okumada ${((K01.tepeOkuma * ISARET_BAYT * ALAN.length) / 1024).toFixed(2)} KiB/s`); console.log(`yedek defteri ${YEDEK_KAYIT} gonderi x ${K01.yanitBayt} B = ` + `${((YEDEK_KAYIT * K01.yanitBayt) / 1024 / 1024).toFixed(2)} MiB; her taze alan bir defter yazmasi ->` + ` ${(K01.tepeOkuma * ALAN.length).toFixed(2)} yazma/s`); console.log(`kati politika arizasiz gunde ${a.dusen}/${ARIZA} istegi dusuruyor` + ` -> tepe okumada ${((K01.tepeOkuma * a.dusen) / ARIZA).toFixed(2)} istek/s`); console.log(`bayat yedekle ayni gunde ${y.dusen} dusen, ${y.bayatAlan} alan bayat sunuluyor` + ` = alanlarin %${((y.bayatAlan / (ARIZA * ALAN.length)) * 100).toFixed(2)}'i`); console.log(`\n-- kesinti butcesine yansimasi (AY14: 15 dk, ayda 1 kez) --`); console.log(`${"senaryo".padEnd(9)}${"politika".padEnd(21)}${"karsilanan".padStart(11)}` + `${"kesinti(dk)".padStart(12)}${"ariza payinin(28,2)".padStart(20)}`); for (const [ad, kip] of [["AY14a", GUN[1][1]], ["AY14b", GUN[2][1]]]) { for (const [pad, p] of POLITIKA) { const r = kosum({ politika: p, kip, ariza: ARIZA }); const dk = 15 * (r.dusen / ARIZA); console.log(`${ad.padEnd(9)}${pad.padEnd(21)}${String(r.yanit).padStart(11)}` + `${dk.toFixed(2).padStart(12)}${`%${((dk / K01.arizaPayi) * 100).toFixed(1)}`.padStart(20)}`); } } console.log(`\n-- yalitimin siniri: hangi kaynagin dusmesi ne birakiyor --`); console.log(`${"dusen kaynak".padEnd(16)}${"etkilenen alan".padStart(15)}${"cekirdek mi".padStart(12)}` + `${"yanit".padStart(7)}${"ort. bayt".padStart(10)}${"son yanit turu".padStart(15)}`); for (const kaynak of ["ucretlendirme", "tahmin", "izdusum"]) { const et = ALAN.filter((x) => x.kaynak === kaynak); const r = kosum({ politika: "yedekli", kip: { ...SAGLAM, [kaynak]: "dusuk" }, ariza: ARIZA }); console.log(`${kaynak.padEnd(16)}${et.map((x) => x.ad).join("+").padStart(15)}` + `${(et.some((x) => x.cekirdek) ? "evet" : "hayir").padStart(12)}` + `${String(r.yanit).padStart(7)}${r.ortBayt.toFixed(1).padStart(10)}${String(r.sonYanitTuru).padStart(15)}`); }
900 tur (120 tur isinmadan sonra); bayatlik siniri 60 tur alanlar: durum(izdusum, cekirdek, 180 B), rota(izdusum, cekirdek, 120 B), tahmin(tahmin, istege bagli, 90 B), ucret(ucretlendirme, istege bagli, 90 B) toplam alan bayti 480 = K01 takip yaniti 480 B -- arizasiz -- politika yanit tam azaltilmis dusen taze/bayat/eksik alan ort. bayt son yanit turu hepsi ya da hicbiri 810 810 0 90 3240/0/0 504.0 899 alan atlama 856 810 46 44 3378/0/46 498.8 900 + bayat yedek 900 810 90 0 3510/90/0 504.0 900 -- AY14a: ucretlendirme durdu (istege bagli alan) -- politika yanit tam azaltilmis dusen taze/bayat/eksik alan ort. bayt son yanit turu hepsi ya da hicbiri 0 0 0 900 0/0/0 0.0 0 alan atlama 856 0 856 44 2545/0/879 405.4 900 + bayat yedek 900 0 900 0 2633/127/840 414.4 900 -- AY14b: izdusum durdu (cekirdek alan) -- politika yanit tam azaltilmis dusen taze/bayat/eksik alan ort. bayt son yanit turu hepsi ya da hicbiri 0 0 0 900 0/0/0 0.0 0 alan atlama 0 0 0 900 0/0/0 0.0 0 + bayat yedek 59 0 59 841 115/121/0 504.0 59 -- arizasiz gunun bedeli -- tazelik gostergesi 6 B x 4 alan = 24 B/yanit = K01 yanitinin %5.0'i, tepe okumada 9.77 KiB/s yedek defteri 5000 gonderi x 480 B = 2.29 MiB; her taze alan bir defter yazmasi -> 1666.68 yazma/s kati politika arizasiz gunde 90/900 istegi dusuruyor -> tepe okumada 41.67 istek/s bayat yedekle ayni gunde 0 dusen, 90 alan bayat sunuluyor = alanlarin %2.50'i -- kesinti butcesine yansimasi (AY14: 15 dk, ayda 1 kez) -- senaryo politika karsilanan kesinti(dk) ariza payinin(28,2) AY14a hepsi ya da hicbiri 0 15.00 %53.2 AY14a alan atlama 856 0.73 %2.6 AY14a + bayat yedek 900 0.00 %0.0 AY14b hepsi ya da hicbiri 0 15.00 %53.2 AY14b alan atlama 0 15.00 %53.2 AY14b + bayat yedek 59 14.02 %49.7 -- yalitimin siniri: hangi kaynagin dusmesi ne birakiyor -- dusen kaynak etkilenen alan cekirdek mi yanit ort. bayt son yanit turu ucretlendirme ucret hayir 900 414.4 900 tahmin tahmin hayir 900 414.4 900 izdusum durum+rota evet 59 504.0 59
Bütün sayılar hesap sınıfındadır: belirlenimli bir tur dizisi üzerinde sayılmışlardır.
Arızasız Günün Bedeli
Üç kalem ödenir ve üçü de arıza olmadan ödenir.
Taşınan alan. Her alan yanında bir tazelik göstergesi taşır: değerin taze mi bayat mı olduğu ve bayatsa yaşı. Altı bayt, dört alan, yanıt başına 24 bayt — K01’in 480 baytlık takip yanıtının yüzde 5,0’i, tepe okuma hızında saniyede 9,77 KiB. Bu gösterge olmadan bozulma sessizdir ve sessiz bozulma en tehlikeli biçimidir: istemci eski bir ücreti güncel sanır.
Yedek defteri. Beş bin gönderinin son bilinen değeri 2,29 MiB tutar, ama asıl bedel bellek değil yazmadır: her taze alan defteri günceller, tepe okumada saniyede 1666,68 defter yazması. Bu, hiçbir arıza olmasa da sürekli ödenen bir yüktür ve bozulma kalıbının en pahalı kalemidir.
Bayat sunulan alan. Bayat yedek açıkken arızasız günde bile 3600 alanın 90’ı bayat sunuluyor — yüzde 2,50. Bunlar geçici zaman aşımlarıdır; taze değer bir sonraki turda gelecekti ama yedek hemen devreye girdi. Yedek yolun kendi tazeliği bir bedeldir.
Buna karşılık ilk tablo katı politikanın kendi bedelini de gösteriyor: arızasız günde 900 isteğin 90’ını düşürüyor, tepe okumada saniyede 41,67 istek. Hiçbir bağımlılık düşmemişken. Katı politika bir taban değil, kendi başına bir kusurdur.
Arızalı Günün Kazancı
AY14a tablosu kalıbın ne satın aldığını gösteriyor. Ücretlendirme servisi on beş dakika durduğunda katı politika 900 isteğin 900’ünü düşürüyor: on beş dakikanın tamamı kesintidir ve K01’in aylık 28,2 dakikalık arıza payının yüzde 53,2’sini yer. Tek bir arıza, ayın yarısından fazlasını harcıyor.
Alan atlama aynı arızada 856 isteği yanıtlıyor ve kesinti 0,73 dakikaya iniyor — payın yüzde 2,6’sı. Bayat yedek eklendiğinde 900 isteğin 900’ü yanıtlanıyor ve kesinti sıfırlanıyor. Yanıtın ortalama boyu 504 bayttan 414,4 bayta düşüyor; kullanıcı gönderisinin nerede olduğunu ve durumunu görüyor, ücreti göremiyor.
Bir tasarım kararı burada görünür oluyor. Ücret alanı ilk altmış turda bayat sunuluyor, sonra bayatlık sınırı aşılınca yanıttan çıkarılıyor: tabloda 127 bayat ve 840 eksik alan. Bayat bir ücret bir süre gerçeğe yakındır, on beş dakika sonra yalnızca yanlıştır. Sınır o “bir süre”nin adıdır.
Yalıtımın Sınırı
AY14b tablosu bu konunun kapanış cümlesini yazıyor. İzdüşüm okuma modeli — çekirdek iki alanın tek kaynağı — durduğunda üç politika da çöküyor. Katı politika ve alan atlama 900 isteğin 900’ünü düşürüyor: on beş dakika kesinti, payın yüzde 53,2’si. Bayat yedek yalnız 59 isteği yanıtlıyor ve 59. turda susuyor; kesinti 14,02 dakika, payın yüzde 49,7’si.
Kazanç bir dakikadır ve o bir dakika bayatlık sınırının kendisidir. Bozulma çekirdeği taşımaz, yalnız erteler. Son tablo bunu üç satırda özetliyor: isteğe bağlı bir kaynak düştüğünde yanıt sayısı 900’de kalır, çekirdek kaynak düştüğünde 59’a iner ve son yanıt 59. turda verilir.
Buradan konunun bütünü hakkında bir şey söylenebilir. Bu konudaki her kalıp arızayı çevreler: bozuk bağımlılığı devreden çıkarır, kaynak havuzlarını ayırır, denemeyi sınırlar, süreyi bütçeler, aşırı yükü kaynağa bildirir, kapasiteyi aşan isteği reddeder, yanıtın çevresini kırpar. Hiçbiri arızayı kaldırmaz. Bozulmuş parça bozulmuş kalır; tek fark, çevresindeki sistemin onunla birlikte bozulmamasıdır.
Çekirdek bir parça bozulduğunda çevrelemenin verecek bir şeyi kalmaz. O noktada gereken tek şey bozuk parçanın yerine geçecek bir kopyadır — ve bu konuda öyle bir kopya hiç tasarlanmadı. Kopyanın nerede duracağı, ne zaman devralacağı, devralma sırasında kaç isteğin düşeceği ve devralma kararının yanlış verilmesinin ne kadara mal olacağı açık sorulardır.
Özet
- Zarif bozulma yanıtın alanlarını çekirdek ve isteğe bağlı kümelere ayırır ve çekirdek varsa isteği yanıtlar; zarif kapanmadan ayrıdır — biri kapanan bir sürecin işini bitirmesi, öteki ayakta kalan bir sistemin yanıtını küçültmesidir.
- Arızasız günün bedeli üç kalemdir: yanıt başına 24 baytlık tazelik göstergesi (K01 yanıtının yüzde 5,0’i, tepe okumada 9,77 KiB/s), 2,29 MiB’lik yedek defteri ile saniyede 1666,68 defter yazması, ve arızasız günde bile bayat sunulan alanların yüzde 2,50’si.
- AY14a’da (isteğe bağlı bağımlılık düştü) katı politika 900 isteğin tamamını düşürür ve 15,00 dakikayla K01’in 28,2 dakikalık arıza payının yüzde 53,2’sini yer; alan atlama bunu 0,73 dakikaya, bayat yedek 0,00 dakikaya indirir. Yanıtın ortalama boyu 504’ten 414,4 bayta düşer.
- Bayat yedek çekirdeği taşımaz, erteler: AY14b’de (çekirdek bağımlılık düştü) yalnız 59 istek yanıtlanır, kesinti 15,00 dakikadan 14,02 dakikaya iner ve kazanç tam olarak bayatlık sınırıdır.
- Bu konunun bütün kalıpları arızayı çevreler, hiçbiri onu kaldırmaz; çekirdek bir parça bozulduğunda çevrelemenin verecek bir şeyi kalmaz.
Sonraki Adım
Konunun bıraktığı boşluk tek cümleyle yazılabilir: bozulan parçanın yerine geçecek bir şey yok. Yalıtım kalıpları arızayı bir kutuya kapattı ve kutunun dışındaki sistemi ayakta tuttu; kutunun içindeki parça ise hâlâ bozuk ve onu düzeltecek bir mekanizma tasarlanmadı. AY14b’nin 14,02 dakikası tam olarak bu boşluğun ölçüsüdür — çevreleme oradan sonrasına dokunamaz. Sıradaki konu kutunun içine bakar ve ilk soruyu sorar: bozuk parçanın yerine hazır bekleyen bir kopya varsa, o kopyanın devralması nasıl kararlaştırılır. Kararın kendisi bir arıza kaynağıdır, çünkü yavaşlamış bir parça ile durmuş bir parça dışarıdan aynı görünür ve yanlış verilen bir devralma kararı, hiç devralmamış olmaktan daha pahalıya mal olabilir. O konu devralma penceresini, kararın tetiklenmesini ve devralmanın kesinti bütçesine yazdığı dakikayı ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.