İçeriğe geç
academia.sh

Ders 04 / 13

Kabaca Büyüklük Hesabı

On iki varsayımın tek bir tabloda toplanması ve tablodan istek hızı, veri artışı ile bant genişliği ihtiyacının aritmetikle çıkarılması: tepe yükün hesaplanması, önbelleğin arkasındaki yük dengesinin bulunması, seyrek toplu işin bant genişliğine hâkim olması ve her varsayımın hangi sonucu kaç katına çıkardığının ölçülmesi.

İçindekiler

Önceki iki ders sayısı olmayan iki boşluk bıraktı. Nitelik senaryosunun ortam parçası “tepe yükünde” yazıyordu ve tepe yükün kaç istek olduğu belirsizdi; eşiklerin karşılanabilir olup olmadığı da aynı belirsizliğe bağlıydı. İkinci derste altı yanıtsız soru altı varsayıma dönüşmüştü ama varsayımlar hiçbir yere yazılmamıştı.

Bu ders o boşluğu doldurur. Kabaca büyüklük hesabı (back-of-the-envelope estimate), bir tasarımın kaynak ihtiyacını az sayıda varsayımdan aritmetikle çıkarma işidir. Amacı doğru sayıyı bulmak değil, doğru büyüklük sırasını bulmak ve tasarım kararlarının hangi varsayıma dayandığını görünür kılmaktır.

Varsayım Tablosu

Bütün hesapların tek bir kaynağı olur. Aşağıdaki on üç varsayım kursun geri kalanında da kullanılır; hiçbir ders kendi başına yeni bir hacim sayısı seçmez.

Kod Varsayım Değer Gerekçe
V1 günlük etkin kullanıcı 2.000.000 takip sayfasını günde en az bir kez açan alıcı ve satıcı
V2 kullanıcı başına günlük takip sorgusu 6 bir gönderi teslime kadar birkaç kez sorulur
V3 günde oluşan yeni gönderi 400.000 satıcı başına günlük gönderi sayısının toplamı
V4 gönderi başına durum olayı 7 kabul, aktarma, dağıtıma çıkış, teslim ve ara durumlar
V5 takip yanıtı gövdesi 480 bayt durum, bölge, güncellenme zamanı ve son üç rota adımı
V6 bir durum olayının kaydı 220 bayt takip numarası, durum, rota adımı, zaman damgası
V7 bir gönderi kaydı 900 bayt ağırlık, hacim, bölge, sözleşme ve tarife alanları
V8 tepe çarpanı 3 tepe saatteki hızın gün ortalamasına oranı
V9 takip sorgusunun önbellekten karşılanma oranı 0,90 aynı takip numarası kısa aralıkla yeniden sorulur
V10 gün sonu işinin penceresi 4 saat satıcı raporu sabah ister
V11 ücretlendirmenin taradığı gün 30 ücretlendirme aylık dönem üzerinden mutabık kalınır
V12 kaydın saklanma süresi 730 gün sözleşme uyuşmazlıkları iki yıl geriye gidebilir
V13 bir fatura satırında toplanan kalem 100 bir satıcının bir günü tek fatura satırıdır; dönem kayıtlarının bölümlenmesi bu orana bağlıdır

Tablonun her satırı bir varsayımdır: doğruluğu tasarımın içinden gösterilemez. Bant genişliği kavramı Bilgisayar Ağları müfredatında kuruldu ve burada yeniden anlatılmaz; hesapta yalnız gövde baytları sayılır, başlık ve protokol yükü ayrı bir varsayım olurdu.

// tasarim/varsayim.mjs — kursun tek varsayim tablosu; butun hesaplar bu tablodan cikar
export const V = {
  gunlukKullanici: 2_000_000,   // V1
  kullaniciBasinaSorgu: 6,      // V2
  gunlukGonderi: 400_000,       // V3
  gonderiBasinaOlay: 7,         // V4
  takipYanitiBayt: 480,         // V5
  olayKaydiBayt: 220,           // V6
  gonderiKaydiBayt: 900,        // V7
  tepeCarpani: 3,               // V8
  onbellekIsabeti: 0.9,         // V9
  topluPencereSaat: 4,          // V10
  topluKapsananGun: 30,         // V11
  saklamaGun: 730,              // V12
  faturaSatirinaKalem: 100,     // V13
};

export const GUN_SANIYE = 86_400;

export function hesapla(v) {
  const gunlukSorgu = v.gunlukKullanici * v.kullaniciBasinaSorgu;
  const gunlukOlay = v.gunlukGonderi * v.gonderiBasinaOlay;
  const okumaOrt = gunlukSorgu / GUN_SANIYE;
  const yazmaOrt = gunlukOlay / GUN_SANIYE;
  const okumaTepe = okumaOrt * v.tepeCarpani;
  const yazmaTepe = yazmaOrt * v.tepeCarpani;
  const depoOkuma = okumaTepe * (1 - v.onbellekIsabeti);
  const topluBayt = v.topluKapsananGun * v.gunlukGonderi * v.gonderiKaydiBayt;
  const gunlukBayt = v.gunlukGonderi * v.gonderiKaydiBayt + gunlukOlay * v.olayKaydiBayt;
  return {
    "gunluk takip sorgusu": gunlukSorgu,
    "gunluk durum olayi": gunlukOlay,
    "ortalama okuma istek/s": okumaOrt,
    "tepe okuma istek/s": okumaTepe,
    "tepe yazma istek/s": yazmaTepe,
    "tepe ucta istek/s": okumaTepe + yazmaTepe,
    "onbellek arkasi okuma/s": depoOkuma,
    "depoya ulasan istek/s": depoOkuma + yazmaTepe,
    "depoda yazma/okuma orani": yazmaTepe / depoOkuma,
    "okuma cikis Mbit/s": (okumaTepe * v.takipYanitiBayt * 8) / 1e6,
    "yazma giris Mbit/s": (yazmaTepe * v.olayKaydiBayt * 8) / 1e6,
    "toplu is okunan GB": topluBayt / 1e9,
    "toplu is tarama kayit/s": (v.topluKapsananGun * v.gunlukGonderi) / (v.topluPencereSaat * 3600),
    "toplu is Mbit/s": (topluBayt * 8) / (v.topluPencereSaat * 3600 * 1e6),
    "gunluk veri artisi MB": gunlukBayt / 1e6,
    "saklanan veri GB": (gunlukBayt * v.saklamaGun) / 1e9,
    "gunluk fatura satiri": v.gunlukGonderi / v.faturaSatirinaKalem,
    "donem satici-gun": (v.topluKapsananGun * v.gunlukGonderi) / v.faturaSatirinaKalem,
  };
}

Birimler ondalık sayılır: MB 10610^6 bayt, GB 10910^9 bayt, Mbit/s 10610^6 bit/s. Karışıklığı önlemek için hesabın içinde yalnız bayt ve saniye kullanılır, dönüştürme son adımda yapılır.

Hesaplar

// tasarim/olcek.mjs — varsayim tablosundan cikan butun hesaplar
import { V, hesapla } from "./varsayim.mjs";

const r = hesapla(V);
const bicim = (x) => (Number.isInteger(x) ? String(x) : x.toFixed(2));
for (const [ad, deger] of Object.entries(r)) console.log(`${ad.padEnd(26)}${bicim(deger).padStart(12)}`);

const gonderiBasinaMs = 1000 / r["toplu is tarama kayit/s"];
console.log(`\ntoplu iste gonderi basina sure = ${gonderiBasinaMs.toFixed(2)} ms (tek isci varsayimiyla)`);
console.log(`ucret cagrisi esigi 1 ms -> kalan pay = ${(gonderiBasinaMs - 1).toFixed(2)} ms`);
console.log(`toplu is bant genisligi / tepe okuma cikisi = ${(r["toplu is Mbit/s"] / r["okuma cikis Mbit/s"]).toFixed(2)}`);
gunluk takip sorgusu          12000000
gunluk durum olayi             2800000
ortalama okuma istek/s          138.89
tepe okuma istek/s              416.67
tepe yazma istek/s               97.22
tepe ucta istek/s               513.89
onbellek arkasi okuma/s          41.67
depoya ulasan istek/s           138.89
depoda yazma/okuma orani          2.33
okuma cikis Mbit/s                1.60
yazma giris Mbit/s                0.17
toplu is okunan GB               10.80
toplu is tarama kayit/s         833.33
toplu is Mbit/s                      6
gunluk veri artisi MB              976
saklanan veri GB                712.48
gunluk fatura satiri              4000
donem satici-gun                120000

toplu iste gonderi basina sure = 1.20 ms (tek isci varsayimiyla)
ucret cagrisi esigi 1 ms -> kalan pay = 0.20 ms
toplu is bant genisligi / tepe okuma cikisi = 3.75

Bu yirmi bir sayının hepsi hesap sınıfındadır: varsayım tablosundan aritmetikle çıkmıştır ve hiçbiri dışarıdan alınmamıştır. Beşi tasarımı doğrudan etkiliyor.

Tepe yük sanıldığı yerde değil. Uçta tepe istek hızı saniyede 513,89. Bunun 416,67’si okuma, 97,22’si yazma. Okuma akışı hâkim görünüyor — ama önbelleğin arkasında tablo tersine dönüyor: depoya ulaşan okuma 41,67, yazma 97,22 ve depodaki yazma/okuma oranı 2,33. Okuma ağırlıklı diye tarif edilen sistem, deponun gördüğü yerde yazma ağırlıklıdır. Önbellek burada bir strateji olarak değil, yalnız hesapta bir çarpan olarak geçiyor; önbellekleme Eşzamansız İşleme kursunda kuruldu.

Seyrek akış bant genişliğine hâkim. Tepe okuma çıkışı 1,60 Mbit/s, gün sonu işinin okuma hızı 6 Mbit/s: oran 3,75. Günde bir kez koşan iş, günün her saniyesi koşan okuma akışının üç buçuk katı bant genişliği istiyor, çünkü 10,80 GB’ı dört saatlik bir pencereye sıkıştırıyor. Bir tasarımın en büyük kaynak kalemi en sık çalışan akış olmak zorunda değildir.

Bir eşik hesaptan doğrulanabilir. Önceki dersin ücret çağrısı eşiği 1 milisaniyeydi ve keyfi görünüyordu. Tarama hızı saniyede 833,33 kayıt olduğuna göre gönderi başına 1,20 milisaniye vardır; 1 milisaniyelik eşik 0,20 milisaniye pay bırakıyor. Eşiğin kaynağı böylece bir beklenti değil bir hesap oluyor. Sayı tek işçi varsayımıyla geçerlidir: iş paralel işçilere bölünürse pay büyür, ama bu bir tasarım kararıdır, aritmetiğin sonucu değil.

Bir rastlantı hesabın tekrarlanmasını gerektiriyor. Depoya ulaşan tepe istek hızı 138,89 ve ortalama okuma hızı da 138,89. İki sayı eşit çünkü 121060,3+2,81063=1210612 \cdot 10^6 \cdot 0{,}3 + 2{,}8 \cdot 10^6 \cdot 3 = 12 \cdot 10^6 olmasıdır; bu bir bağıntı değil, seçilen varsayımların ürettiği bir çakışmadır. Varsayımlardan biri değiştiğinde eşitlik bozulur, bu yüzden hesap ezberlenmez, yeniden koşturulur.

Bir bölme iki ayrı sayı verir. Günde 400.000 gönderi V13 oranıyla günde 4000 fatura satırına düşüyor; her satır bir satıcının bir gününe karşılık geldiğine göre bu sayı aynı zamanda satıcı sayısıdır. Otuz günü tarayan ücretlendirme işi ise 120.000 satırla karşılaşır. İki sayı aynı bölmeden çıkıyor ama aynı şeyi saymıyor: 4000 satıcı, 120.000 satıcı-gün. Bu kursun ilerleyen Temel Nitelikler konusu gün sonu işini bu ikinci sayı üzerinden bölümlere ayırır, bu yüzden ikisinin birbirinin yerine kullanılmaması gerekir.

Duyarlılık

Bir varsayım tablosunun en önemli çıktısı sayılar değil, sayıların varsayımlara duyarlılığıdır. Aşağıdaki betik on üç varsayımı tek tek oynatır ve yedi sonucun kaç katına çıktığını yazar. Önbellek isabeti ikiye katlanamayacağı için oynatması isabetsizliğin iki katına çıkması olarak tanımlanmıştır; toplu pencere ile fatura satırına toplanan kalem ise yarılanır, çünkü ikisinin de sıkılaşması küçülmesidir.

// tasarim/duyarlilik.mjs — her varsayim tek basina oynatildiginda hangi sonuc kac katina cikiyor
import { V, hesapla } from "./varsayim.mjs";

const OYNAMA = {
  gunlukKullanici: (v) => v * 2,
  kullaniciBasinaSorgu: (v) => v * 2,
  gunlukGonderi: (v) => v * 2,
  gonderiBasinaOlay: (v) => v * 2,
  takipYanitiBayt: (v) => v * 2,
  olayKaydiBayt: (v) => v * 2,
  gonderiKaydiBayt: (v) => v * 2,
  tepeCarpani: (v) => v * 2,
  onbellekIsabeti: () => 0.8,          // isabet 0.90 -> 0.80: isabetsizlik iki katina cikiyor
  topluPencereSaat: (v) => v / 2,      // pencere yarilaniyor: ayni is yarim surede bitmeli
  topluKapsananGun: (v) => v * 2,
  saklamaGun: (v) => v * 2,
  faturaSatirinaKalem: (v) => v / 2,   // satira yarisi kadar kalem toplanir
};

const SONUC = [["tepe ucta istek/s", "uc/s"], ["depoya ulasan istek/s", "depo/s"],
  ["okuma cikis Mbit/s", "cikis"], ["toplu is Mbit/s", "toplu"],
  ["gunluk veri artisi MB", "artis"], ["saklanan veri GB", "saklama"],
  ["donem satici-gun", "sat-gun"]];
const taban = hesapla(V);
const kat = {};

console.log(`${"oynatilan varsayim".padEnd(26)}${SONUC.map(([, k]) => k.padStart(8)).join("")}`);
for (const [ad, oynat] of Object.entries(OYNAMA)) {
  const yeni = hesapla({ ...V, [ad]: oynat(V[ad]) });
  kat[ad] = SONUC.filter(([s]) => Math.abs(yeni[s] - taban[s]) > 1e-9).map(([s]) => s);
  const satir = SONUC.map(([s]) => (kat[ad].includes(s) ? `x${(yeni[s] / taban[s]).toFixed(2)}` : "-").padStart(8));
  console.log(`${ad.padEnd(26)}${satir.join("")}`);
}

const enGenis = Object.entries(kat).sort((a, b) => b[1].length - a[1].length)[0];
console.log(`\nen cok sonuc oynatan varsayim = ${enGenis[0]} (${enGenis[1].length}/${SONUC.length})`);
for (const [s] of SONUC) {
  const kaynak = Object.keys(kat).filter((a) => kat[a].includes(s));
  console.log(`${s.padEnd(23)} bagli varsayim = ${kaynak.length}`);
}
oynatilan varsayim            uc/s  depo/s   cikis   toplu   artis saklama sat-gun
gunlukKullanici              x1.81   x1.30   x2.00       -       -       -       -
kullaniciBasinaSorgu         x1.81   x1.30   x2.00       -       -       -       -
gunlukGonderi                x1.19   x1.70       -   x2.00   x2.00   x2.00   x2.00
gonderiBasinaOlay            x1.19   x1.70       -       -   x1.63   x1.63       -
takipYanitiBayt                  -       -   x2.00       -       -       -       -
olayKaydiBayt                    -       -       -       -   x1.63   x1.63       -
gonderiKaydiBayt                 -       -       -   x2.00   x1.37   x1.37       -
tepeCarpani                  x2.00   x2.00   x2.00       -       -       -       -
onbellekIsabeti                  -   x1.30       -       -       -       -       -
topluPencereSaat                 -       -       -   x2.00       -       -       -
topluKapsananGun                 -       -       -   x2.00       -       -   x2.00
saklamaGun                       -       -       -       -       -   x2.00       -
faturaSatirinaKalem              -       -       -       -       -       -   x2.00

en cok sonuc oynatan varsayim = gunlukGonderi (6/7)
tepe ucta istek/s       bagli varsayim = 5
depoya ulasan istek/s   bagli varsayim = 6
okuma cikis Mbit/s      bagli varsayim = 4
toplu is Mbit/s         bagli varsayim = 4
gunluk veri artisi MB   bagli varsayim = 4
saklanan veri GB        bagli varsayim = 5
donem satici-gun        bagli varsayim = 3

Matris üç şey söylüyor. Birincisi, hiçbir varsayım bütün sonuçları oynatmıyor: en geniş etkili varsayım günlük gönderi sayısı ve o da yedi sonucun altısını tutuyor. İkincisi, “iki katına çıkarsa iki katına çıkar” beklentisi çoğu hücrede yanlış. Günlük etkin kullanıcı iki katına çıktığında uçtaki tepe istek hızı 1,81 katına çıkıyor, çünkü yazma akışı bu varsayıma bağlı değil; deponun gördüğü yük yalnız 1,30 katına çıkıyor, çünkü okumanın yüzde onu depoya ulaşıyor. Aynı büyüme farklı katmanlarda farklı büyüklükte görünüyor.

Üçüncüsü, bir sonucun kaç varsayıma bağlı olduğu güvenilirliğinin ölçüsüdür. Depoya ulaşan istek hızı altı varsayıma birden bağlı; içlerinden biri yanlışsa sayı yanlıştır. Saklanan veri beş varsayıma bağlı. Bu yüzden bir tasarım tartışmasında “depoya saniyede yüz otuz dokuz istek geliyor” cümlesi tek başına savunulamaz; savunma varsayım tablosuna işaret eder.

Özet

  • Kabaca büyüklük hesabı doğru sayıyı değil doğru büyüklük sırasını arar; girdisi tek bir yerde toplanmış varsayım tablosudur.
  • On üç varsayımdan çıkan hesaplar: uçta tepe 513,89 istek/s (okuma 416,67, yazma 97,22), günlük veri artışı 976 MB, 730 günde 712,48 GB, günde 4000 fatura satırı ve dönemde 120.000 satıcı-gün — son ikisi aynı bölmeden çıkar ama aynı şeyi saymaz.
  • Önbelleğin arkasında yük dengesi tersine dönüyor: depoya ulaşan okuma 41,67, yazma 97,22 ve yazma/okuma oranı 2,33 — okuma ağırlıklı sistem depoda yazma ağırlıklıdır.
  • Seyrek akış bant genişliğine hâkim olabilir: gün sonu işi 10,80 GB’ı dört saate sıkıştırdığı için 6 Mbit/s istiyor, tepe okuma çıkışının 3,75 katı.
  • Bir eşik hesapla doğrulanabilir: tarama saniyede 833,33 kayıt olduğundan gönderi başına 1,20 ms vardır ve önceki dersin 1 ms eşiği 0,20 ms pay bırakır.
  • Duyarlılık matrisi “iki kat girdi iki kat sonuç” beklentisini yanlışlıyor: günlük kullanıcı iki katına çıktığında uçtaki tepe 1,81, depodaki yük 1,30 katına çıkıyor.

Sonraki Adım

Elde bir bileşen listesi, bir eşik kümesi ve yirmi bir hesaplanmış sayı var. Bunlar bir tasarım değil, tasarımın malzemesidir; tasarım bir başkasına anlatılıp savunulduğunda vardır. Sonraki ders bu anlatımı ele alır: bileşenlerin ve akışların diyagrama nasıl geçtiğini, hangi sayının hangi kenarda durduğunu, ödünleşimin nasıl yazıldığını ve her sayının yanına sınıfının yazılmasının anlatımı nasıl denetlenebilir kıldığını.

İ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