İçeriğe geç
academia.sh

Ders 05 / 20

Sürümleme ve Takma Adlar

Takma ad üzerinden ağırlık kaydırma ölçülür: sürüm değişmez kalır, takma ad taşınır. Her adımda etkilenen istek ve fark etme turu sayılır; soğuk başlangıcın kanarya ölçümüne karışması ile geri almanın tek anahtar çevirme oluşu ayrı ayrı çıkarılır.

İçindekiler

Eşikler sayıldı: süre sınırı, bellek sınırı, eşzamanlılık tavanı. Hangi işin bu eşiklerin içine sığmadığı yazıldı. Sığan işin ne olacağı ise hiç sorulmadı — o işlev yazıldıktan sonra çalışan sisteme nasıl girecek?

Aşamalı yayının kalıp tarafı — kararın hangi ölçütle, hangi pencereyle, hangi eşikle verildiği — ölçülmüş bir konudur ve tekrarlanmıyor. Buranın sorusu daha dardır: bu merdiven takma ad denen tek bir işaretçi üzerinden yürür ve mekanizmanın kendine ait iki olgusu vardır. Geri alma tek bir yazmadır; soğuk başlangıç ise yeni sürümde sıfırdan başlar.

  • IH25. Kurgusal bölgesel ölçüm ağının doğrulama işlevi dakikada dokuz yüz istek alır; günün saatine göre değişim modellenmiyor. Ağ da rakamlar da kurgudur.
  • IH26. Sıcak örnekte işlem iki yüz yirmi milisaniye sürer; soğuk başlangıç bin sekiz yüz milisaniye ekler. Paket boyutunun etkisi dersin dışındadır.
  • IH27. Boşta kalan örnek dört dakika sonra düşürülür. Havuz sürüm başına ayrıdır: takma ad taşınsa da iki sürümün havuzu birleşmez.
  • IH28. Kapı tek kalem okur: yeni sürümün ortalama gecikmesi. Taban ağırlık sıfırken ölçülür, eşik tabanın bir virgül iki beş katıdır.
  • IH29. İstekler üstel aralıklarla gelir; üreteç kendi yazılmıştır, tohum görünürdür. Her ağırlık adımı beş adet iki dakikalık tur içerir.
  • IH30. Takma ad yazması, yayılma ve yeniden yayım süreleri kurgudur.

Sürüm Değişmez, Takma Ad Taşınır

Ölçülen şey gerçek bir çalışma ortamı değil, node ile kurulan bir modeldir. İki nesne vardır: sürüm, özeti değişmeyen donmuş bir kayıt; takma ad, bu sürümlerden birini gösteren ve üzerine yazılabilen bir işaretçi. Sürüm başına ayrı bir sıcak havuz tutulur.

// takmaad.mjs — surum, takma ad ve sicak havuz modeli; gercek bir calisma ortami degil, modeldir
export const TOHUM = 20260420, ISTEK_DK = 900;   // kurgu: dogrulama islevine dakikada gelen istek
export const HIZMET_MS = 220, SOGUK_EK_MS = 1800, BOSTA_MS = 240000;  // sicak, soguk ek, bosta omru
export const TUR_DK = 2, TUR = 5, KAPI = 1.25, GERILEME_MS = 120;
export const AGIRLIKLAR = [1, 2, 5, 25, 100];

export function uretec(tohum) {                  // dogrusal eslesik uretec, tohum gorunur
  let x = tohum >>> 0;
  return () => { x = (Math.imul(x, 1664525) + 1013904223) >>> 0; return x / 4294967296; };
}

// Surum dondurulmustur: ozeti bir daha degismez. Takma ad ise uzerine yazilabilen bir isaretcidir.
export const surum = (etiket, ozet) => Object.freeze({ etiket, ozet });
export const takmaAd = (ad, hedef) => ({ ad, hedef, yazma: 0 });
export const tasi = (t, hedef) => Object.assign(t, { hedef, yazma: t.yazma + 1 });

// Havuz surum basinadir: bosta ornek bulunursa sicak calisir, bulunmazsa yeni ornek acilir.
export const havuz = () => ({ ornekler: [], soguk: 0 });
export const ayakta = (h, t) => h.ornekler.filter((o) => o.son + BOSTA_MS > t).length;
export function cagir(h, t, ekMs) {
  h.ornekler = h.ornekler.filter((o) => o.son + BOSTA_MS > t);
  const o = h.ornekler.find((x) => x.mesgul <= t), sure = HIZMET_MS + ekMs + (o ? 0 : SOGUK_EK_MS);
  if (o) { o.mesgul = t + sure; o.son = t + sure; }
  else { h.soguk += 1; h.ornekler.push({ mesgul: t + sure, son: t + sure }); }
  return sure;
}

// Bir adim: istekler ustel araliklarla gelir, agirliga gore eski ya da yeni surume dusurulur.
export function adim(rnd, hE, hY, agirlik, ekMs, t0, tur = TUR, turDk = TUR_DK) {
  const lam = ISTEK_DK / 60000, turlar = [];
  let t = t0 - Math.log(1 - rnd()) / lam;
  for (let k = 0; k < tur; k += 1) {
    const son = t0 + (k + 1) * turDk * 60000;
    let ny = 0, ne = 0, sy = 0, se = 0, s0 = hY.soguk;
    while (t < son) {
      if (rnd() * 100 < agirlik) { sy += cagir(hY, t, ekMs); ny += 1; } else { se += cagir(hE, t, 0); ne += 1; }
      t -= Math.log(1 - rnd()) / lam;
    }
    turlar.push({ ny, ortY: ny ? sy / ny : 0, ortE: ne ? se / ne : 0, soguk: hY.soguk - s0 });
  }
  return turlar;
}

// Merdiven: once agirlik sifirken taban okunur, sonra agirlik buyur. Havuzlar adimlar arasi
// tasinir: yeni surumun havuzu yalnizca ilk adimda bostur.
export function merdiven(tohum, ekMs, agirliklar = AGIRLIKLAR, isit = 0) {
  const rnd = uretec(tohum), hE = havuz(), hY = havuz();
  const taban = adim(rnd, hE, hY, 0, 0, 0, TUR).reduce((x, y) => x + y.ortE, 0) / TUR;
  const satirlar = [];
  let t = TUR * TUR_DK * 60000, etkilenen = 0;
  for (let i = 0; i < isit; i += 1) cagir(hY, t - 30000, 0);   // es zamanli yapay isitma cagrilari
  for (const a of agirliklar) {
    const turlar = adim(rnd, hE, hY, a, ekMs, t, TUR);
    t += TUR * TUR_DK * 60000;
    etkilenen += turlar.reduce((x, y) => x + y.ny, 0);
    satirlar.push({ agirlik: a, turlar, etkilenen });
  }
  return { taban, satirlar };
}

export const imza = (x) => `${x < 0 ? '' : '+'}${Math.round(x)}`;
export const satir = (g, ...x) => x.map((v, i) => String(v).padEnd(g[i])).join('');

Devredilen karar burada görünür: hangi isteğin hangi sürüme gideceği, kaç örnek açılacağı yazılmıyor — yerine tek bir sayı yazılıyor. Kısıt da aynı yerdedir: havuz sürüm başına ayrı olduğu için yeni sürüm ısınmasını sıfırdan yapar.

Her Adımda İki Sayı

// kosum1.mjs — takma ad agirligi adim adim kaydirilir; her adimda soguk cagri, gecikme ve kapi okunur
import { merdiven, surum, takmaAd, tasi, imza, satir, TOHUM, ISTEK_DK, HIZMET_MS,
  SOGUK_EK_MS, KAPI, GERILEME_MS, AGIRLIKLAR } from './takmaad.mjs';

const v7 = surum('v7', 'e3bb1237'), v8 = surum('v8', 'd8bb00e6'), canli = takmaAd('canli', v7);
try { v7.ozet = 'ustune-yazildi'; } catch { /* donmus kayda yazma reddedilir */ }
console.log(`tohum ${TOHUM} | ${ISTEK_DK} istek/dk | sicak ${HIZMET_MS} ms | soguk ek ${SOGUK_EK_MS} ms`);
console.log(`takma ad "${canli.ad}" -> ${canli.hedef.etiket}, tasindi -> ${tasi(canli, v8).hedef.etiket}` +
  ` | yazma ${canli.yazma} | ozet ${v7.ozet} (ustune yazilamadi)`);

const G = [9, 11, 12, 10, 10, 11, 11, 11];
for (const [ad, ek, goster] of [['temiz surum', 0, AGIRLIKLAR],
  [`kusurlu surum (+${GERILEME_MS} ms gercek gerileme)`, GERILEME_MS, [1]]]) {
  const { taban, satirlar } = merdiven(TOHUM, ek);
  console.log(`\n${ad} | merdiven ${AGIRLIKLAR.join('-')} | taban ${Math.round(taban)} ms | kapi esigi ${Math.round(taban * KAPI)} ms`);
  console.log(satir(G, 'agirlik', 'istek/tur', 'tur1 soguk', 'tur1 ort', 'tur2 ort',
    'tur1 fark', 'tur2 fark', 'ilk temiz') + 'etkilenen');
  for (const s of satirlar.filter((x) => goster.includes(x.agirlik))) {
    const [a, b] = s.turlar, t = s.turlar.findIndex((x) => x.ortY <= taban * KAPI);
    console.log(satir(G, `%${s.agirlik}`, a.ny, a.soguk, Math.round(a.ortY), Math.round(b.ortY),
      imza(a.ortY - taban), imza(b.ortY - taban), t < 0 ? 'hicbiri' : `tur ${t + 1}`) + s.etkilenen);
  }
}
tohum 20260420 | 900 istek/dk | sicak 220 ms | soguk ek 1800 ms
takma ad "canli" -> v7, tasindi -> v8 | yazma 1 | ozet e3bb1237 (ustune yazilamadi)

temiz surum | merdiven 1-2-5-25-100 | taban 226 ms | kapi esigi 283 ms
agirlik  istek/tur  tur1 soguk  tur1 ort  tur2 ort  tur1 fark  tur2 fark  ilk temiz  etkilenen
%1       21         2           391       220       +165       -6         tur 2      85
%2       38         1           267       220       +41        -6         tur 1      266
%5       99         1           238       220       +12        -6         tur 1      717
%25      468        2           228       220       +1         -6         tur 1      2968
%100     1823       7           227       220       +1         -6         tur 1      11969

kusurlu surum (+120 ms gercek gerileme) | merdiven 1-2-5-25-100 | taban 226 ms | kapi esigi 283 ms
agirlik  istek/tur  tur1 soguk  tur1 ort  tur2 ort  tur1 fark  tur2 fark  ilk temiz  etkilenen
%1       21         2           511       340       +285       +114       hicbiri    85

İkinci satır dersin başlığını doğruluyor: takma ad v7’den v8’e taşındı — bir yazma — ve aynı anda v7’nin özetine yazma girişimi reddedildi. Yayın, kayıtları değiştirmek değil, üzerine yazılabilen tek bir alanı güncellemektir.

Etkilenen istek sütunu kaydırmanın kazancını yazıyor: yüzde bir adımının sonunda seksen beş, yüzde yüze varıldığında on bir bin dokuz yüz altmış dokuz — yüz kırk kata yakın bir fark.

Fark etme turu sütunu ise beklenmedik bir yerde bozuluyor. Temiz sürümde yüzde bir adımının birinci turu kapıyı tetikliyor: ortalama üç yüz doksan bir milisaniye, eşik iki yüz seksen üç. Aynı sürüm ikinci turda iki yüz yirmiye iniyor; kusurlu sürümde fark her turda yüz on dört milisaniye civarındadır. Ayırt edici olan farkın büyüklüğü değil, sönüp sönmediğidir.

Sebep havuzun sürüm başına ayrı olmasıdır: yeni sürüm ilk adıma boş havuzla girer, iki örnek açar ve o örnekler merdivenin geri kalanında sıcak kalır. Soğuk başlangıç bedeli yalnızca ilk adıma düşer — tanım gereği en küçük örneklemi olan adıma. Aritmetiği tek satırdır: kapının payı elli yedi milisaniyedir, yüzde bir payda tura on sekiz istek düşer ve bin sekiz yüz milisaniyelik tek bir soğuk çağrı ortalamaya yüz milisaniye ekler; yüzde ikide elli, yüzde beşte yirmi. Küçük pay hem etkilenen isteği azaltıyor hem ölçümü soğuk başlangıca duyarlı kılıyor — ilki isteniyordu, ikincisi kısıt olarak geldi.

Geri Alma Tek Anahtar Çevirmedir

// kosum2.mjs — geri almanin iki yolu, tam gecisten sonra eski havuz, dolasma yollarinin bedeli
import { merdiven, uretec, havuz, adim, ayakta, imza, satir, TOHUM, ISTEK_DK,
  BOSTA_MS, TUR_DK, KAPI, AGIRLIKLAR } from './takmaad.mjs';

// Kurgu sureler: yazma 120, yayilma 900, paket yukleme (42 MB / 20 MB-sn) 2100, surum 3000 ms.
const YOLLAR = { 'takma ad cevirme': [120, 900], 'yeniden yayim': [2100, 3000, 120, 900] };
console.log(satir([20, 7, 11], 'geri alma yolu', 'adim', 'sure') + 'bu surede kusurlu surume dusen istek');
for (const [ad, a] of Object.entries(YOLLAR)) {
  const ms = a.reduce((x, y) => x + y, 0);
  console.log(satir([20, 7, 11], ad, a.length, `${(ms / 1000).toFixed(2)} sn`) + Math.round(ISTEK_DK / 60000 * ms));
}

// Tam gecisten sonra eski surumun havuzu bosalir; geri alma o havuzu yeniden acmak zorunda kalir.
function gecisVeGeriAl(beklemeDk) {
  const rnd = uretec(TOHUM), hE = havuz(), hY = havuz();
  adim(rnd, hE, hY, 0, 0, 0, 5, 1);                        // eski surum isinir
  const gecen = adim(rnd, hE, hY, 100, 0, 300000, beklemeDk, 1).reduce((x, y) => x + y.ny, 0);
  const t = 300000 + beklemeDk * 60000, kalan = ayakta(hE, t), s0 = hE.soguk;
  const geri = adim(rnd, hE, hY, 0, 0, t, 1, 1)[0];        // takma ad geri alindi: bir dakika okunur
  return { gecen, kalan, soguk: hE.soguk - s0, ort: Math.round(geri.ortE) };
}
const H = [9, 25, 26, 19];
console.log(`
tam gecisten (%100) sonra geri alma — bosta ornek ${BOSTA_MS / 60000} dk sonra dusuruluyor`);
console.log(satir(H, 'bekleme', 'yeni surume gitmis istek', 'eski havuzda kalan ornek', 'geri almada soguk') + 'ilk dk ort');
for (const b of [3, 4, 5]) {
  const g = gecisVeGeriAl(b);
  console.log(satir(H, `${b} dk`, g.gecen, g.kalan, g.soguk) + `${g.ort} ms`);
}

// Ilk adimin soguk baslangicindan kacmanin yollari; her yolun bedeli ayri bir kalemdir.
const pay = merdiven(TOHUM, 0).taban * (KAPI - 1), Y = [30, 16, 12, 10, 7, 12, 11];
console.log(`
ilk adimda soguk baslangictan kacmanin yollari — kapi payi ${Math.round(pay)} ms`);
console.log(satir(Y, 'yol', 'merdiven', 'karar turu', 'yayin dk', 'yapay', 'ilk turda', 'tur1 soguk') + 'karar turunda fark');
for (const [ad, ag, isit, kt] of [['tur1 at, tur2 ile karar ver', AGIRLIKLAR, 0, 2],
  ['1 es zamanli yapay cagri', AGIRLIKLAR, 1, 1], ['3 es zamanli yapay cagri', AGIRLIKLAR, 3, 1],
  ['ilk adimi %25 yap', [25, 100], 0, 1]]) {
  const { taban, satirlar } = merdiven(TOHUM, 0, ag, isit), t1 = satirlar[0].turlar[0];
  console.log(satir(Y, ad, ag.join('-'), kt, ag.length * kt * TUR_DK, isit, t1.ny, t1.soguk) +
    `${imza(satirlar[0].turlar[kt - 1].ortY - taban)} ms`);
}
geri alma yolu      adim   sure       bu surede kusurlu surume dusen istek
takma ad cevirme    2      1.02 sn    15
yeniden yayim       4      6.12 sn    92

tam gecisten (%100) sonra geri alma — bosta ornek 4 dk sonra dusuruluyor
bekleme  yeni surume gitmis istek eski havuzda kalan ornek  geri almada soguk  ilk dk ort
3 dk     2680                     12                        0                  220 ms
4 dk     3584                     4                         14                 247 ms
5 dk     4490                     0                         39                 296 ms

ilk adimda soguk baslangictan kacmanin yollari — kapi payi 57 ms
yol                           merdiven        karar turu  yayin dk  yapay  ilk turda   tur1 soguk karar turunda fark
tur1 at, tur2 ile karar ver   1-2-5-25-100    2           20        0      21          2          -6 ms
1 es zamanli yapay cagri      1-2-5-25-100    1           10        1      21          1          +79 ms
3 es zamanli yapay cagri      1-2-5-25-100    1           10        3      21          0          -6 ms
ilk adimi %25 yap             25-100          1           4         0      477         5          +13 ms

İlk tablo sürümün değişmez olmasının ne satın aldığını gösteriyor. Eski sürüm bir kayıt olarak durduğu için geri alma iki adımdır — bir yazma ve yayılma — toplam bir virgül sıfır iki saniye ve kusurlu sürüme düşen on beş istek. Sürüm saklanmasaydı yol dört adıma, altı virgül on iki saniyeye ve doksan iki isteğe çıkardı; fark altı kattır.

İkinci tablo bu rahatlığın sınırını yazıyor. Ağırlık yüzde yüze çıkarıldıktan sonra eski sürüm hiç istek almaz ve havuzu dört dakikada boşalır. Üç dakika sonra geri alındığında havuzda on iki örnek duruyordu, hiç soğuk çağrı olmadı; beş dakika sonra sıfır örnek kalır ve ilk dakika otuz dokuz soğuk çağrı ödeyerek ortalamayı iki yüz doksan altıya çıkarır. Geri alma hâlâ tek yazmadır, ama bedeli işlemden değil aradan geçen süreden gelir.

Üçüncü tablo dolaşmanın faturasını yazıyor. Birinci turu atmak kararı temizler, yayını on dakikadan yirmi dakikaya çıkarır. Önceden ısıtma süreyi korur ama tek yapay çağrı yetmez: tur içindeki yığılma ikinci örneği açtırır ve fark yetmiş dokuz milisaniyede kalır. Üç eş zamanlı çağrı soğuk sayısını sıfırlar; bedeli merdiven başına on beş yapay çağrıdır — ölçütlere karışan, gerçek kullanıcıdan gelmeyen istekler. Merdiveni yukarıdan başlatmak en pahalısıdır: fark on üç milisaniyeye iner ama ilk turda etkilenen istek yirmi birden dört yüz yetmiş yediye çıkar.

Özet

  • Takma ad v7’den v8’e taşındı: tek bir yazma. Aynı anda sürümün özetine yazma girişimi reddedildi — yayın, kayıtları değiştirmek değil, bir işaretçiyi güncellemektir.
  • Etkilenen istek yüzde bir adımının sonunda seksen beş, yüzde yüze varıldığında on bir bin dokuz yüz altmış dokuzdur.
  • Temiz bir sürüm yüzde bir adımının ilk turunda kapıyı tetikledi: iki soğuk çağrı, üç yüz doksan bir milisaniye, eşik iki yüz seksen üç. İkinci turda iki yüz yirmiye indi; kusurlu sürümde fark hiçbir turda sönmedi.
  • Yüzde bir payda tura on sekiz istek düşer ve tek soğuk çağrı ortalamaya yüz milisaniye ekler; kapı payı elli yedidir.
  • Geri alma iki adım ve bir virgül sıfır iki saniyedir; sürüm saklanmasaydı dört adım, altı virgül on iki saniye ve doksan iki istek olurdu.
  • Tam geçişten beş dakika sonra eski havuzda sıfır örnek kalır; geri almanın ilk dakikası otuz dokuz soğuk çağrı öder ve ortalama iki yüz doksan altıya çıkar.

Sonraki Adım

Ölçümün her yerinde aynı sayı sabit gibi duruyordu: soğuk başlangıcın eklediği bin sekiz yüz milisaniye. Kanarya turunu bozan, geri almanın gecikmiş bedelini yazan ve önceden ısıtmayı gerekli kılan oydu. Oysa o sayı sabit değildir — paket ne kadar büyükse indirilecek bayt o kadar çoktur. Sonraki ders paketi ölçer: boyut ile soğuk başlangıç arasındaki ilişkiyi tarar, bağımlılıkları paylaşılan bir katmana taşımanın neyi küçültüp neyi küçültmediğini sayar, sürüm sabitlemenin ve bir katman güncellemesinin kaç işleve dokunduğunun hesabını çıkarır — ve kullanılmayan bir bağımlılığın taşınan bayt olarak bedelini yazar.

İ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