İçeriğe geç
academia.sh

Ders 05 / 16

Hatalı Nesne Yaratımı

Pahalı istemcilerin her istekte yeniden yaratılması: eşzamanlılık artarken verimin artmamasının iki karşıt nedeni, yaratım oranının düzeltmenin yönünü seçmesi, kurulum işinin tekrar sayısıyla erimesi ve havuzun karşılığında tuttuğu nesne-turun bekleyen istek-tura karşı tartılması.

İçindekiler

Buraya kadarki dört ölçüm bir isteğin taşıdığı veriyi saydı. Bir isteğin maliyetinin bir parçası ise hiç taşınmaz: istek, kendisine hizmet edecek nesneler kurulmadan başlayamaz. Depo bağlantısı, seri hâle getirici, imza doğrulayıcı, biçim çözümleyici. Bu nesnelerin ne zaman kurulduğu bugüne kadar sorulmadı; hepsinin hazır durduğu varsayıldı.

Bağlantı havuzunun kendisi Veritabanı İşletimi ve Servis Tasarımı kurslarında kuruldu; havuz boyutunun bağlantı sınırına bağlılığı orada ölçüldü. Burada o mekanik tekrarlanmaz. Buradaki soru tanıdır: hangi belirti nesne yaratımını gösterir, aynı belirtiyi başka ne verir ve ikisini hangi sayı ayırır.

Belirti: Verim Eşzamanlılıkla Artmıyor

Belirti K01’in yazma yolunda görünüyor. Depoya ulaşan tepe istek hızı saniyede 138,89. İşçi süreç eklendikçe verim artmıyor; her isteğin yaptığı iş sabit — sınır oranı 1,00, taşınan bayt değişmemiş, alan sayısı aynı. Önceki dört ölçüt de temiz.

Neden A — nesne her istekte yeniden yaratılıyor. Kurulum işi istek sayısıyla çarpılıyor ve işlemcinin turdaki bütçesini yiyor. Hatalı nesne yaratımı (improper instantiation) budur.

Neden B — tek bir paylaşılan nesne var. Hiç yeniden yaratılmıyor, ama aynı anda tek istek kullanabiliyor. Verim nesnenin tutuş süresine kilitlenmiş.

İkisi de “verim düz” belirtisini verir ve düzeltmeleri birbirinin tersidir: biri daha az yaratmayı, öteki daha çok yaratmayı ister. Yanlış yöne gidilirse belirti kötüleşir.

Ölçüm Düzeneği

Aşağıdaki koşum bir modeldir: tur soyut bir adımdır, süre ölçülmez. Sayılan şey yaratım sayısı, iş birimi, bekleyen istek-tur ve tutulan nesne-turdur. Varışlar tohumlu bir üreteçten Poisson gelir.

KK5 — bir turda yapılabilen iş 100 birim; nesne kurulumu 60, kullanımı 10 birim; nesnenin tutuş süresi 3 tur; alt kaynağın kabul ettiği eşzamanlı nesne 24. Gerekçe: kurulum el sıkışma, kimlik doğrulama ve tampon ayırmayı içerir, kullanım tek bir çağrının hazırlanmasıdır, tutuş alt sistemin yanıt beklemesidir; son sayı her nesnenin alt tarafta bir oturum tuttuğunu ve bunun sonsuz olmadığını söyler. Duyarlılığı son tabloda kurulum maliyeti üzerinden verildi. Yirmi dört nesnelik sınır bu koşumda bağlayıcı olmuyor.

// nesne/yaratim.mjs — pahali istemcinin her istekte yeniden yaratilmasi. MODELDIR: tur soyut
// bir adimdir, sure olculmez; sayilan sey yaratim, is birimi, bekleyen istek-tur ve tutulan
// nesne-turdur. Varislar tohumlu bir uretecten Poisson.
const T = 4000, CEVRIM = 100;                    // 4000 tur, 100 tur = 1 s
const IS = 100, KUR = 60, KUL = 10, TUTUS = 3;   // KK5: tur basina is butcesi ve nesne maliyetleri
const SINIR = 24;                                // KK5: alt kaynagin kabul ettigi eszamanli nesne
const TEPE = 138.89, ORT = 46.30;                // K01: depoya ulasan tepe ve ortalama istek/s

function kosum({ havuz, lam }) {                 // havuz: null ise her istekte yeni nesne
  let s = 20260801 % 2147483647;
  const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;
  const poisson = (l) => { const L = Math.exp(-l); let k = 0, p = 1;
    do { k += 1; p *= rast(); } while (p > L); return k - 1; };
  const kuyruk = [];                             // bekleyen istek sayisi
  let bosta = 0, acik = 0;                       // havuzda bos duran nesne, alt kaynakta acik nesne
  const mesgul = [];                             // { bitis } — kullanimdaki nesneler
  const c = { gelen: 0, biten: 0, yaratim: 0, bekleyen: 0, tutulan: 0,
    kurulumIs: 0, kullanimIs: 0 };

  for (let t = 0; t < T; t += 1) {
    for (let n = mesgul.length - 1; n >= 0; n -= 1) if (mesgul[n].bitis <= t) {
      mesgul.splice(n, 1);
      if (havuz === null) acik -= 1; else bosta += 1;     // havuzsuz duzen nesneyi atar
    }
    const gelen = poisson(lam);
    c.gelen += gelen;
    for (let n = 0; n < gelen; n += 1) kuyruk.push(t);
    let butce = IS;
    while (kuyruk.length > 0) {
      let nesne = false;
      if (havuz === null) {                               // her istekte yarat
        if (acik >= SINIR) break;
        if (butce < KUR + KUL) break;
        butce -= KUR; c.kurulumIs += KUR; c.yaratim += 1; acik += 1; nesne = true;
      } else if (bosta > 0) {                             // havuzdan al
        bosta -= 1; nesne = true;
      } else if (acik < Math.min(havuz, SINIR)) {         // havuzu buyut
        if (butce < KUR + KUL) break;
        butce -= KUR; c.kurulumIs += KUR; c.yaratim += 1; acik += 1; nesne = true;
      }
      if (!nesne) break;
      if (butce < KUL) break;
      butce -= KUL; c.kullanimIs += KUL;
      kuyruk.shift(); c.biten += 1; mesgul.push({ bitis: t + TUTUS });
    }
    c.bekleyen += kuyruk.length;
    c.tutulan += acik;
  }
  return c;
}

const say = (x) => x.toLocaleString("tr-TR");
const PLAN = [["her istekte yarat", null], ["tek paylasilan nesne", 1],
  ["havuz 5", 5], ["havuz 12", 12], ["havuz 24", 24]];
console.log(`model: ${T} tur (${T / CEVRIM} s), tur basina is butcesi ${IS} birim, nesne kurulumu ` +
  `${KUR} + kullanimi ${KUL} birim, tutus ${TUTUS} tur, alt kaynak siniri ${SINIR} nesne (KK5); ` +
  `varislar Poisson, tohum 20260801`);

for (const [etiket, lam] of [["ortalama", ORT / CEVRIM], ["tepe", TEPE / CEVRIM]]) {
  console.log(`\n${etiket} yuk: ${(lam * CEVRIM).toFixed(2)} istek/s (${lam.toFixed(4)} varis/tur)`);
  console.log(`${"plan".padEnd(22)}${"biten".padStart(8)}${"verim/s".padStart(10)}` +
    `${"yaratim".padStart(9)}${"yaratim orani".padStart(15)}${"tekrar".padStart(9)}` +
    `${"kurulum is payi".padStart(17)}${"bekleyen istek-tur".padStart(20)}${"tutulan nesne-tur".padStart(19)}`);
  for (const [ad, havuz] of PLAN) {
    const k = kosum({ havuz, lam });
    const tekrar = k.biten / Math.max(k.yaratim, 1);
    console.log(ad.padEnd(22) + say(k.biten).padStart(8) + (k.biten / (T / CEVRIM)).toFixed(2).padStart(10) +
      say(k.yaratim).padStart(9) + (k.yaratim / Math.max(k.biten, 1)).toFixed(4).padStart(15) +
      tekrar.toFixed(2).padStart(9) +
      (k.kurulumIs / Math.max(k.kurulumIs + k.kullanimIs, 1)).toFixed(4).padStart(17) +
      say(k.bekleyen).padStart(20) + say(k.tutulan).padStart(19));
  }
}

const t1 = kosum({ havuz: null, lam: TEPE / CEVRIM }), t5 = kosum({ havuz: 5, lam: TEPE / CEVRIM });
const t24 = kosum({ havuz: 24, lam: TEPE / CEVRIM });
console.log(`\ntavanlar (hesap, tur basina tam istek): her istekte yarat ` +
  `${Math.floor(IS / (KUR + KUL)) * CEVRIM} istek/s; isinmis havuz p ile ` +
  `${(CEVRIM / TUTUS).toFixed(2)} x p, is butcesi tavani ${Math.floor(IS / KUL) * CEVRIM} istek/s; ` +
  `alt kaynak siniri ${((SINIR / TUTUS) * CEVRIM).toFixed(2)} istek/s (p=5 icin ${((5 / TUTUS) * CEVRIM).toFixed(2)})`);
console.log(`tepe yukte: yaratim ${say(t1.yaratim)} -> ${say(t5.yaratim)} ` +
  `(${(t1.yaratim / Math.max(t5.yaratim, 1)).toFixed(1)} kat az), kurulum isi ` +
  `${say(t1.kurulumIs)} -> ${say(t5.kurulumIs)} birim, bekleyen istek-tur ` +
  `${say(t1.bekleyen)} -> ${say(t5.bekleyen)}`);
console.log(`havuzun bedeli: tutulan nesne-tur havuz 5'te ${say(t5.tutulan)}, havuz 24'te ` +
  `${say(t24.tutulan)} (${(t24.tutulan / t5.tutulan).toFixed(2)} kat); havuz 24 verimi ` +
  `${(t24.biten / (T / CEVRIM)).toFixed(2)} istek/s, havuz 5 verimi ${(t5.biten / (T / CEVRIM)).toFixed(2)}`);

console.log(`\nkurulum isinin payi tekrarla nasil eriyor (hesap): pay = ${KUR} / (${KUR} + tekrar x ${KUL})`);
console.log(`${"tekrar".padStart(8)}${"kurulum is payi".padStart(17)}${"istek basina is".padStart(17)}`);
for (const tekrar of [1, 2, 5, 10, 50, 200])
  console.log(String(tekrar).padStart(8) + (KUR / (KUR + tekrar * KUL)).toFixed(4).padStart(17) +
    (KUR / tekrar + KUL).toFixed(2).padStart(17));

console.log(`\nkurulum maliyeti degisirse havuzun kazanci (hesap, tekrar 200)`);
console.log(`${"kurulum".padStart(8)}${"tekrar 1".padStart(10)}${"tekrar 200".padStart(12)}` +
  `${"kazanc kat".padStart(12)}${"kurtarilan birim".padStart(18)}`);
for (const kur of [5, 10, 30, 60]) {
  const bir = kur + KUL, ikiyuz = kur / 200 + KUL;
  console.log(String(kur).padStart(8) + bir.toFixed(2).padStart(10) + ikiyuz.toFixed(2).padStart(12) +
    (bir / ikiyuz).toFixed(2).padStart(12) + (bir - ikiyuz).toFixed(2).padStart(18));
}
model: 4000 tur (40 s), tur basina is butcesi 100 birim, nesne kurulumu 60 + kullanimi 10 birim, tutus 3 tur, alt kaynak siniri 24 nesne (KK5); varislar Poisson, tohum 20260801

ortalama yuk: 46.30 istek/s (0.4630 varis/tur)
plan                     biten   verim/s  yaratim  yaratim orani   tekrar  kurulum is payi  bekleyen istek-tur  tutulan nesne-tur
her istekte yarat        1.867     46.67    1.867         1.0000     1.00           0.8571                 866              5.598
tek paylasilan nesne     1.333     33.33        1         0.0008  1333.00           0.0045           1.141.381              3.997
havuz 5                  1.870     46.75        5         0.0027   374.00           0.0158                  29             19.966
havuz 12                 1.870     46.75        7         0.0037   267.14           0.0220                   2             27.439
havuz 24                 1.870     46.75        7         0.0037   267.14           0.0220                   2             27.439

tepe yuk: 138.89 istek/s (1.3889 varis/tur)
plan                     biten   verim/s  yaratim  yaratim orani   tekrar  kurulum is payi  bekleyen istek-tur  tutulan nesne-tur
her istekte yarat        4.000    100.00    4.000         1.0000     1.00           0.8571           3.205.927             11.997
tek paylasilan nesne     1.334     33.35        1         0.0007  1334.00           0.0045           8.539.260              4.000
havuz 5                  5.601    140.03        5         0.0009  1120.20           0.0053               6.456             19.990
havuz 12                 5.608    140.20       12         0.0021   467.33           0.0127                  28             45.257
havuz 24                 5.608    140.20       12         0.0021   467.33           0.0127                  28             45.257

tavanlar (hesap, tur basina tam istek): her istekte yarat 100 istek/s; isinmis havuz p ile 33.33 x p, is butcesi tavani 1000 istek/s; alt kaynak siniri 800.00 istek/s (p=5 icin 166.67)
tepe yukte: yaratim 4.000 -> 5 (800.0 kat az), kurulum isi 240.000 -> 300 birim, bekleyen istek-tur 3.205.927 -> 6.456
havuzun bedeli: tutulan nesne-tur havuz 5'te 19.990, havuz 24'te 45.257 (2.26 kat); havuz 24 verimi 140.20 istek/s, havuz 5 verimi 140.03

kurulum isinin payi tekrarla nasil eriyor (hesap): pay = 60 / (60 + tekrar x 10)
  tekrar  kurulum is payi  istek basina is
       1           0.8571            70.00
       2           0.7500            40.00
       5           0.5455            22.00
      10           0.3750            16.00
      50           0.1071            11.20
     200           0.0291            10.30

kurulum maliyeti degisirse havuzun kazanci (hesap, tekrar 200)
 kurulum  tekrar 1  tekrar 200  kazanc kat  kurtarilan birim
       5     15.00       10.03        1.50              4.97
      10     20.00       10.05        1.99              9.95
      30     40.00       10.15        3.94             29.85
      60     70.00       10.30        6.80             59.70

Koşum sayıları ölçüm sınıfındadır ve tohuma bağlıdır; tavanlar ve son iki tablo hesaptır.

Yaratım Oranı Yönü Seçiyor

Ayırt eden ölçüm yaratım oranıdır: yaratılan nesne sayısının tamamlanan istek sayısına bölümü. Tepe yükte her istekte yaratan düzende 1,0000, tek paylaşılan nesnede 0,0007. İki plan da aynı belirtiyi veriyor — verim gelen 138,89 istek/s’nin altında kalıyor, sırasıyla 100,00 ve 33,35 — ama tanı zıttır.

Oran 1’e yakınsa kurulum işi her istekte yeniden ödeniyordur; düzeltme yaratımı azaltmaktır. Oran sıfıra yakın ve verim yine düzse nesne yeterince yaratılmamıştır; düzeltme yaratımı artırmaktır. Tek bir sayı, iki karşıt yön.

Kurulum işi payı sütunu birinci nedenin büyüklüğünü veriyor: her istekte yaratan düzende toplam işin yüzde 85,71’i kurulumdur. İstek başına 70 birim işin 60’ı, isteğin kendi işiyle hiç ilgisi olmayan hazırlıktır. Havuz 5’te aynı pay yüzde 0,53’e iniyor.

Kalıp Ortalama Yükte Görünmüyor

Ortalama yük tablosu bir uyarı taşıyor. Saniyede 46,30 istekte, her istekte yaratan düzen 46,67 istek/s veriyor; havuz 5’in 46,75’iyle neredeyse aynı. Bekleyen istek-tur 866’ya karşı 29 — görünür ama küçük. Ortalama yükte karşıt kalıp yok gibidir.

Tepede tablo kopuyor. Her istekte yaratan düzenin tavanı hesapla 100 istek/s’dir: bir turda 100 birim iş vardır ve bir istek kurulumla birlikte 70 birim yer, yani tura bir istek sığar. Gelen 138,89 istek/s bu tavanın üstündedir ve fark kuyruğa yazılır: bekleyen istek-tur 866’dan 3.205.927’ye çıkıyor, 3702 kat. Havuz 5’te aynı sayı 29’dan 6.456’ya çıkıyor, 223 kat.

Tek paylaşılan nesne her iki yükte de aynı yerde: 33,33 ve 33,35 istek/s. Tavanı yükten değil, tutuştan gelir — tur çevrimi 100 ve tutuş 3 tur olduğuna göre tek nesne saniyede 33,33 istek taşıyabilir. Bu plan ortalama yükte bile yetersizdir; bekleyen istek-tur 1.141.381.

Her İstekte Yaratmanın Doğru Olduğu Koşul

Nesneyi her istekte yaratmak bir hata değildir; hata, pahalı bir nesneyi her istekte yaratmaktır ve pahalılığın ölçüsü kurulum işinin kullanım işine oranıdır.

Kurulum payı tablosu bu oranın tekrar sayısıyla nasıl eridiğini veriyor. Tekrar 1’de pay 0,8571 ve istek başına iş 70 birim; tekrar 10’da 0,3750 ve 16 birim; tekrar 200’de 0,0291 ve 10,30 birim. Kazanç tekrarın kendisiyle değil, kurulumun büyüklüğüyle sınırlıdır: son tablo aynı tekrarda kurulum 60 birimken 6,80 kat, 5 birimken yalnız 1,50 kat kazanıldığını söylüyor.

Koşul bir sayıyla yazılabilir: kurulum işi kullanım işinin yarısından küçükse havuzun kazanabileceği en büyük şey 1,50 kattır — model ölçeğinde kurulum 5, kullanım 10 birim. Havuz tutulan nesne-turu ve bakım yükünü de getirdiğine göre, bu ölçekte havuz kurmamak savunulabilir. Aynı nesne kurulumu 60 birime çıktığında aynı karar 6,80 katı bırakmak olur.

Havuzun Karşılığında Büyüyen

Havuz iki şeyi birden büyütür ve ikisi de sayılabilir.

Tutulan nesne-tur. Havuz 5 tepe yükte 19.990 nesne-tur tutuyor; havuz 24, 45.257 tutuyor — 2,26 kat. Bu nesneler alt kaynakta oturum tutar ve KK5’in yirmi dört nesnelik sınırını yer. Havuz büyütmenin bedeli budur ve bedelin karşılığı verimde görünmüyor: havuz 24 saniyede 140,20 istek tamamlıyor, havuz 5 ise 140,03. Fark yüzde 0,12.

Ama bekleyende görünüyor. Havuz 5’in bekleyen istek-turu 6.456, havuz 12’nin 28. Havuz boyutunu 5’ten 12’ye çıkarmak kaynağı 2,26 kat büyütüp bekleyeni 231 kat küçültüyor. İki sayı ters yönde ve seçim hangisinin tavan verdiğine bağlıdır. Havuz 24, havuz 12’yle birebir aynı sonucu veriyor — talep on ikiyi hiç aşmıyor, yani on ikiden sonrası yalnız tutulan kaynaktır.

Üçüncü karşılık sayılmaz ama görülür: havuzdan alınan bir nesne geri verilmezse havuz kalıcı olarak küçülür. Her istekte yaratan düzende böyle bir sızıntı isteği yavaşlatır ve biter; havuzlu düzende sistemi kalıcı olarak daraltır. Havuz, bir hatayı geçici olmaktan çıkarıp kalıcı yapar.

Özet

  • Belirti verimin eşzamanlılıkla artmamasıdır ve iki karşıt neden aynı belirtiyi verir: her istekte yaratma (tepede 100,00 istek/s) ve tek paylaşılan nesne (33,35 istek/s).
  • Ayırt eden ölçüm yaratım oranıdır: 1,0000 ise yaratım azaltılır, 0,0007 gibi sıfıra yakınsa yaratım artırılır. Tek sayı, iki karşıt yön.
  • Kalıp ortalama yükte görünmez: 46,30 istek/s’de her istekte yaratan düzen 46,67, havuz 46,75 veriyor. Tepede bekleyen istek-tur 866’dan 3.205.927’ye çıkıyor (3702 kat).
  • Kurulum işinin payı tekrarla erir: tekrar 1’de 0,8571 ve istek başına 70 birim, tekrar 200’de 0,0291 ve 10,30 birim. Havuz 5 yaratımı 4.000’den 5’e indiriyor (800 kat).
  • Koşul kurulumun kullanıma oranıdır: kurulum 5, kullanım 10 birimken havuzun kazanabileceği en çok 1,50 kattır; kurulum 60 birimken 6,80 kat.
  • Havuzun karşılığı tutulan nesne-turdur: havuz 24, havuz 5’in 2,26 katı kaynak tutup verimi yüzde 0,12 artırıyor; buna karşılık havuz 12 bekleyeni 6.456’dan 28’e indiriyor.

Sonraki Adım

Beş kalıp da aynı yerde ölçüldü: tek bir sürecin içinde ve tek bir deponun önünde. Hesabın katmanı, istemcinin işi, çağrının taneciği, alanın genişliği ve nesnenin ömrü — hepsi bir isteğin kendi israfını saydı ve hepsinin düzeltmesi o sürecin ya da o yanıtın içinde kaldı. Beşinin ortak varsayımı hiç sorulmadı: bütün bu istekler aynı depoya gidiyor. Takip sorgusu, durum olayı ve gün sonu ücretlendirme aynı motorda, aynı kaynak havuzunda, aynı bakım penceresinde. Deponun neden tek olduğu bir tasarım kararı değil, bir varsayımdı. Sonraki ders o varsayımı belirtiden yola çıkarak sınar: tek deponun sınırının hangi ölçümle göründüğü ve ayırmanın karşılığında neyin büyüdüğü.

İ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