Ders 11 / 18
Uyarı Yorgunluğu
Otuz günlük uyarı akışına gruplama, susturma ve bağımlılık bastırma uygulanması: kişi başına uyarı sayısının, eyleme dönen uyarı oranının ve okunmadan kapatılan gerçek olayların sayılması, bastırma penceresinin taranarak bastırmanın kaçırdığı olayın ölçülmesi.
İçindekiler
Önceki dersin üç kuralı on günde 41 uyarı üretti ve bunların 21’i hiçbir olaya denk gelmedi. Bir sistemde üç kural yoktur; her servis için birkaç kural vardır ve hepsi aynı kişiye bağlanır. Bu ders otuz günlük bir uyarı akışını baştan sona kurar, üç süzgeci sırayla uygular ve her aşamada aynı üç sayıyı ölçer: kişiye kaç bildirim gidiyor, bunların kaçı bir işe dönüşüyor, ve kaç gerçek olay o kişiye ulaşmadan kayboluyor.
Akış bölgesel ölçüm ağının (kurgu) altı servisinden ve on dört kuralından doğuyor; servislerin altında ortak bir veri deposu duruyor ve olayların bir kısmı oradan yukarı yayılıyor.
Uyarı yorgunluğu bir ruh hâli değil, ölçülebilir bir eşiktir: bir kişinin yirmi dört saatte aldığı uyarı sayısı arttıkça yanıt süresi uzar ve belirli bir sayıdan sonra uyarılar okunmadan kapatılır. Bu dersteki model o eğriyi varsayım olarak alır ve sonucunu sayar.
Otuz Günlük Akış
// yorgunluk/akis.mjs — otuz gunluk uyari akisinin MODELI. IG25: bes servis ve aralarindaki // bagimlilik kurgudur; veri deposu ucunun altinda dort servis vardir. IG26: yirmi gercek olay // bilinen olaydir; olay servisinde 1-3 kural, ona bagli her serviste 1-2 turev kural calar. // IG27: on dort kuraldan uc tanesi gurultucudur ve olaydan bagimsiz uyari uretir. export const TOHUM = 20260805, GUN = 30, NOBETCI = 2; export const BAGIMLILIK = { gecit: ["okuma", "fatura"], okuma: ["depo"], dogrulama: ["depo"], fatura: ["isemri", "depo"], isemri: ["depo"], depo: [] }; export const SERVIS = Object.keys(BAGIMLILIK); export const KURAL = SERVIS.flatMap((s) => [`${s}.hata_orani`, `${s}.gecikme`]) .concat(["depo.baglanti", "depo.disk"]); export const GURULTUCU = ["gecit.gecikme", "depo.baglanti", "isemri.gecikme"]; // Bir servisin ustunde duran servisler: o servis bozulunca bunlar da uyarir. export const ustler = (s) => SERVIS.filter((u) => BAGIMLILIK[u].includes(s)); export function akis() { let s = TOHUM; const r = () => ((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32); const dk = GUN * 1440, olay = [], uyari = []; for (let i = 0; i < 20; i += 1) { const t = Math.floor(r() * dk), servis = SERVIS[Math.floor(r() * SERVIS.length)]; olay.push({ id: i, t, servis, sure: 30 + Math.floor(r() * 150) }); } olay.sort((a, b) => a.t - b.t).forEach((o, i) => { o.id = i; }); for (const o of olay) { const kendi = KURAL.filter((k) => k.startsWith(`${o.servis}.`)); for (const k of kendi.slice(0, 1 + Math.floor(r() * kendi.length))) uyari.push({ t: o.t + Math.floor(r() * 8), kural: k, servis: o.servis, olay: o.id, turev: false }); for (const u of ustler(o.servis)) { // kaskad: ust servisler de calar const ku = KURAL.filter((k) => k.startsWith(`${u}.`)); for (const k of ku.slice(0, 1 + Math.floor(r() * 2))) uyari.push({ t: o.t + 2 + Math.floor(r() * 12), kural: k, servis: u, olay: o.id, turev: true }); } } for (const k of KURAL) { // olaydan bagimsiz gurultu const n = GURULTUCU.includes(k) ? 40 + Math.floor(r() * 30) : 2 + Math.floor(r() * 6); for (let i = 0; i < n; i += 1) uyari.push({ t: Math.floor(r() * dk), kural: k, servis: k.split(".")[0], olay: null, turev: false }); } uyari.sort((a, b) => a.t - b.t); return { olay, uyari }; } if (import.meta.filename === process.argv[1]) { const { olay, uyari } = akis(); const gercek = uyari.filter((u) => u.olay !== null); console.log(`tohum ${TOHUM}, ${GUN} gun, ${KURAL.length} kural, ${SERVIS.length} servis, ` + `${olay.length} gercek olay, ${uyari.length} ham uyari`); console.log(`olaya bagli uyari ${gercek.length} (${gercek.filter((u) => u.turev).length} turev), ` + `olaydan bagimsiz ${uyari.length - gercek.length}`); console.log(`gunde ${(uyari.length / GUN).toFixed(1)} uyari, nobetci basina ` + `${(uyari.length / GUN / NOBETCI).toFixed(1)}\n`); const say = new Map(); for (const u of uyari) say.set(u.kural, (say.get(u.kural) || 0) + 1); console.log(`${"en cok uyaran kural".padEnd(22)}${"uyari".padStart(7)}${"olayli".padStart(8)}`); [...say].sort((a, b) => b[1] - a[1]).slice(0, 5).forEach(([k, n]) => console.log(`${k.padEnd(22)}${String(n).padStart(7)}` + `${String(uyari.filter((u) => u.kural === k && u.olay !== null).length).padStart(8)}`)); }
tohum 20260805, 30 gun, 14 kural, 6 servis, 20 gercek olay, 268 ham uyari olaya bagli uyari 56 (26 turev), olaydan bagimsiz 212 gunde 8.9 uyari, nobetci basina 4.5 en cok uyaran kural uyari olayli isemri.gecikme 70 2 gecit.gecikme 58 3 depo.baglanti 40 0 gecit.hata_orani 16 9 fatura.hata_orani 13 9
Otuz günde 268 uyarı üretildi; günde 8,9. Bunların 212’si hiçbir olaya bağlı değil ve 56’sı yirmi gerçek olaydan doğdu — 56’nın 26’sı türev, yani olayın kendisinde değil, ona bağlı bir üst serviste doğan uyarı. Veri deposu ucunun altında dört servis olduğu için depoya değen her olay dörde kadar servisten uyarı üretiyor.
En çok uyaran kural listesi ikinci bir ayrımı gösteriyor: iş emri gecikme kuralı otuz günde 70 uyarı üretti ve bunların yalnız ikisi bir olaya denk geldi. Geçit hata oranı kuralı 16 uyarı üretti, dokuzu olaylı. Kural sayısı değil, kural başına boş uyarı sayılır.
Üç Süzgeç
Süzgeçler sırayla uygulanır: aynı servisteki yakın uyarılar tek bildirimde toplanır, kısa sürede çok uyarı üreten kural geçici olarak susturulur, ve bir servisin bağımlılığı zaten uyarıyorsa o servisin uyarısı bastırılır.
Ölçümdeki “eyleme dönen bildirim” dar tanımlıdır: bir bildirim ancak gerçek bir olaya bağlıysa ve o olay için okunan ilk bildirimse eyleme dönmüş sayılır. Aynı olayın ikinci uyarısı bir iş tanımlamaz, çünkü iş zaten başlamıştır; olaysız uyarı da bir iş tanımlamaz. Bu tanım oranı düşük gösterir, ama kişinin gerçekten yaptığı işi sayar.
// yorgunluk/suzge.mjs — ham uyari akisina uc suzgec sirayla uygulanir ve her asamada ayni olcumler // yeniden alinir. IG28: yanit suresi tabani 4 dk; nobetcinin son 24 saatte aldigi her uyari icin // yuzde 18 uzar; son 24 saatteki dokuzuncu ve sonraki uyarilar okunmadan kapatilir. // IG29: gruplama penceresi 15 dk (ayni servis), susturma esigi son 24 saatte 3 uyari (ayni kural), // bagimlilik bastirma penceresi 20 dk. IG30: nobet iki kisi arasinda on beser gunluk donusumle // paylasilir. import { akis, BAGIMLILIK, GUN, NOBETCI, TOHUM } from "./akis.mjs"; const { olay, uyari } = akis(); const TABAN = 4, ARTIS = 0.18, KOR = 9, PENCERE = { grup: 15, sustur: 3, bagimlilik: 45 }; const yorgunlukEsigi = Math.ceil(1 + 1 / ARTIS); // yanit suresinin iki katina ciktigi sira const gruplama = (U) => U.filter((u, i) => !U.some((v, j) => j < i && v.servis === u.servis && u.t - v.t <= PENCERE.grup)); const susturma = (U) => U.filter((u) => U.filter((v) => v.kural === u.kural && v.t <= u.t && u.t - v.t < 1440).length <= PENCERE.sustur); // Bastirma nedensel: once bagimlilik uyardiysa, ustteki servisin uyarisi bastirilir. const bastirma = (U) => U.filter((u) => !U.some((v) => BAGIMLILIK[u.servis].includes(v.servis) && v.t <= u.t && u.t - v.t <= PENCERE.bagimlilik)); function olc(U) { const gorulen = new Set(), sure = [], siralar = [], teslim = new Set(U.map((u) => u.olay)); let eyleme = 0, korlenen = 0; // sure: gorulen olayin ilk okunan bildiriminin yanit suresi for (let i = 0; i < U.length; i += 1) { const u = U[i]; const sira = U.filter((v, j) => j <= i && u.t - v.t < 1440).length; siralar.push(sira); if (sira >= KOR) { korlenen += 1; continue; } // okunmadan kapatildi if (u.olay !== null && !gorulen.has(u.olay)) { gorulen.add(u.olay); eyleme += 1; sure.push(TABAN * (1 + ARTIS * (sira - 1))); } } const ort = (x) => (x.length ? x.reduce((a, b) => a + b, 0) / x.length : 0); const teslimsiz = olay.filter((o) => !teslim.has(o.id)).length; return { bildirim: U.length, kisi: U.length / GUN, eyleme: eyleme / U.length * 100, kapsanan: gorulen.size, teslimsiz, korOlay: olay.length - gorulen.size - teslimsiz, yanit: ort(sure), korlenen, yorgun: siralar.filter((x) => x >= yorgunlukEsigi).length / U.length * 100 }; } const ASAMA = [["ham akis", uyari]]; ASAMA.push(["gruplama", gruplama(ASAMA[0][1])]); ASAMA.push(["+ susturma", susturma(ASAMA[1][1])]); ASAMA.push(["+ bagimlilik bastirma", bastirma(ASAMA[2][1])]); console.log(`yorgunluk esigi: ${yorgunlukEsigi}. uyaridan sonra yanit suresi tabanin iki kati ` + `(${TABAN} dk -> ${(TABAN * (1 + ARTIS * (yorgunlukEsigi - 1))).toFixed(1)} dk)\n`); console.log(`${"asama".padEnd(22)}${"bildirim".padStart(9)}${"gun".padStart(6)}${"eyleme donen".padStart(14)}` + `${"kapsanan".padStart(10)}${"teslimsiz".padStart(11)}${"korlenen".padStart(10)}` + `${"olay yaniti".padStart(12)}${"esik ustu".padStart(11)}`); const sonuc = ASAMA.map(([ad, U]) => { const d = olc(U); console.log(`${ad.padEnd(22)}${String(d.bildirim).padStart(9)}${d.kisi.toFixed(1).padStart(6)}` + `${`%${d.eyleme.toFixed(1)}`.padStart(14)}${`${d.kapsanan}/${olay.length}`.padStart(10)}` + `${String(d.teslimsiz).padStart(11)}${String(d.korOlay).padStart(10)}` + `${`${d.yanit.toFixed(1)} dk`.padStart(12)}${`%${d.yorgun.toFixed(0)}`.padStart(11)}`); return d; }); const [ilk, son] = [sonuc[0], sonuc[3]]; console.log(`\nkisi basina ${GUN / NOBETCI} nobet gunu: ham akista ` + `${(ilk.bildirim / NOBETCI).toFixed(0)} bildirim, suzgeclerden sonra ${(son.bildirim / NOBETCI).toFixed(0)}`); console.log(`okunmadan kapatilan uyari ${ilk.korlenen} -> ${son.korlenen}`); const kalan = olay.filter((o) => !ASAMA[3][1].some((u) => u.olay === o.id)); console.log(`suzgeclerin teslim etmedigi gercek olay ${kalan.length}: ` + `${kalan.map((o) => `${o.id}. olay (${o.servis})`).join(", ") || "yok"}`); for (const [ad, once, sonra] of [["gruplama", ASAMA[0][1], ASAMA[1][1]], ["susturma", ASAMA[1][1], ASAMA[2][1]]]) { const k = once.filter((u) => !sonra.includes(u)); console.log(`${ad} ${k.length} bildirim kaldirdi, ${k.filter((u) => u.olay !== null).length}'i olayli`); } console.log(`\n${"bastirma penceresi".padEnd(20)}${"kaldirilan".padStart(11)}${"turev".padStart(7)}` + `${"bagimsiz olay".padStart(15)}${"gurultu".padStart(9)}${"teslimsiz olay".padStart(16)}`); for (const w of [15, 45, 120, 360]) { PENCERE.bagimlilik = w; const B = bastirma(ASAMA[2][1]), kaldirilan = ASAMA[2][1].filter((u) => !B.includes(u)); const teslimsiz = olay.filter((o) => !B.some((u) => u.olay === o.id)).length; console.log(`${`${w} dk`.padEnd(20)}${String(kaldirilan.length).padStart(11)}` + `${String(kaldirilan.filter((u) => u.turev).length).padStart(7)}` + `${String(kaldirilan.filter((u) => u.olay !== null && !u.turev).length).padStart(15)}` + `${String(kaldirilan.filter((u) => u.olay === null).length).padStart(9)}` + `${String(teslimsiz).padStart(16)}`); }
yorgunluk esigi: 7. uyaridan sonra yanit suresi tabanin iki kati (4 dk -> 8.3 dk) asama bildirim gun eyleme donen kapsanan teslimsiz korlenen olay yaniti esik ustu ham akis 268 8.9 %3.0 8/20 0 12 7.8 dk %80 gruplama 247 8.2 %3.2 8/20 0 12 7.6 dk %77 + susturma 208 6.9 %5.8 12/20 0 8 7.8 dk %64 + bagimlilik bastirma 191 6.4 %6.8 13/20 0 7 7.8 dk %59 kisi basina 15 nobet gunu: ham akista 134 bildirim, suzgeclerden sonra 96 okunmadan kapatilan uyari 152 -> 40 suzgeclerin teslim etmedigi gercek olay 0: yok gruplama 21 bildirim kaldirdi, 18'i olayli susturma 39 bildirim kaldirdi, 1'i olayli bastirma penceresi kaldirilan turev bagimsiz olay gurultu teslimsiz olay 15 dk 15 14 0 1 0 45 dk 17 14 0 3 0 120 dk 25 15 3 7 3 360 dk 46 16 6 24 6
Yorgunluğun Sayısı
Yorgunluk eşiği hesaptan çıkıyor: yedinci uyarıdan sonra yanıt süresi tabanın iki katına, 4 dakikadan 8,3 dakikaya çıkıyor. Ham akışta bildirimlerin yüzde 80’i bu eşiğin üstünde bir sırada geliyor. Yani nöbetçiye ulaşan uyarıların beşte dördü, o kişinin son yirmi dört saatte zaten altı uyarı aldığı bir anda geliyor.
Sonucu üçüncü sütun taşıyor. Ham akışta yirmi gerçek olayın yalnız sekizi görülüyor; on ikisi okunmadan kapatılan uyarıların içinde kalıyor. Hiçbir uyarı kaybolmadı, hiçbir kural yanlış yazılmadı, teslim edilmeyen olay sıfır — olaylar yalnızca sırada çok gerideydiler.
Süzgeçler bu sayıyı sekizden on üçe çıkarıyor. Kazancın kaynağı şudur: süzgeçler hiçbir yeni bilgi eklemiyor, aynı bilgiyi daha az bildirimle veriyor; gürültü kalktıkça gerçek olayın bildirimi sıranın önüne geliyor. Eyleme dönen bildirim oranı yüzde 3,0’dan 6,8’e, yani iki katına çıkıyor — ve yine de bildirimlerin yüzde 93’ü bir işe dönüşmüyor.
Üç süzgecin katkısı eşit değil. Gruplama 21 bildirim kaldırdı ve bunların 18’i olaylıydı: aynı olayda aynı servisin birkaç kuralı birden çalıyor ve gruplama bunları tek bildirimde topluyor. Kaldırılan bildirim sayısı küçük, çünkü gürültü tek bir servise toplanmıyor, on dört kurala dağılıyor. Susturma tam tersi: 39 bildirim kaldırdı ve yalnız biri olaylıydı. Görülen olay sayısını sekizden on ikiye çıkaran adım bu — üç gürültücü kuralın günlük payı kesilince nöbetçinin sırası kısalıyor ve arkada kalan gerçek olaylar eşiğin altına iniyor.
Görülen olayların yanıt süresi ise değişmiyor: dört aşamada da 7,8 dakika. Bunun nedeni süzgeçlerin sıranın kendisini değil sayısını düşürmesidir — yeni görülen olaylar da yüksek sıralarda geliyor. Kazanç yanıt süresinde değil, görülen olay sayısındadır.
Bastırmanın Bedeli
Bağımlılık bastırması en tehlikeli süzgeçtir, çünkü bilgi siler. Pencere taraması bedeli gösteriyor. On beş dakikalık pencerede kaldırılan 15 bildirimin 14’ü türev, biri gürültü; hiçbir bağımsız olayın kendi uyarısı silinmiyor. Kırk beş dakikada tablo aynı: türev kazancı 14’te duruyor, çünkü türev uyarılar zaten olayın ilk kırk beş dakikasında doğuyor.
Pencereyi büyütmek bundan sonrası için yalnız zarar veriyor. Yüz yirmi dakikada üç bağımsız olayın kendi uyarısı bastırılıyor ve üç gerçek olay hiçbir bildirim almıyor; üç yüz altmış dakikada bu sayı altıya çıkıyor. Bastırma penceresi, bağımlılığın etkisinin sürdüğü süreye göre seçilir; daha uzunu üstteki servisin kendi olayını bağımlılığın gölgesinde bırakır.
Buradaki asıl ayrım şudur: gruplama ve susturma bildirimi geciktirir ya da toplar, bağımlılık bastırması ise bildirimi yok eder. İlk ikisinin hatası fark edilir, üçüncüsünün hatası fark edilmez — bastırılan uyarı hiçbir listede görünmez.
Özet
- Otuz günlük akışta 268 uyarının 212’si hiçbir olaya bağlı değildi; tek bir gürültücü kural 70 uyarı üretti ve bunların yalnız ikisi bir olaya denk geldi.
- Yorgunluk eşiği yedinci uyarıdır: o sıradan sonra yanıt süresi 4 dakikadan 8,3 dakikaya çıkıyor ve ham akışta bildirimlerin yüzde 80’i bu eşiğin üstünde geliyor.
- Ham akışta yirmi gerçek olayın sekizi görüldü; on ikisi teslim edildiği hâlde okunmadan kapatıldı — kayıp toplamada değil, sıradaydı.
- Üç süzgeç bildirimi 268’den 191’e, gün başına 8,9’dan 6,4’e indirdi; görülen olay sekizden on üçe, eyleme dönen bildirim oranı yüzde 3,0’dan 6,8’e çıktı. Görülen olayı asıl artıran susturma oldu: kaldırdığı 39 bildirimin yalnız biri olaylıydı.
- Görülen olayların yanıt süresi dört aşamada da 7,8 dakika kaldı: süzgeçler sırayı değil sayıyı düşürüyor, kazanç görülen olay sayısında.
- Bağımlılık bastırmasının kazancı kırk beş dakikada doyuyor; yüz yirmi dakikalık pencerede üç, üç yüz altmış dakikalık pencerede altı gerçek olay hiçbir bildirim almıyor.
Sonraki Adım
Bu ders boyunca her sinyal gerçek trafikten doğdu: bir istek geldi, bir kural çaldı, bir kişi uyarıldı. Gerçek trafiğin görmediği durumlar da vardır. Gece üç ile beş arasında fatura sorgusu neredeyse hiç gelmez; o saatte bozulan bir akış sabah dokuza kadar hiçbir uyarı üretmez, çünkü uyarıyı doğuracak istek yoktur. Yılda birkaç kez kullanılan bir akış aylardır bozuk olabilir. Dış bir bağımlılığın kendi arızası ise ancak birisi ona istek gönderdiğinde görünür. Sonraki ders dışarıdan periyodik yoklama kurar, yoklama sıklığını tarayarak fark etme gecikmesiyle yoklama maliyetini birlikte ölçer ve yoklamanın geçtiği hâlde gerçek kullanıcı akışının bozuk olduğu durumu adıyla yazar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.