İçeriğe geç
academia.sh

Ders 17 / 18

Okuma Modellerinin Türetilmesi

İzdüşümün olay kütüğünden yansıtmayla kurulması ve sıfırdan yeniden üretilmesi: artımlı bakımla yeniden üretimin aynı satırları vermesi, izdüşümün günlük artışa 192 MB ve saklanan veriye 140,16 GB eklemesi, açık pencerenin tam saklamaya göre 146 kat az olay okuması ve yeniden üretimin 2,11 saatlik gerilik penceresi ile yanında üretimin 140,16 GB'lık geçici yer bedeli.

İçindekiler

Önceki ders kütüğü yazma yolunun kaynağı yaptı ve bunun bedelini iki yerde gösterdi: saklanan veri 1,20 katına çıktı, dönemsel tarama 3,24 katına. İkinci sayı kütüğün asıl sınırıdır — bir sorgunun yanıtı sekiz olayın katlanmasından çıkıyorsa okuma yolu kütüğün uzunluğuna bağlıdır. Çözüm ilk derste görülmüştü: sorgunun istediği satırı hazır tutmak. Şimdi o satırın nereden türetildiği belli: kütükten.

Bu ders türetmenin kendisini ele alır. Yansıtma kütükteki olayların bir okuma modeline uygulanmasıdır; ürünü izdüşümdür (projection). Ölçülecek üç şey var: izdüşümün ne kadar yer tuttuğu, sıfırdan yeniden üretilmesinin kaç olay okuduğu ve yeniden üretim sürerken akan yeni olayların yakalanıp yakalanamadığı.

Bir Kütük, Birden Çok İzdüşüm

İzdüşüm bir katlama işlevidir: olay dizisini alır, satır üretir. Katlama saf olduğu için aynı kütük her zaman aynı satırları verir ve bu, izdüşümün atılabilir olmasını sağlar. Atılabilir olması ölçekleme açısından belirleyicidir — bir okuma modeli bozulduğunda, şeması değiştiğinde ya da yeni bir düğüme kopyalanması gerektiğinde yedekten değil kütükten kurulur.

Aynı kütükten birden çok izdüşüm türetilebilir ve her biri kendi erişim örüntüsüne göre biçimlenir. Bu konuda ikisi var: takip numarasına göre tekil okumayı karşılayan takip izdüşümü ve aktarma noktasına göre bekleyen gönderi sayısını tutan nokta sayacı. Birincinin satır sayısı gönderi sayısına, ikincinin satır sayısı aktarma noktası sayısına bağlıdır; ikisi aynı olaylardan beslenir. Önceden hesaplanmış sonuçların depo içinde tutulması bu kursun Veri Dağıtımı konusunda ayrıca ele alınıyor; buradaki fark, izdüşümün deponun değil kütüğün türevi olmasıdır.

// turetme/izdusum.mjs — olay kutugunden turetilen iki okuma modeli. Her izdusum bir katlama
// islevidir; sayaclar okunan olayi ve yazilan satiri ayri tutar. Surec ici modeldir.
export function takipIzdusumu(surum) {
  const satir = new Map();
  const s = { olay: 0, yazma: 0 };
  return {
    ad: `takip v${surum}`, satir, sayac: s,
    uygula(o) {
      s.olay += 1;
      if (o.tur === "gonderi-olusturuldu") {
        const r = { id: o.id, bolge: o.bolge, durum: "kabul-edildi", sonAdim: [] };
        if (surum === 2) r.aktarma = 0;
        satir.set(o.id, r);
        s.yazma += 1;
        return;
      }
      const r = satir.get(o.id);
      if (o.tur === "teslim-edildi") { r.durum = "teslim-edildi"; s.yazma += 1; return; }
      r.durum = "aktarmada";
      r.sonAdim = [...r.sonAdim, o.nokta].slice(-3);
      if (surum === 2) r.aktarma += 1;
      s.yazma += 1;
    },
    goruntu: () => JSON.stringify([...satir.entries()].sort()),
  };
}

// Ikinci okuma modeli: aktarma noktasina gore bekleyen gonderi sayaci. Ayni kutukten turetilir,
// satir sayisi gonderi sayisina degil nokta sayisina baglidir.
export function noktaIzdusumu() {
  const satir = new Map(), yer = new Map();
  const s = { olay: 0, yazma: 0 };
  return {
    ad: "nokta sayaci", satir, sayac: s,
    uygula(o) {
      s.olay += 1;
      if (o.tur === "gonderi-olusturuldu") return;
      const onceki = yer.get(o.id);
      if (onceki !== undefined) { satir.set(onceki, satir.get(onceki) - 1); s.yazma += 1; }
      if (o.tur === "teslim-edildi") { yer.delete(o.id); return; }
      satir.set(o.nokta, (satir.get(o.nokta) ?? 0) + 1);
      s.yazma += 1;
      yer.set(o.id, o.nokta);
    },
    goruntu: () => JSON.stringify([...satir.entries()].sort()),
  };
}

// Kutuk ureteci: her gonderi bir olusturma ve V4 aktarma olayi alir; kapali gonderiler
// ayrica teslim olayi tasir. Uretec sabittir, ayni girdi ayni kutugu verir.
export function kutukUret(sayi, olayBasina) {
  const NOKTA = ["34", "06", "35", "01", "16"];
  let x = 7;
  const sonraki = () => (x = (x * 48271 + 11) % 2147483647);
  const kutuk = [], acik = new Set();
  for (let i = 1; i <= sayi; i += 1) {
    const id = `G${i}`;
    kutuk.push({ tur: "gonderi-olusturuldu", id, bolge: NOKTA[sonraki() % NOKTA.length] });
    for (let k = 0; k < olayBasina; k += 1)
      kutuk.push({ tur: "aktarmaya-girdi", id, nokta: NOKTA[sonraki() % NOKTA.length] });
    if (i % 5 === 0) acik.add(id);
    else kutuk.push({ tur: "teslim-edildi", id });
  }
  return { kutuk, acik };
}

surum parametresi şema değişikliğini modelliyor: ikinci sürüm satıra bir aktarma sayacı ekler. Yeni alanın eski satırlara işlenmesinin tek yolu izdüşümü kütükten yeniden üretmektir.

Ölçüm

Ölçüm iki katmanlıdır. Model katmanı türetmenin doğruluğunu ve olay başına yazma sayısını verir; bunlar belirlenimli sayılardır. Hesap katmanı bu sayıları K01’in hacimlerine uygular ve iki yeni varsayım gerektirir.

OY3 — bir gönderinin açık kalma süresi: 5 gün. Gerekçesi, K01’in 730 günlük saklama varsayımının (V12) sözleşme uyuşmazlıkları için olması, gönderinin akışı için olmamasıdır; kabulden teslime kadar geçen süre bundan kısadır. Duyarlılığı: 10 gün alınırsa açık pencerenin olay sayısı ve yeniden üretim süresi iki katına çıkar.

OY4 — yeniden üretimin olay tüketme hızının canlı akışa oranı: 20. Gerekçesi, yeniden üretimin toplu okuma yapması, istek başına ağ turu ve doğrulama taşımamasıdır. Oran seçilir, mutlak hız değil; bu yüzden sayı bir ölçüm değildir. Duyarlılığı tabloda üç değerle veriliyor ve bir eşik gösteriyor.

// turetme/olc.mjs — izdusum artimli bakimla ve sifirdan yeniden uretimle kurulur, ikisi
// karsilastirilir; sonra K01'in hacimlerine ve bu konunun iki varsayimina uygulanir.
import { takipIzdusumu, noktaIzdusumu, kutukUret } from "./izdusum.mjs";

const V4 = 7, V5 = 480, V12 = 730, G_GONDERI = 400_000, V8 = 3, GUN = 86_400;
const OY3 = 5, OY4 = 20;   // bu konunun varsayimlari: acik kalma gunu, yeniden uretim kat sayisi
const N = 200;

const { kutuk, acik } = kutukUret(N, V4);
const artimli = takipIzdusumu(1);
for (const o of kutuk) artimli.uygula(o);

const tam = takipIzdusumu(1);
for (const o of kutuk) tam.uygula(o);

const aktifKutuk = kutuk.filter((o) => acik.has(o.id));
const aktif = takipIzdusumu(1);
for (const o of aktifKutuk) aktif.uygula(o);

const v2 = takipIzdusumu(2);
for (const o of kutuk) v2.uygula(o);
const nokta = noktaIzdusumu();
for (const o of kutuk) nokta.uygula(o);

const b = (x, n = 2) => x.toFixed(n);
const p = (x, n) => String(x).padStart(n);
console.log(`kutuk: ${N} gonderi, ${kutuk.length} olay, acik gonderi ${acik.size}` +
  `, aktif kutuk ${aktifKutuk.length} olay`);
console.log(`artimli bakim ile sifirdan yeniden uretim ayni mi = ${artimli.goruntu() === tam.goruntu()}`);
console.log(`aktif yeniden uretim acik gonderileri ayni kuruyor mu = ` +
  `${[...acik].every((id) => JSON.stringify(aktif.satir.get(id)) === JSON.stringify(tam.satir.get(id)))}`);
console.log(`v2 satirinda yeni alan var mi = ${"aktarma" in v2.satir.get("G5")}` +
  `, v1 satirinda = ${"aktarma" in tam.satir.get("G5")}\n`);

console.log(`${"izdusum".padEnd(14)}${"okunan olay".padStart(13)}${"yazilan satir".padStart(15)}` +
  `${"satir sayisi".padStart(14)}${"olay basina yazma".padStart(19)}`);
for (const [ad, r] of [["takip v1 tam", tam], ["takip v1 aktif", aktif],
  ["takip v2 tam", v2], ["nokta sayaci", nokta]])
  console.log(`${ad.padEnd(14)}${p(r.sayac.olay, 13)}${p(r.sayac.yazma, 15)}` +
    `${p(r.satir.size, 14)}${b(r.sayac.yazma / r.sayac.olay).padStart(19)}`);

// K01'e donus: izdusumun sakladigi veri
const gunlukIzdusum = (G_GONDERI * V5) / 1e6;
console.log(`\nizdusum satiri ${V5} bayt (K01 V5), gunde ${G_GONDERI} satir`);
console.log(`izdusumun ekledigi gunluk artis = ${b(gunlukIzdusum)} MB` +
  `, ${V12} gunde ${b((gunlukIzdusum * V12) / 1000)} GB`);
for (const [ad, gun, sak] of [["K01", 976, 712.48], ["olay kutugu (onceki ders)", 1168, 852.64]])
  console.log(`${ad.padEnd(26)} ${b(gun)} MB/gun, ${b(sak)} GB -> izdusumle ` +
    `${b(gun + gunlukIzdusum)} MB/gun, ${b(sak + (gunlukIzdusum * V12) / 1000)} GB`);

// Yeniden uretim: okunan olay ve yakalama
const gunlukOlay = G_GONDERI * (1 + V4);
const tepeAkis = (gunlukOlay / GUN) * V8;
const tamOlay = gunlukOlay * V12, aktifOlay = gunlukOlay * OY3;
console.log(`\ntepe olay akisi = ${b(tepeAkis)} olay/s (K01: gunde ${gunlukOlay} olay, tepe carpani ${V8})`);
console.log(`${"pencere".padEnd(22)}${"okunan olay".padStart(15)}${"kat".padStart(8)}`);
console.log(`${`tam saklama (${V12} gun)`.padEnd(22)}${p(tamOlay, 15)}${b(tamOlay / aktifOlay).padStart(8)}`);
console.log(`${`acik pencere (OY3=${OY3})`.padEnd(22)}${p(aktifOlay, 15)}${"1.00".padStart(8)}`);

console.log(`\n${"OY4".padStart(5)}${"tuketme olay/s".padStart(16)}${"net olay/s".padStart(12)}` +
  `${"acik pencere saat".padStart(19)}${"tam pencere gun".padStart(17)}`);
for (const k of [OY4, OY4 / 2, 1.5, 1]) {
  const tuket = k * tepeAkis, net = tuket - tepeAkis;
  const saat = net <= 0 ? null : aktifOlay / net / 3600;
  console.log(`${b(k, 1).padStart(5)}${b(tuket).padStart(16)}${b(net).padStart(12)}` +
    `${(saat === null ? "yakalayamaz" : b(saat)).padStart(19)}` +
    `${(saat === null ? "yakalayamaz" : b(tamOlay / net / 86400)).padStart(17)}`);
}
console.log(`\nyerinde yeniden uretimde gerilik penceresi = ` +
  `${b(aktifOlay / ((OY4 - 1) * tepeAkis) / 3600)} saat; yaninda uretimde 0`);
console.log(`yaninda uretimin gecici yer bedeli = ${b((gunlukIzdusum * V12) / 1000)} GB` +
  `, tepe saklama ${b(852.64 + 2 * (gunlukIzdusum * V12) / 1000)} GB`);
kutuk: 200 gonderi, 1760 olay, acik gonderi 40, aktif kutuk 320 olay
artimli bakim ile sifirdan yeniden uretim ayni mi = true
aktif yeniden uretim acik gonderileri ayni kuruyor mu = true
v2 satirinda yeni alan var mi = true, v1 satirinda = false

izdusum         okunan olay  yazilan satir  satir sayisi  olay basina yazma
takip v1 tam           1760           1760           200               1.00
takip v1 aktif          320            320            40               1.00
takip v2 tam           1760           1760           200               1.00
nokta sayaci           1760           2760             5               1.57

izdusum satiri 480 bayt (K01 V5), gunde 400000 satir
izdusumun ekledigi gunluk artis = 192.00 MB, 730 gunde 140.16 GB
K01                        976.00 MB/gun, 712.48 GB -> izdusumle 1168.00 MB/gun, 852.64 GB
olay kutugu (onceki ders)  1168.00 MB/gun, 852.64 GB -> izdusumle 1360.00 MB/gun, 992.80 GB

tepe olay akisi = 111.11 olay/s (K01: gunde 3200000 olay, tepe carpani 3)
pencere                   okunan olay     kat
tam saklama (730 gun)      2336000000  146.00
acik pencere (OY3=5)         16000000    1.00

  OY4  tuketme olay/s  net olay/s  acik pencere saat  tam pencere gun
 20.0         2222.22     2111.11               2.11            12.81
 10.0         1111.11     1000.00               4.44            27.04
  1.5          166.67       55.56              80.00           486.67
  1.0          111.11        0.00        yakalayamaz      yakalayamaz

yerinde yeniden uretimde gerilik penceresi = 2.11 saat; yaninda uretimde 0
yaninda uretimin gecici yer bedeli = 140.16 GB, tepe saklama 1132.96 GB

Türetmenin Doğruluğu

İlk üç satır türetmenin taşıdığı üç sözü sınıyor. Artımlı bakımla kurulan izdüşüm ile sıfırdan yeniden üretilen izdüşüm aynı çıktı: yansıtma, olayların hangi hızla uygulandığından bağımsızdır. Yalnız açık gönderilerin olaylarıyla yapılan kısmi üretim, o gönderilerin satırlarını tam üretimle aynı kurdu: kapanmış gönderilerin olayları açık gönderilerin satırını etkilemiyor. Üçüncüsü, ikinci sürüm satırında aktarma sayacı var, birincide yok — şema değişikliği izdüşümün kendi işidir, kütüğe dokunmaz.

Olay başına yazma sütunu izdüşümler arasındaki farkı gösteriyor. Takip izdüşümü her olayda tek satır yazar (1,00), çünkü olayın etkilediği satır bellidir. Nokta sayacı 1,57 yazar, çünkü bir gönderinin bir noktadan ötekine geçmesi iki satırı birden değiştirir. Satır sayısı sütunu ikinci farkı veriyor: takip izdüşümü 200 satır, nokta sayacı 5 satır. Bir izdüşümün maliyeti kütüğün uzunluğuna değil, olayın kaç satırı oynattığına ve satırların ne kadar yer tuttuğuna bağlıdır.

Saklama Bedeli

İzdüşüm satırı takip yanıtının gövdesidir ve boyu K01’de tanımlıdır (V5, 480 bayt). Günde 400.000 gönderi için 192 MB, 730 günlük saklama penceresinde 140,16 GB eder.

Bu, önceki dersin sayılarına eklenir: günlük artış 1168 MB’dan 1360 MB‘a, saklanan veri 852,64 GB’dan 992,80 GB‘a çıkar. K01’in 976 MB ve 712,48 GB’ıyla karşılaştırıldığında iki kararın toplam bedeli günde 384 MB ve 280,32 GB, yani 1,39 kat.

Tablodaki bir çakışma dikkat çekiyor: izdüşüm K01’in kalıcılığına eklendiğinde de 1168 MB/gün ve 852,64 GB çıkıyor — kaynak olayın ek alanlarının bedeliyle aynı. Bu bir bağıntı değil, seçilen varsayımların ürettiği bir denk gelmedir; 400.000 × 480 ile 3.200.000 × 60 aynı sayıdır. K01 aynı türde bir çakışmayı kendi tablosunda da işaretlemişti; ezberlenmez, yeniden hesaplanır.

Yeniden Üretim ve Yakalama

Yeniden üretimin ölçüsü süre değil okunan olay sayısıdır; süre ortama bağlıdır, okunan olay değildir. Tam saklama penceresi 2.336.000.000 olay tutuyor. Açık pencere (OY3 = 5 gün) 16.000.000 olay tutuyor: 146 kat az. Bu oran izdüşüm tasarımının en önemli kararını belirliyor — takip izdüşümü yalnız açık gönderiler için gerekiyorsa yeniden üretim açık pencereyle sınırlanabilir; kapanmış gönderilerin satırına da ihtiyaç varsa sınırlanamaz.

Süreye çevirmek OY4’ü gerektiriyor ve tablo bir eşik gösteriyor. Yeniden üretim canlı akışın 20 katı hızla tükettiğinde net ilerleme saniyede 2111,11 olaydır ve açık pencere 2,11 saatte kapanır; tam pencere 12,81 gün sürer. Oran 10’a inerse süreler 4,44 saat ve 27,04 güne çıkar. Oran 1,5 iken açık pencere 80 saat, tam pencere 486,67 gün sürer — yani yeniden üretim saklama penceresinden uzun olur ve hiçbir zaman bitmez. Oran 1 olduğunda tüketme hızı akış hızına eşittir ve üretim yakalayamaz. Kural tek cümleyle yazılır: yeniden üretimin süresi tüketme hızıyla değil, tüketme hızı ile akış hızı arasındaki farkla belirlenir.

Yerinde mi, Yanında mı

Yeniden üretim canlı izdüşümün üzerine yapılırsa okuma modeli üretim boyunca eksiktir; gerilik penceresi 2,11 saattir ve bu sürede takip sorguları eksik satır görür. Alternatif, yeni izdüşümü eskisinin yanında kurmak ve bittiğinde okuma yolunu ona çevirmektir. Gerilik penceresi bu durumda 0 olur, çünkü eski izdüşüm bütün üretim boyunca çalışmaya devam eder.

Bedel yerdir: üretim boyunca iki izdüşüm birden durur ve 140,16 GB’lık ikinci bir kopya taşınır; saklanan veri tepede 1132,96 GB’a çıkar. Bu, kursun her dersinde tekrarlanan takasın bir başka biçimidir — gerilik penceresi yer karşılığında kapatılıyor. Hangisinin seçileceği izdüşümün ne kadar süre eksik kalabileceğine bağlıdır ve bu bir alan kararıdır, teknik bir tercih değil.

Özet

  • İzdüşüm kütükten katlamayla türetilir; artımlı bakım ile sıfırdan yeniden üretim aynı satırları verdi ve kısmi üretim açık gönderilerin satırını tam üretimle aynı kurdu.
  • Bir izdüşümün maliyeti kütüğün uzunluğuna değil olayın oynattığı satır sayısına bağlıdır: takip izdüşümü olay başına 1,00 satır ve 200 satır tutuyor, nokta sayacı 1,57 satır ve 5 satır.
  • İzdüşüm günlük artışa 192 MB, saklanan veriye 140,16 GB ekliyor: 1168 → 1360 MB/gün, 852,64 → 992,80 GB. K01’in tabanına göre iki kararın toplamı 1,39 kat.
  • Yeniden üretimin ölçüsü okunan olaydır: tam pencere 2.336.000.000, açık pencere (OY3 = 5 gün) 16.000.000 olay — 146 kat fark.
  • Süre tüketme hızıyla akış hızının farkından çıkar: OY4 = 20’de açık pencere 2,11 saat, 10’da 4,44 saat, 1,5’te 80 saat, 1’de hiç yakalayamaz.
  • Yerinde üretim 2,11 saatlik gerilik penceresi bırakır; yanında üretim pencereyi 0 yapar ve karşılığında 140,16 GB geçici yer ister (tepede 1132,96 GB).

Sonraki Adım

Üç ders boyunca gerilik penceresi bir kaynak ölçüsü olarak ele alındı: kaç olay, kaç saat, kaç gigabayt. Ama pencerenin içinde duran şey bir sayı değil, bir kullanıcıdır. Bir alıcı adresini düzeltir ve sayfayı yeniden yükleyip eski adresi görür; bir taşıyıcı durum gönderir ve panoda kendi gönderdiği olayı bulamaz; iki taraf aynı gönderiyi aynı anda değiştirir ve biri ötekinin değişikliğinin kaybolduğunu fark eder. Sonraki ders pencerenin arayüzdeki karşılığını ölçer: kullanıcının gördüğü bayat değer sayısını, beklediği tur sayısını, çakışma bildirimi sayısını ve her çözümün K01’in depo yüküne geri eklediği isteği.

İ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