İçeriğe geç
academia.sh

Ders 02 / 20

İşlev Çağırma Modelleri

Aynı doğrulama işi üç çağırma modelinde koşturulur ve dört şey ayrı ayrı sayılır: çağıranın gördüğü gecikme, hatayı kimin gördüğü, yeniden denemenin kimde olduğu ve yinelenen işleme oranı; ardından akış tabanlı modelde toplu okuma boyu birden iki bin beş yüze taranarak çağrı sayısı, fazladan işleme, ölü mektup kutusuna eş düşen sağlam kayıt ve süre sınırına sığmayan toplu iş çıkarılır.

İçindekiler

Önceki ders işlevi tek bir biçimde çağırdı: istek geldi, işlev çalıştı, sonuç döndü. Ama ağın işleri aynı ucun üzerinde durmaz: saha ekibine giden bildirimin yanıtını kimse beklemez; gece toplu işlemesi bir sıradan okunur; geçit üzerinden gelen doğrulama isteği bir istemcinin ucundadır.

Çağırma modeli dört ayrı sayının aynı anda değiştiği bir seçimdir: gecikme, hatayı kimin gördüğü, yeniden denemenin kimde olduğu ve aynı kaydın kaç kez işlendiği. Bu ders dördünü de sayar.

IH7. Bölgesel ölçüm ağının — kurgu bir yazılımın — gece toplu işlemesine giren 20.000 sayaç okuması ölçülür; kayıt sınıfları kendi yazılan bir üreteçle dağıtılır, tohum 20260803’tür. IH8. Bir doğrulama 400 ms, çağrı başına sabit yük 250 ms, eşzamansız kabul yanıtı 5 ms tutar. IH9. Geçici hata ikinci denemede geçer, zehirli kayıt hiç geçmez. IH10. Eşzamanlı modelde çağıran bir kez yeniden dener; eşzamansız ve akış tabanlı modelde yeniden denemeyi altyapı üstlenir, üç deneme ve 60 saniye ara ile. IH11. Akış tabanlı modelde toplu iş bölünmez: tek kayıt hata verirse toplu işin tamamı yeniden okunur, üçüncü denemeden sonra tamamı ölü mektup kutusuna gider; kayıtlar saniyede 250 varır. IH12. Fiyatlar kurgu birimle yazılır (çağrı başına 0,0005, işlem milisaniyesi başına 0,0000025) ve süre sınırı 900 saniyedir.

Aynı İş, Üç Çağırma Yolu

// olcum-agi/cagirma-modelleri.mjs — ayni dogrulama isi uc cagirma modelinde (model)

// Kurgu sayilar: bir okuma dogrulamasi 400 ms, cagri basina sabit yuk 250 ms, kabul yaniti 5 ms.
export const N = 20000, ISLEM = 400, SABIT = 250, KABUL = 5, BEKLE = 60000;
export const CAGRI_B = 0.0005, MS_B = 0.0000025;   // kurgu birim: cagri basina ve ms basina

export const uretec = (t) => { let s = t >>> 0; return () => {
  s ^= s << 13; s >>>= 0; s ^= s >>> 17; s ^= s << 5; s >>>= 0; return s / 4294967296; }; };

// Gece toplu islemesine giren 20000 sayac okumasi: cogu temiz, kimi gecici hatali, kimi zehirli.
export const kayitlar = (tohum = 20260803) => {
  const r = uretec(tohum);
  return Array.from({ length: N }, () => { const v = r();
    return v < 0.001 ? "zehirli" : v < 0.021 ? "gecici" : "temiz"; });
};

const yuzde = (a, p) => [...a].sort((x, y) => x - y)[Math.floor(a.length * p)];
const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length;

// Eszamanli: cagiran yaniti bekler, hatayi gorur, yeniden denemeyi kendi yapar.
export const eszamanli = (k) => {
  let cagri = 0, yeniden = 0; const bitis = [];
  for (const d of k) {
    const deneme = d === "temiz" ? 1 : 2;
    cagri += deneme; yeniden += deneme - 1;
    bitis.push(deneme * (SABIT + ISLEM) + (deneme - 1) * 200);
  }
  return { ad: "eszamanli", bitis, cagri, yeniden, islenen: cagri, sure: cagri * (SABIT + ISLEM),
    oluMektup: 0, esDusen: 0, hataGoren: "cagiran", denemeKimde: "cagiran" };
};

// Eszamansiz: cagiran kabul yanitini alip cikar; yeniden denemeyi altyapi yapar.
export const eszamansiz = (k) => {
  let cagri = 0, yeniden = 0, olu = 0; const bitis = [];
  for (const d of k) {
    const deneme = d === "temiz" ? 1 : d === "gecici" ? 2 : 3;
    cagri += deneme; yeniden += deneme - 1;
    bitis.push(deneme * (SABIT + ISLEM) + (deneme - 1) * BEKLE);
    if (d === "zehirli") olu++;
  }
  return { ad: "eszamansiz", bek: KABUL, bitis, cagri, yeniden, islenen: cagri,
    sure: cagri * (SABIT + ISLEM), oluMektup: olu, esDusen: 0,
    hataGoren: "hic kimse", denemeKimde: "altyapi" };
};

// Akis tabanli: kayitlar sirali okunur, toplu is tek cagridir, tek hata butun toplu isi tekrarlatir.
export const akis = (k, boy, varis = 250) => {
  let cagri = 0, islenen = 0, olu = 0, esDusen = 0; const bitis = [];
  for (let i = 0; i < k.length; i += boy) {
    const t = k.slice(i, i + boy);
    const zehirli = t.filter((d) => d === "zehirli").length;
    const deneme = zehirli ? 3 : t.some((d) => d === "gecici") ? 2 : 1;
    const sure = deneme * (SABIT + t.length * ISLEM) + (deneme - 1) * BEKLE;
    cagri += deneme; islenen += deneme * t.length;
    if (zehirli) { olu += t.length; esDusen += t.length - zehirli; }
    for (let j = 0; j < t.length; j++) bitis.push(t.length / varis * 1000 + sure);
  }
  return { ad: `akis tabanli (boy ${boy})`, bek: KABUL, bitis, cagri, islenen,
    yeniden: islenen - N, sure: cagri * SABIT + islenen * ISLEM,
    oluMektup: olu, esDusen, hataGoren: "hic kimse", denemeKimde: "altyapi" };
};

export const olc = (m) => ({ ...m, bekOrt: m.bek ?? ort(m.bitis), bitOrt: ort(m.bitis),
  bit99: yuzde(m.bitis, 0.99), maliyet: m.cagri * CAGRI_B + m.sure * MS_B });

if (import.meta.url === `file://${process.argv[1]}`) {
  const k = kayitlar(), say = (d) => k.filter((x) => x === d).length;
  console.log(`${N} kayit: ${say("temiz")} temiz, ${say("gecici")} gecici hatali, ${say("zehirli")} zehirli`);
  const m = [eszamanli(k), eszamansiz(k), akis(k, 100)].map(olc);
  console.log("\n" + "model".padEnd(24) + "cagiranin gordugu".padEnd(19) +
    "is biter (ort)".padEnd(16) + "is biter (99)".padEnd(15) + "islem cagrisi".padEnd(15) +
    "fazladan isleme".padEnd(17) + "olu mektup".padEnd(12) + "maliyet");
  for (const x of m)
    console.log(x.ad.padEnd(24) + `${x.bekOrt.toFixed(0)} ms`.padEnd(19) +
      `${(x.bitOrt / 1000).toFixed(1)} sn`.padEnd(16) + `${(x.bit99 / 1000).toFixed(1)} sn`.padEnd(15) +
      String(x.cagri).padEnd(15) + String(x.yeniden).padEnd(17) + String(x.oluMektup).padEnd(12) +
      x.maliyet.toFixed(2));
  console.log("\n" + "model".padEnd(24) + "hatayi goren".padEnd(15) + "yeniden deneme kimde".padEnd(22) +
    "100 kayda dusen fazladan isleme");
  for (const x of m)
    console.log(x.ad.padEnd(24) + x.hataGoren.padEnd(15) + x.denemeKimde.padEnd(22) +
      (x.yeniden / N * 100).toFixed(1));
  const a = m[2];
  console.log(`\nolu mektup kutusuna dusen ${a.oluMektup} kaydin ${a.esDusen} tanesi saglamdi: ` +
    `zehirli kayit basina ${(a.esDusen / say("zehirli")).toFixed(1)} saglam kayit es dustu`);
}
20000 kayit: 19551 temiz, 436 gecici hatali, 13 zehirli

model                   cagiranin gordugu  is biter (ort)  is biter (99)  islem cagrisi  fazladan isleme  olu mektup  maliyet
eszamanli               669 ms             0.7 sn          1.5 sn         20449          449              0           43.45
eszamansiz              5 ms               2.1 sn          61.3 sn        20462          462              13          43.48
akis tabanli (boy 100)  5 ms               130.9 sn        241.2 sn       380            18000            1300        38.43

model                   hatayi goren   yeniden deneme kimde  100 kayda dusen fazladan isleme
eszamanli               cagiran        cagiran               2.2
eszamansiz              hic kimse      altyapi               2.3
akis tabanli (boy 100)  hic kimse      altyapi               90.0

olu mektup kutusuna dusen 1300 kaydin 1287 tanesi saglamdi: zehirli kayit basina 99.0 saglam kayit es dustu

Birinci tablonun iki sütunu ters yönde hareket eder. Çağıranın gördüğü gecikme 669 ms’den 5 ms’ye iner: eşzamansız modelde çağıran işin bitmesini değil, kabul edilmesini bekler. Ama işin bittiği an 0,7 saniyeden 2,1 saniyeye, yüzde doksan dokuzuncu dilim 61,3 saniyeye çıkar. Kazanılan gecikme yok olmaz; çağıranın göremediği bir yere taşınır.

İkinci tablo asıl devri gösterir. Eşzamanlı modelde hatayı çağıran görür ve yeniden denemeye o karar verir; on üç zehirli kaydın on üçü de bildirilir. Öteki iki modelde hatayı hiç kimse görmez: altyapı üç kez dener, kaydı ölü mektup kutusuna bırakır, çağıran çoktan gitmiştir. Yeniden deneme sorumluluğunu devretmek onu ortadan kaldırmaz, hatanın görünürlüğünü kaldırır.

Son sütun devrin bedelini verir. İlk iki modelde her yüz kayda 2,2 fazladan işleme düşer; akış tabanlı modelde 90. Neden toplu işin bölünmemesidir: yüz kayıtlık bir toplu işte tek geçici hata yüz kaydın hepsini yeniden işletir. Aynı bölünmezlik ölü mektup kutusunda da geçerlidir — 1.300 kaydın 1.287’si sağlamdır ve tek suçları zehirli bir kayıtla aynı toplu işe düşmektir.

Toplu Okuma Boyutu

Toplu boy tek bir sayıdır ama üç şeyi birden belirler: çağrı sayısını, yeniden işleme miktarını ve bir kaydın sonucuna ne zaman ulaşıldığını.

// olcum-agi/toplu-tarama.mjs — akis tabanli modelde toplu okuma boyu taranir (model)
import { N, ISLEM, SABIT, kayitlar, akis, olc } from "./cagirma-modelleri.mjs";

export const SINIR = 900;                          // kurgu sure siniri, saniye
export const BOY = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500];

if (import.meta.url === `file://${process.argv[1]}`) {
  const k = kayitlar(), zehirli = k.filter((x) => x === "zehirli").length;
  console.log("boy".padEnd(7) + "cagri".padEnd(9) + "islenen kayit".padEnd(15) +
    "fazladan".padEnd(11) + "toplam sure".padEnd(14) + "maliyet".padEnd(10) +
    "kaydin gecikmesi".padEnd(18) + "olu mektup".padEnd(12) + "es dusen".padEnd(10) + "toplu is / sinir");
  const satir = BOY.map((b) => olc(akis(k, b)));
  for (let i = 0; i < BOY.length; i++) {
    const x = satir[i], toplu = (SABIT + BOY[i] * ISLEM) / 1000;
    console.log(String(BOY[i]).padEnd(7) + String(x.cagri).padEnd(9) + String(x.islenen).padEnd(15) +
      `%${(x.yeniden / N * 100).toFixed(0)}`.padEnd(11) + `${(x.sure / 1000).toFixed(0)} sn`.padEnd(14) +
      x.maliyet.toFixed(2).padEnd(10) + `${(x.bitOrt / 1000).toFixed(1)} sn`.padEnd(18) +
      String(x.oluMektup).padEnd(12) + String(x.esDusen).padEnd(10) +
      `${toplu.toFixed(0)}/${SINIR} sn` + (toplu > SINIR ? " — sigmiyor" : ""));
  }
  const ucuz = satir.reduce((a, b) => (b.maliyet < a.maliyet ? b : a));
  const hizli = satir.reduce((a, b) => (b.sure < a.sure ? b : a));
  console.log(`\nen ucuz boy: ${ucuz.ad} — ${ucuz.maliyet.toFixed(2)} birim; ` +
    `en kisa toplam sure: ${hizli.ad} — ${(hizli.sure / 1000).toFixed(0)} sn`);
  const b1 = satir[0], b500 = satir[8];
  console.log(`boy 1'den 500'e: cagri ${b1.cagri} -> ${b500.cagri} (${(b1.cagri / b500.cagri).toFixed(0)} kat az), ` +
    `islenen kayit ${b1.islenen} -> ${b500.islenen} (${(b500.islenen / b1.islenen).toFixed(1)} kat cok)`);
  console.log(`${zehirli} zehirli kayit boy 1'de ${b1.esDusen} saglam kaydi, boy 500'de ${b500.esDusen} ` +
    `saglam kaydi birlikte olu mektup kutusuna dusurdu`);
}
boy    cagri    islenen kayit  fazladan   toplam sure   maliyet   kaydin gecikmesi  olu mektup  es dusen  toplu is / sinir
1      20462    20462          %2         13300 sn      43.48     2.1 sn            13          0         1/900 sn
2      10456    20912          %5         10979 sn      32.68     3.8 sn            26          13        1/900 sn
5      4440     22200          %11        9990 sn       27.20     9.1 sn            65          52        2/900 sn
10     2420     24200          %21        10285 sn      26.92     17.8 sn           130         117       4/900 sn
25     1166     29150          %46        11952 sn      30.46     42.5 sn           325         312       10/900 sn
50     684      34200          %71        13851 sn      34.97     77.4 sn           650         637       20/900 sn
100    380      38000          %90        15295 sn      38.43     130.9 sn          1300        1287      40/900 sn
250    172      43000          %115       17243 sn      43.19     285.5 sn          3000        2987      100/900 sn
500    91       45500          %127       18223 sn      45.60     534.1 sn          5500        5487      200/900 sn
1000   49       49000          %145       19612 sn      49.06     1071.6 sn         9000        8987      400/900 sn
2500   23       57500          %188       23006 sn      57.53     2998.2 sn         17500       17487     1000/900 sn — sigmiyor

en ucuz boy: akis tabanli (boy 10) — 26.92 birim; en kisa toplam sure: akis tabanli (boy 5) — 9990 sn
boy 1'den 500'e: cagri 20462 -> 91 (225 kat az), islenen kayit 20462 -> 45500 (2.2 kat cok)
13 zehirli kayit boy 1'de 0 saglam kaydi, boy 500'de 5487 saglam kaydi birlikte olu mektup kutusuna dusurdu

Maliyet sütunu bir çukur çizer: boy 1’de 43,48, boy 10’da 26,92, boy 2500’de 57,53 birim. Sol yamaç çağrı başına sabit yükten gelir — her çağrı 250 ms kurulum ister ve bu yirmi bin kez ödenir. Sağ yamaç yeniden işlemeden gelir: boy büyüdükçe bir toplu işte hatalı kayıt bulunma olasılığı artar ve boy 2500’de kayıtların %188’i fazladan işlenir. En ucuz nokta en hızlı nokta değildir: en kısa süre boy 5’te, en düşük maliyet boy 10’dadır.

Üçüncü kuvvet gecikmedir ve tek yönde artar: bir kaydın sonucuna ulaşma süresi boy 1’de 2,1 saniye, boy 500’de 534 saniyedir; kayıt, kendisiyle ilgisi olmayan 499 kaydın işlenmesini bekler. Dördüncüsü bir eşiktir: boy 2500’de toplu işin kendisi 1.000 saniye tutar ve 900 saniyelik süre sınırına sığmaz. Satır yazılır ama seçilemez.

Eş düşen sütunu bölünmezliğin bedelini tek sayıya indirir: on üç zehirli kayıt boy 1’de hiçbir sağlam kaydı götürmez, boy 500’de 5.487 sağlam kaydı ölü mektup kutusuna düşürür. Toplu boyu büyütmek verimle birlikte hata yarıçapını da büyütür.

Yinelenen İşlemenin Bedeli

Fazladan işleme bir maliyet kalemi olarak sayıldı; asıl soru aynı kaydı iki kez işlemenin zararsız olup olmadığıdır. Doğrulama için zararsızdır, fatura satırı için değildir.

// olcum-agi/tekillestirme.mjs — yinelenen islemenin bedeli ve tekillestirmenin bedeli (model)
import { N, MS_B, kayitlar, eszamanli, eszamansiz, akis, olc } from "./cagirma-modelleri.mjs";

export const OKU = 15, YAZ = 10, PENCERE = 24 * 3600;   // ms, ms, saniye (kurgu)
export const SURME_GECIKMESI = 3 * 24 * 3600;           // olu mektup kutusu elle 3 gun sonra surulur

if (import.meta.url === `file://${process.argv[1]}`) {
  const k = kayitlar();
  const m = [eszamanli(k), eszamansiz(k), akis(k, 10)].map(olc);
  console.log("model".padEnd(23) + "fazladan isleme".padEnd(17) + "fazla fatura satiri".padEnd(21) +
    "tekillestirme eki".padEnd(19) + "ek maliyet".padEnd(12) + "pencere disi yineleme");
  for (const x of m) {
    const ek = x.islenen * OKU + N * YAZ;
    console.log(x.ad.padEnd(23) + String(x.yeniden).padEnd(17) + String(x.yeniden).padEnd(21) +
      `${(ek / 1000).toFixed(0)} sn`.padEnd(19) + (ek * MS_B).toFixed(2).padEnd(12) +
      String(x.oluMektup));
  }
  const a = m[2], oran = (a.islenen * OKU + N * YAZ) / a.sure;
  console.log(`\ntekillestirme penceresi ${PENCERE / 3600} saat; olu mektup kutusu ${SURME_GECIKMESI / 3600} saat ` +
    `sonra surulur — pencere kapali, ${a.oluMektup} kayit ikinci kez islenir`);
  console.log(`akis tabanli (boy 10) icin tekillestirme is suresinin %${(oran * 100).toFixed(1)}'i kadar ek yuk getirir; ` +
    `karsiliginda ${a.yeniden} fazla fatura satiri onlenir`);
}
model                  fazladan isleme  fazla fatura satiri  tekillestirme eki  ek maliyet  pencere disi yineleme
eszamanli              449              449                  507 sn             1.27        0
eszamansiz             462              462                  507 sn             1.27        13
akis tabanli (boy 10)  4200             4200                 563 sn             1.41        130

tekillestirme penceresi 24 saat; olu mektup kutusu 72 saat sonra surulur — pencere kapali, 130 kayit ikinci kez islenir
akis tabanli (boy 10) icin tekillestirme is suresinin %5.5'i kadar ek yuk getirir; karsiliginda 4200 fazla fatura satiri onlenir

Tekilleştirmenin bedeli küçüktür: iş süresinin %5,5’i ve 1,41 birim. Karşılığında 4.200 fazla fatura satırı önlenir; bu kıyas tekilleştirmeyi bir seçenek olmaktan çıkarır.

Son sütun tekilleştirmenin de bir kısıtla geldiğini gösterir. Anahtar sonsuza kadar saklanmaz, pencere 24 saattir; ölü mektup kutusu ise elle, 72 saat sonra sürülür. Sürülen 130 kaydın tekilleştirme kaydı çoktan silinmiştir ve hepsi ikinci kez işlenir. Önlemin kendi penceresi, önlemin kapsamadığı bir yol açar.

Özet

  • Çağıranın gördüğü gecikme 669 ms’den 5 ms’ye iner ama işin bittiği an 0,7 saniyeden 2,1 saniyeye, yüzde doksan dokuzuncu dilim 61,3 saniyeye çıkar; gecikme yok olmaz, görünmez olur.
  • Eşzamanlı modelde on üç zehirli kaydı çağıran görür; öteki ikisinde hatayı hiç kimse görmez — deneme sorumluluğunu devretmek onu kaldırmaz, görünürlüğü kaldırır.
  • Toplu boy taramasında maliyet çukur çizer: boy 1’de 43,48, boy 10’da 26,92, boy 2500’de 57,53 birim. En kısa süre boy 5’te, en düşük maliyet boy 10’dadır ve boy 2500 süre sınırına sığmaz.
  • Toplu iş bölünmediği için hata yarıçapı boyla büyür: on üç zehirli kayıt boy 1’de hiçbir sağlam kaydı, boy 500’de 5.487 sağlam kaydı ölü mektup kutusuna düşürür.
  • Tekilleştirme iş süresine %5,5 ekleyip 4.200 fazla fatura satırını önler, ama 24 saatlik penceresi vardır; 72 saat sonra sürülen 130 kayıt pencerenin dışında kalır ve ikinci kez işlenir.

Sonraki Adım

Üç modelin gecikme sayıları da tek bir varsayımın üzerine kuruldu: çağrı geldiğinde işlevi çalıştıracak bir örnek hazırdır. Sabit yük olarak yazılan 250 ms o hazır durumun bedelidir.

Hazır örnek her zaman yoktur. Kapasite kararı devredildiği için örnekler istek geldikçe yaratılır, boşta kalınca geri alınır. Sonraki ders bir sıcak havuz modeli koşturur ve havuz ömrü ile trafik profili değiştikçe soğuk çağrı oranını, gecikmeye eklenen süreyi ve kuyruğun ne zaman oluştuğunu sayar; ardından üç azaltma yolunu ayrı ayrı ölçer.

İ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