Ders 03 / 20
Soğuk Başlangıç
Bir sıcak havuz modeli koşturularak isteğin örnek bulup bulamadığı sayılır: üç kurgu trafik profilinde soğuk çağrı oranı, gecikmeye eklenen süre ve kuyruğa giren istek ölçülür; havuz ömrü sıfırdan bin sekiz yüz saniyeye taranarak soğuk oranın düştüğü eşik ile karşılığında boşta duran örnek-saniye çıkarılır ve üç azaltma yolu ayrı ayrı fiyatlandırılır.
İçindekiler
Önceki iki dersin gecikme sayıları tek bir varsayıma yaslandı: çağrı geldiğinde işlevi çalıştıracak bir örnek hazır bekliyordu. Kapasite kararı devredildiği için bu her zaman doğru değildir. Örnekler istek geldikçe yaratılır, boşta kalınca geri alınır; hazır örnek bulamayan istek soğuk başlangıç yaşar — çalışma zamanının kurulması, paketin açılması ve başlatma kodu istek yolunun içine girer.
M23/K02 aynı dengeyi — imaja gömülen kalemle açılışta kalan iş — saniye ölçeğinde ölçtü; o ölçüm tekrarlanmaz. Burada ölçek milisaniye, nesne imaj değil pakettir. Sorulan tek bir orandır: kaç çağrı soğuk başlıyor, bu neye bağlı ve azaltmanın bedeli ne.
IH13. Ölçüm penceresi 1800 saniyedir; bölgesel ölçüm ağının üç kurgu trafik profili kendi yazılan bir üreteçle kurulur, tohum 20260804’tür. IH14. Sıcak çağrı 400 ms tutar, soğuk çağrıya 900 ms eklenir; bu ek gecikmeye girer, faturaya girmez. IH15. Profiller: saha bildirimi seyrek (ortalama 90 sn ara), okuma doğrulaması düzenli (ortalama 250 ms ara), gece toplu işlemesi ani (600 saniyede bir, 60 saniyelik patlama, 25 ms ara). IH16. Havuz ömrü, bir örneğin boşta kalıp geri alınmadan önce beklediği süredir; taban değer 300 saniyedir. IH17. İşlevin eşzamanlılık payı 40’tır; havuz dolduğunda gelen istek kuyruğa girer, düşmez. IH18. Fiyatlar kurgu birimle yazılır: çağrı 0,0005, işlem milisaniyesi 0,0000025, önceden ısıtılan örnek-saniye 0,0002 birim.
Havuzda Örnek Var mı
Model tek kural üzerinedir: havuzda boşta örnek varsa çağrı sıcaktır; yoksa ve pay dolmamışsa yeni örnek yaratılır; pay da dolmuşsa istek kuyruğa girer.
// olcum-agi/sicak-havuz.mjs — istek geldiginde havuzda ornek varsa sicak, yoksa soguk cagri (model) export const PENCERE = 1800000, ISLEM = 400, SOGUK = 900; // ms: olcum penceresi, isleme, soguk ek export const OMUR = 300000, SINIR = 40; // ms bosta tutma, islevin eszamanlilik payi export const CAGRI_B = 0.0005, MS_B = 0.0000025, ISIT_B = 0.0002; // kurgu birim 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; }; }; // Uc kurgu trafik profili: saha bildirimi seyrek, dogrulama duzenli, gece toplu islemesi ani. export const PROFIL = { seyrek: { ara: 90000, pencereler: [[0, PENCERE]] }, duzenli: { ara: 250, pencereler: [[0, PENCERE]] }, ani: { ara: 25, pencereler: [[0, 60000], [600000, 660000], [1200000, 1260000]] }, }; export const varislar = (ad, tohum = 20260804) => { const r = uretec(tohum), p = PROFIL[ad], v = []; for (const [bas, son] of p.pencereler) { let t = bas; while (t < son) { t += -Math.log(1 - r()) * p.ara; if (t < son) v.push(t); } } return v; }; const yuzde = (a, p) => [...a].sort((x, y) => x - y)[Math.floor(a.length * p)]; const bosta = (o, son) => Math.max(0, son - o.dogum - o.mesgul) / 1000; // Havuz: her ornek bosaldigi anda "bos" damgasi alir; damga uzerinden omur dolarsa geri alinir. export const kos = (varis, { omur = OMUR, sinir = SINIR, soguk = SOGUK, islem = ISLEM, isit = 0, ekCagri = 0 } = {}) => { const havuz = []; for (let i = 0; i < isit; i++) havuz.push({ bos: 0, dogum: 0, mesgul: 0, sabit: true }); let sogukSayi = 0, kuyrukta = 0, enUzunBekleme = 0, bostaSn = 0, enCok = havuz.length, isSuresi = 0; const gecikme = []; for (const t of varis) { for (let i = havuz.length - 1; i >= 0; i--) { const o = havuz[i]; if (!o.sabit && o.bos + omur < t) { bostaSn += bosta(o, o.bos + omur); havuz.splice(i, 1); } } let ornek = havuz.find((o) => o.bos <= t), bas = t, ek = 0, bekleme = 0; if (!ornek && havuz.length < sinir) { ornek = { bos: 0, dogum: t, mesgul: 0, sabit: false }; havuz.push(ornek); ek = soguk; sogukSayi++; } else if (!ornek) { ornek = havuz.reduce((a, b) => (b.bos < a.bos ? b : a)); bekleme = ornek.bos - t; bas = ornek.bos; kuyrukta++; if (bekleme > enUzunBekleme) enUzunBekleme = bekleme; } const sure = ek + islem + ekCagri; ornek.bos = bas + sure; ornek.mesgul += sure; isSuresi += sure; gecikme.push(bekleme + sure); if (havuz.length > enCok) enCok = havuz.length; } for (const o of havuz) bostaSn += bosta(o, o.sabit ? PENCERE : Math.min(PENCERE, o.bos + omur)); return { cagri: varis.length, soguk: sogukSayi, oran: sogukSayi / varis.length, ortGecikme: gecikme.reduce((a, b) => a + b, 0) / gecikme.length, g99: yuzde(gecikme, 0.99), kuyrukta, enUzunBekleme, enCok, bostaSn, maliyet: varis.length * CAGRI_B + isSuresi * MS_B + isit * (PENCERE / 1000) * ISIT_B }; }; if (import.meta.url === `file://${process.argv[1]}`) { console.log(`pencere ${PENCERE / 1000} sn, isleme ${ISLEM} ms, soguk ek ${SOGUK} ms, ` + `omur ${OMUR / 1000} sn, pay ${SINIR}`); console.log("\n" + "profil".padEnd(10) + "cagri".padEnd(9) + "soguk".padEnd(8) + "soguk oran".padEnd(12) + "ort gecikme".padEnd(14) + "99. dilim".padEnd(12) + "kuyruga giren".padEnd(15) + "en uzun bekleme".padEnd(17) + "en cok ornek".padEnd(14) + "bosta ornek-sn"); for (const ad of Object.keys(PROFIL)) { const s = kos(varislar(ad)); console.log(ad.padEnd(10) + String(s.cagri).padEnd(9) + String(s.soguk).padEnd(8) + `%${(s.oran * 100).toFixed(2)}`.padEnd(12) + `${s.ortGecikme.toFixed(0)} ms`.padEnd(14) + `${s.g99.toFixed(0)} ms`.padEnd(12) + String(s.kuyrukta).padEnd(15) + `${s.enUzunBekleme.toFixed(0)} ms`.padEnd(17) + String(s.enCok).padEnd(14) + s.bostaSn.toFixed(0)); } const a = kos(varislar("ani")); console.log(`\nani profilde soguk cagrilar gecikmeye ${(a.soguk * SOGUK / 1000).toFixed(0)} sn ekliyor; ` + `sicak cagri ${ISLEM} ms, soguk cagri ${ISLEM + SOGUK} ms — ${((ISLEM + SOGUK) / ISLEM).toFixed(2)} kat`); }
pencere 1800 sn, isleme 400 ms, soguk ek 900 ms, omur 300 sn, pay 40 profil cagri soguk soguk oran ort gecikme 99. dilim kuyruga giren en uzun bekleme en cok ornek bosta ornek-sn seyrek 18 2 %11.11 500 ms 1300 ms 0 0 ms 1 1722 duzenli 7242 9 %0.12 401 ms 400 ms 0 0 ms 8 10510 ani 7241 120 %1.66 419 ms 1300 ms 135 539 ms 40 38159 ani profilde soguk cagrilar gecikmeye 108 sn ekliyor; sicak cagri 400 ms, soguk cagri 1300 ms — 3.25 kat
Üç profil üç ayrı davranış gösterir. Düzenli trafikte soğuk oran %0,12’dir: istekler 250 ms arayla gelir, havuz sekiz örnekte oturur ve yalnız dokuz çağrı soğuk başlar. Seyrek trafikte oran %11,11’dir ve bu oran yükten değil çağrı seyrekliğinden gelir. Ani trafikte oran %1,66’dır ama asıl sayı başka sütundadır: 135 istek kuyruğa girer, en uzun bekleme 539 ms.
Kuyruk soğuk başlangıcın ikinci yüzüdür. Patlama başladığında havuz boştur; her yeni istek yeni bir örnek ister ve her örnek 900 ms kurulum harcar. Pay 40’a dayanınca istekler beklemeye başlar. Soğuk çağrı yalnız kendi gecikmesini artırmaz, havuzun dolmasını yavaşlatarak arkasındaki isteklere kuyruk oluşturur: ortalama 419 ms görünür, yüzde doksan dokuzuncu dilim 1.300 ms’dir.
Havuz Ömrü Taraması
Havuz ömrü devredilmiş bir karardır: bir örneğin ne kadar boşta tutulacağına sağlayıcı karar verir. Tarama ömrü sıfırdan 1800 saniyeye çıkarır.
// olcum-agi/omur-taramasi.mjs — havuz omru ve trafik profili degistikce soguk cagri orani (model) import { PROFIL, varislar, kos } from "./sicak-havuz.mjs"; export const OMURLER = [0, 15, 30, 60, 120, 300, 600, 1800]; // saniye export const ADLAR = Object.keys(PROFIL); if (import.meta.url === `file://${process.argv[1]}`) { const varis = Object.fromEntries(ADLAR.map((a) => [a, varislar(a)])); console.log("havuz omru".padEnd(12) + ADLAR.map((a) => `${a}: soguk / bosta`.padEnd(24)).join("") + "ani: kuyruk / ort gecikme"); const tablo = {}; for (const o of OMURLER) { const s = Object.fromEntries(ADLAR.map((a) => [a, kos(varis[a], { omur: o * 1000 })])); tablo[o] = s; console.log(`${o} sn`.padEnd(12) + ADLAR.map((a) => `%${(s[a].oran * 100).toFixed(2)} / ${s[a].bostaSn.toFixed(0)}`.padEnd(24)).join("") + `${s.ani.kuyrukta} / ${s.ani.ortGecikme.toFixed(0)} ms`); } console.log(""); for (const a of ADLAR) { const iyi = OMURLER.find((o) => tablo[o][a].oran < 0.01); const sifir = tablo[0][a], en = tablo[1800][a]; console.log(`${a.padEnd(9)} omur 0'da %${(sifir.oran * 100).toFixed(1)} soguk ve ${sifir.bostaSn.toFixed(0)} bosta ornek-sn; ` + `omur 1800'de %${(en.oran * 100).toFixed(2)} ve ${en.bostaSn.toFixed(0)}; ` + (iyi === undefined ? "hicbir omurde %1'in altina inmiyor" : `%1'in altina ${iyi} sn omurde iniyor`)); } }
havuz omru seyrek: soguk / bosta duzenli: soguk / bosta ani: soguk / bosta ani: kuyruk / ort gecikme 0 sn %100.00 / 0 %100.00 / 0 %49.99 / 0 3621 / 969 ms 15 sn %88.89 / 266 %1.35 / 7651 %1.78 / 3819 135 / 420 ms 30 sn %77.78 / 489 %0.65 / 8493 %1.73 / 5713 135 / 419 ms 60 sn %72.22 / 895 %0.33 / 9208 %1.66 / 9359 135 / 419 ms 120 sn %38.89 / 1364 %0.18 / 9883 %1.66 / 16559 135 / 419 ms 300 sn %11.11 / 1722 %0.12 / 10510 %1.66 / 38159 135 / 419 ms 600 sn %5.56 / 1781 %0.11 / 10873 %0.59 / 57609 47 / 407 ms 1800 sn %5.56 / 1781 %0.11 / 10873 %0.55 / 69047 47 / 406 ms seyrek omur 0'da %100.0 soguk ve 0 bosta ornek-sn; omur 1800'de %5.56 ve 1781; hicbir omurde %1'in altina inmiyor duzenli omur 0'da %100.0 soguk ve 0 bosta ornek-sn; omur 1800'de %0.11 ve 10873; %1'in altina 30 sn omurde iniyor ani omur 0'da %50.0 soguk ve 0 bosta ornek-sn; omur 1800'de %0.55 ve 69047; %1'in altina 600 sn omurde iniyor
Tarama üç ayrı eğri verir. Düzenli trafikte 15 saniyelik ömür soğuk oranı %100’den %1,35’e indirir; ötesi kazandırmaz ama boşta örnek-saniyeyi 7.651’den 10.873’e çıkarır. Ani trafikte oran 15 saniyeden 300 saniyeye kadar hiç değişmez — %1,66’da takılır — ve 600 saniyede aniden %0,59’a düşer. Eşik tesadüf değildir: patlamalar arasındaki boşluk 540 saniyedir, ömür o boşluğu geçtiği anda havuz iki patlama arasında yaşar. Kuyruğa giren istek de aynı satırda 135’ten 47’ye iner.
Eşiğin fiyatı aynı satırdadır: boşta örnek-saniye 38.159’dan 57.609’a çıkar. Soğuk çağrıyı üçte bire indirmek boşta kapasiteyi yarı yarıya artırmakla ödenir.
Seyrek profil hiçbir ömürde %1’in altına inmez; 1800 saniyede bile oran %5,56’dır, çünkü on sekiz çağrının biri pencerenin ilkidir ve öncesinde havuz yoktur. Seyrek trafikte soğuk başlangıç bir ayar sorunu değil, trafiğin kendi özelliğidir.
Üç Azaltma Yolu
// olcum-agi/azaltma.mjs — soguk baslangici azaltmanin uc yolu ve her yolun bedeli (model) import { SOGUK, ISLEM, PENCERE, varislar, kos } from "./sicak-havuz.mjs"; // [ad, kos secenekleri, bedelin cinsi] export const YOL = [ ["azaltma yok", {}, "—"], ["onceden isitma (16)", { isit: 16 }, "16 ornek 1800 sn bosta durur"], ["paket kucultme", { soguk: 350 }, "bagimliliklarin 3'u disari alinir"], ["baslatma tasinmasi", { soguk: 500, ekCagri: 40 }, "her cagriya 40 ms tembel yukleme"], ["kucultme + isitma", { soguk: 350, isit: 16 }, "ikisinin bedeli birlikte"], ]; if (import.meta.url === `file://${process.argv[1]}`) { const v = varislar("ani"), taban = kos(v); console.log(`ani profil, ${v.length} cagri, havuz omru 300 sn; sicak cagri ${ISLEM} ms`); console.log("\n" + "yol".padEnd(22) + "soguk".padEnd(8) + "soguk oran".padEnd(12) + "ort gecikme".padEnd(14) + "99. dilim".padEnd(12) + "kuyruga giren".padEnd(15) + "bosta ornek-sn".padEnd(16) + "maliyet".padEnd(10) + "gecikme kazanci"); for (const [ad, sec] of YOL) { const s = kos(v, sec); console.log(ad.padEnd(22) + String(s.soguk).padEnd(8) + `%${(s.oran * 100).toFixed(2)}`.padEnd(12) + `${s.ortGecikme.toFixed(1)} ms`.padEnd(14) + `${s.g99.toFixed(0)} ms`.padEnd(12) + String(s.kuyrukta).padEnd(15) + s.bostaSn.toFixed(0).padEnd(16) + s.maliyet.toFixed(2).padEnd(10) + `${(taban.ortGecikme - s.ortGecikme).toFixed(1)} ms`); } console.log("\n" + "yol".padEnd(22) + "bedeli".padEnd(38) + "kazanilan ms basina ek maliyet"); for (const [ad, sec, bedel] of YOL.slice(1)) { const s = kos(v, sec), kazanc = taban.ortGecikme - s.ortGecikme; console.log(ad.padEnd(22) + bedel.padEnd(38) + (kazanc > 0 ? ((s.maliyet - taban.maliyet) / kazanc).toFixed(3) : "kazanc yok")); } const esik = 40 / (SOGUK - 500); console.log(`baslatma tasinmasi ancak soguk oran %${(esik * 100).toFixed(0)}'un ustundeyse kazandirir: ` + `40 ms her cagriya, kazanilan 400 ms yalniz soguk cagriya duser — bu profilde oran %1.66`); const i = kos(v, { isit: 16 }); console.log(`\nonceden isitma bostada gecen kapasiteyi ${taban.bostaSn.toFixed(0)} ornek-sn'den ` + `${i.bostaSn.toFixed(0)} ornek-sn'ye cikariyor; ${PENCERE / 1000} sn'lik pencerede ` + `${(i.maliyet - taban.maliyet).toFixed(2)} birim ek — soguk ekin kendisi ${SOGUK} ms`); }
ani profil, 7241 cagri, havuz omru 300 sn; sicak cagri 400 ms yol soguk soguk oran ort gecikme 99. dilim kuyruga giren bosta ornek-sn maliyet gecikme kazanci azaltma yok 120 %1.66 418.9 ms 1300 ms 135 38159 11.13 0.0 ms onceden isitma (16) 49 %0.68 406.1 ms 400 ms 0 42736 16.73 12.8 ms paket kucultme 111 %1.53 405.4 ms 750 ms 0 35500 10.96 13.5 ms baslatma tasinmasi 120 %1.66 448.5 ms 940 ms 22 38229 11.74 -29.7 ms kucultme + isitma 43 %0.59 402.1 ms 400 ms 0 40933 16.66 16.8 ms yol bedeli kazanilan ms basina ek maliyet onceden isitma (16) 16 ornek 1800 sn bosta durur 0.438 paket kucultme bagimliliklarin 3'u disari alinir -0.013 baslatma tasinmasi her cagriya 40 ms tembel yukleme kazanc yok kucultme + isitma ikisinin bedeli birlikte 0.329 baslatma tasinmasi ancak soguk oran %10'un ustundeyse kazandirir: 40 ms her cagriya, kazanilan 400 ms yalniz soguk cagriya duser — bu profilde oran %1.66 onceden isitma bostada gecen kapasiteyi 38159 ornek-sn'den 42736 ornek-sn'ye cikariyor; 1800 sn'lik pencerede 5.60 birim ek — soguk ekin kendisi 900 ms
Üç yol üç ayrı cinsten bedel öder. Önceden ısıtma soğuk oranı %0,68’e, kuyruğu sıfıra indirir ve yüzde doksan dokuzuncu dilimi 1.300 ms’den 400 ms’ye çeker: havuzda hep on altı örnek beklediği için patlamanın ilk saniyesi soğuk değildir. Bedeli birinci dersin kaçındığı şeydir — boşta örnek-saniye 42.736’ya, fatura 11,13 birimden 16,73 birime çıkar, yani %50 artar.
Paket küçültme tek bedavaya benzeyen yoldur: soğuk ek 900 ms’den 350 ms’ye inince hem gecikme hem maliyet düşer. Ama bedel tabloda değildir — üç bağımlılık paketten çıkarılmıştır ve bir yerde karşılanması gerekir. Kısıtın etrafından dolaşmanın en sessiz biçimi budur.
Üçüncü yol zarar eder. Başlatma işinin taşınması soğuk eki 500 ms’ye indirir ama her çağrıya 40 ms tembel yükleme ekler; ortalama gecikme 29,7 ms artar ve yirmi iki istek kuyruğa girer. Son satır eşiği verir: 40 ms bütün çağrılara, kazanılan 400 ms yalnız soğuk çağrılara düşer, yani yol ancak soğuk oran %10’un üstündeyse kazandırır. Bu profilde oran %1,66, seyrek profilde %11,11’dir.
Özet
- Soğuk çağrı 1.300 ms, sıcak çağrı 400 ms tutar: 3,25 kat. Ani profilde oran %1,66 olsa da 135 istek kuyruğa girer, en uzun bekleme 539 ms olur.
- Havuz ömrü taramasında eşik trafiğin biçiminden çıkar: ani profilde oran 15–300 saniye arasında %1,66’da takılır, 600 saniyede %0,59’a iner, çünkü patlamalar arasındaki boşluk 540 saniyedir. Eşiğin bedeli aynı satırda yazılıdır: boşta örnek-saniye 38.159’dan 57.609’a çıkar.
- Önceden ısıtma kuyruğu sıfıra indirir ve faturayı %50 artırır; paket küçültme ikisini de düşürür ama üç bağımlılığı paketten çıkarmayı ister.
- Başlatma işinin taşınması bu profilde gecikmeyi 29,7 ms artırır; ancak soğuk oran %10’un üstündeyse kazandırır — azaltma yolunun kendisi bir eşiğe bağlıdır.
Sonraki Adım
Bu derste eşzamanlılık payı 40 sabit bir sayıydı ve kuyruğun nereden çıktığını açıkladı. Oysa tek başına duran bir sayı değildir: bellek seçimi işlemci payını, işlemci payı işlem süresini, işlem süresi de aynı payla kaç iş yapılacağını belirler.
Sonraki ders üç eşiği — bellek, süre ve eşzamanlılık — bir iş kümesine uygular ve kaç işin sığmadığını sayar. Bellek taranır, süre ile birim maliyetin ters yönde değiştiği ve en ucuz noktanın ortada çıktığı gösterilir. Eşzamanlılık sınırı aşıldığında kısma ile arkadaki kuyruk sayılır; sınırın hesap düzeyinde paylaşılması bir örnekle ölçülür.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.