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.