İçeriğe geç
academia.sh

Ders 04 / 20

Kaynak ve Süre Sınırları

Üç eşik — bellek, süre ve eşzamanlılık — on iki işlik bir kümeye uygulanır ve kaç işin sığmadığı sayılır; bellek kademeleri taranarak sürenin düştüğü ama birim maliyetin çukur çizdiği gösterilir, en ucuz nokta ortada çıkar; eşzamanlılık sınırı hesap düzeyinde paylaşıldığında bir işlevin ötekini aç bıraktığı kısma oranı ve kayıp isteklerle ölçülür.

İçindekiler

Üç ders boyunca aynı sayılar arka planda durdu: 900 saniyelik süre sınırı, bellek kademeleri ve 200’lük eşzamanlılık. Bu ders üçünü ölçünün merkezine alır, çünkü kapasite yönetimini devretmenin karşılığı tam olarak budur — kapasite kararı gitmiştir, yerine üç sayı gelmiştir.

Kısıtlama iki biçimde görünür: kimi iş eşiğe hiç sığmaz ve bölünmek zorunda kalır, kimi iş sığar ama en ucuz ya da en hızlı biçiminde koşamaz. İkisi de sayılabilir.

IH19. Eşikler kurgudur: bellek tavanı 3008 MB, süre sınırı 900 saniye, hesap düzeyindeki eşzamanlılık sınırı 200’dür. IH20. Ölçüm ağının on iki kurgu işi bellek, süre ve tepe eşzamanlılık değerleriyle listelenir; süreler 1024 MB’lık kademeye göredir. IH21. İşlemci payı bellekle orantılıdır: 256 MB’da bir birim, her katta bir kat artar ve 2048 MB’da sekizde tavan yapar. IH22. Bir işin çalışma kümesi seçilen belleğe sığmazsa çöp toplama süresi eklenir; katsayı 0,15’tir ve 256 MB’ın altında iş bellek yetersizliğinden düşer. IH23. Eşzamanlılık modelinde gece işi 900 parçaya bölünmüştür, her parça yaklaşık 245 saniyedir ve sapma kendi yazılan üreteçten gelir, tohum 20260805’tir; saha bildirimi saniyede 25 istektir. IH24. Kısılan bildirim isteği bir saniye sonra yeniden dener, üçüncü denemeden sonra kaybedilir; fiyatlar kurgu birimdedir.

Üç Eşik, On İki İş

// olcum-agi/is-kumesi.mjs — uc esik bir is kumesine uygulanir, kac is sigmiyor (model)

export const BELLEK_TAVAN = 3008, SURE_SINIR = 900, ESZAMAN_SINIR = 200;   // MB, sn, es zamanli cagri

// Bolgesel olcum aginin kurgu isleri: [ad, calisma kumesi MB, tek kosum sn, tepe eszamanlilik]
export const IS = [
  ["okuma dogrulama", 180, 0.4, 148],
  ["saha bildirimi", 120, 0.3, 25],
  ["sube uc raporu", 300, 45, 8],
  ["gunluk ozet", 512, 60, 3],
  ["fatura uretimi", 900, 240, 40],
  ["gece toplu isleme (tek parca)", 700, 220600, 1],
  ["gece toplu isleme (246 parca)", 700, 897, 246],
  ["anomali taramasi", 2200, 700, 12],
  ["arsiv sikistirma", 1400, 1100, 6],
  ["aylik fatura kapanisi", 2600, 1500, 4],
  ["sayac kalibrasyon dokumu", 3400, 420, 2],
  ["sayac gorsel dogrulama", 5200, 95, 3],
];

export const denetle = ([ad, mb, sn, ez]) => {
  const asan = [];
  if (mb > BELLEK_TAVAN) asan.push("bellek");
  if (sn > SURE_SINIR) asan.push("sure");
  if (ez > ESZAMAN_SINIR) asan.push("eszamanlilik");
  return { ad, mb, sn, ez, asan };
};

// Sigmayan is icin dolasma yolu ve bedelinin cinsi.
export const DOLASMA = {
  bellek: (i) => `durumu disari al: ${Math.ceil(i.mb / BELLEK_TAVAN)} parca ve ${i.mb - BELLEK_TAVAN} MB dis okuma`,
  sure: (i) => `parcala: ${Math.ceil(i.sn / SURE_SINIR)} cagri ve ${Math.ceil(i.sn / SURE_SINIR) - 1} ilerleme kaydi`,
  eszamanlilik: (i) => `kis: ${i.ez - ESZAMAN_SINIR} cagri bekler, ${Math.ceil(i.ez / ESZAMAN_SINIR)} tur`,
};

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log(`esikler: bellek ${BELLEK_TAVAN} MB, sure ${SURE_SINIR} sn, eszamanlilik ${ESZAMAN_SINIR}`);
  console.log("\n" + "is".padEnd(32) + "bellek".padEnd(10) + "sure".padEnd(11) + "eszaman".padEnd(10) + "sonuc");
  const d = IS.map(denetle);
  for (const i of d)
    console.log(i.ad.padEnd(32) + `${i.mb} MB`.padEnd(10) + `${i.sn} sn`.padEnd(11) +
      String(i.ez).padEnd(10) + (i.asan.length ? `${i.asan.join(" + ")} asiyor` : "sigiyor"));
  const sigmayan = d.filter((i) => i.asan.length);
  const say = (e) => d.filter((i) => i.asan.includes(e)).length;
  console.log(`\n${IS.length} isten ${sigmayan.length} tanesi sigmiyor: bellek ${say("bellek")}, ` +
    `sure ${say("sure")}, eszamanlilik ${say("eszamanlilik")} (bir is birden cok esigi asabilir)`);
  console.log("\n" + "sigmayan is".padEnd(32) + "asilan esik".padEnd(15) + "dolasma yolu ve bedeli");
  for (const i of sigmayan)
    for (const e of i.asan) console.log(i.ad.padEnd(32) + e.padEnd(15) + DOLASMA[e](i));
}
esikler: bellek 3008 MB, sure 900 sn, eszamanlilik 200

is                              bellek    sure       eszaman   sonuc
okuma dogrulama                 180 MB    0.4 sn     148       sigiyor
saha bildirimi                  120 MB    0.3 sn     25        sigiyor
sube uc raporu                  300 MB    45 sn      8         sigiyor
gunluk ozet                     512 MB    60 sn      3         sigiyor
fatura uretimi                  900 MB    240 sn     40        sigiyor
gece toplu isleme (tek parca)   700 MB    220600 sn  1         sure asiyor
gece toplu isleme (246 parca)   700 MB    897 sn     246       eszamanlilik asiyor
anomali taramasi                2200 MB   700 sn     12        sigiyor
arsiv sikistirma                1400 MB   1100 sn    6         sure asiyor
aylik fatura kapanisi           2600 MB   1500 sn    4         sure asiyor
sayac kalibrasyon dokumu        3400 MB   420 sn     2         bellek asiyor
sayac gorsel dogrulama          5200 MB   95 sn      3         bellek asiyor

12 isten 6 tanesi sigmiyor: bellek 2, sure 3, eszamanlilik 1 (bir is birden cok esigi asabilir)

sigmayan is                     asilan esik    dolasma yolu ve bedeli
gece toplu isleme (tek parca)   sure           parcala: 246 cagri ve 245 ilerleme kaydi
gece toplu isleme (246 parca)   eszamanlilik   kis: 46 cagri bekler, 2 tur
arsiv sikistirma                sure           parcala: 2 cagri ve 1 ilerleme kaydi
aylik fatura kapanisi           sure           parcala: 2 cagri ve 1 ilerleme kaydi
sayac kalibrasyon dokumu        bellek         durumu disari al: 2 parca ve 392 MB dis okuma
sayac gorsel dogrulama          bellek         durumu disari al: 2 parca ve 2192 MB dis okuma

On iki işin altısı sığmaz: üçü süre, ikisi bellek, biri eşzamanlılık sınırını aşar. Alt tablo dolaşmanın bedelini kendi biriminde yazar — gece toplu işlemesi tek parçada 220.600 saniye tuttuğu için 246 çağrıya ve 245 ilerleme kaydına bölünür. Tek bir işin içinde bedava olan “nerede kaldım” bilgisi, bölününce dışarıda tutulan ve her çağrıda okunup yazılan bir kaleme dönüşür.

İki satır aynı işin iki halidir. Gece işi tek parçada süre sınırına takılır; 246 parçaya bölününce ondan kurtulur ve eşzamanlılık sınırına takılır. Bir eşiğin etrafından dolaşmak işi başka bir eşiğe taşır: 246 parça 200’lük sınıra iki turda sığar, 46 çağrı ilk turu bekler.

Bellek tavanını aşan iki işin dolaşma yolu başkadır: durumu dışarı almak. Sayaç görsel doğrulaması 5.200 MB ister, tavan 3.008 MB’dır ve aradaki 2.192 MB her koşumda dışarıdan okunur — bellek erişimini ağ erişimine çevirmek demektir.

Bellek Kademesi Taraması

Bellek tek başına bir sınır değildir; işlemci payını da belirler. Bu yüzden belleği artırmak süreyi kısaltır ve birim maliyet iki karşıt kuvvetin çarpımı olur.

// olcum-agi/bellek-taramasi.mjs — bellek artinca sure duser, birim maliyet once duser sonra artar (model)
import { SURE_SINIR } from "./is-kumesi.mjs";

export const KADEME = [128, 256, 512, 768, 1024, 1536, 2048, 3008];   // MB, kurgu kademeler
export const TABAN_MB = 256, TAVAN_PAY = 8;      // islemci payi bellekle orantili, 2048'de tavan
export const CALISMA_KUMESI = 900, GC_KAT = 0.15, ALT_SINIR = 256;
export const SERI = 4000, PARALEL = 944000;      // ms: fatura uretiminin seri ve paralel bolumu
export const GB_SN = 0.001, CAGRI_B = 0.0005;    // kurgu birim

export const pay = (mb) => Math.min(mb / TABAN_MB, TAVAN_PAY);
export const cop = (mb) => (mb >= CALISMA_KUMESI ? 0 : (CALISMA_KUMESI / mb - 1) ** 2 * GC_KAT * PARALEL);
export const kos = (mb) => {
  if (mb < ALT_SINIR) return { mb, sigar: false, neden: "bellek yetmiyor" };
  const sure = (SERI + PARALEL / pay(mb) + cop(mb)) / 1000;
  return { mb, sigar: sure <= SURE_SINIR, neden: sure > SURE_SINIR ? "sure siniri" : "",
    sure, pay: pay(mb), cop: cop(mb) / 1000,
    maliyet: (mb / 1024) * sure * GB_SN + CAGRI_B };
};

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log(`fatura uretimi: calisma kumesi ${CALISMA_KUMESI} MB, paralel bolum ` +
    `${PARALEL / 1000} sn (${TABAN_MB} MB'da), islemci payi tavani ${TAVAN_PAY}`);
  console.log("\n" + "bellek".padEnd(10) + "islemci payi".padEnd(14) + "cop toplama".padEnd(14) +
    "sure".padEnd(12) + "birim maliyet".padEnd(16) + "sonuc");
  const s = KADEME.map(kos);
  for (const x of s)
    console.log(`${x.mb} MB`.padEnd(10) + (x.sigar === false && !x.sure ? "—".padEnd(14) + "—".padEnd(14) +
      "—".padEnd(12) + "—".padEnd(16) : x.pay.toFixed(2).padEnd(14) + `${x.cop.toFixed(1)} sn`.padEnd(14) +
      `${x.sure.toFixed(1)} sn`.padEnd(12) + x.maliyet.toFixed(4).padEnd(16)) +
      (x.sigar ? "sigiyor" : x.neden));
  const uygun = s.filter((x) => x.sigar);
  const ucuz = uygun.reduce((a, b) => (b.maliyet < a.maliyet ? b : a));
  const hizli = uygun.reduce((a, b) => (b.sure < a.sure ? b : a));
  const genis = uygun[uygun.length - 1];
  console.log(`\nen ucuz kademe ${ucuz.mb} MB: ${ucuz.sure.toFixed(1)} sn, ${ucuz.maliyet.toFixed(4)} birim`);
  console.log(`en hizli kademe ${hizli.mb} MB: ${(ucuz.sure / hizli.sure).toFixed(2)} kat hizli, ` +
    `%${((hizli.maliyet / ucuz.maliyet - 1) * 100).toFixed(1)} pahali`);
  console.log(`en genis kademe ${genis.mb} MB: sure ayni, maliyet ` +
    `%${((genis.maliyet / ucuz.maliyet - 1) * 100).toFixed(0)} pahali — islemci payi tavan yaptigi icin`);
}
fatura uretimi: calisma kumesi 900 MB, paralel bolum 944 sn (256 MB'da), islemci payi tavani 8

bellek    islemci payi  cop toplama   sure        birim maliyet   sonuc
128 MB    —             —             —           —               bellek yetmiyor
256 MB    1.00          896.1 sn      1844.1 sn   0.4615          sure siniri
512 MB    2.00          81.3 sn       557.3 sn    0.2792          sigiyor
768 MB    3.00          4.2 sn        322.8 sn    0.2426          sigiyor
1024 MB   4.00          0.0 sn        240.0 sn    0.2405          sigiyor
1536 MB   6.00          0.0 sn        161.3 sn    0.2425          sigiyor
2048 MB   8.00          0.0 sn        122.0 sn    0.2445          sigiyor
3008 MB   8.00          0.0 sn        122.0 sn    0.3589          sigiyor

en ucuz kademe 1024 MB: 240.0 sn, 0.2405 birim
en hizli kademe 2048 MB: 1.97 kat hizli, %1.7 pahali
en genis kademe 3008 MB: sure ayni, maliyet %49 pahali — islemci payi tavan yaptigi icin

Süre sütunu tek yönde iner: 1.844 saniyeden 122 saniyeye. Maliyet sütunu inip çıkar: 0,4615’ten 0,2405’e düşer, sonra 0,3589’a yükselir; en ucuz kademe 1024 MB, tablonun ortasıdır. Sağdaki yükselişin nedeni son satırdadır — işlemci payı 2048 MB’da tavan yapar, 3008 MB seçmek süreyi kısaltmadan faturayı %49 artırır.

Soldaki yükselişin nedeni başkadır. 256 MB’da işin çalışma kümesi belleğe sığmaz ve çöp toplama 896 saniye ekler; iş 1.844 saniye sürer ve süre sınırının dışına düşer. Bu satır iki eşiğin bağlı olduğunu gösterir: bellek kademesini düşürmek işi süre sınırına çarptırır. 512 MB’da aynı etki 81 saniyeye iner ve iş sığar, ama 1024 MB’dan hem yavaş hem pahalıdır.

Son satırlar kararın tek olmadığını söyler: 2048 MB, 1024 MB’dan 1,97 kat hızlı ve yalnız %1,7 pahalıdır. Gecikmenin önemli olduğu iş için bu takas ucuzdur, kimsenin beklemediği gece işi için gereksizdir. Aynı tablo iki işe iki ayrı satır önerir.

Paylaşılan Sınır ve Kısma

Süre ve bellek işin kendi kararlarıdır. Eşzamanlılık değildir: sınır hesap düzeyindedir ve bütün işlevler onu paylaşır.

// olcum-agi/eszamanlilik.mjs — hesap duzeyinde paylasilan eszamanlilik siniri ve kisma (model)
import { ESZAMAN_SINIR } from "./is-kumesi.mjs";

export const ADIM_MS = 40, PENCERE_SN = 2400, ADIM = PENCERE_SN * 1000 / ADIM_MS;
export const PARCA = 900, PARCA_SN = 245, SAPMA = 20;   // gece isi: 900 parca, ~245 sn
export const BILDIRIM_ADIM = 8, YENIDEN = 25;           // 300 ms islem, 1 sn sonra yeniden deneme

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; }; };

export const kos = (rezerve) => {
  const tavan = ESZAMAN_SINIR - rezerve, r = uretec(20260805);
  const biterG = new Int32Array(ADIM + 20000), biterB = new Int32Array(ADIM + 20000);
  const bek = [new Int32Array(ADIM + 200), new Int32Array(ADIM + 200), new Int32Array(ADIM + 200)];
  let gAktif = 0, bAktif = 0, kalan = PARCA, kisilan = 0, kayip = 0, basari = 0, gecikme = 0;
  let geceBitis = -1, enCokG = 0, enCokB = 0;
  for (let a = 0; a < ADIM; a++) {
    gAktif -= biterG[a]; bAktif -= biterB[a];
    for (let d = 0; d < 3; d++) {
      const n = (d === 0 ? 1 : 0) + bek[d][a];
      for (let i = 0; i < n; i++) {
        if (gAktif + bAktif < ESZAMAN_SINIR) {
          bAktif++; biterB[a + BILDIRIM_ADIM]++; basari++; gecikme += d * YENIDEN * ADIM_MS;
        } else { kisilan++; if (d < 2) bek[d + 1][a + YENIDEN]++; else kayip++; }
      }
    }
    while (kalan > 0 && gAktif + bAktif < ESZAMAN_SINIR && gAktif < tavan) {
      const sn = PARCA_SN + (r() * 2 - 1) * SAPMA;
      gAktif++; biterG[a + Math.round(sn * 1000 / ADIM_MS)]++; kalan--;
    }
    if (gAktif > enCokG) enCokG = gAktif;
    if (bAktif > enCokB) enCokB = bAktif;
    if (kalan === 0 && gAktif === 0 && geceBitis < 0) geceBitis = a;
  }
  return { rezerve, tavan, geceBitis: geceBitis * ADIM_MS / 1000, tur: Math.ceil(PARCA / tavan),
    kisilan, kayip, basari, gelen: ADIM, kismaOrani: kisilan / ADIM, enCokG, enCokB };
};

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log(`hesap siniri ${ESZAMAN_SINIR}; gece isi ${PARCA} x ~${PARCA_SN} sn, ` +
    `bildirim ${1000 / ADIM_MS}/sn x ${BILDIRIM_ADIM * ADIM_MS} ms`);
  console.log("\n" + "duzen".padEnd(24) + "gece tavani".padEnd(13) + "gece biter".padEnd(13) +
    "tur".padEnd(6) + "kisilan bildirim".padEnd(18) + "kisma orani".padEnd(13) +
    "kaybedilen".padEnd(12) + "en cok yuva (gece / bildirim)");
  const p = kos(0), y = kos(40);
  for (const s of [p, y])
    console.log((s.rezerve ? `ayrilmis pay ${s.rezerve}` : "paylasilan").padEnd(24) +
      String(s.tavan).padEnd(13) + `${s.geceBitis.toFixed(0)} sn`.padEnd(13) + String(s.tur).padEnd(6) +
      String(s.kisilan).padEnd(18) + `%${(s.kismaOrani * 100).toFixed(1)}`.padEnd(13) +
      String(s.kayip).padEnd(12) + `${s.enCokG} / ${s.enCokB}`);
  console.log(`\nayrilmis pay gece isini ${(y.geceBitis - p.geceBitis).toFixed(0)} sn geciktiriyor; ` +
    `karsiliginda ${p.kisilan} kisma ve ${p.kayip} kayip bildirim onleniyor — ` +
    `gelen ${p.gelen} istekte kisma orani %${(p.kisilan / p.gelen * 100).toFixed(1)}`);
}
hesap siniri 200; gece isi 900 x ~245 sn, bildirim 25/sn x 320 ms

duzen                   gece tavani  gece biter   tur   kisilan bildirim  kisma orani  kaybedilen  en cok yuva (gece / bildirim)
paylasilan              200          1254 sn      5     14814             %24.7        4923        199 / 14
ayrilmis pay 40         160          1496 sn      6     0                 %0.0         0           160 / 8

ayrilmis pay gece isini 242 sn geciktiriyor; karsiliginda 14814 kisma ve 4923 kayip bildirim onleniyor — gelen 60000 istekte kisma orani %24.7

Paylaşılan düzende gece işi 199 yuvayı tutar. Bildirim isteklerinin %24,7’si kısılır, %8,2’si üç denemeden sonra kaybolur: 4.923 bildirim hiç gönderilmez. Gece işi bu sırada hiçbir hata görmez. Aç bırakma tek taraflı bir olaydır; kurbanın günlüğünde görünür, failin günlüğünde görünmez.

Ayrılmış pay bunu düzeltir ve bedelini açıkça yazar: gece tavanı 160’a inince iş beş tur yerine altı turda biter ve 1.254 saniye yerine 1.496 saniye sürer. 242 saniye gecikme, 14.814 kısma ve 4.923 kayıp bildirimin karşılığıdır. Ayrılmış pay yeni kapasite yaratmaz; var olanı bölüştürür ve bölüşümü bir kez, önceden yapmayı zorunlu kılar.

Özet

  • On iki işin altısı eşiklere sığmaz: üçü süre, ikisi bellek, biri eşzamanlılık sınırını aşar.
  • Bir eşiğin etrafından dolaşmak işi başka bir eşiğe taşır: gece işi tek parçada süre sınırını aşar, 246 parçaya bölününce eşzamanlılık sınırına takılır ve 245 ilerleme kaydı ödetir.
  • Bellek taramasında süre 1.844 saniyeden 122 saniyeye düşerken maliyet çukur çizer; en ucuz kademe 1024 MB’dır, 3008 MB süreyi hiç kısaltmadan faturayı %49 artırır.
  • 256 MB’da çalışma kümesi sığmadığı için çöp toplama 896 saniye ekler ve iş süre sınırının dışına düşer: bellek kademesini düşürmek işi ikinci bir eşiğe çarptırır.
  • Eşzamanlılık sınırı hesap düzeyinde paylaşıldığından gece işi 199 yuvayı tutar; bildirim isteklerinin %24,7’si kısılır, %8,2’si kaybolur ve gece işi bunu hiç görmez.
  • Ayrılmış pay kısmayı sıfıra indirir, bedeli gece işine yazar: beş tur yerine altı, 242 saniye ek.

Sonraki Adım

Bu ders işlevin etrafındaki üç duvarı ölçtü ve bütün ölçümler sessiz bir varsayım taşıdı: ölçülen kod, çalışan koddur.

Oysa gece işini 246 parçaya bölen değişiklik ya da bellek kademesini 512’den 1024’e çeken ayar bir gün yayımlanır ve o gün iki sürüm bir arada bulunur. Trafiğin hangi sürüme gideceği ve ayarların sürümle birlikte taşınıp taşınmadığı ayrı bir ölçü ister. Sonraki ders işlevin sürümlenmesini ve trafiğin sürümler arasında paylaştırılmasını ö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