İçeriğe geç
academia.sh

Ders 15 / 22

Çoğaltma

Bellek içi deponun tek düğümden çıkması: çoğaltmanın bir ayar değil deponun onaylama biçiminin zorunlu sonucu olması, kopya sayısı ile yayılım gecikmesinin aynı iş yükünde koşturulup düğüm başına düşen iş, tutulan veri, bayat okuma sayısı ve oranının ölçülmesi, bayatlık penceresinin gecikme çarpı yazma hızına indirgenmesi, ana düğümdeki çıkış tamponunun bellek olarak sayılması ve yetişemeyen kopyanın tamponu taşırıp tam eşitlemeye ve hizmet dışı turlara yol açmasının gösterilmesi.

İçindekiler

Önceki konu kalıcılığı ve tahliyeyi tek bir düğümün kararları olarak kurdu: hangi anın diske yazılacağı, bellek sınırı dolduğunda hangi girişin atılacağı, süresi dolmuş anahtarın ne zaman temizleneceği. Bunların hepsi tek bir sürecin içinde verildi ve hepsi o sürecin ayakta olduğunu varsaydı. Sürecin kendisi durduğunda ne olacağı hiç sorulmadı.

Bu konu deponun birden çok düğüme yayıldığı kurulumları ele alır. İlk soru en basit olanıdır: aynı veri ikinci bir düğümde de dursun. Kütüphane katalog ve ödünç sistemi burada da örnek alandır; ölçülen iş, katalog önbelleğinin okunması ve ödünç kayıtlarının yazılmasıdır.

Onaylama Biçiminin Zorunlu Sonucu

Çoğaltmanın mekaniği bu kursun konusu değil. Günlük akışı, çoğaltma gecikmesi ve kopya eklemenin azalan kazancı Veri Katmanı Ölçekleme kursunda ölçüldü; kümenin bir üyeyi kaybettiğinde kendi kararını nasıl verdiği İlişkisel Olmayan Veri Modelleri kursunda ölçüldü. Burada tekrarlanmaz.

Bu dersin sorusu bellek içi deponun kendi kısıtıdır. Depo bir yazmayı kabul ederken onu belleğine yazar ve hemen onaylar; onayı kopyanın uygulamasına bağlamak, deponun var oluş nedenini iptal etmek olur. Bu yüzden bellek içi depoda çoğaltma eşzamansızdır ve bu bir ayar değil, onaylama biçiminin sonucudur. Bunun üç ölçülebilir bedeli vardır ve üçü de bellekten ödenir:

  1. Her kopya veri kümesinin tamamını tutar. Kopya eklemek saklanan baytı böler değil, çarpar. Diskte bu bir kapasite kalemidir; bellekte doğrudan satın alma kalemidir.
  2. Ana düğüm her kopya için bir çıkış tamponu tutar. Kopyaya henüz ulaşmamış yazmalar ana düğümün belleğinde bekler. Tampon da bellektir.
  3. Kopyanın geriliği bir zaman aralığı değil, bir yazma sayısıdır. Kopyadan okunan her anahtar, o pencerede yazılmışsa bayat döner.

Düzenek

Aşağıdaki düzenek bir modeldir: gerçek depo, ağ ya da kopya kurulmaz. Tur soyut bir adımdır; yayılım gecikmesi ve uygulama kapasitesi tur cinsinden parametrelerdir, ölçülmüş süre değildir. Modelin tek gerçekçi varsayımı yukarıdaki eşzamansızlıktır.

BK1 — yayılım gecikmesi varsayılan olarak 2 turdur ve kopya, ana düğümün yazma hızına yetişir. Gerekçe: sağlıklı bir kopya birikmiş iş taşımaz, yalnız sabit bir gerilikle gelir. BK2 — katalog girişi 240 bayt, çoğaltma akışındaki bir yazma kaydı 96 bayttır. Gerekçe: kayıt yalnız değişikliği taşır, girişin tamamını değil. BK3 — erişimlerin yüzde 70’i anahtarların yüzde 10’una gider. Gerekçe: ödünç ve arama trafiği popüler kitaplarda toplanır. BK1 ve BK2 doğrusal etkilidir: gecikme iki katına çıkarsa bayatlık penceresi de iki katına çıkar.

// cogaltma/model.mjs — bellek ici deponun cogaltmasi SUREC ICI MODELDIR. Tur soyut bir adimdir;
// yayilim gecikmesi ve uygulama kapasitesi tur cinsinden parametrelerdir, olculmus sure degildir.
// Gercek depo, ag ya da kopya kurulmaz. Modelin tek gercekci varsayimi cogaltmanin ESZAMANSIZ
// olmasidir: ana dugum yazmayi bellegine alip hemen onaylar, kopyanin uygulamasini beklemez.
export const GIRIS_BAYT = 240;   // katalog girisi basina: anahtar + deger + ustveri (kendi hesabim)
export const KAYIT_BAYT = 96;    // cogaltma akisinda bir yazma kaydinin bayti

export function uretec(tohum) {  // dogrusal esleskli uretec; tohum gorunurdur
  let s = tohum >>> 0;
  return () => { s = (Math.imul(s, 1103515245) + 12345) >>> 0; return s / 4294967296; };
}

export function kosum({ kopya, gecikme, kapasite = null, tamponSiniri = Infinity, esitlemeTur = 5,
                        tur = 200, yazma = 40, okuma = 400, anahtar = 2000, tohum = 20260731 }) {
  const rnd = uretec(tohum);
  const sicak = Math.floor(anahtar * 0.10);                  // populer kitaplar: %10 anahtar
  const sec = () => (rnd() < 0.70 ? Math.floor(rnd() * sicak)  // erisimlerin %70'i onlara gider
                                  : sicak + Math.floor(rnd() * (anahtar - sicak)));
  const sira = new Int32Array(anahtar);                      // anahtarin son yazmasinin sira numarasi
  const uygulanan = Array(kopya).fill(0);                    // kopyanin uyguladigi yazma sayisi
  const disari = Array(kopya).fill(0);                       // esitleme yuzunden hizmet disi tur
  const zirve = Array(kopya).fill(0);                        // kopya basina en buyuk cikis tamponu
  let kabul = 0, bayat = 0, kopyaOkuma = 0, tamEsitleme = 0, ilkTasma = null, disariToplam = 0;

  for (let t = 1; t <= tur; t += 1) {
    for (let w = 0; w < yazma; w += 1) { kabul += 1; sira[sec()] = kabul; }
    for (let i = 0; i < kopya; i += 1) {
      const hedef = Math.max(0, (t - gecikme[i]) * yazma);   // gecikme kadar geriden gelir
      if (disari[i] > 0) {                                   // tam esitleme suruyor: okuma karsilamaz
        disari[i] -= 1; disariToplam += 1;
        if (disari[i] === 0) uygulanan[i] = hedef;           // esitleme kopyayi olagan gerilige getirir
        continue;
      }
      uygulanan[i] = Math.min(hedef, uygulanan[i] + (kapasite === null ? yazma : kapasite[i]));
      const tampon = (kabul - uygulanan[i]) * KAYIT_BAYT;    // ana dugumdeki cikis tamponu: BELLEKTIR
      if (tampon > zirve[i]) zirve[i] = tampon;
      if (tampon > tamponSiniri) {                           // tampon tasti: kopya dusurulur
        tamEsitleme += 1; disari[i] = esitlemeTur;
        if (ilkTasma === null) ilkTasma = t;
      }
    }
    const acik = [0, ...[...Array(kopya).keys()].map((i) => i + 1).filter((n) => disari[n - 1] === 0)];
    for (let r = 0; r < okuma; r += 1) {
      const n = acik[r % acik.length];                       // okumalar acik dugumlere sirayla dagilir
      const k = sec();
      if (n === 0) continue;                                 // ana dugum her zaman guncel
      kopyaOkuma += 1;
      if (sira[k] > uygulanan[n - 1]) bayat += 1;            // kopya bu anahtari henuz uygulamadi
    }
  }
  const dugum = kopya + 1, tampon = zirve.reduce((a, b) => a + b, 0);
  return { kabul, bayat, kopyaOkuma, tamEsitleme, ilkTasma, tampon, disariToplam,
           veri: dugum * anahtar * GIRIS_BAYT,               // her dugum veri kumesinin TAMAMINI tutar
           enYuklu: Math.round(okuma / dugum) + yazma };     // ana dugum: okuma payi + butun yazmalar
}
// cogaltma/olc.mjs — ayni is yuku uc ayarda: kopya sayisi, yayilim gecikmesi, yavas kopya
import { kosum, GIRIS_BAYT, KAYIT_BAYT } from "./model.mjs";

const s = (x, n) => String(x).padStart(n);
const kib = (b, n = 7) => s((b / 1024).toFixed(1), n);
const yuzde = (r) => s(((r.bayat / r.kopyaOkuma) * 100).toFixed(2) + "%", 11);

console.log("200 tur; her turda 40 odunc/oturum yazmasi, 400 katalog okumasi. 2.000 anahtar,");
console.log("giris basina 240 bayt, cogaltma kaydi 96 bayt. Tohum 20260731. Gecikme 2 tur.\n");
console.log("kopya | tutulan veri | en yuklu dugum | kopyadan okuma |  bayat | bayat orani");
console.log("------|--------------|----------------|----------------|--------|------------");
for (let k = 0; k <= 4; k += 1) {
  const r = kosum({ kopya: k, gecikme: Array(k).fill(2) });
  console.log(`${s(k, 5)} | ${kib(r.veri, 8)} KiB | ${s(r.enYuklu, 7)} is/tur | ${s(r.kopyaOkuma, 14)} |` +
    ` ${s(r.bayat, 6)} | ${k === 0 ? s("yok", 11) : yuzde(r)}`);
}

console.log("\n2 kopya sabit; yayilim gecikmesi degisiyor:");
console.log("gecikme | bayatlik penceresi | kopyadan okuma |  bayat | bayat orani | cikis tamponu");
console.log("--------|--------------------|----------------|--------|-------------|--------------");
for (const g of [1, 2, 4, 8]) {
  const r = kosum({ kopya: 2, gecikme: [g, g] });
  console.log(`${s(g, 7)} | ${s(g * 40, 12)} yazma | ${s(r.kopyaOkuma, 14)} | ${s(r.bayat, 6)} |` +
    ` ${yuzde(r)} | ${kib(r.tampon)} KiB`);
}

console.log("\n2 kopya; ikincisinin uygulama kapasitesi dusuk, tampon siniri 64 KiB, esitleme 5 tur:");
console.log("kapasite | tampon buyume | ilk tasma | tam esitleme | hizmet disi | zirve tampon |  bayat");
console.log("---------|---------------|-----------|--------------|-------------|--------------|-------");
for (const c of [40, 36, 32, 24]) {
  const r = kosum({ kopya: 2, gecikme: [2, 2], kapasite: [40, c], tamponSiniri: 64 * 1024 });
  console.log(`${s(c, 8)} | ${s((40 - c) * KAYIT_BAYT, 7)} b/tur | ` +
    `${s(r.ilkTasma === null ? "yok" : r.ilkTasma, 9)} | ${s(r.tamEsitleme, 12)} | ` +
    `${s(r.disariToplam, 7)} tur | ${kib(r.tampon)} KiB | ${s(r.bayat, 6)}`);
}

const N = [0, 1, 2, 3, 4];
console.log("\nkosumdan bagimsiz nicelikler:");
console.log("  bayatlik penceresi = gecikme x yazma hizi (yazma)");
console.log("  tampon buyume hizi = (yazma hizi - uygulama kapasitesi) x " + KAYIT_BAYT + " bayt/tur");
console.log("  kopya sayisi   : " + N.map((n) => s(n, 8)).join(""));
console.log("  okuma/dugum    : " + N.map((n) => s((400 / (n + 1)).toFixed(1), 8)).join(""));
console.log("  toplam veri KiB: " + N.map((n) => s(((n + 1) * 2000 * GIRIS_BAYT / 1024).toFixed(1), 8)).join(""));
200 tur; her turda 40 odunc/oturum yazmasi, 400 katalog okumasi. 2.000 anahtar,
giris basina 240 bayt, cogaltma kaydi 96 bayt. Tohum 20260731. Gecikme 2 tur.

kopya | tutulan veri | en yuklu dugum | kopyadan okuma |  bayat | bayat orani
------|--------------|----------------|----------------|--------|------------
    0 |    468.8 KiB |     440 is/tur |              0 |      0 |         yok
    1 |    937.5 KiB |     240 is/tur |          40000 |   7132 |      17.83%
    2 |   1406.3 KiB |     173 is/tur |          53200 |   9494 |      17.85%
    3 |   1875.0 KiB |     140 is/tur |          60000 |  10740 |      17.90%
    4 |   2343.8 KiB |     120 is/tur |          64000 |  11420 |      17.84%

2 kopya sabit; yayilim gecikmesi degisiyor:
gecikme | bayatlik penceresi | kopyadan okuma |  bayat | bayat orani | cikis tamponu
--------|--------------------|----------------|--------|-------------|--------------
      1 |           40 yazma |          53200 |   4992 |       9.38% |     7.5 KiB
      2 |           80 yazma |          53200 |   9494 |      17.85% |    15.0 KiB
      4 |          160 yazma |          53200 |  16344 |      30.72% |    30.0 KiB
      8 |          320 yazma |          53200 |  25517 |      47.96% |    60.0 KiB

2 kopya; ikincisinin uygulama kapasitesi dusuk, tampon siniri 64 KiB, esitleme 5 tur:
kapasite | tampon buyume | ilk tasma | tam esitleme | hizmet disi | zirve tampon |  bayat
---------|---------------|-----------|--------------|-------------|--------------|-------
      40 |       0 b/tur |       yok |            0 |       0 tur |    15.0 KiB |   9494
      36 |     384 b/tur |       153 |            1 |       5 tur |    71.6 KiB |  16660
      32 |     768 b/tur |        78 |            2 |      10 tur |    72.0 KiB |  16769
      24 |    1536 b/tur |        40 |            4 |      20 tur |    72.0 KiB |  16480

kosumdan bagimsiz nicelikler:
  bayatlik penceresi = gecikme x yazma hizi (yazma)
  tampon buyume hizi = (yazma hizi - uygulama kapasitesi) x 96 bayt/tur
  kopya sayisi   :        0       1       2       3       4
  okuma/dugum    :    400.0   200.0   133.3   100.0    80.0
  toplam veri KiB:    468.8   937.5  1406.3  1875.0  2343.8

Kopya Eklemenin Bilançosu

Satın alınan şey okumanın bölünmesidir, saklanan verinin bölünmesi değil. İlk tablo iki sütunu yan yana koyuyor: dört kopyada düğüm başına okuma 400’den 80’e iner, tutulan veri 468,8 KiB’den 2.343,8 KiB’ye çıkar. Bu bir dağıtma değil, çoğaltmadır — adın kendisi bunu söylüyor. Diskte aynı çarpan bir kapasite kalemidir; bellekte doğrudan satın alınan bir kalemdir ve kopya başına maliyeti sabittir: veri kümesinin tamamı, 468,8 KiB.

Kopya eklemek veriyi bayatlatmıyor; bayat okumanın payını büyütüyor. Bayat oranı bir kopyada yüzde 17,83, dört kopyada yüzde 17,84 — değişmiyor. Değişen, kopyaya giden okuma sayısıdır: 40.000’den 64.000’e. Bayat okuma sayısı da onunla birlikte 7.132’den 11.420’ye çıkıyor. Oran gecikmeye bağlıdır, kopya sayısına değil; sayı ise ikisinin çarpımıdır.

Bayatlık bir süre değil, bir yazma sayısıdır. İkinci tablo bunu doğrudan gösteriyor: pencere gecikme × yazma hızı ile 40, 80, 160 ve 320 yazmadır ve bayat oranı yüzde 9,38’den yüzde 47,96’ya çıkar. Sekiz turluk gecikmede kopyadan yapılan okumaların neredeyse yarısı güncel olmayan bir katalog kaydı döndürür. Bu, kopyanın bozuk olduğu anlamına gelmez; ödünç sayacının o anda ana düğümdeki değerini değil, 320 yazma öncesindeki değerini döndürdüğü anlamına gelir.

Gecikmenin bir de bellek fiyatı vardır. Aynı tablonun son sütunu çıkış tamponunu ölçüyor: 7,5 KiB’den 60 KiB’ye. Bu bayt, kopyalarda değil ana düğümde durur ve doğrudan gecikmeyle orantılıdır. Kopyanın geride kalması yalnız okuyucunun sorunu değildir; geriliğin karşılığı ana düğümün bellek bütçesinden çekilir.

Yetişemeyen Kopya

Üçüncü tablo, kopyanın sabit bir gerilikle gelmeyi bıraktığı durumu ölçüyor. Uygulama kapasitesi yazma hızının altına düştüğü anda tampon her tur (40 − kapasite) × 96 bayt büyür ve bu büyüme durmaz: kapasite 36’da 384 bayt, 24’te 1.536 bayt. Tampon sınırına ne zaman çarpılacağı bölmeden çıkar — 64 KiB sınırında ilk taşma sırasıyla 153., 78. ve 40. turdadır.

Taşmanın sonucu kopyanın düşürülmesi ve tam eşitlemedir: kopya artık akışı takip edemediği için veri kümesinin tamamını yeniden yükler. Bunun bellek bütçesindeki karşılığı en kötü anda ortaya çıkar — ana düğüm zaten tamponu taşırmış durumdayken bir de veri kümesinin tamamının anlık görüntüsünü, yani 468,8 KiB’lik bir kalemi üretmek zorundadır. Tabloda tam eşitleme sayısı kapasite düştükçe 1, 2 ve 4’e çıkıyor ve hizmet dışı tur 5’ten 20’ye.

Son sütun ilk bakışta ters görünen bir sayı taşıyor: yetişemeyen kopyada bayat okuma 9.494’ten 16.660’a çıkıyor ama kapasite daha da düştüğünde 16.769’da kalıyor, hatta 24’te 16.480’e iniyor. Nedeni tablodaki komşu sütundur. Hizmet dışı turlarda o kopya hiç okuma karşılamaz; okumalar ana düğüme ve sağlıklı kopyaya kayar ve oradan güncel yanıt döner. Bayat okumanın azalması bir iyileşme değildir: kopya kaldırıldığı için düğüm başına okuma yeniden yükselmiştir. Yavaş bir kopya, okuma kapasitesi olarak sayıldığı sürece ölçüyü iki kez bozar — bayat yanıt verdiği sürece bir kez, verecek durumda olmadığı sürece bir kez daha.

Özet

  • Bellek içi depoda çoğaltma bir ayar değil, yazmayı bellekten onaylamanın sonucudur; onayı kopyaya bağlamak deponun kendi gerekçesini iptal eder.
  • Kopya eklemek okumayı böler ama saklanan veriyi çarpar: düğüm başına okuma 400’den 80’e inerken tutulan veri 468,8 KiB’den 2.343,8 KiB’ye çıktı ve kopya başına maliyet sabittir.
  • Bayat okuma oranı kopya sayısıyla değişmedi (yüzde 17,83’e karşı yüzde 17,84); değişen, kopyaya giden okuma sayısı ve dolayısıyla bayat okuma sayısıdır (7.132’ye karşı 11.420).
  • Bayatlık penceresi gecikme × yazma hızıdır: 40, 80, 160 ve 320 yazmalık pencerelerde bayat oranı yüzde 9,38’den yüzde 47,96’ya çıktı.
  • Ana düğümdeki çıkış tamponu bir bellek kalemidir ve gecikmeyle doğru orantılıdır: 7,5 KiB’den 60 KiB’ye; kopyanın geriliğinin faturası ana düğüme kesilir.
  • Uygulama kapasitesi yazma hızının altına düştüğünde tampon (40 − kapasite) × 96 bayt/tur büyür, 64 KiB sınırını 153., 78. ve 40. turda aşar ve her aşımda tam eşitleme ile hizmet dışı tur doğurur.

Sonraki Adım

Bu ders çoğaltmayı ana düğümün ayakta olduğu varsayımıyla ölçtü: kopya geride kalabilir, tamponu taşırabilir, hatta yeniden eşitlenebilir — yazmaları kabul eden düğüm hep aynıdır. Ana düğüm durduğunda ise iki soru aynı anda açılır. Birincisi kimin karar vereceğidir: düğümün gerçekten durduğuna hükmetmek, ona ulaşamayan bir gözlemcinin tek başına verebileceği bir karar değildir. İkincisi ve bu kursa özgü olanı şudur: kopya, tanım gereği ana düğümün gerisindedir. Yerine geçtiği anda elinde olmayan yazmalar, ödünç işlemi başarılı diye bildirilmiş yazmalardır. Sonraki ders gözcü süreçlerinin çoğunluk kararını, devralma penceresinde kaybedilen kabul edilmiş yazma sayısını ve algılama eşiğinin kısaltılmasının doğurduğu yanlış devralmayı sayar.

İ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