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.