Ders 01 / 18
Ölçüt Toplama Modelleri
Çekme ve itme temelli toplama aynı pencerede koşturulur ve işletimde gerçekten sorulan on iki sorudan oluşan bir kümeye uygulanır: hangi model kaç soruyu yanıtlıyor, kısa ömürlü iş çekmede neden kaçıyor, itmede kaynak kimliği neden karışıyor, keşif gecikmesi ve soru başına bayt ne kadar.
İçindekiler
Bir önceki kursun kapanışı altyapının kayda bağlandığı, her değişikliğin bir gözden geçirmeden ve bir kapıdan geçtiği noktada bitti. Ama kapıdan geçtikten sonra sistemin koşarken ne yaptığını kimse görmüyordu. Bu kursun ilk sorusu oradan devralınır ve bir adım daha ileri gider: neyin ölçüleceğine kim karar veriyor?
Bu kursun ölçü birimi veri değil, sorudur. Bir toplama kurulumunun iyi olup olmadığı kaç gigabayt biriktirdiğiyle değil, işletimde gerçekten sorulan sorulardan kaçını yanıtladığıyla ölçülür. Bu ders o soru kümesini kurar ve iki toplama modelini — çekme temelli ve itme temelli — aynı pencerede koşturup kümeye uygular.
Ölçüm yine bölgesel ölçüm ağı üzerindedir: su sayaçlarından okuma toplayan, okumaları
doğrulayan, faturaya çeviren ve saha ekiplerine iş emri açan bir yazılım. Ağ da, ölçülen sayılar
da kurgudur; gerçek bir toplayıcı koşturulmaz, sayılan şey node ile kurulmuş bir
modeldir.
OG1. On iki soru kurgudur ve önceden yazılıdır; her sorunun gerektirdiği kaynak sınıfı, ölçüt
ve etiketler de öyle.
OG2. Envanter kurgudur: üç ortamda 29 uzun ömürlü örnek, bir saatlik pencerede 11 yeniden
başlatma ve 42 gecelik doğrulama koşumu.
OG3. Çekme temelli toplayıcı 15 saniyede bir kazır, hedef envanterini 30 saniyede bir
yeniler; itme temelli gönderici uzun ömürlü süreçte 10 saniyede bir boşaltır, toplu iş her adım
bitiminde gönderir.
OG4. Bir kayıt 16 bayt, bir seri künyesi 120 bayttır.
OG5. Bir kaynak sınıfı ancak ömürlerinin en az yüzde 90’ından ikişer ölçüm alınabiliyorsa
kapsam içinde sayılır; tek ölçüm bir değişimi göstermez.
OG6. Yeniden başlatma zamanları ve koşum süreleri kendi üretecimizle üretilir, tohum
20260901.
İşletimde Sorulan On İki Soru
Soru kümesi ölçüm aracının değil, işletimin ürünüdür: nöbet sırasında, sabah raporunda ve olay incelemesinde gerçekten sorulmuş cümlelerdir. Her soru üç şeye bağlanır — hangi kaynak sınıfından veri gerekiyor, hangi ölçüt, hangi etiketler.
// ag.mjs — bolgesel olcum agi modeli ve isletim soru kumesi. Ikisi de kurgudur. export const ORNEK = { // ortam -> servis -> uzun omurlu ornek uretim: { "okuma-toplayici": 8, dogrulayici: 6, faturalama: 4, "is-emri": 3 }, sinama: { "okuma-toplayici": 2, dogrulayici: 2, faturalama: 1, "is-emri": 1 }, gelistirme: { "okuma-toplayici": 1, dogrulayici: 1, faturalama: 0, "is-emri": 0 } }; export const UZUN_SAYISI = Object.values(ORNEK) .reduce((t, o) => t + Object.values(o).reduce((a, b) => a + b, 0), 0); export const OLCUT_UZUN = { "istek-sayisi": { sonuc: 5 }, "istek-suresi": { dilim: 12 }, "kuyruk-boyu": { kuyruk: 3 }, "islenen-okuma": { bolge: 11, sonuc: 5 }, "surec-baslangic-zamani": {}, "cop-toplama-duraklamasi": { kova: 8 }, "dosya-tanitici-sayisi": {} }; export const OLCUT_KISA = { "is-adimi-suresi": { adim: 6 }, "is-islenen-kayit": {} }; export const seri = (o) => Object.values(o) .reduce((t, e) => t + Object.values(e).reduce((c, k) => c * k, 1), 0); // isletimde gercekten sorulan on iki soru: [kimlik, metin, kaynak sinifi, olcut, gereken alanlar] export const SORU = [ ["S1", "hangi servis yavasladi", "uzun", "istek-suresi", ["servis"]], ["S2", "gecikmenin ust dilimi ne", "uzun", "istek-suresi", ["servis", "dilim"]], ["S3", "hangi ortamda hata artti", "uzun", "istek-sayisi", ["ortam", "sonuc"]], ["S4", "hangi surumden sonra bozuldu", "uzun", "istek-sayisi", ["surum"]], ["S5", "gecelik is kac okuma isledi", "kisa", "is-islenen-kayit", ["is"]], ["S6", "gecelik is dun neden gec bitti", "kisa", "is-adimi-suresi", ["is", "adim"]], ["S7", "hangi bolgenin okumasi dogrulanmadi", "uzun", "islenen-okuma", ["bolge", "sonuc"]], ["S8", "hangi ornek yeniden basladi", "uzun", "istek-sayisi", ["ornek"]], ["S9", "hangi dogrulama kosumu yavasti", "kisa", "is-adimi-suresi", ["is", "ornek"]], ["S10", "hangi hata kodu artti", "uzun", "istek-sayisi", ["sonuc"]], ["S11", "is emri kuyrugu neden birikti", "uzun", "kuyruk-boyu", ["servis", "kuyruk"]], ["S12", "bir fatura hangi okumadan uretildi", "istek", "-", ["islem-kimligi"]], ]; export const yanit = (kapsam, alan) => SORU.filter(([, , k, , a]) => kapsam.includes(k) && a.every((e) => alan.includes(e))); export const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648; export const KAYIT_BAYT = 16, SERI_BAYT = 120; export const mb = (b) => (b / 1024 ** 2).toFixed(1);
Üç kaynak sınıfı vardır. Uzun ömürlü olan, saatlerce koşan servis örneğidir. Kısa ömürlü olan, gecelik toplu işin her koşumudur; ortalama yarım dakika yaşar. İstek sınıfı tek bir işlemin kendisidir ve hiçbir ölçüt onu taşıyamaz, çünkü işlem kimliğinin kardinalitesi sınırsızdır. S12 bu yüzden baştan işaretlidir: bir ölçüt hattı onu ne kadar veri toplarsa toplasın yanıtlayamaz.
Çekme ve İtme Aynı Pencerede
İki model aynı bir saatlik pencerede koşturulur. Fark üç yerde toplanır: neyin görüldüğü (kapsam), ne zaman görüldüğü (keşif gecikmesi) ve kimin gördüğü olarak kaydedildiği (kaynak kimliği).
// topla.mjs — cekme ve itme temelli toplama ayni pencerede kosturulur ve soru kumesine uygulanir. import { ORNEK, UZUN_SAYISI, OLCUT_UZUN, OLCUT_KISA, seri, SORU, yanit, uretec, KAYIT_BAYT, SERI_BAYT, mb } from "./ag.mjs"; const PENCERE = 3600, KAZIMA = 15, ENVANTER = 30, ITME = 10; // saniye const rast = uretec(20260901); // tohum gorunur const omur = []; // 29 ornek pencere basindan, 11 yeniden baslatma for (let i = 0; i < UZUN_SAYISI; i++) omur.push({ sinif: "uzun", bas: 0, bit: PENCERE }); for (let i = 0; i < 11; i++) { const h = omur[Math.floor(rast() * UZUN_SAYISI)], t = 300 + Math.floor(rast() * 3000); h.bit = t; omur.push({ sinif: "uzun", bas: t + 20, bit: PENCERE }); } const kosum = Array.from({ length: 42 }, (_, i) => { // gecelik dogrulama kosumlari const bas = 60 + i * 80 + Math.floor(rast() * 30); return { sinif: "kisa", bas, bit: bas + 6 + Math.floor(rast() * 33) }; }); const hepsi = [...omur, ...kosum]; const cekme = (o) => { // envanter yenilendikten sonraki kazimalar const t = [], gorunur = Math.ceil(o.bas / ENVANTER) * ENVANTER; for (let s = Math.ceil(gorunur / KAZIMA) * KAZIMA; s < o.bit; s += KAZIMA) t.push(s); return t; }; const itme = (o) => { // surec kendi gonderir; kesif turu yok const t = []; if (o.sinif === "kisa") { // toplu is her adim bitiminde gonderir for (let a = 1; a <= 6; a++) t.push(o.bas + Math.round(((o.bit - o.bas) * a) / 6)); return t; } for (let s = o.bas + ITME; s < o.bit; s += ITME) t.push(s); return t; }; const kapsanan = (f, s) => hepsi.filter((o) => o.sinif === s && f(o).length >= 2).length; const toplam = (s) => hepsi.filter((o) => o.sinif === s).length; const kesif = (f) => { // yalniz pencere icinde baslayan omurler const g = omur.filter((o) => o.bas > 0).map((o) => f(o)[0] - o.bas); // yeniden baslayan ornekler return [(g.reduce((a, b) => a + b, 0) / g.length).toFixed(1), Math.max(...g)]; }; const ALAN = ["servis", "ortam", "surum", "sonuc", "dilim", "kuyruk", "bolge", "is", "adim"]; const MODEL = [["cekme", cekme, UZUN_SAYISI, kapsanan(cekme, "kisa")], // kimlik envanterden gelir ["itme", itme, omur.length, 3]]; // kimlik surecin kendi bildirimi, is sablonu sabit console.log(`bolgesel olcum agi (kurgu): ${UZUN_SAYISI} uzun omurlu ornek, ${Object.keys(ORNEK).length} ortam,` + ` ${omur.length - UZUN_SAYISI} yeniden baslatma, ${kosum.length} gecelik dogrulama kosumu`); console.log(`ornek basina ${seri(OLCUT_UZUN)} seri, kosum basina ${seri(OLCUT_KISA)} seri; pencere ${PENCERE} sn\n`); console.log("model uzun omur kisa omur kesif ort/azami kimlik uzun kimlik kisa"); const ozet = []; for (const [ad, f, kimlikU, kimlikK] of MODEL) { const [ort, azami] = kesif(f), ku = kapsanan(f, "uzun"), kk = kapsanan(f, "kisa"); const olcum = hepsi.reduce((t, o) => t + f(o).length * seri(o.sinif === "uzun" ? OLCUT_UZUN : OLCUT_KISA), 0); const seriSayisi = kimlikU * seri(OLCUT_UZUN) + kimlikK * seri(OLCUT_KISA); ozet.push([ad, ku, kk, olcum, seriSayisi, kimlikU === UZUN_SAYISI]); // kimlik yeniden baslatmada korunuyor mu console.log(`${ad.padEnd(7)}${String(`${ku}/${toplam("uzun")}`).padStart(9)}` + `${String(`${kk}/${toplam("kisa")}`).padStart(11)}${String(`${ort} / ${azami} sn`).padStart(18)}` + `${String(`${kimlikU}/${omur.length}`).padStart(14)}${String(`${kimlikK}/${kosum.length}`).padStart(13)}`); } console.log("\nsoru kumesine karsi (12 soru)"); console.log("model yanitlanan bayt/saat soru basina yanitsiz kalan"); for (const [ad, ku, kk, olcum, seriSayisi, kararli] of ozet) { const kapsam = [ku / toplam("uzun") >= 0.9 && "uzun", kk / toplam("kisa") >= 0.9 && "kisa"].filter(Boolean); const alan = kararli ? [...ALAN, "ornek"] : ALAN; // kimlik kararsizsa ornek etiketi yok const y = yanit(kapsam, alan), bayt = olcum * KAYIT_BAYT + seriSayisi * SERI_BAYT; console.log(`${ad.padEnd(7)}${String(`${y.length}/${SORU.length}`).padStart(9)}` + `${String(`${mb(bayt)} MB`).padStart(11)}${String(`${mb(bayt / y.length)} MB`).padStart(13)} ` + SORU.filter((s) => !y.includes(s)).map(([k]) => k).join(" ")); } const bos = Object.keys(OLCUT_UZUN).filter((a) => !SORU.some(([, , , o]) => o === a)); const bosSeri = bos.reduce((t, a) => t + seri({ [a]: OLCUT_UZUN[a] }), 0); console.log(`\nhicbir soruyu yanitlamayan olcutler: ${bos.join(", ")}`); console.log(` ornek basina ${bosSeri}/${seri(OLCUT_UZUN)} seri (%${(100 * bosSeri / seri(OLCUT_UZUN)).toFixed(1)}),` + ` cekmede saatte ${mb(UZUN_SAYISI * bosSeri * (PENCERE / KAZIMA) * KAYIT_BAYT)} MB`); const kacan = kosum.length - kapsanan(cekme, "kisa"), RAPOR = 7 * 3600, BASLANGIC = 2 * 3600; const bekleme = kosum.reduce((t, o) => t + (RAPOR - BASLANGIC - o.bit), 0) / kosum.length / 3600; console.log(`cekmede seri uretmeyen ${kacan} kosum: basarisizlik ancak sabah raporunda,` + ` ortalama ${bekleme.toFixed(1)} saat sonra`);
bolgesel olcum agi (kurgu): 29 uzun omurlu ornek, 3 ortam, 11 yeniden baslatma, 42 gecelik dogrulama kosumu ornek basina 85 seri, kosum basina 7 seri; pencere 3600 sn model uzun omur kisa omur kesif ort/azami kimlik uzun kimlik kisa cekme 40/40 13/42 14.6 / 27 sn 29/40 13/42 itme 40/40 42/42 10.0 / 10 sn 40/40 3/42 soru kumesine karsi (12 soru) model yanitlanan bayt/saat soru basina yanitsiz kalan cekme 8/12 9.7 MB 1.2 MB S5 S6 S9 S12 itme 9/12 14.5 MB 1.6 MB S8 S9 S12 hicbir soruyu yanitlamayan olcutler: surec-baslangic-zamani, cop-toplama-duraklamasi, dosya-tanitici-sayisi ornek basina 10/85 seri (%11.8), cekmede saatte 1.1 MB cekmede seri uretmeyen 29 kosum: basarisizlik ancak sabah raporunda, ortalama 4.5 saat sonra
Uzun ömürlü tarafta iki model eşittir: kırk ömrün kırkı da her iki modelde kapsanır. Ayrım kısa ömürlü tarafta açılır. Çekme temelli toplayıcı 42 doğrulama koşumunun yalnız on üçünden iki ya da daha fazla ölçüm alabilir. Nedeni iki gecikmenin üst üste binmesidir: envanter otuz saniyede bir yenilenir, kazıma on beş saniyede bir yapılır, koşumların ortalama ömrü ise otuz saniyenin altındadır. Koşum, kendisini görecek olan turdan önce biter. Yirmi dokuz koşum hiçbir seri üretmeden geçer ve geçtikleri de görünmez — eksik seri bir hata değil, yalnız bir yokluktur.
İtme tarafında bu sorun yoktur, çünkü kimse koşumu keşfetmek zorunda değildir: koşum kendi verisini kendi gönderir ve her adım bitiminde bir kez daha gönderir. Kırk iki koşumun kırk ikisi kapsanır.
Kimlik sütunları ayrımı tersine çevirir. Çekmede kimlik envanterden gelir; bir örnek yeniden başladığında envanterdeki girdi aynı kaldığı için seri de aynı kalır — kırk ömür yirmi dokuz kimlik altında toplanır ve yeniden başlatma serideki boşlukla görünür. İtmede kimlik sürecin kendi bildirimidir; her yeni süreç kendine yeni bir kimlik üretir, kırk ömür kırk ayrı kimlik yaratır ve yeniden başlayan bir örnek ile hiç görülmemiş yeni bir örnek birbirinden ayırt edilemez. Kısa ömürlü tarafta aynı mekanizma ters yönde bozar: toplu iş şablonu iş adını sabit yazdığı için kırk iki koşum üç kimlik altında birleşir ve tek tek koşumlar birbirine karışır.
İki Modelin Yanıtsız Bıraktığı Sorular
Çekme sekiz soruyu yanıtlar, itme dokuz soruyu. Yanıtsız kalanlar aynı değildir ve bu, ders için tablonun en önemli satırıdır.
Çekmede S5, S6 ve S9 düşer: gecelik işin kaç okuma işlediği, dün neden geç bittiği ve hangi koşumun yavaş olduğu. Üçü de kısa ömürlü kaynak sınıfına bağlıdır ve o sınıf kapsam dışıdır. Bunun bedeli son satırdadır: seri üretmeyen yirmi dokuz koşumdan biri başarısız olduğunda bunu gösteren tek sinyal sabahki mutabakat raporudur; iş gece iki ile üç arasında koşarken rapor yediye kadar beklenir — ortalama dört buçuk saat. Faturalama zincirinin başındaki bir doğrulama koşumu sessizce düştüğünde o dört buçuk saat, düzeltilmesi gereken kayıt sayısına doğrudan çarpar.
İtmede S8 ve S9 düşer: hangi örneğin yeniden başladığı ve hangi doğrulama koşumunun yavaş olduğu.
İkisi de tek bir etiketin güvenilirliğine bağlıdır — ornek. Etiket teknik olarak vardır ve her
kayıtta yazılıdır; güvenilir olmayan şey, aynı örneğin iki farklı zamanda aynı değeri taşıyacağı
güvencesidir. Bu, toplamanın hiç veri kaybetmeden bir soruyu kapatabildiğini gösterir: veri
eksik değil, ölçülemez durumdadır.
S12 her iki modelde de yanıtsızdır ve bu ders boyunca öyle kalır. Bir faturanın hangi okumadan üretildiğini sormak, tek bir işlemin dört servis arasındaki yolunu istemek demektir; ölçüt hattı bu yolu taşıyamaz, çünkü taşımak için işlem kimliğini etiket yapmak gerekir ve o etiketin kardinalitesi işlem sayısı kadardır.
Hiçbir Soruyu Yanıtlamayan Ölçüt
Son blok, toplanan verinin hangi bölümünün karşılığı olmadığını sayar. Yedi ölçütün üçü — süreç başlangıç zamanı, çöp toplama duraklaması ve dosya tanıtıcı sayısı — on iki sorunun hiçbirinde geçmez. Örnek başına seksen beş serinin onu budur, yüzde on iki. Çekme modelinde saatte 1,1 megabayt, otuz günlük saklamada sekiz yüz megabayttan fazla eder ve karşılığında hiçbir soru kapanmaz.
Bu üç ölçüt kötü değildir; birer sorusu olmadığı için maliyettir. Çöp toplama duraklaması yarın bir soru kümesine girerse aynı bayt anlamlı olur. Ölçüyü kuran şey ölçütün kendisi değil, onu isteyen sorunun varlığıdır.
Soru başına maliyet iki modeli aynı ölçekte karşılaştırmayı sağlar: çekme 1,2, itme 1,6 megabayt. İtme daha fazla soru yanıtlar ama soru başına yüzde otuz daha pahalıdır, çünkü on saniyelik gönderim aralığı on beş saniyelik kazımadan sık, kimlik çoğalması da seri sayısını kırk kimliğe yayıyor. “Hangisi daha iyi” sorusunun yanıtı tek bir sayıda değil, bu iki sütunun birlikte okunmasındadır.
Özet
- Soru kümesi on iki sorudan oluşur; her soru bir kaynak sınıfına, bir ölçüte ve bir etiket kümesine bağlıdır. Ölçü birimi toplanan bayt değil, yanıtlanan sorudur.
- Çekme temelli toplama 42 kısa ömürlü koşumun 13’ünü kapsar; envanter yenileme (30 sn) ile kazıma (15 sn) gecikmeleri üst üste bindiği için koşum kendisini görecek turdan önce biter.
- İtme temelli toplama kısa ömürlünün 42/42’sini kapsar ama kimliği süreç bildirdiği için 40 ömür 40 ayrı kimlik üretir; kısa ömürlü tarafta 42 koşum 3 kimlik altında birleşir.
- Çekme 8/12, itme 9/12 soru yanıtlar; yanıtsız kalanlar kesişmez — çekmede S5, S6, S9, itmede S8, S9. S12 (bir faturanın hangi okumadan üretildiği) iki modelde de yanıtsızdır.
- Toplanan ölçütlerin 10/85 serisi (%11,8) hiçbir soruyu yanıtlamaz; çekmede saatte 1,1 MB. Soru başına maliyet çekmede 1,2, itmede 1,6 MB.
- Kapsanmayan koşumun bedeli sayıya bağlanır: seri üretmeyen 29 koşumdan birinin başarısızlığı ortalama 4,5 saat sonra, sabah raporunda görünür.
Sonraki Adım
Bu derste toplanan veri bir kutu gibi ele alındı: ölçüm sayısı, seri sayısı, bayt. Oysa serinin
kendisi bir yapıdır ve o yapının içinde bir karar durur — hangi etiketler var. Yanıtlanan sekiz
ya da dokuz sorunun her biri belirli bir etiketin varlığına bağlıydı; ornek etiketi düştüğünde
iki soru kapandı. Bir sonraki ders bu bağı ters yönden ölçer: bir etiket eklemek hangi soruyu
açıyor, kaç seriye ve kaç bayta mal oluyor, ve hangi etiket eklendiğinde hiçbir soru açılmıyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.