İçeriğe geç
academia.sh

Ders 16 / 16

Maliyet Farkındalığı

Tasarım kararlarının işletme yükünün kaynak birimiyle sayılması: aylık kaynak tüketiminin iş hacmine bölünerek birim maliyete çevrilmesi, hacim büyümesi ile birim maliyet büyümesinin aynı toplamı verdiği hâlde iş birimi başına kaynakla ayrılması, satın alınan kapasitenin ne kadarının iş yaptığının ölçülmesi ve hiçbir düzeltmenin maliyeti kaldırmayıp kalemler arasında taşıdığının gösterilmesi.

İçindekiler

Önceki ders bir sayı üretti: kaç düğüm. Yanına bir kaynak birimi de yazdı — bugün ayda 1.440 düğüm-saat, on kat ölçekte 5.760. Ama o düğümlerin neye mal olduğu ve buraya kadarki bütün kursların tasarım kararlarının işletme yükünü nasıl değiştirdiği hiç sorulmadı. Önbellek isabetini yükseltmek neyi azaltır, veriyi ayırmak neyi çoğaltır, bir kopya eklemek hangi kalemi büyütür, izlemenin kendi bedeli nerede görünür.

Bu ders o soruyu ele alır ve kursun tanı kuralını son bir kez uygular: belirti bir sayıdır, aynı belirtiyi veren iki neden kurulur, ikisini ayıran bir ölçüm gösterilir.

Maliyet Kaynak Birimiyle Yazılır

İşletme maliyeti bu kursta para birimiyle yazılmaz. Bir fiyat sağlayıcıya, sözleşmeye ve tarihe bağlıdır; beş yıl sonra okunduğunda yanlış olur. Kaynak birimi bağlı değildir: işlemci-saniye, GB-ay, düğüm-saat, aktarılan GB, istek başına dokunuş. Bir tasarım kararının işletme yükü bu birimlerle yazıldığında, fiyat değişse de karşılaştırma geçerli kalır.

Birim maliyet bu kursta kaynak cinsindendir: bir iş biriminin — bir isteğin ya da bir kaydın — tükettiği kaynak. Aşağıdaki hesabın bütün girdileri önceki derslerin sayılarıdır ve hiçbiri yeniden hesaplanmaz; yeni varsayım da eklenmez.

// maliyet/birim.mjs — tasarim kararlarinin isletme yuku, kaynak birimiyle. Butun girdiler
// onceki derslerin sayilaridir ve hicbiri yeniden hesaplanmaz. Para birimi kullanilmaz.
const SORGU_GUN = 12_000_000;   // K01: gunluk takip sorgusu
const OLAY_GUN = 2_800_000;     // K01: gunluk durum olayi
const YANIT_BAYT = 480;         // K01 (V5): takip yaniti govdesi
const OLAY_BAYT = 220;          // K01 (V6): bir durum olayi kaydi
const TOPLU_GB = 10.80;         // K01: gun sonu isinin okudugu
const SAKLANAN_GB = 712.48;     // K01: 730 gunde saklanan veri
const ISLEMCI_S = 0.00085;      // bu kursun yuk testi dersi: istek basina islemci payi (s)
const TEPE = 513.89;            // K01: tepe ucta istek/s
const IZLEME_HAM = 239.76;      // bu kursun enstrumantasyon dersi: ham olay, GB-ay
const IZLEME_HIST = 2.07;       // ayni ders: saniyelik histogram, GB-ay
const AY = 30, SAAT = 720;
const b = (x, n = 2) => x.toFixed(n);

const dugum = (tepe) => Math.ceil(tepe / ((1 / ISLEMCI_S) * 0.7)) + 1;   // 05'in kurali
const istekAy = (SORGU_GUN + OLAY_GUN) * AY;

const kalem = (k = 1) => ({
  "islemci-saniye": istekAy * k * ISLEMCI_S,
  "dugum-saat": dugum(TEPE * k) * SAAT,
  "aktarilan GB": ((SORGU_GUN * YANIT_BAYT + OLAY_GUN * OLAY_BAYT) * AY * k) / 1e9 + TOPLU_GB * AY * k,
  "saklama GB-ay": SAKLANAN_GB * k,
  "izleme GB-ay": IZLEME_HIST,
});

const taban = kalem();
console.log(`aylik is hacmi ${istekAy.toLocaleString("tr-TR")} istek (K01: gunluk 12.000.000 sorgu + 2.800.000 olay)`);
console.log(`${"kalem".padEnd(16)}${"aylik miktar".padStart(15)}${"istek basina".padStart(16)}`);
for (const [ad, deger] of Object.entries(taban))
  console.log(`${ad.padEnd(16)}${b(deger).padStart(15)}${deger / istekAy < 1e-4
    ? (deger / istekAy).toExponential(2).padStart(16) : b(deger / istekAy, 6).padStart(16)}`);

const alinan = dugum(TEPE) * SAAT * 3600;
console.log(`\nsatin alinan dugum-saniye ${alinan.toLocaleString("tr-TR")}, ` +
  `is yapan islemci-saniye ${Math.round(taban["islemci-saniye"]).toLocaleString("tr-TR")}`);
console.log(`kaynak verimi %${b((100 * taban["islemci-saniye"]) / alinan)} — kalani kapasite payi, ` +
  `yedeklilik ve tepe disi saatlerdir`);

console.log(`\nolcek buyudukce hangi kalem kac katina cikiyor:`);
console.log(`${"olcek".padStart(6)}${"dugum".padStart(7)}${Object.keys(taban).map((a) => a.padStart(16)).join("")}`);
for (const k of [1, 2, 4, 10]) {
  const y = kalem(k);
  console.log(`${(k + "x").padStart(6)}${String(dugum(TEPE * k)).padStart(7)}` +
    `${Object.keys(taban).map((a) => `${b(y[a] / taban[a])} kat`.padStart(16)).join("")}`);
}
console.log(`hacimle buyumeyen iki kalem birim maliyeti dusurur: 10 kat hacimde dugum-saat ` +
  `${b(dugum(TEPE * 10) / dugum(TEPE))} kat, izleme 1,00 kat`);

console.log(`\nayni toplam buyumesi, iki ayri neden (ayiran olcum: istek basina islemci-saniye):`);
console.log(`${"ay".padStart(4)}${"A: istek".padStart(16)}${"A: islemci-sn".padStart(15)}` +
  `${"A: istek basina".padStart(17)}${"B: istek".padStart(16)}${"B: islemci-sn".padStart(15)}${"B: istek basina".padStart(17)}`);
for (const ay of [0, 6, 12]) {
  const buyume = 1.06 ** ay;                       // A: hacim buyuyor, birim maliyet sabit
  const aIstek = istekAy * buyume, aIslemci = aIstek * ISLEMCI_S;
  const bIstek = istekAy, bIslemci = bIstek * ISLEMCI_S * buyume;   // B: hacim sabit, birim buyuyor
  console.log(`${String(ay).padStart(4)}${Math.round(aIstek).toLocaleString("tr-TR").padStart(16)}` +
    `${Math.round(aIslemci).toLocaleString("tr-TR").padStart(15)}${(aIslemci / aIstek).toExponential(3).padStart(17)}` +
    `${Math.round(bIstek).toLocaleString("tr-TR").padStart(16)}` +
    `${Math.round(bIslemci).toLocaleString("tr-TR").padStart(15)}${(bIslemci / bIstek).toExponential(3).padStart(17)}`);
}

console.log(`\nkaynak profili kaymasi — hicbir karar maliyeti kaldirmaz, kalemler arasi tasir:`);
const KARAR = [
  ["kenar onbellegi (K01 V9: isabet 0,90)", `depoya ulasan okuma ${b(416.67 / 41.67)} kat azalir`,
    "tutulan bellek ve bayatlik penceresi buyur (nicel karsiligi K04'te)"],
  ["tek parca kaliciligin ayrilmasi", "donem taramasi 801 kat az kayit tarar",
    `depo yazmasi ${b(194.44 / 97.22)} kat, isletilen depo 1 -> 3`],
  ["bir dugum daha (yedeklilik)", "tek dugum arizasi artik kesinti uretmez",
    `dugum-saat ${b(2160 / 1440)} kat (1.440 -> 2.160)`],
  ["ham olay yerine saniyelik histogram", `izleme ${b(IZLEME_HAM / IZLEME_HIST)} kat az GB-ay tutar`,
    "kayit kimligi kaybolur: p99 hatasi %10,0'a cikar"],
];
for (const [ad, azalan, artan] of KARAR) console.log(`  ${ad}\n    azalan: ${azalan}\n    artan : ${artan}`);
aylik is hacmi 444.000.000 istek (K01: gunluk 12.000.000 sorgu + 2.800.000 olay)
kalem              aylik miktar    istek basina
islemci-saniye        377400.00        0.000850
dugum-saat              1440.00         3.24e-6
aktarilan GB             515.28         1.16e-6
saklama GB-ay            712.48         1.60e-6
izleme GB-ay               2.07         4.66e-9

satin alinan dugum-saniye 5.184.000, is yapan islemci-saniye 377.400
kaynak verimi %7.28 — kalani kapasite payi, yedeklilik ve tepe disi saatlerdir

olcek buyudukce hangi kalem kac katina cikiyor:
 olcek  dugum  islemci-saniye      dugum-saat    aktarilan GB   saklama GB-ay    izleme GB-ay
    1x      2        1.00 kat        1.00 kat        1.00 kat        1.00 kat        1.00 kat
    2x      3        2.00 kat        1.50 kat        2.00 kat        2.00 kat        1.00 kat
    4x      4        4.00 kat        2.00 kat        4.00 kat        4.00 kat        1.00 kat
   10x      8       10.00 kat        4.00 kat       10.00 kat       10.00 kat        1.00 kat
hacimle buyumeyen iki kalem birim maliyeti dusurur: 10 kat hacimde dugum-saat 4.00 kat, izleme 1,00 kat

ayni toplam buyumesi, iki ayri neden (ayiran olcum: istek basina islemci-saniye):
  ay        A: istek  A: islemci-sn  A: istek basina        B: istek  B: islemci-sn  B: istek basina
   0     444.000.000        377.400         8.500e-4     444.000.000        377.400         8.500e-4
   6     629.822.486        535.349         8.500e-4     444.000.000        535.349         1.206e-3
  12     893.415.233        759.403         8.500e-4     444.000.000        759.403         1.710e-3

kaynak profili kaymasi — hicbir karar maliyeti kaldirmaz, kalemler arasi tasir:
  kenar onbellegi (K01 V9: isabet 0,90)
    azalan: depoya ulasan okuma 10.00 kat azalir
    artan : tutulan bellek ve bayatlik penceresi buyur (nicel karsiligi K04'te)
  tek parca kaliciligin ayrilmasi
    azalan: donem taramasi 801 kat az kayit tarar
    artan : depo yazmasi 2.00 kat, isletilen depo 1 -> 3
  bir dugum daha (yedeklilik)
    azalan: tek dugum arizasi artik kesinti uretmez
    artan : dugum-saat 1.50 kat (1.440 -> 2.160)
  ham olay yerine saniyelik histogram
    azalan: izleme 115.83 kat az GB-ay tutar
    artan : kayit kimligi kaybolur: p99 hatasi %10,0'a cikar

Satın Alınan Kaynak ve İş Yapan Kaynak

İkinci blok dersin en rahatsız edici sayısını veriyor. Ayda 5.184.000 düğüm-saniye satın alınıyor ve bunun 377.400’ü iş yapıyor: kaynak verimi yüzde 7,28. Kalanı boşa gitmiş değildir, üç ayrı karar tarafından bilerek satın alınmıştır. Kapasite payı, doluluğun tavanı geçmemesi için tutulur ve gerekçesi kuyruk modelidir. Yedeklilik, bir düğüm düştüğünde hizmetin sürmesi için tutulur. Üçüncüsü aritmetiktir: kapasite tepeye göre alınır, iş ise ortalamada yapılır ve K01’in tepe çarpanı üçtür.

Bu sayı bir israf ölçüsü olarak okunursa yanlış okunur. Doğru okunuşu şudur: erişilebilirlik hedefinin ve gecikme hedefinin kaynak cinsinden fiyatı budur. Yüzde 7,28’i yükseltmenin tek yolu o iki hedeften birinden vazgeçmektir; hedefler durduğu sürece oran bir sonuçtur, bir kusur değil. Maliyet farkındalığı, bu oranı düşürmeye çalışmak değil, ne satın alındığını bilmektir.

Belirti: Kaynak Hacimden Hızlı Büyüyor

Aylık kaynak tüketiminin büyümesi bir belirtidir ve tek başına hiçbir şey söylemez. İki neden aynı toplamı verir. A: hacim büyümüştür, birim maliyet sabittir. B: hacim sabittir, birim maliyet büyümüştür. Üçüncü tablo ikisini yan yana koyuyor ve toplam sütunları on ikinci ayda birebir aynı: 759.403 işlemci-saniye.

Ayıran ölçüm iş birimi başına kaynaktır. A’da istek başına işlemci-saniye on iki ay boyunca 8,500e-4’te sabit kalıyor; B’de 8,500e-4’ten 1,710e-3’e, iki katına çıkıyor. Toplam kaynağa bakan biri iki durumu ayıramaz ve büyük olasılıkla ikisine de aynı yanıtı verir: düğüm ekler. A’da bu doğru yanıttır. B’de düğüm eklemek belirtiyi örter ve nedeni yerinde bırakır.

B’nin gerçek bir kaynağı bu kursta ölçüldü. Dayanıklılık testi, aynı yükte çalışan bir sürecin bakım geçişi başına adımının 61 katına çıktığını gösterdi; birikme, istek başına işi hacimden bağımsız olarak büyütür. Birim maliyetin zaman serisi, bir dayanıklılık testinin bulduğu şeyi üretimde de bulur — üstelik test koşturmadan.

Birim Maliyet Ölçekle Düşer

İkinci tablo kalemlerin ölçekle aynı hızda büyümediğini gösteriyor. İşlemci-saniye, aktarılan GB ve saklama hacimle doğrusal: on kat iş, on kat kaynak. Düğüm-saat değil — on kat hacimde yalnız 4,00 katına çıkıyor, çünkü önceki dersin arıza kısıtı küçük ölçekte bir düğüm fazlası ister ve o fazlanın payı ölçekle erir. İzleme kalemi hiç büyümüyor: saniyelik histogram, istek hızından bağımsız olarak 2,07 GB-ay tutuyor.

Sonuç şudur: birim maliyet ölçekten bağımsız bir sayı değildir. İstek başına düğüm-saat on kat ölçekte 2,5 kat ucuzlar, istek başına izleme on kat ucuzlar, istek başına işlemci-saniye hiç değişmez. Bir işletme yükü tartışmasında “bu özellik istek başına şu kadar tutuyor” cümlesi, hangi ölçekte ölçüldüğü söylenmeden okunamaz — kursun ilk dersindeki kuralın aynısı, bu kez maliyet tarafında.

Kaynak Profili Kayması

Son blok dört tasarım kararını alıyor ve hiçbirinin maliyeti kaldırmadığını, yalnız kalemler arasında taşıdığını gösteriyor. Kenar önbelleği depoya ulaşan okumayı 10,00 kat azaltır ve karşılığında bellek tutar. Tek parça kalıcılığı ayırmak dönem taramasını 801 kat küçültür ve depo yazmasını 2,00 katına çıkarır, işletilen depo sayısını 1’den 3’e taşır. Bir düğüm daha eklemek tek düğüm arızasının kesinti üretmesini engeller ve düğüm-saati 1,50 katına çıkarır. Ham olay yerine histogram toplamak izlemeyi 115,83 kat ucuzlatır ve kayıt kimliğini siler.

Dördünün ortak biçimi kursun tanı kuralının maliyet tarafındaki karşılığıdır: bir düzeltme savunulurken hangi kalemin küçüldüğü ve hangisinin büyüdüğü birlikte yazılır. Yalnız küçüleni yazan bir gerekçe eksik bir gerekçedir, çünkü kaynak profili değişmiştir ve yeni profilin darboğazı başka bir yerdedir.

Özet

  • İşletme yükü para birimiyle değil kaynak birimiyle yazılır — işlemci-saniye, GB-ay, düğüm-saat, aktarılan GB — çünkü fiyat sağlayıcıya ve tarihe bağlıdır, kaynak birimi değildir.
  • Ayda 5.184.000 düğüm-saniye satın alınıyor, 377.400’ü iş yapıyor: kaynak verimi yüzde 7,28. Kalanı kapasite payının, yedekliliğin ve tepe çarpanının kaynak cinsinden fiyatıdır, israf değil.
  • Aynı kaynak büyümesini iki neden verir ve toplam onları ayıramaz (on ikinci ayda ikisi de 759.403 işlemci-saniye); ayıran ölçüm iş birimi başına kaynaktır: A’da 8,500e-4 sabit, B’de 1,710e-3.
  • Birim maliyet ölçekle değişir: on kat hacimde işlemci-saniye 10,00, düğüm-saat 4,00, izleme 1,00 katına çıkar; istek başına maliyet hangi ölçekte ölçüldüğü söylenmeden okunamaz.
  • Hiçbir düzeltme maliyeti kaldırmaz, kalemler arasında taşır: histogram izlemeyi 115,83 kat ucuzlatıp kayıt kimliğini siler, ayırma taramayı 801 kat küçültüp yazmayı 2,00 katına çıkarır.

Kurs Kapanışı

Bu kurs on altı derste tek bir işi yaptı: bir belirtiyi bir nedene bağlamak. Aşağıdaki tablo her dersin belirtisini, ayırt eden ölçümünü ve düzeltmenin karşılığında büyüttüğü şeyi bir arada veriyor.

Ders Belirti Ayırt eden ölçüm Düzeltmenin karşılığında büyüyen
Meşgul Veritabanı Depo doluyken uygulama boşta Sınır oranı: 1,00 ise iş yukarı, çok üstündeyse aşağı Uygulamada satır işi 0 → 240.000 kayıt (saniyede 3333,33)
Meşgul Ön Yüz Sunucu ölçütleri sabitken görünen süre büyür Kayıt başına iş birimi: yükte %0,95, kodda %16,1 Yanıt 3.771 → 3.775 bayt ve bölünen önbellek anahtarı
Gevezelik Eden Girdi/Çıktı Her çağrı hızlı, yararlı yük küçük, açılış yavaş Baytın işe yarayan payı: zarf 0,4661 / kullanılmayan yük 0,6177 Birleştirmede kullanılmayan yük, ayırmada tur sayısı (6 tur)
Gereksiz Veri Çekme İstek sabitken kenar isabeti 0,90’ın altına iner Çalışma kümesinin çarpanı: bayt 5,43 kat / çeşit 4,00 kat Daraltma çeşitlendirir: isabet 0,8042 → 0,6348
Hatalı Nesne Yaratımı Verim eşzamanlılıkla artmıyor Yaratım oranı: 1,0000 ise azalt, 0,0007 ise artır Tutulan nesne-tur: havuz 24, havuz 5’in 2,26 katı kaynak tutar
Tek Parça Kalıcılık Yazma başına iş büyüyor Kendi sınıfına hizmet eden pay: dizin 0,33, tarama 801 kat Depo yazması 97,22 → 194,44/s, depo sayısı 1 → 3, atomiklik
Önbelleksizlik Uygulama katmanı doyuma yaklaşıyor Hesap anahtarına göre tekilleştirme: okuma 1,00 / hesap 125,00 Bellek 960 → 119.365 girdi ve yanlışlık yüzeyi (0,5000)
Gürültülü Komşu Küçük kiracıların beklemesi 0,24 → 0,98 tur İstek payı 0,6143’te sabitken iş payı 0,1702 → 0,2415 S1’in gecikmesi 0,47 → 2,96 tur, tutulan 200 sayaç
Eşzamanlı Girdi/Çıktı Verim tavana çarpıyor, işçi eklemek işe yaramıyor Bağımlılığın kendi doluluğu: 0,9999 / 0,1819 Uçuştaki istek 8 → 46 (5,75 kat); kabul denetimi gerekir
Yeniden Deneme Fırtınası Bağımlılığa varan çağrı hızı büyüyor Tekil istek kimliği 4,00’te sabit, başarı oranı 0,0400 İzni kısmak düşen istek üretir: izin 1’de 180 istek
İzleme Kategorileri On tanının hepsi var olmayan bir ölçümü varsayıyor Kategori kapsaması: kullanım 10/10, başarım 7/10 Toplanacak ölçüt listesi on altı kaleme çıkar
Enstrümantasyon Tasarımı İzleme kaydı sistemin kendi yazmasının 5,29 katı Bedel başına korunan bilgi: %93,0 hataya karşı %10,0 Toplulaştırma kayıt kimliğini siler, en büyüğü sınırlayamaz
Gösterge Tabloları ve Uyarılar Uyarı ya sürekli çalıyor ya hiç çalmıyor Eşik–pencere taraması ve tüketim hızı: %0,5 eşiği 7,7 hız Pencere uzadıkça 2,0 dk gecikme, 5 dk’da 3,29 dk bütçe
Yük Testi Bugünkü ölçüm yarınki yük hakkında susuyor Üç ayrı test: ortanca yerinde, p95 ve p99 iki katına yakın Sıçramanın bedeli sıçramadan büyük: 1.542 fazla istek
Kapasite Planlama Kaç düğüm gerektiği ölçümden okunamıyor Yük kısıtı ile arıza kısıtı: bugün her tavanda n = 2 Yedeklilik primi %100; 1.440 → 2.160 düğüm-saat
Maliyet Farkındalığı Aylık kaynak, iş hacminden hızlı büyüyor İş birimi başına kaynak: 8,500e-4 sabit / 1,710e-3 büyüyen Her düzeltme kalemi kaydırır: 115,83 kat az GB-ay, silinen kimlik

Tablonun üçüncü sütunu kursun kuralıdır: belirti bir tanı değildir. “Yavaş”, “pahalı”, “ölçeklenmiyor” cümlelerinin hiçbiri bir nedene işaret etmez; tanı, aynı belirtiyi veren iki nedeni birbirinden ayıran ölçümdür. On altı dersin hiçbirinde belirti tek başına yeterli olmadı ve birkaçında en çok bakılan ölçüt en az ayırt eden ölçüt çıktı — işçi doluluğu iki nedeni ayıramadı (0,9562 ile 0,9545), toplam kaynak iki nedeni ayıramadı (ikisi de 759.403), yanıt süresi yüzdeliği on tanının altısında birden göründü.

Dördüncü sütun ikinci kuralı taşır: hiçbir kalıp her koşulda yanlış değildir. Her ders aynı biçimin doğru olduğu koşulu bir sayıyla sınırladı. Hesabın depoda kalması, sınırdan geçen kaydı azalttığı ölçüde haklıdır — F1’de 100 kat azaltıyor. Fazla alan taşımak, ortadan kaldırdığı çağrının 280 baytlık zarfından küçükse haklıdır. Önbelleksizlik, tekrar 1,01 olan bir akışta doğru tasarımdır; orada belleme kazanmak yerine 0,71 kata düşer. Paylaşılan kaynak, gürültü katsayısı bire yakınken ve hiçbir tek istek turluk kapasiteyi aşmazken doğrudur. Engelleyen çağrı, bekleme yerel işle aynı mertebedeyken doğrudur. Karşıt kalıp bir yasak değil, bir ölçekte yanlışa dönen bir seçimdir; o ölçeği veren şey de üçüncü sütundaki ölçümdür.

Altı kurs bir tasarım dilini parça parça kurdu: trafiğin nasıl karşılandığı, uygulamanın nasıl bölündüğü, verinin nasıl dağıtıldığı, arızanın nasıl çevrelendiği ve bütün bunların nasıl görünür kılındığı. Her kurs kendi sorusunu kendi ölçüsüyle yanıtladı. Yapılmayan tek şey şudur: bu parçaların tek bir problemde birlikte kullanılması ve seçimlerin gerekçesiyle baştan sona anlatılması. Bir tasarım tartışmasında sorular kurs sınırlarına göre sıraya girmez; hepsi aynı anda sorulur ve aralarındaki ödünleşim tek tek değil birlikte savunulur. Sonraki kurs Vaka Çalışmaları o işi yapar.

İ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