Ders 06 / 13
Gecikme ve Verim
İki ölçütün birbirinden bağımsız iki eksen olduğunun ölçülmesi: eşzamanlılık artarken verimin doyması ve gecikmenin kötüleşmesi, eşzamanlılık ile verim ve gecikme arasındaki bağıntının ölçümle doğrulanması, doyuma yaklaşmanın gecikme maliyetinin bir kuyruk modeliyle gösterilmesi ve her sayının varsayım, hesap ya da ölçüm olarak sınıflandırılması.
İçindekiler
Önceki konu bir tasarımın nasıl kurulduğunu ve nasıl anlatıldığını ele aldı: bileşenlerin ayrılması, gereksinimin işlevsel ve işlevsel olmayan yarılarına bölünmesi, kaynak ihtiyacının kabaca hesaplanması ve her kararın bir gerekçeyle sunulması. Gerekçenin dayandığı şey ise adlandırılmadı. “Bu tasarım hızlıdır”, “bu tasarım ölçeklenir”, “bu tasarım ayakta kalır” cümlelerinin hiçbiri bir ölçüt içermez; üçü de tartışmayı bitirmek yerine başlatır, çünkü karşı taraf aynı cümleyi tersine çevirdiğinde elde ölçülecek bir şey kalmaz.
Bu konu o ölçütleri tanımlar. İlk ders en sık birbirine karıştırılan çiftle başlar: bir önceki konuda eşiklerde geçen “takip yanıtı ortancası” ile “depoya ulaşan istek hızı” iki ayrı ölçütün adıdır ve ikisi arasında hiçbir zorunlu bağ yoktur. Dersin işi bu bağımsızlığı bir düzenekte ölçmek, sonra bağımsızlığın nerede bittiğini ve neden bittiğini göstermektir.
Üç Akış ve Sayının Sınıfı
Kurs boyunca aynı sistem ele alınır: bir gönderi takip ve ücretlendirme servisi. Üç akışı vardır. Okuma akışı takip sorgusudur: kullanıcı bir takip numarası verir, gönderinin son durumunu alır. Yazma akışı taşıyıcıdan gelen durum olayıdır: küçük kayıtlar sürekli akar. Toplu akış satıcının gün sonu ücretlendirmesidir: günde bir kez, çok büyük bir iş.
Bu konu yeni varsayım seçmez. Kabaca Büyüklük Hesabı dersinin on iki satırlık varsayım tablosu ve ondan çıkan hesaplar burada girdi olarak kullanılır. Üç akışın ihtiyaç duyulan sayıları şunlardır: uçta tepe istek hızı 513,89 istek/s — 416,67’si okuma, 97,22’si yazma; önbelleğin arkasında depoya ulaşan tepe hız 138,89 istek/s; gün sonu işi otuz günü kapsayan 12 milyon kaydı dört saatlik pencerede tarar, yani 833,33 kayıt/s ve kayıt başına 1,20 ms. Hepsi hesap sınıfındadır ve hiçbiri dışarıdan alınmamıştır.
Sistem Tasarımı Nedir dersinde kurulan sınıflandırma bu konunun bütün sayılarında da uygulanır: bir sayı ya seçilmiş bir varsayımdır, ya varsayımlardan çıkan bir hesaptır, ya da bir düzenekten alınmış bir ölçümdür. Bu dersin katkısı üçüncü sınıftadır — yukarıdaki hesaplar gereken kapasiteyi söylüyor, ama bir sürecin ne taşıdığını söylemiyor. O sayı ölçülür.
İki Ölçüt İki Ayrı Eksendir
Gecikme (latency) bir işin başlangıcından bitişine kadar geçen süredir; birimi zamandır. Ağ Modelleri ve Protokoller kursunda dört bileşene ayrılmıştı: iletim, yayılım, kuyruk ve işleme. Verim (throughput) birim zamanda tamamlanan iş sayısıdır; birimi iş bölü zamandır. İki ölçütün birimleri farklıdır, dolayısıyla biri ötekinin yerine kullanılamaz.
Üç akış bu iki ekseni ayrı köşelere yerleştirir. Takip sorgusu düşük gecikme ister; kullanıcı yanıtı bekler ve tek bir yanıtın süresi doğrudan ona görünür. Gün sonu ücretlendirmesi yüksek verim ister; 12 milyon kaydın dört saatte taranması gerekir ve tek tek hiçbir kaydın ne zaman bittiği önemli değildir. Aynı sistemin bir akışında milisaniye, ötekinde saat ölçek birimidir.
Ayrımın kritik sonucu şudur: bir akışın verimini artırmak gecikmesini kötüleştirebilir. Gün sonu işi kayıtları gruplayarak verimini katlayabilir, ama gruplanan her kayıt grubun tamamlanmasını bekler. Tersi de olur: gecikmeyi kısaltmak verimi düşürebilir, çünkü her işi hemen başlatmak gruplamanın kazancından vazgeçmek demektir.
İki ölçütün bir asimetrisi daha vardır. Verim tek bir sayıdır: birim zamanda tamamlanan iş sayısı sayılır ve biter. Gecikme tek bir sayı değildir, bir dağılımdır; aynı yükte bazı istekler hızlı, bazıları yavaş yanıtlanır. Bu yüzden gecikme yüzdeliklerle bildirilir: ortanca isteklerin yarısının altında kaldığı süre, p99 yüzde birinin aştığı süredir. Ortalama gecikme bildirmek en az bilgi taşıyan seçenektir, çünkü tek bir çok yavaş istek ortalamayı kaydırır ve dağılımın biçimini saklar.
Eşzamanlılık Arttıkça Ne Oluyor
Aşağıdaki düzenek takip ucunu yerel bir sunucu olarak kurar. Her istek iki şey harcar: kayıt aramasının yerine geçen bir bekleme ve bir işlemci payı. İkisi de düzeneğin parametresidir, ölçüm değildir.
// takip/sunucu.mjs — takip sorgusu ucu: her istek bir bekleme ve bir islemci payi harcar import { createServer } from "node:http"; const BEKLEME = 3; // kayit aramasinin yerine gecen bekleme (ms), duzenegin parametresi const ISLEMCI = 0.20; // istek basina islemci payi (ms), duzenegin parametresi function isle(ms) { // ms kadar islemci mesgul eder const bit = performance.now() + ms; let t = 0; while (performance.now() < bit) t += 1; return t; } const port = Number(process.argv[2]); if (Number.isInteger(port) === false) console.log("kullanim: node takip/sunucu.mjs <baglanti-noktasi>"); else createServer(async (istek, yanit) => { const no = new URL(istek.url, "http://yerel").searchParams.get("no") ?? "-"; await new Promise((c) => setTimeout(c, BEKLEME)); isle(ISLEMCI); const govde = JSON.stringify({ no, durum: "aktarma merkezinde", bolge: "35", adim: 4 }); yanit.writeHead(200, { "content-type": "application/json" }); yanit.end(govde); }).listen(port);
İstemci yedi eşzamanlılık (concurrency) düzeyinde çalışır. Her düzeyde belirtilen sayıda istek hep havada tutulur; iki saniye boyunca gönderilen istek sayısı verimi, tek tek ölçülen süreler gecikme yüzdeliklerini verir.
// takip/yukle.mjs — artan escamanlilikla istek gonderir; her duzeyde verim ve gecikme yazar import { Agent, request } from "node:http"; const port = Number(process.argv[2]); const DUZEY = [1, 2, 4, 8, 16, 32, 64]; const SURE = 2000; // her duzeyin olcum suresi (ms) const agent = new Agent({ keepAlive: true, maxSockets: 256 }); function birIstek(no) { return new Promise((coz, sap) => { const bas = performance.now(); const r = request({ port, path: `/takip?no=${no}`, agent }, (y) => { y.resume(); y.on("end", () => coz(performance.now() - bas)); }); r.on("error", sap); r.end(); }); } function yuzdelik(dizi, p) { const s = [...dizi].sort((a, b) => a - b); return s[Math.min(s.length - 1, Math.floor((p / 100) * s.length))]; } async function duzey(n) { const gecikme = []; const bit = performance.now() + SURE; const bas = performance.now(); await Promise.all(Array.from({ length: n }, async (_, k) => { let i = 0; while (performance.now() < bit) gecikme.push(await birIstek(`G${k}-${i++}`)); })); const gecen = (performance.now() - bas) / 1000; return { n, istek: gecikme.length, verim: gecikme.length / gecen, orta: yuzdelik(gecikme, 50), p99: yuzdelik(gecikme, 99) }; } if (Number.isInteger(port) === false) console.log("kullanim: node takip/yukle.mjs <baglanti-noktasi>"); else { await birIstek("isinma"); console.log("escaman istek verim(istek/s) ortanca(ms) p99(ms) verim*ortanca"); for (const n of DUZEY) { const s = await duzey(n); const little = (s.verim * s.orta) / 1000; console.log(`${String(s.n).padStart(6)} ${String(s.istek).padStart(6)} ` + `${s.verim.toFixed(0).padStart(13)} ${s.orta.toFixed(2).padStart(10)} ` + `${s.p99.toFixed(2).padStart(7)} ${little.toFixed(2).padStart(22)}`); } agent.destroy(); }
Sürücü betik sunucuyu başlatır, ölçümü koşturur ve sunucuyu durdurur. Bağlantı noktası numarası ortama bağlıdır; makinede kullanımdaysa değiştirilmelidir.
# olc.sh — sunucu baslatilir, yedi escamanlilik duzeyi olculur, sunucu durdurulur node takip/sunucu.mjs 8811 & SUNUCU=$! sleep 1 node takip/yukle.mjs 8811 kill $SUNUCU
escaman istek verim(istek/s) ortanca(ms) p99(ms) verim*ortanca
1 463 231 4.33 4.78 1.00
2 936 468 4.46 5.05 2.09
4 1764 880 4.80 5.38 4.23
8 3038 1515 5.67 6.14 8.59
16 4849 2417 6.65 7.57 16.06
32 8089 4031 8.21 9.56 33.10
64 8593 4268 15.15 16.46 64.64
Bu sayılar ölçümdür ve bu makinede alınmıştır. Mutlak değerleri başka bir makinede tekrarlanmaz; tekrarlanan şey tablonun biçimidir.
İki Bölge
Tablo iki ayrı bölgeye ayrılır ve dersin savı bu ayrımdadır.
Birinci bölgede, eşzamanlılık 1’den 4’e çıkarken verim 231’den 880’e, yani 3,81 katına çıktı; ortanca gecikme 4,33 ms’den 4,80 ms’ye, yani 1,11 katına çıktı. Verim neredeyse eşzamanlılıkla birlikte büyüdü, gecikme yerinde saydı. Bu bölgede iki ölçüt bağımsızdır: verim artıyor, gecikme hakkında hiçbir şey söylemiyor.
İkinci bölgede tablo tersine döner. Eşzamanlılık 32’den 64’e çıkarken verim 4031’den 4268’e, yani yalnızca 1,06 katına çıktı; ortanca gecikme 8,21 ms’den 15,15 ms’ye, yani 1,85 katına çıktı. Eşzamanlılığı iki katına çıkarmanın karşılığı %6 verim ve iki kat gecikmedir. Bu bölgede bağımsızlık biter: verim bir üst sınıra dayanmıştır ve eklenen her istek yalnızca beklemeye eklenir.
Üst sınırın nereden geldiği düzenekte yazılıdır. Her istek 0,20 ms işlemci payı harcıyor ve sunucu tek bir iş parçacığında çalışıyor; işlemci payı bölünemeyen kaynaktır. Beklemeler üst üste binebilir, işlemci payı binemez. Sunucu Tarafı Temelleri kursunda kurulan ayrım budur: bekleyen girdi-çıktı ucuzdur, işlemciyi meşgul eden hesap sırayı kilitler.
Bağıntı
Son sütun iki ölçütü birbirine bağlar. Her satırda verim ile ortanca gecikmenin çarpımı, eşzamanlılık düzeyine eşit çıkıyor: 1,00, 2,09, 4,23, 8,59, 16,06, 33,10, 64,64. Bu bir kaza değil, kuyruk kuramının temel bağıntısıdır. Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda biçiminde kurulmuştu; buradaki karşılığı şudur:
havadaki iş sayısı, verim, gecikmedir. Bağıntının tasarım sonucu doğrudandır: üç büyüklükten ikisi seçilirse üçüncüsü seçilemez. Havadaki iş sayısı sabit tutulup verim artırılamıyorsa, gecikme büyümek zorundadır — başka çıkışı yoktur. İkinci bölgedeki davranış bu zorunluluğun görünür hâlidir.
Aynı bağıntı ölçüm okumanın kuralını da verir. Yalnız verimi bildiren bir rapor, hangi eşzamanlılıkta alındığını söylemedikçe gecikme hakkında hiçbir şey söylemez; yalnız gecikmeyi bildiren bir rapor da yükü söylemedikçe okunamaz. Bir ölçütün tek başına bildirilmesi eksik bildirimdir.
Doyuma Yaklaşmanın Bedeli
İkinci bölgenin girişinde ne olduğunu bir model gösterir. Tek sunuculu bir kuyrukta, servis hızı ve varış hızı iken doluluk (utilization) olarak tanımlanır ve sistemde geçirilen ortalama süre olur. Aşağıdaki hesap bu modeli ölçülen üst sınırla besler. Bu bir modeldir, ölçüm değildir; varışların ve servis sürelerinin dağılımı hakkında varsayım içerir ve gerçek bir sunucunun gecikmesini öngörmez. Gösterdiği şey oranların yönüdür.
// hesap/kuyruk.mjs — tek sunuculu kuyruk MODELI: doyuma yaklasan verimin gecikmeye maliyeti const MU = 4268; // olculen ust sinir: bu duzenekte bir surecin doyum verimi (istek/s) console.log(`servis hizi mu = ${MU} istek/s (olculen ust sinir)`); console.log("doluluk varis hizi(istek/s) modeldeki ortalama sure(ms) %30 duruma gore kat"); const taban = 1000 / (MU - 0.30 * MU); for (const rho of [0.30, 0.50, 0.70, 0.80, 0.90, 0.95, 0.99]) { const T = 1000 / (MU - rho * MU); console.log(`${(rho * 100).toFixed(0).padStart(6)}% ${(rho * MU).toFixed(0).padStart(19)} ` + `${T.toFixed(2).padStart(27)} ${(T / taban).toFixed(1).padStart(18)}`); } const tepe = [416.67, 833.33]; // Kabaca Buyukluk Hesabi: tepe okuma hizi ve sorgu varsayimi ikiye katlanirsa for (const t of tepe) { console.log(`tepe ${t} istek/s -> doluluk ${((t / MU) * 100).toFixed(1)}%, ` + `ust sinir tepenin ${(MU / t).toFixed(1)} kati, ` + `modeldeki ortalama sure ${(1000 / (MU - t)).toFixed(2)} ms`); }
servis hizi mu = 4268 istek/s (olculen ust sinir)
doluluk varis hizi(istek/s) modeldeki ortalama sure(ms) %30 duruma gore kat
30% 1280 0.33 1.0
50% 2134 0.47 1.4
70% 2988 0.78 2.3
80% 3414 1.17 3.5
90% 3841 2.34 7.0
95% 4055 4.69 14.0
99% 4225 23.43 70.0
tepe 416.67 istek/s -> doluluk 9.8%, ust sinir tepenin 10.2 kati, modeldeki ortalama sure 0.26 ms
tepe 833.33 istek/s -> doluluk 19.5%, ust sinir tepenin 5.1 kati, modeldeki ortalama sure 0.29 ms
Model tek bir şeyi söylüyor: dolulukla birlikte verim doğrusal büyürken süre doğrusal büyümüyor. %30’dan %99’a çıkmak varış hızını 3,3 katına, süreyi 70 katına çıkarıyor. Verimin son parçası, gecikmenin sınırsız büyümesiyle satın alınır. Doluluğun yüksek tutulması bir verimlilik başarısı gibi görünür ve bir gecikme kararıdır.
Son iki satır hesabı ölçümle birleştirir. Tepe okuma hızı 416,67 istek/s, düzenekte ölçülen üst sınır 4268 istek/s; oran 10,2’dir ve doluluk %9,8’de kalır. Kullanıcı başına sorgu iki katına çıktığında oran 5,1 olur. Buradan çıkan sonuç ölçünün kendisi değil, yöntemdir: tepe hız varsayımlardan hesaplanır, üst sınır düzenekten ölçülür, ikisinin oranı payı verir. Gerçek takip ucu bu düzenekten fazlasını yapacağı için üst sınırı daha düşük olur; oran ise aynı biçimde okunur. Oran 1’in altına düştüğünde tasarım artık çalışmıyordur; 2 ile 3 arasındayken tek bir arıza bütün payı silecek kadar dar demektir.
Özet
- Gecikme bir işin süresi, verim birim zamanda tamamlanan iş sayısıdır; birimleri farklıdır ve biri ötekinin yerine kullanılamaz.
- Ölçümde eşzamanlılık 1’den 4’e çıkarken verim 3,81 katına çıktı, ortanca gecikme 1,11 katında kaldı: bu bölgede iki ölçüt bağımsızdır.
- Eşzamanlılık 32’den 64’e çıkarken verim 1,06 katına çıktı, gecikme 1,85 katına çıktı: verim üst sınıra dayandığında eklenen her istek yalnızca beklemeye eklenir.
- Ölçülen her satırda tuttu; üç büyüklükten ikisi seçilirse üçüncüsü seçilemez, bu yüzden tek başına bildirilen verim ya da gecikme okunamaz.
- Kuyruk modeli dolulukla sürenin doğrusal büyümediğini gösterdi: %30’dan %99’a varış hızı 3,3 katına, süre 70 katına çıkıyor; doluluğu yüksek tutmak bir gecikme kararıdır.
- Hesaplanan tepe okuma hızı 416,67 istek/s, ölçülen üst sınır 4268 istek/s; oran 10,2’dir ve kullanıcı başına sorgu iki katına çıktığında 5,1’e iner.
Sonraki Adım
Bu ders tek bir süreci sabit tuttu ve yükü değiştirdi. Ortaya çıkan iki bölge, “bu sistem hızlıdır” cümlesinin neden yetersiz olduğunu gösterdi: sistemin hızı ölçüldüğü yüke bağlıdır ve düşük yükte alınmış bir sayı yüksek yükteki davranış hakkında hiçbir şey söylemez. Buradan iki ayrı soru çıkar. Birincisi, belirli bir yükte sistem ne kadar iyidir. İkincisi, yük büyüdüğünde bu iyilik ne kadar dayanır. İki soru sık sık tek bir sözcükle karşılanır ve karşılanmamalıdır: birinin adı başarım, ötekinin adı ölçeklenebilirliktir. Sonraki ders iki kavramı ayırır: gün sonu işinin iki gerçekleştirimini dört ayrı yükte ölçer, ikisinin de bugünün eşiğini karşıladığını gösterir ve aradaki farkın ancak yük büyütüldüğünde sayılabildiğini ortaya koyar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.