İçeriğe geç
academia.sh

Ders 08 / 19

Altın Sinyaller

Gecikme, trafik, hata ve doygunluğun ödünç sisteminin yedi günlük kayıtlarından hesaplanması: altı olay sınıfı üzerinde her sinyalin tek başına kaçırdığı olayların sayılması, doygunluğun hatadan kaç dakika önce tetiklediğinin ölçülmesi ve dört sinyalin birlikte bile göremediği sessiz kaybın gösterilmesi.

İçindekiler

Önceki ders üç gösterge tanımını tek bir kötü istek ölçütü üzerine kurdu: durum kodu ya da süre. Ödünç sisteminde bir isteğin kötüye gitmesinin tek yolu bu değil. Katalog servisi hiç hata döndürmeden yavaşlayabilir, bildirim kuyruğu hatasız çalışırken dolabilir, ücret servisine hiç istek gelmemesi tek başına bir arıza belirtisi olabilir. Bunların hepsi aynı telemetride yazılıdır, ama tek bir orana bakan gösterge bir kısmını göremez.

Bu ders aynı kayıtlardan dört sinyal hesaplar, altı ayrı olay sınıfının üzerinden geçirir ve her sinyalin tek başına neyi kaçırdığını sayar.

Dört Sinyal, Dört Ayrı Soru

  • Gecikme: bir isteğin ne kadar sürdüğü. Sorusu “yavaş mı”.
  • Trafik: birim zamanda kaç istek geldiği. Sorusu “yük ne”.
  • Hata: kaç isteğin başarısız döndüğü. Sorusu “bozuk mu”.
  • Doygunluk: sistemin en kıt kaynağının ne kadarının dolu olduğu. Sorusu “ne kadar yerim kaldı”.

Dördü bir arada seçilir çünkü ilk üçü olmuş olanı, dördüncüsü olacak olanı anlatır. Bu sinyalin adı Sistem Tasarımına Giriş kursunda doyum olarak geçen kavramın aynısıdır; sinyal listesinin katalog biçimi olduğu için burada doygunluk yazılır.

İlk üçü istek kaydından doğrudan çıkar. Doygunluk çıkmaz: kıt kaynağın ne olduğu uygulamaya özgüdür ve kodda açıkça ölçülmek zorundadır. Bölünmüş ödünç sisteminde bu kaynak bildirim kuyruğudur; her bildirim isteği kuyruğa yazılırken o anki derinliği kendi kaydına da yazar. Kuyruk derinliği bir ölçerdir, sayaç değil: artar ve azalır.

Yedi Günlük Kayıt ve Altı Olay Sınıfı

// sinyal/kayit.mjs — odunc sisteminin 7 gunluk istek kaydi ve bildirim kuyrugu olceri.
// Kayit: [dakika, servis, durum, sure_ms, kuyruk_derinligi, teslim(-1: bildirim disi)].
export const DK = 7 * 1440, TOHUM = 20260731, SINIR = 500, TUKETIM = 25;
export const SERVIS = ["katalog", "uyelik", "odunc", "bildirim", "ucret"];
const TABAN = [40, 25, 60, 30, 45];
// SD1 (varsayim): dakikada 08-22 arasi 100, disinda 30 istek; 0. gun olaysizdir (taban gunu).
// SD2 (varsayim): alti olay sinifi [gun, saat, sure dk, ad].
export const OLAY = [
  [1, 10, 60, "hata patlamasi"], [2, 14, 90, "sessiz yavaslama"],
  [3, 3, 120, "trafik cokusu"], [4, 15, 120, "kuyruk doygunlugu"],
  [5, 12, 30, "trafik sicramasi"], [6, 9, 180, "sessiz teslim kaybi"],
];
export const pencere = (i) => [OLAY[i][0] * 1440 + OLAY[i][1] * 60, OLAY[i][2]];

export function kayitlar() {
  let s = TOHUM;
  const rast = (n) => Math.floor(((s = (s * 1664525 + 1013904223) >>> 0) / 2 ** 32) * n);
  const k = [];
  let kuyruk = 0;
  for (let t = 0; t < DK; t += 1) {
    const saat = Math.floor(t / 60) % 24;
    const ic = (i) => t >= pencere(i)[0] && t < pencere(i)[0] + OLAY[i][2];
    let n = saat >= 8 && saat < 22 ? 100 : 30;
    if (ic(2)) n = Math.round(n * 0.1);
    if (ic(4)) n = Math.round(n * 2.5);
    kuyruk = Math.max(0, kuyruk - (ic(3) ? 14 : TUKETIM));
    for (let i = 0; i < n; i += 1) {
      const sv = rast(5);
      let durum = 200, sure = TABAN[sv] + rast(60), teslim = -1;
      if (rast(1000) < 1) durum = 500;
      if (ic(0) && rast(1000) < 80) durum = 500;
      if (ic(1) && sv === 0) sure += 700 + rast(400);
      if (sv === 3 && durum === 200) {
        if (kuyruk >= SINIR) durum = 503;
        else { kuyruk += 1; teslim = rast(1000) < (ic(5) ? 970 : 4) ? 0 : 1; }
      }
      k.push([t, SERVIS[sv], durum, sure, kuyruk, teslim]);
    }
  }
  return k;
}

if (import.meta.filename === process.argv[1]) {
  const K = kayitlar();
  console.log(`tohum ${TOHUM}, ${DK} dakika, ${K.length} istek, kuyruk siniri ${SINIR}`);
  console.log(`olay siniflari: ${OLAY.map((o) => o[3]).join(", ")}`);
}
tohum 20260731, 10080 dakika, 715260 istek, kuyruk siniri 500
olay siniflari: hata patlamasi, sessiz yavaslama, trafik cokusu, kuyruk doygunlugu, trafik sicramasi, sessiz teslim kaybi

Altı olay sınıfı ayrı ayrı seçildi: biri yalnız durum kodunu, biri yalnız süreyi, biri yalnız istek sayısını, biri yalnız kuyruğu kıpırdatır. Sonuncusunda bildirim istekleri 200 döner, süreleri değişmez, kuyruk normal boşalır — ama gönderilen bildirim üyeye ulaşmaz.

Dördünü Hesaplamak

Her sinyal bir eşikle karara çevrilir. Gecikme ve trafik eşiği olaysız 0. günden türetilir, hata ve doygunluk eşiği sabittir. Bir sinyalin olayı yakalamış sayılması için pencere içinde üst üste üç dakika tetiklemesi gerekir; tek dakikalık tetik sayılmaz.

// sinyal/altin.mjs — dort altin sinyalin ayni kayitlardan dakika dakika hesaplanmasi ve her
// sinyalin tek basina hangi olay sinifini kacirdiginin sayilmasi. Yakalama olcutu: pencere
// icinde ust uste 3 dakika tetiklemek.
import { kayitlar, DK, OLAY, pencere, SINIR } from "./kayit.mjs";
const K = kayitlar();
const say = new Int32Array(DK), hat = new Int32Array(DK), kuy = new Int32Array(DK);
const ms = Array.from({ length: DK }, () => []);
for (const [t, , durum, sure, kuyruk] of K) {
  say[t] += 1; ms[t].push(sure); kuy[t] = Math.max(kuy[t], kuyruk);
  if (durum >= 500) hat[t] += 1;
}
const p95 = (a) => [...a].sort((x, z) => x - z)[Math.floor(a.length * 0.95)];
const gec = new Int32Array(DK);
for (let t = 0; t < DK; t += 1) gec[t] = say[t] ? p95(ms[t]) : 0;

// SD3 (varsayim): gecikme ve trafik esigi 0. gunden turetilir, hata ve doygunluk esigi sabittir.
const P95 = p95(K.filter((r) => r[0] < 1440).map((r) => r[3])), st = new Float64Array(24);
for (let t = 0; t < 1440; t += 1) st[Math.floor(t / 60)] += say[t] / 60;
const T = {
  gecikme: (t) => gec[t] > 2 * P95,
  trafik: (t) => say[t] < 0.5 * st[Math.floor(t / 60) % 24] || say[t] > 2 * st[Math.floor(t / 60) % 24],
  hata: (t) => say[t] > 0 && hat[t] / say[t] > 0.01,
  doygunluk: (t) => kuy[t] / SINIR > 0.85,
};
const AD = Object.keys(T);
const ilk3 = (a, bas, sr) => {
  for (let t = bas, ard = 0; t < bas + sr; t += 1)
    if ((ard = T[a](t) ? ard + 1 : 0) === 3) return t - bas - 2;
  return -1;
};
console.log(`taban p95 ${P95} ms, gecikme esigi ${2 * P95} ms, hata esigi %1, ` +
  `doygunluk esigi ${0.85 * SINIR}/${SINIR}\n`);
console.log(`${"olay sinifi".padEnd(22)}${"sure".padStart(7)}` +
  `${AD.map((a) => a.padStart(14)).join("")}${"yakalayan".padStart(11)}`);
const tut = AD.map(() => new Set());
OLAY.forEach(([, , sr, ad], i) => {
  const [bas] = pencere(i);
  const s = AD.map((a) => {
    let n = 0;
    for (let t = bas; t < bas + sr; t += 1) if (T[a](t)) n += 1;
    return [n, ilk3(a, bas, sr)];
  });
  s.forEach(([, k], j) => { if (k >= 0) tut[j].add(i); });
  console.log(`${ad.padEnd(22)}${(sr + " dk").padStart(7)}` +
    `${s.map(([n, k]) => (k >= 0 ? `${n} dk / ${k}.dk` : "-").padStart(14)).join("")}` +
    `${String(s.filter(([, k]) => k >= 0).length).padStart(11)}`);
});
const ici = (t) => OLAY.some((o, i) => t >= pencere(i)[0] && t < pencere(i)[0] + o[2]);
console.log(`\n${"sinyal".padEnd(12)}${"yakaladigi".padStart(11)}${"olay disi tetik".padStart(17)}` +
  `  kacirdigi olay siniflari`);
AD.forEach((a, j) => {
  let d = 0;
  for (let t = 0; t < DK; t += 1) if (T[a](t) && !ici(t)) d += 1;
  console.log(`${a.padEnd(12)}${`${tut[j].size}/${OLAY.length}`.padStart(11)}${(d + " dk").padStart(17)}` +
    `  ${OLAY.filter((_, i) => !tut[j].has(i)).map((o) => o[3]).join(", ")}`);
});
const hepsi = new Set(tut.flatMap((s) => [...s]));
console.log(`\ndordu birlikte: ${hepsi.size}/${OLAY.length} olay sinifi; ` +
  `kacan: ${OLAY.filter((_, i) => !hepsi.has(i)).map((o) => o[3]).join(", ")}`);
const teslim = (a, b) => {
  const bs = K.filter((r) => r[5] >= 0 && r[0] >= a && r[0] < b);
  return `%${((100 * bs.filter((r) => r[5] === 1).length) / bs.length).toFixed(1)}`;
};
const [b5, s5] = [pencere(5)[0], OLAY[5][2]];
console.log(`teslim orani: olay oncesi ${teslim(b5 - s5, b5)}, olay sirasinda ${teslim(b5, b5 + s5)}`);
let dusuk = 0, disi = 0, ilkKuyruk = -1;
for (let t = 0; t < DK; t += 1) if (!ici(t)) {
  if (T.hata(t)) { disi += 1; if (say[t] <= 40) dusuk += 1; }
  if (T.doygunluk(t) && ilkKuyruk < 0) ilkKuyruk = t;
}
const [bd, sd] = [pencere(3)[0], OLAY[3][2]];
console.log(`hatanin olay disi ${disi} tetiginin ${dusuk} tanesi 40 istek/dk altindaki ` +
  `dakikalarda; doygunlugun olay disi ilk tetigi ${ilkKuyruk}. dakika, olay ${bd + sd}. dakikada bitti`);
console.log(`kuyruk doygunlugunda: doygunluk ${ilk3("doygunluk", bd, sd)}. dakikada, ` +
  `hata ${ilk3("hata", bd, sd)}. dakikada yakaladi`);
taban p95 105 ms, gecikme esigi 210 ms, hata esigi %1, doygunluk esigi 425/500

olay sinifi              sure       gecikme        trafik          hata     doygunluk  yakalayan
hata patlamasi          60 dk             -             -  60 dk / 0.dk             -          1
sessiz yavaslama        90 dk  90 dk / 0.dk             -             -             -          1
trafik cokusu          120 dk             - 120 dk / 0.dk             -             -          1
kuyruk doygunlugu      120 dk             -             - 43 dk / 72.dk 59 dk / 61.dk          2
trafik sicramasi        30 dk             -  30 dk / 0.dk 12 dk / 18.dk 15 dk / 15.dk          3
sessiz teslim kaybi    180 dk             -             -             -             -          0

sinyal       yakaladigi  olay disi tetik  kacirdigi olay siniflari
gecikme             1/6             0 dk  hata patlamasi, trafik cokusu, kuyruk doygunlugu, trafik sicramasi, sessiz teslim kaybi
trafik              2/6             0 dk  hata patlamasi, sessiz yavaslama, kuyruk doygunlugu, sessiz teslim kaybi
hata                3/6           162 dk  sessiz yavaslama, trafik cokusu, sessiz teslim kaybi
doygunluk           2/6            23 dk  hata patlamasi, sessiz yavaslama, trafik cokusu, sessiz teslim kaybi

dordu birlikte: 5/6 olay sinifi; kacan: sessiz teslim kaybi
teslim orani: olay oncesi %99.7, olay sirasinda %3.0
hatanin olay disi 162 tetiginin 136 tanesi 40 istek/dk altindaki dakikalarda; doygunlugun olay disi ilk tetigi 6780. dakika, olay 6780. dakikada bitti
kuyruk doygunlugunda: doygunluk 61. dakikada, hata 72. dakikada yakaladi

Her Sinyalin Kör Noktası

Hiçbir sinyal altı olayın dördünden fazlasını görmüyor. Gecikme altıda birini, trafik ile doygunluk altıda ikisini, hata altıda üçünü yakalıyor. Bu sayılar sinyallerin kalitesiyle ilgili değil: her biri başka bir soruyu yanıtladığı için başka bir olay sınıfını kaçırıyor.

En öğretici satır trafik çöküşüdür. İki saat boyunca istek sayısı onda birine düşüyor; hata oranı bu sırada sıfır, gecikme taban değerinde, kuyruk boş. Yalnız hata oranına bakan bir gösterge o iki saatte yüzde yüz başarı görür, çünkü gelen az sayıda isteğin hepsi başarılı dönmüştür. Bir üst katmandaki üretici durduğunda ya da bir yönlendirme bozulduğunda görülen tablo tam olarak budur: oran temizdir, çünkü bölen çökmüştür.

Kuyruk doygunluğu satırı sinyalin zaman değerini veriyor. Bildirim tüketicisi yavaşlıyor ve kuyruk dakikada altı bildirim büyüyor. Doygunluk 61. dakikada üç dakikalık eşiğini geçiyor; kuyruk sınıra dayanıp bildirim istekleri reddedilmeye başladığında hata sinyali de tetikliyor, ama bu 72. dakikada oluyor. Aradaki 11 dakika, arızanın üyeye ulaşmadan önce müdahale edilebildiği süredir. Doygunluk ölçülmezse o on bir dakika kaybedilir ve olay ilk kez düşen isteklerle görünür.

Olay dışı tetikler iki ayrı şeyi gösteriyor. Hata sinyalinin 162 tetiğinin 136’sı dakikada 40’ın altında istek alan dakikalarda: gece trafiğinde bölen 30 iken tek bir 5xx yüzde 3,3 eder ve yüzde 1’lik eşiği aşar. Oran tabanlı bir sinyal, bölen küçüldükçe gürültülenir — önceki dersin bölen tartışması burada uyarı gürültüsü olarak geri döner. Doygunluğun 23 tetiği ise yanlış değil: ilki tam olarak kuyruk doygunluğu olayının bittiği 6780. dakikada başlıyor ve kuyruğun boşalma süresini ölçüyor. Sinyalin penceresi olayın penceresiyle aynı olmak zorunda değildir.

Dördünün Birlikte Göremediği

Dört sinyal birlikte altı olay sınıfının beşini kapsıyor. Kaçan altıncısı sessiz teslim kaybı: bildirim istekleri 200 dönüyor, süreleri değişmiyor, kuyruk normal boşalıyor, hiçbir eşik kıpırdamıyor. Aynı kayıtların içindeki teslim alanı ise olaydan önce yüzde 99,7, olay sırasında yüzde 3,0 diyor.

Buradaki ayrım kalıcıdır: dört altın sinyal taşımayı ölçer, doğruluğu ölçmez. Bir isteğin kabul edilmesi, hızlı yanıtlanması ve kaynak tüketmemesi, işin yapıldığı anlamına gelmez. Ödünç sisteminde işin yapılmış olması “gecikme bildirimi üyeye ulaştı” demektir ve bunu ancak iş düzeyinde bir sayaç söyler. Dört sinyal her servise aynı biçimde konur; beşinci sayaç her servis için ayrı düşünülmek zorundadır ve bu yüzden çoğu zaman hiç yazılmaz.

Özet

  • Dört altın sinyal dört ayrı soru sorar: gecikme “yavaş mı”, trafik “yük ne”, hata “bozuk mu”, doygunluk “ne kadar yerim kaldı”; doygunluk Sistem Tasarımına Giriş kursundaki doyum ile aynı kavramdır.
  • İlk üçü istek kaydından doğrudan çıkar; doygunluk çıkmaz ve kıt kaynak kodda ölçülmek zorundadır — burada her bildirim isteği kuyruk derinliğini kendi kaydına yazar.
  • Altı olay sınıfında hiçbir sinyal tek başına üçten fazlasını yakalamadı: gecikme 1/6, trafik 2/6, doygunluk 2/6, hata 3/6.
  • Trafik çöküşünde hata oranı sıfırdır ve gösterge kusursuz görünür; oran tabanlı sinyal bölen çöktüğünde kör kalır, bölen küçüldüğünde gürültülenir (162 olay dışı tetiğin 136’sı 40 istek/dk altındaki dakikalarda).
  • Doygunluk, kuyruk dolarken 61. dakikada tetikledi; hata ancak istekler reddedilmeye başlayınca 72. dakikada tetikledi — 11 dakikalık erken uyarı.
  • Dördü birlikte altı sınıfın beşini kapsıyor; kaçan sınıf sessiz teslim kaybıdır (teslim oranı yüzde 99,7’den yüzde 3,0’a düştü), çünkü altın sinyaller taşımayı ölçer, doğruluğu ölçmez.

Sonraki Adım

Dört sinyal artık dakika dakika hesaplanıyor ve bir hedefle karşılaştırılabiliyor. Hedefin altına düşüldüğünde ne olacağı ise hâlâ yazılı değil. Ödünç sistemine haftada iki yayın da yapılabilir, on yayın da; her yayın kayıtlarda ölçülebilir bir bozulma bırakır ve hedefin altında kalan her dakika bir yerden ödenir. Sonraki ders bu ödemeyi telemetriden hesaplar: aynı istek kayıtlarından bir bütçe çıkarır, iki farklı yayın hızının bu bütçeyi hangi hızla tükettiğini sayar ve bütçe bittiğinde kodda neyin değiştiğini gösterir.

İ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