İçeriğe geç
academia.sh

Ders 10 / 22

Anlık Görüntü Kalıcılığı

Deponun bütününü aralıklarla diske yazan kalıcılık biçimi: aralığın kayıp penceresindeki yazma sayısına etkisi, üç aralığın disk maliyeti, bellekte tutulan bayt ile görüntü dosyasının boyutu arasındaki fark ve görüntü alırken duraklatmak ile kopyalamak arasındaki seçim.

İçindekiler

Önceki konu ödünç sistemini bütünüyle bellekte kurdu: katalog girişleri, oturum kayıtları, ödünç sayaçları, bekleme listeleri, sıralama tabloları. Her yapı için tutulan bayt sayıldı ve karşılığında ne satın alındığı ölçüldü. Bütün o ölçümlerin ortak ve sessiz bir varsayımı vardı: süreç çalışıyor. Süreç durduğunda geriye hiçbiri kalmaz. Dayanıklılığın bir ayar olduğu söylendi; o ayarın ne yaptığı, neye mal olduğu ve kapalıyken tam olarak neyin yittiği sorulmadı.

Bu ders ayarın ilk biçimini ele alır: belirli aralıklarla deponun bütününü diske yazmak. İki sorusu vardır. Süreç durduğunda kaç yazma yiter, ve görüntüyü almanın kendisi çalışmaya devam eden depoya ne kadara mal olur? İkisi de aynı düğmeye — aralığa — bağlıdır ve ters yönlere çeker.

Deponun ve Ölçünün Kurulumu

Ölçüm için ödünç deposu doğrudan yazılır. Depo bir anahtar–değer eşlemesidir; her yazmada tuttuğu bayt sayısını da günceller, böylece bellek maliyeti tahmin edilmez, sayılır.

KB1. Bir girişin bellek maliyeti anahtarın baytı, değerin baytı ve giriş başına sabit 48 bayt üstveridir. Bu 48 bayt karma tablo yuvasını, iki uzunluk alanını ve giriş işaretçisini temsil eder; gerçek bir çalışma zamanında sayı biraz oynar, ölçümün yönü oynamaz.

// depo.mjs — bellek içi ödünç deposu ve anlık görüntü alıcısı
export const USTVERI = 48;          // KB1: giriş başına sabit üstveri (yuva + işaretçi + uzunluk)

export class Depo {
  constructor() { this.girisler = new Map(); this.bayt = 0; }
  #maliyet(a, d) { return Buffer.byteLength(a) + Buffer.byteLength(d) + USTVERI; }
  yaz(a, d) {
    const eski = this.girisler.get(a);
    if (eski !== undefined) this.bayt -= this.#maliyet(a, eski);
    this.girisler.set(a, d);
    this.bayt += this.#maliyet(a, d);
  }
  get sayi() { return this.girisler.size; }
  goruntule() {                     // anlık görüntü: bütün girişler tek geçişte diziye çevrilir
    let s = '';
    for (const [a, d] of this.girisler) s += a + '\t' + d + '\n';
    return s;
  }
}

export function uretec(tohum) {     // belirlenimci sözde rastgele üreteç
  let a = tohum >>> 0;
  return () => {
    a = (a + 0x6d2b79f5) >>> 0;
    let t = a;
    t = Math.imul(t ^ (t >>> 15), t | 1);
    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

export function yukUret(sayi, tohum, uyeSayisi = 20000) {
  const r = uretec(tohum), liste = [];
  for (let i = 0; i < sayi; i++) {
    const u = Math.floor(r() * uyeSayisi);
    liste.push([
      'odunc:u' + String(u).padStart(5, '0'),
      `sube=${1 + (u % 8)};gun=${[7, 14, 28][i % 3]};yenileme=${i % 4}`,
    ]);
  }
  return liste;
}

Yük, kütüphanenin ödünç trafiğidir: yirmi bin üyeye dağılan altmış bin ödünç yazması. Üreteç kendi yazılmıştır ve tohumu görünürdür, dolayısıyla aşağıdaki sayıların hepsi yeniden üretilebilir.

Aralık, Kayıp Penceresi ve Disk

Anlık görüntü kalıcılığında dayanıklılık tek bir düğmeyle ayarlanır: kaç yazmada bir görüntü alınacağı. Aşağıdaki koşum aynı altmış bin yazmayı üç aralıkla oynatır. Her yazmadan sonra “o anda süreç dursaydı kaç yazma yiterdi” sorusunun yanıtı biriktirilir; sonda ortalaması ve en kötüsü basılır.

// aralik.mjs — üç anlık görüntü aralığının kayıp penceresi ve disk maliyeti
import { writeFileSync, statSync } from 'node:fs';
import { Depo, yukUret } from './depo.mjs';

const YUK = yukUret(60000, 20260731);
console.log('yük: 60000 yazma, 20000 üye, tohum 20260731');
console.log('aralık  görüntü  diske(MB)  ortalama kayıp  en kötü kayıp');

for (const aralik of [1000, 5000, 20000]) {
  const depo = new Depo();
  let goruntu = 0, diskBayt = 0, kayipToplam = 0, enKotu = 0, sonGoruntu = 0;
  for (let i = 0; i < YUK.length; i++) {
    depo.yaz(YUK[i][0], YUK[i][1]);
    const kayip = (i + 1) - sonGoruntu;        // süreç bu anda dursa yitecek yazma sayısı
    kayipToplam += kayip;
    if (kayip > enKotu) enKotu = kayip;
    if ((i + 1) % aralik === 0) {
      diskBayt += Buffer.byteLength(depo.goruntule());
      goruntu++;
      sonGoruntu = i + 1;
    }
  }
  console.log(String(aralik).padStart(6), String(goruntu).padStart(8),
    String(Math.round(diskBayt / 1048576)).padStart(10),
    String(Math.round(kayipToplam / YUK.length)).padStart(15), String(enKotu).padStart(14));
}

const son = new Depo();
for (const [a, d] of YUK) son.yaz(a, d);
writeFileSync('goruntu.txt', son.goruntule());
console.log('depo:', son.sayi, 'giriş,', son.bayt, 'bayt bellekte |',
  'görüntü dosyası', statSync('goruntu.txt').size, 'bayt');
yük: 60000 yazma, 20000 üye, tohum 20260731
aralık  görüntü  diske(MB)  ortalama kayıp  en kötü kayıp
  1000       60         30             501           1000
  5000       12          6            2501           5000
 20000        3          2           10001          20000
depo: 19040 giriş, 1593100 bayt bellekte | görüntü dosyası 717260 bayt

Kayıp penceresi aralığın doğrudan işlevidir: ortalaması aralığın yarısı, en kötüsü aralığın kendisidir. Bin yazmalık aralık, yirmi binliğe göre ortalama 9.500 yazmayı kurtarır. Bu satın alınan şeydir ve bedeli aynı satırda yazılıdır: 2 MB yerine 30 MB disk yazımı, yani on beş kat. Bedelin böyle büyümesinin nedeni, anlık görüntünün her seferinde deponun tamamını yazmasıdır. Bin yazmalık bir değişiklik için de yaklaşık beş yüz kilobaytlık bütün depo yeniden diske gider.

Son satır ikinci bir ayrımı verir. Altmış bin yazmadan geriye 19.040 giriş kalmıştır; geri kalanı aynı üyelerin kayıtlarının üzerine yazmıştır. Anlık görüntünün boyutu yazma sayısıyla değil anahtar sayısıyla büyür — bu, sonraki dersteki günlük biçimiyle arasındaki temel farktır. Aynı veri bellekte 1.593.100 bayt, dosyada 717.260 bayt tutar: dosya, belleğin yarısından azıdır. Fark üstveridir. Karma tablo yuvaları, işaretçiler ve uzunluk alanları diske gitmez. Diskteki dosyanın küçüklüğüne bakıp deponun belleğe rahat sığacağı sonucunu çıkarmak, giriş başına iki katlık bir hatayı baştan kabul etmek olur.

Görüntü Almanın Kendi Maliyeti

Görüntünün tutarlı olması gerekir: yarısı eski, yarısı yeni bir dosyadan kurtarma yapılamaz. Tutarlılığı sağlamanın iki yolu vardır ve ikisi de bedava değildir.

Duraklatmak. Görüntü alınırken yazmalar bekletilir. Bellek maliyeti sıfırdır, bedelini istemciler bekleme süresiyle öder.

Kopyalamak. Yazmalar sürer; görüntüye girecek bir giriş değiştirilmek üzereyken eski hâli kopyalanır ve görüntü kopyayı okur. Kimse beklemez, bedelini bellek öder: görüntü bitene kadar kopyalar da tutulur.

KB2. Görüntü alma anlık değildir; taranan her bin giriş kırk yazmalık süre alır. Süre, koşum ortamına değil giriş sayısına bağlı bir birimle sayılır.

// kopya.mjs — görüntü alma sırasındaki iki seçenek: duraklatmak ya da kopyalamak
import { Depo, USTVERI, yukUret } from './depo.mjs';

const YUK = yukUret(60000, 20260731);
const TARAMA = 40;                    // KB2: her 1.000 giriş için 40 yazmalık tarama süresi
console.log('aralık  görüntü  tarama  duraklatan: bekleyen  kopyalayan: giriş  tepe bayt');

for (const aralik of [1000, 5000, 20000]) {
  const depo = new Depo();
  let goruntu = 0, sure = 0, bekleyen = 0, kopyaSayi = 0, tepe = 0, kalan = 0, kopya = null;
  for (let i = 0; i < YUK.length; i++) {
    const [a, d] = YUK[i];
    if (kalan > 0) {                  // görüntü alınıyor: değişen giriş önce kopyalanır
      const eski = depo.girisler.get(a);
      if (eski !== undefined && !kopya.has(a)) { kopya.set(a, eski); kopyaSayi++; }
      if (--kalan === 0) {
        let b = 0;
        for (const [k, v] of kopya) b += Buffer.byteLength(k) + Buffer.byteLength(v) + USTVERI;
        if (b > tepe) tepe = b;
        kopya = null;
      }
    }
    depo.yaz(a, d);
    if ((i + 1) % aralik === 0) {
      sure = Math.ceil((depo.sayi / 1000) * TARAMA);
      goruntu++; bekleyen += sure; kalan = sure; kopya = new Map();
    }
  }
  console.log(String(aralik).padStart(6), String(goruntu).padStart(8), String(sure).padStart(7),
    String(bekleyen).padStart(21), String(kopyaSayi).padStart(18), String(tepe).padStart(10));
}
aralık  görüntü  tarama  duraklatan: bekleyen  kopyalayan: giriş  tepe bayt
  1000       60     762                 33285              24985      59565
  5000       12     762                  6946               4710      58498
 20000        3     762                  1965                913      49266

Tarama süresi üç satırda da aynıdır: 762 yazma. Görüntü alma aralığa değil giriş sayısına bağlıdır, dolayısıyla aralığı kısaltmak taramayı hızlandırmaz, yalnız daha sık yapar.

Duraklatan seçenek bin yazmalık aralıkta altmış bin yazmanın 33.285’ini bekletir — yükün yarısından fazlası. Yirmi binlik aralıkta bu sayı 1.965’e iner. Kopyalayan seçenek hiçbir yazmayı bekletmez; karşılığında görüntü sürerken en çok 59.565 bayt fazladan tutar. Bu, deponun 1.593.100 baytının yaklaşık yüzde 3,7’sidir. Tepe değerin üç aralıkta da birbirine yakın çıkması aynı nedendendir: tepeyi belirleyen aralık değil, tarama süresi boyunca kaç ayrı anahtara dokunulduğudur. 762 yazma en fazla 762 ayrı giriş kopyalatabilirdi; tekrar eden üyeler yüzünden sayı görüntü başına dört yüz civarında kalır. Yazmalar birkaç sıcak anahtara yığılsaydı kopya daha da azalırdı; her yazma ayrı bir anahtara gitseydi tepe iki katına yaklaşırdı.

Toplam kopyalanan giriş sayısı ise aralıkla birlikte artar: 24.985 karşısında 913. Kopyalama tepe bellekte ucuzdur, ama görüntü sıklaştıkça yapılan iş olarak birikir.

Bin yazmalık aralıkta gizli bir sınır da görünür hâle gelir. Tarama 762 yazma sürüyorsa, depo bin yazmanın 762’sinde görüntü alıyor demektir. Aralık tarama süresinin altına indirildiğinde görüntüler üst üste biner; yeni istek ya atlanır ya da öncekiyle yarışır. Her iki durumda da gerçekleşen aralık ayarlanandan büyük olur ve yapılandırmada yazan kayıp penceresi gerçeği anlatmaz.

Aralık Kararı

Üç ölçüm tek tabloda toplanır. Sayılar altmış bin yazmalık koşuma aittir.

Aralık Ortalama kayıp En kötü kayıp Disk yazımı Kopyalanan giriş
1.000 501 yazma 1.000 yazma 30 MB 24.985
5.000 2.501 yazma 5.000 yazma 6 MB 4.710
20.000 10.001 yazma 20.000 yazma 2 MB 913

Karar, kaybedilen yazmanın ne olduğuna bakılarak verilir. Katalog önbelleği için yirmi binlik aralık bile fazla korumadır: yiten girişler zaten kaynağından yeniden üretilebilir. Ödünç sayaçları ve bekleme listesi için on bin yazmalık ortalama kayıp, kütüphanenin bir günlük işlemine denk gelebilir ve bunun geri alınması elle yapılır.

Anlık görüntünün yapısal sınırı buradadır: aralık ne kadar kısaltılırsa kısaltılsın kayıp penceresi sıfır olmaz, çünkü son görüntüden sonraki her yazma korumasızdır. Aralığı tarama süresinin altına indirmek de bir işe yaramaz. Kayıp penceresini gerçekten kapatmak için deponun tamamını değil, her yazmanın kendisini kaydeden bir biçim gerekir.

Özet

  • Anlık görüntü kalıcılığı deponun bütününü aralıklarla diske yazar; kayıp penceresinin ortalaması aralığın yarısı, en kötüsü aralığın kendisidir.
  • Ölçümde bin yazmalık aralık ortalama kaybı 10.001’den 501’e indirdi ve bunun karşılığında disk yazımını 2 MB’tan 30 MB’a çıkardı; görüntü her seferinde deponun tamamını yazar.
  • Görüntünün boyutu yazma sayısıyla değil anahtar sayısıyla büyür: 60.000 yazma 19.040 giriş bıraktı ve dosya 717.260 bayt oldu.
  • Aynı veri bellekte 1.593.100 bayt tutar; aradaki fark diske gitmeyen üstveridir, bu yüzden dosya boyutundan bellek gereksinimi çıkarılamaz.
  • Görüntü alırken duraklatmak 33.285 yazmayı bekletti, kopyalamak hiçbirini bekletmedi ama tepe 59.565 bayt fazladan tuttu; tepeyi aralık değil tarama süresindeki ayrı anahtar sayısı belirler.

Sonraki Adım

Anlık görüntü, deponun bir anındaki hâlini yazar ve iki an arasında olan biteni yazmaz. Kayıp penceresini kapatmanın tek yolu, durumun kendisi yerine duruma götüren yazmaları kaydetmektir. Sonraki ders bunu ele alır: her yazma bir kayıt olarak dosyanın sonuna eklenir, kurtarma bu kayıtları yeniden oynatır. Ölçülecek olan, kaydın yazma başına kaç bayt tuttuğu, dosya sınırsız büyüdüğünde onu kısaltan yeniden yazımın ne kadar yer kazandırdığı ve kayıtların diske ne sıklıkta eşzamanlanacağı seçiminin kayıp penceresiyle yazma maliyetini nasıl karşı karşıya getirdiğidir.

İ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