Ders 05 / 27
Sapma
Bir sapma tespiti yazılır: kayıt okunur, gerçek durum diskten okunur, kalem kalem fark çıkarılır ve her farkın kaynağı ayrılır. Otuz günlük bir dönemde biriken sapma, tarama sıklığına göre tespit gecikmesi, kaydın kapsamı dışında kaldığı için hiç kapanmayan sapma ve geri almanın çalışan bir şeyi bozduğu durum sayılır.
İçindekiler
Önceki dört ders aynı şeyi dört yerden söyledi. İki kurulum dokuz kalemde ayrıldı; kısmi başarısızlıktan sonra kayıt ile ortam üç kalemde uyuşmadı; yeniden oluşturma acil düzeltmeleri sildi; yeniden sağlamadan sonra dokuz kalem on beş dakika kaydın söylemediği değerde kaldı. Hepsinin adı aynıdır.
Sapma, kaydın söylediği ile gerçeğin arasındaki farktır. Bu ders onu doğrudan ölçer: bir tespit yazılır — kayıt okunur, gerçek durum diskten okunur, kalem kalem fark çıkarılır ve her farkın kaynağı ayrılır. Ardından otuz günlük bir dönem koşturulur ve dört şey sayılır: biriken sapma, tarama sıklığına göre tespit gecikmesi, kaydın kapsamı dışında kaldığı için hiç kapanmayan sapma, ve düzeltmenin bedeli. Sonuncusu en az öteki üçü kadar önemli: bir sapmayı geri almak bazen çalışan bir şeyi bozar.
Bir ayrım baştan konur. M22/K03’te küme mimarisi ele alınırken ölçülen uzlaşma döngüsü sürekli koşuyordu ve fark doğduğu anda kapanıyordu; burada uygulama tetiklenir ve iki tetik arasında sapma birikir. Bu dersin tüm sayıları o boşlukta doğuyor.
Ortam bölgesel ölçüm ağının hazırlık ortamıdır ve kurgudur. Kayıt ile gerçek durum
gerçekten diske yazılır ve tespit gerçekten koşar; otuz günlük dönem node ile modellenir ve
üreteç kendi yazılıdır.
AT25. Kayıt yirmi kalem yazar. Gerçek durum bir dizin ağacıdır ve yirmi beş dosyadır; tespit onu kayıttan değil, diskten okur. AT26. Sağlayıcının belgelenmiş varsayılanları ayrı bir dosyadadır. Kayıtta olmayan bir kalem o listedeyse kaynağı sağlayıcı varsayılanı, değilse kayıt dışı kaynaktır. AT27. Otuz günlük dönemde olaylar üreteçle üretilir (tohum 4471903, üreteç kendi yazılıdır); günlük olay sayısı sıfır, bir ya da ikidir. AT28. Bir olayın kaynağı elle değişiklik, kayıt dışı kaynak ya da sağlayıcı varsayılanıdır. Yalnız elle değişiklik kaydın kapsamındadır; ötekiler bir uygulamayla kapanmaz. AT29. Uygulama tetiklenir: 1., 12. ve 25. günlerde. Tarama uygulamadan ayrıdır — tespit eder, kapatmaz. AT30. Elle değişikliklerin bir kısmı bir olayı kapatmak için yapılmış canlı düzeltmedir; geri alındığında kapattığı sorun geri gelir.
Kayıt ve Gerçek
#!/usr/bin/env bash # Kayit ve gercek ortam: kayit bir dosya, gercek durum bir dizin agacidir. Ikisi de diske yazilir. set -e rm -rf gercek cat > kayit.alt <<'SON' kaynak ag "olcum-agi" { blok = "10.40.0.0/16" alt_ag_sayisi = 3 ozel = "dogru" } kaynak makine "toplayici" { sayi = 3 boyut = "orta" disk_gb = 40 imaj = "taban-7" } kaynak makine "dogrulayici" { sayi = 2 boyut = "kucuk" disk_gb = 20 imaj = "taban-7" } kaynak kuyruk "okuma" { bolum = 6 saklama_saat = 72 olu_mektup = "acik" } kaynak veri_deposu "olcum" { boyut_gb = 200 yedek_gun = 14 surum = "5.2" } kaynak nesne_deposu "arsiv" { sinif = "seyrek" surumleme = "acik" yasam_gun = 365 } SON # Saglayicinin belgelenmis varsayilanlari: kayitta yazmayan, kendiliginden olusan alanlar. cat > varsayilan.txt <<'SON' ag.olcum-agi.cikis_yolu kuyruk.okuma.sifreleme veri_deposu.olcum.bakim_penceresi nesne_deposu.arsiv.erisim_kurali SON yaz() { mkdir -p "gercek/$(dirname "$1")"; printf '%s\n' "$2" > "gercek/$1"; } # Kayitla uyusan on dort kalem yaz ag/olcum-agi/blok 10.40.0.0/16; yaz ag/olcum-agi/ozel dogru yaz makine/toplayici/boyut orta; yaz makine/toplayici/imaj taban-7 yaz makine/dogrulayici/sayi 2; yaz makine/dogrulayici/boyut kucuk yaz makine/dogrulayici/disk_gb 20; yaz makine/dogrulayici/imaj taban-7 yaz kuyruk/okuma/bolum 6; yaz kuyruk/okuma/olu_mektup acik yaz veri_deposu/olcum/boyut_gb 200; yaz veri_deposu/olcum/surum 5.2 yaz nesne_deposu/arsiv/surumleme acik; yaz nesne_deposu/arsiv/yasam_gun 365 # Elle degistirilmis bes kalem (kayittaki degerden farkli) yaz ag/olcum-agi/alt_ag_sayisi 4; yaz makine/toplayici/sayi 5 yaz makine/toplayici/disk_gb 80; yaz kuyruk/okuma/saklama_saat 24 yaz veri_deposu/olcum/yedek_gun 7 # nesne_deposu/arsiv/sinif silinmis: kayitta var, gercekte yok # Saglayici varsayilani (uc kalem) ve kayit disi kaynak (uc kalem) yaz ag/olcum-agi/cikis_yolu acik; yaz kuyruk/okuma/sifreleme saglayici-anahtari yaz veri_deposu/olcum/bakim_penceresi pazar-03:00 yaz guvenlik/gecici/giris 0.0.0.0-8443; yaz ad_kaydi/toplayici/ic toplayici.ic yaz makine/tanilama/sayi 1 printf 'kayit %s satir gercek %s dosya\n' "$(wc -l < kayit.alt | tr -d ' ')" \ "$(find gercek -type f | wc -l | tr -d ' ')"
kayit 6 satir gercek 25 dosya
Kalem Kalem Fark
// sapma.mjs — kaydi okur, gercek durumu diskten okur, kalem kalem fark cikarir. Hicbir sey duzeltmez. import { readFileSync, readdirSync, statSync } from "node:fs"; const BLOK = /^kaynak\s+(\w+)\s+"([\w-]+)"\s*\{(.*)\}$/; const kayit = new Map(); for (const s of readFileSync("kayit.alt", "utf8").split("\n")) { const m = BLOK.exec(s.trim()); if (m) for (const x of m[3].matchAll(/(\w+)\s*=\s*("[^"]*"|[\w./-]+)/g)) kayit.set(`${m[1]}.${m[2]}.${x[1]}`, x[2].replaceAll('"', "")); } const varsayilan = new Set(readFileSync("varsayilan.txt", "utf8").trim().split("\n")); const gercek = new Map(); // gercek durum diskten okunur, kayittan degil const gez = (yol, on = []) => { for (const ad of readdirSync(yol).sort()) { const t = `${yol}/${ad}`; if (statSync(t).isDirectory()) gez(t, [...on, ad]); else gercek.set([...on, ad].join("."), readFileSync(t, "utf8").trim()); } }; gez("gercek"); const tum = [...new Set([...kayit.keys(), ...gercek.keys()])].sort(); const fark = tum.filter((k) => kayit.get(k) !== gercek.get(k)).map((k) => ({ k, kaynak: !gercek.has(k) ? "eksik kalem" : !kayit.has(k) ? (varsayilan.has(k) ? "saglayici varsayilani" : "kayit disi kaynak") : "elle degisiklik" })); const say = (t) => fark.filter((f) => f.kaynak === t).length; console.log(`kayit ${kayit.size} kalem gercek ${gercek.size} kalem birlesim ${tum.length}`); console.log(`sapma ${fark.length} kalem` + ` elle ${say("elle degisiklik")} eksik ${say("eksik kalem")}` + ` kayit disi ${say("kayit disi kaynak")} varsayilan ${say("saglayici varsayilani")}`); for (const f of fark) console.log(` ${f.kaynak.padEnd(22)} ${f.k.padEnd(34)} kayit "${kayit.get(f.k) ?? "-"}"` + ` gercek "${gercek.get(f.k) ?? "-"}"`); const gorunen = fark.filter((f) => kayit.has(f.k)).length; console.log(`kaydin kapsaminda olan, yani bir uygulamanin kapatabilecegi sapma ${gorunen}` + ` kapsam disi ${fark.length - gorunen}`);
kayit 20 kalem gercek 25 kalem birlesim 26 sapma 12 kalem elle 5 eksik 1 kayit disi 3 varsayilan 3 kayit disi kaynak ad_kaydi.toplayici.ic kayit "-" gercek "toplayici.ic" elle degisiklik ag.olcum-agi.alt_ag_sayisi kayit "3" gercek "4" saglayici varsayilani ag.olcum-agi.cikis_yolu kayit "-" gercek "acik" kayit disi kaynak guvenlik.gecici.giris kayit "-" gercek "0.0.0.0-8443" elle degisiklik kuyruk.okuma.saklama_saat kayit "72" gercek "24" saglayici varsayilani kuyruk.okuma.sifreleme kayit "-" gercek "saglayici-anahtari" kayit disi kaynak makine.tanilama.sayi kayit "-" gercek "1" elle degisiklik makine.toplayici.disk_gb kayit "40" gercek "80" elle degisiklik makine.toplayici.sayi kayit "3" gercek "5" eksik kalem nesne_deposu.arsiv.sinif kayit "seyrek" gercek "-" saglayici varsayilani veri_deposu.olcum.bakim_penceresi kayit "-" gercek "pazar-03:00" elle degisiklik veri_deposu.olcum.yedek_gun kayit "14" gercek "7" kaydin kapsaminda olan, yani bir uygulamanin kapatabilecegi sapma 6 kapsam disi 6
On iki kalem sapmış ve son satır ölçünün asıl yerini gösteriyor: on ikinin altısı kaydın kapsamında. Kalan altı kalem için bir uygulama koşturmak hiçbir şey değiştirmez, çünkü kayıt o kalemler hakkında bir şey söylemiyor — üçü sağlayıcının kendiliğinden açtığı alan, üçü kayıt yazılmadan yaratılmış kaynak. Bunları görebilmenin tek nedeni tespitin iki yönlü olmasıdır: yalnız kayıttaki kalemler taranmıyor, gerçek durumun tamamı dolaşılıyor ve kayıtta karşılığı olmayanlar da yazılıyor.
Kaynak ayrımı bir etiketleme işi değil, bir eylem ayrımıdır. Elle değişiklik bir uygulamayla kapanır. Eksik kalem bir uygulamayla geri gelir. Kayıt dışı kaynak ancak kayda alınarak ya da silinerek kapanır; sağlayıcı varsayılanı ise ne kapanır ne kapanmalıdır — yalnız kaydın onun hakkında sessiz olduğu bilinmelidir. Dört ayrı fark türü, dört ayrı karar.
Bir Dönem Boyunca
// donem.mjs — otuz gunluk sapma birikimi, tespit gecikmesi ve duzeltmenin bedeli. Model. const TOHUM = 4471903, GUN = 30, UYGULAMA = [1, 12, 25]; // uygulama tetiklenir, surekli kosmaz const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648; const r = uretec(TOHUM); const olay = []; for (let g = 1; g <= GUN; g++) for (let n = (r() < 0.55) + (r() < 0.18); n > 0; n--) { const p = r(); const kaynak = p < 0.45 ? "elle" : p < 0.72 ? "kayit disi" : "varsayilan"; olay.push({ g, kaynak, kapsamda: kaynak === "elle", canli: kaynak === "elle" && r() < 0.35 }); } const say = (t) => olay.filter((o) => o.kaynak === t).length; const kapsamli = olay.filter((o) => o.kapsamda); console.log(`tohum ${TOHUM} gun ${GUN} olay ${olay.length} uygulama gunleri` + ` ${UYGULAMA.join(", ")}`); console.log(`sapmanin kaynagi elle ${say("elle")} kayit disi ${say("kayit disi")}` + ` saglayici varsayilani ${say("varsayilan")} kapsamda ${kapsamli.length}`); // Iki rejim: uygulama tetiklenir (uc gun) ve surekli uzlasma (her gun). Ikisi de yalniz kapsamdakini kapatir. const rejim = (gunler) => { const toplam = [], kapsam = []; let kapatilan = 0; for (let g = 1; g <= GUN; g++) { if (gunler.includes(g)) kapatilan = kapsamli.filter((o) => o.g <= g).length; kapsam.push(kapsamli.filter((o) => o.g <= g).length - kapatilan); toplam.push(olay.filter((o) => o.g <= g).length - kapatilan); } const alan = (x) => x.reduce((a, b) => a + b, 0); return { toplam, kapsam, alanT: alan(toplam), alanK: alan(kapsam) }; }; const A = rejim(UYGULAMA), B = rejim([...Array(GUN)].map((_, i) => i + 1)); console.log(`\nacik sapma (gun sonu, ${GUN} gun)`); console.log(` tetiklenen uygulama toplam ${A.toplam.join(" ")}`); console.log(` tetiklenen uygulama kapsam ${A.kapsam.join(" ")}`); console.log(` surekli uzlasma toplam ${B.toplam.join(" ")}`); console.log(` gun-kalem alani kapsamdaki sapma: tetiklenen ${A.alanK} surekli ${B.alanK}`); console.log(` gun-kalem alani tum sapma: tetiklenen ${A.alanT} surekli ${B.alanT}` + ` fark ${A.alanT - B.alanT}`); console.log(`\ntespit gecikmesi (yalniz kapsamdaki ${kapsamli.length} sapma; tarama tespit eder, kapatmaz)`); for (const n of [1, 3, 7, 30]) { const gecikme = kapsamli .map((o) => { for (let g = o.g; g <= GUN; g++) if (g % n === 0) return g - o.g; return null; }) .filter((x) => x !== null); console.log(` tarama ${String(n).padStart(2)} gunde bir ortalama` + ` ${(gecikme.reduce((a, b) => a + b, 0) / gecikme.length).toFixed(1)} gun` + ` en kotu ${Math.max(...gecikme)} gun tespit edilen ${gecikme.length}/${kapsamli.length}`); } const geriAlinan = kapsamli.filter((o) => o.g <= UYGULAMA[UYGULAMA.length - 1]); const bozulan = geriAlinan.filter((o) => o.canli); console.log(`\nduzeltmenin bedeli`); console.log(` geri alinan sapma ${geriAlinan.length} bunun canli duzeltme olani` + ` ${bozulan.length} geri alinca calisan bir sey bozulur`); console.log(` kalici olarak kapanan ${geriAlinan.length - bozulan.length}` + ` geri gelen ${bozulan.length} (%${(100 * bozulan.length / geriAlinan.length).toFixed(0)})`); console.log(` kapsam disi ${olay.length - kapsamli.length} sapma hicbir uygulamayla kapanmadi;` + ` donem sonunda hepsi duruyor`);
tohum 4471903 gun 30 olay 21 uygulama gunleri 1, 12, 25 sapmanin kaynagi elle 9 kayit disi 6 saglayici varsayilani 6 kapsamda 9 acik sapma (gun sonu, 30 gun) tetiklenen uygulama toplam 1 1 2 2 2 3 3 3 4 5 6 3 5 6 7 8 8 8 9 9 10 11 12 13 9 10 10 11 11 13 tetiklenen uygulama kapsam 0 0 1 1 1 1 1 1 2 3 3 0 1 2 2 2 2 2 2 2 2 2 3 4 0 1 1 1 1 1 surekli uzlasma toplam 1 1 1 1 1 2 2 2 2 2 3 3 4 4 5 6 6 6 7 7 8 9 9 9 9 9 9 10 10 12 gun-kalem alani kapsamdaki sapma: tetiklenen 45 surekli 0 gun-kalem alani tum sapma: tetiklenen 205 surekli 160 fark 45 tespit gecikmesi (yalniz kapsamdaki 9 sapma; tarama tespit eder, kapatmaz) tarama 1 gunde bir ortalama 0.0 gun en kotu 0 gun tespit edilen 9/9 tarama 3 gunde bir ortalama 1.0 gun en kotu 2 gun tespit edilen 9/9 tarama 7 gunde bir ortalama 3.1 gun en kotu 5 gun tespit edilen 9/9 tarama 30 gunde bir ortalama 13.7 gun en kotu 27 gun tespit edilen 9/9 duzeltmenin bedeli geri alinan sapma 8 bunun canli duzeltme olani 2 geri alinca calisan bir sey bozulur kalici olarak kapanan 6 geri gelen 2 (%25) kapsam disi 12 sapma hicbir uygulamayla kapanmadi; donem sonunda hepsi duruyor
Otuz günde yirmi bir sapma doğdu ve dokuzu kaydın kapsamındaydı. İki dizi arasındaki fark tetiklenen uygulamanın ne demek olduğunu tek satıra indiriyor: kapsamdaki sapma tetiklenen rejimde kırk beş gün-kalem açık kaldı, sürekli uzlaşmada sıfır. Üç tetik günü dizide açıkça görünüyor — 1., 12. ve 25. günlerde kapsam satırı sıfıra iniyor, sonra yeniden tırmanıyor. Sapma yok olmuyor, her tetik arasında yeniden doğuyor; biriken şey sapmanın kendisi değil, kapanmamış sapmadır.
Toplam satırı ise iki rejimde de tırmanmaya devam ediyor ve otuzuncu günde on üç ile on ikide duruyor. Aradaki fark yalnız kırk beş gün-kalemdir ve o da kapsamdaki dokuz kalemden geliyor. Kalan on iki sapma hiçbir rejimde kapanmadı: uygulamanın sürekli koşması onları görünür kılmıyor, çünkü görünmemelerinin nedeni sıklık değil, kapsam. Bu, konunun ilk dersinde beş kalem olarak görülen şeyin bir dönem boyunca ne kadar büyüdüğünü gösteriyor.
Tespit Gecikmesi ve Düzeltmenin Bedeli
Tarama tablosu ayrı bir kararı ölçüyor. Tarama uygulamadan bağımsızdır: bir sapmayı kapatmadan görünür kılar. Günlük tarama gecikmeyi sıfırlıyor, üç günde bir tarama ortalama bir güne, haftalık tarama üç virgül bir güne, aylık tarama on üç virgül yedi güne çıkarıyor — ve aylık taramada en kötü gecikme yirmi yedi gün. Yirmi yedi gün, bir kalemin kaydın söylemediği değerde koştuğu ve kimsenin bilmediği süredir. Tarama sıklığını seçmek, bu sayıyı seçmektir.
Son tablo bu dersin en ters sayısını taşıyor. Yirmi beşinci güne kadar sekiz sapma geri alındı ve ikisi canlı düzeltmeydi: bir olayı kapatmak için elle yapılmış, sorunu gerçekten gideren değişiklikler. Geri alındıklarında kapattıkları sorun geri geldi ve ikisi de sonraki günlerde yeniden yapıldı. Geri almanın kalıcı olarak kapattığı sapma altı, geri geleni iki — yüzde yirmi beş.
Bu iki kalem sapmanın tek yönlü okunamayacağını gösteriyor. Bir sapma “kayıt haklı, gerçek yanlış” demek değildir; yalnız ikisinin ayrıldığı demektir. Ayrılmanın iki yorumu vardır ve hangisinin doğru olduğu farkın kendisinden okunamaz: ya kayıt güncellenmeli ve düzeltme kayda işlenmeli, ya gerçek geri alınmalı. Otomatik uygulama her zaman ikinciyi seçer, çünkü başka bir seçeneği yoktur. Kaydın bir kalem hakkında sessiz kalmasının bedeli görünmezlikti; kaydın bir kalem hakkında eski kalmasının bedeli, çalışan bir şeyin bozulmasıdır.
Özet
- Tespit 26 kalemi karşılaştırdı ve 12 sapma buldu: 5 elle değişiklik, 1 eksik kalem, 3 kayıt dışı kaynak, 3 sağlayıcı varsayılanı; bunların yalnız 6’sı bir uygulamayla kapanabilir.
- Otuz günde 21 sapma doğdu; 9’u kaydın kapsamındaydı, 12’si dönem sonunda hâlâ açıktı ve hiçbir rejimde kapanmadı.
- Tetiklenen uygulama kapsamdaki sapmayı 45 gün-kalem açık bıraktı, sürekli uzlaşma 0; fark sıklıktan, kapanmayan 12 kalem ise kapsamdan geliyor.
- Tarama sıklığı gecikmeyi doğrudan belirliyor: günlük 0,0 gün, haftalık 3,1 gün, aylık 13,7 gün ortalama ve 27 gün en kötü.
- Geri alınan 8 sapmanın 2’si canlı düzeltmeydi ve geri alınca çalışan bir şeyi bozdu; geri almanın kalıcı kapattığı 6, geri gelen 2 kalemdir.
Sonraki Adım
Sapma bu noktada sayılabilir bir şey. Kaydın kapsamı biliniyor, kapsam dışındaki kalem adıyla yazılabiliyor, farkın kaynağı dörde ayrılabiliyor, tespit gecikmesi tarama sıklığına bağlanabiliyor ve düzeltmenin bir bedeli olduğu ölçülmüş durumda. Ölçünün tamamı tek bir varsayıma yaslanıyor: ortada okunabilir bir kayıt var.
O kaydın kendisi ise hiç ele alınmadı. Beş derste kayıt hep hazır bulundu — altı satırlık bir dosya, kalemlerini değerleriyle sayan bir liste. Nasıl yazıldığı, hangi yapılarla kurulduğu, bir kaynağın ötekine nasıl bağlandığı, aynı tanımın üç ortam için nasıl tekrar edilmeden yazılacağı, bir değerin nereden geleceği ve bir değişiklik uygulanmadan önce ne göstereceği — bunların hiçbiri sorulmadı. Sonraki konu kaydın kendisini yazmakla başlıyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.