İçeriğe geç
academia.sh

Ders 06 / 12

İstek Üzerine Ortam Sağlama

Aynı doksan günlük talep akışı iki yoldan geçirilir: insanın kurduğu talep kuyruğu ve istek üzerine üretilen ortam. Bekleme süresi, ortam ömrü, boşta duran ortam-günü ve unutulan ortam sayılır; ömür sınırı taranarak kısa ömrün yeniden kurma ve veri kaybı karşılığı çıkarılır.

İçindekiler

Önceki konu platformun ne olduğunu tanımladı ve sınırlarını çizdi: hangi kararın devralındığı, hangisinin ekipte kaldığı, iç müşterinin kim olduğu. Tanım yerinde duruyor, ama bir ekip sabah işe başladığında platformdan somut olarak ne isteyeceği hâlâ söylenmedi. İstenecek ilk şey neredeyse her zaman aynıdır: üzerinde çalışılacak bir ortam.

İstek üzerine ortam, bir ekibin ortam kurulumunu bir talep formuna yazıp beklemek yerine kendi başlattığı ve kendi bitirdiği ortamdır. Ortamın nasıl sağlandığı — bildirimden gerçeğe giden yol, kayıt ile gerçek arasındaki sapma — M22/K01’in ortam sağlama dersinde ve M22/K05’te ölçüldü; burada tekrarlanmaz. Bu dersin ölçtüğü şey sağlama mekaniği değil, ortamın yaşam döngüsüdür: ne kadar beklendiği, ne kadar yaşadığı ve yaşadığı sürenin ne kadarında kullanılmadığı.

Ölçüm bölgesel ölçüm ağı üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha iş emri açan kurgu yazılım. Gerçek altyapı kurulmaz; ölçülen şey node ile yazılmış bir modeldir.

PT1. Ağın yazılımını beş ekip üretir: sayaç okuma, doğrulama, faturalama, saha, raporlama. Ekipler ve talep oranları kurgudur. PT2. Gözlem penceresi 90 gündür. Talep akışı kendi yazılan bir üreteçle çıkarılır; tohum görünürdür. PT3. Elle ortam kurmak 6 saat insan emeğidir ve platform ekibinin elle kurma kapasitesi günde bir ortamdır. PT4. İstek üzerine yolda üretim 0,5 saat sürer; eş zamanlı açık ortam havuzu 16’dır. PT5. Kuyruk yolunda teslim edilen ortam kapatılmaz — yeniden beklemek pahalıdır. İstek üzerine yolda ekip kullanımı bitince kapatır; kapatmayı unuttuğu durumlar önceden yazılıdır, rastgelelik yoktur. PT6. Platform iki ortam biçimi sunar: küçük ve orta. Alan donanımlı biçim sunulmaz. Unutulan ortam, son kullanım gününden sonra en az yedi gün açık kalan ortamdır.

Talep Kuyruğu ve İstek Üzerine

// veri.mjs — bes ekibin doksan gunluk ortam talebi; model, uretec kendi yazildi, tohum gorunur.
export const EKIP = ["sayac-okuma", "dogrulama", "faturalama", "saha", "raporlama"];
export const GUN = 90, TOHUM = 20260801;
export const uretec = (t) => () => ((t = (t * 1103515245 + 12345) % 2147483648) / 2147483648);

const ORAN = { "sayac-okuma": 0.24, dogrulama: 0.16, faturalama: 0.10, saha: 0.30, raporlama: 0.06 };
const BICIM = { "sayac-okuma": "kucuk", dogrulama: "orta", faturalama: "orta",
  saha: "alan-donanimli", raporlama: "orta" };      // platform yalniz kucuk ve orta sunuyor
export const SUNULAN = ["kucuk", "orta"];

export const talepler = () => {                     // her ekip icin gun gun bagimsiz cekilis
  const r = uretec(TOHUM), t = [];
  for (let g = 0; g < GUN; g++)
    for (const e of EKIP) {
      const [a, b, c] = [r(), r(), r()];
      if (a < ORAN[e]) t.push({ ekip: e, gun: g, bicim: BICIM[e],
        kullanim: 1 + Math.floor(b * 9),            // fiilen kac gun kullanilacak
        durumlu: c < 0.45 });                       // ortamda uretilmis veri kaliyor mu
    }
  return t;
};

Aynı talep akışı iki yoldan geçirilir. Kuyruk yolunda her talebi insan karşılar. Platform yolunda sunulan biçimdeki talepler istek üzerine üretilir; sunulmayan biçimdekiler altın yolun dışında kalır ve o ekip ortamını kendi kurar.

// yol.mjs — ayni talep akisi iki yoldan gecirilir: talep kuyrugu ve istek uzerine ortam.
import { talepler, GUN, EKIP, SUNULAN } from "./veri.mjs";

const KAPASITE = 1, HAVUZ = 16, URETIM_SAAT = 0.5, ELLE_SAAT = 6, UNUT = 7;
const T = talepler();
const ort = (d) => (d.length ? d.reduce((a, b) => a + b, 0) / d.length : 0).toFixed(1);

const kuyruk = (liste) => {                         // insan kurar: gunde en cok bir ortam
  const bekleyen = [], ortam = [];
  for (let g = 0; g < GUN; g++) {
    bekleyen.push(...liste.filter((t) => t.gun === g));
    for (let k = 0; k < KAPASITE && bekleyen.length; k++) {
      const t = bekleyen.shift();
      ortam.push({ ...t, acilis: g, bekleme: (g - t.gun) * 24 + ELLE_SAAT, kapanis: GUN });
    }                                               // kuyruk yolunda ortam biraktirilmaz
  }
  return { ortam, teslimsiz: bekleyen.length, dolu: 0 };
};

const istekUzerine = (liste) => {                   // bir istekle uretilir, havuz sinirli
  const bekleyen = [], ortam = [], acik = [];
  let dolu = 0;
  for (let g = 0; g < GUN; g++) {
    for (let i = acik.length - 1; i >= 0; i--) if (acik[i].kapanis <= g) acik.splice(i, 1);
    bekleyen.push(...liste.filter((t) => t.gun === g));
    while (bekleyen.length && acik.length < HAVUZ) {
      const t = bekleyen.shift();
      const unutuldu = (t.gun * 7 + t.kullanim) % 4 === 0;  // onceden yazili, rastgele degil
      const o = { ...t, acilis: g, bekleme: (g - t.gun) * 24 + URETIM_SAAT, unutuldu,
        kapanis: unutuldu ? GUN : Math.min(GUN, g + t.kullanim) };
      ortam.push(o); acik.push(o);
    }
    if (acik.length >= HAVUZ) dolu++;
  }
  return { ortam, teslimsiz: bekleyen.length, dolu };
};

const kendiKuran = (liste) => ({ dolu: 0, teslimsiz: 0,   // dis yolda ekip kendi kurar, kapatmaz
  ortam: liste.map((t) => ({ ...t, acilis: t.gun, bekleme: ELLE_SAAT, kapanis: GUN })) });

const olc = (ad, { ortam, teslimsiz, dolu }) => {
  const gun = ortam.reduce((a, o) => a + (o.kapanis - o.acilis), 0);
  const kullanilan = ortam.reduce((a, o) => a + Math.min(o.kullanim, o.kapanis - o.acilis), 0);
  const unutulan = ortam.filter((o) => o.kapanis - o.acilis - o.kullanim >= UNUT).length;
  console.log(`${ad.padEnd(20)} teslim ${String(ortam.length).padStart(2)}` +
    `  teslimsiz ${teslimsiz}  bekleme ${ort(ortam.map((o) => o.bekleme)).padStart(5)} saat` +
    `  ortam-gun ${String(gun).padStart(4)}  bosta ${String(gun - kullanilan).padStart(4)}` +
    ` (%${String(Math.round((gun - kullanilan) / gun * 100)).padStart(2)})  unutulan ${unutulan}`);
  return { gun, kullanilan, unutulan, dolu, n: ortam.length };
};

const ic = T.filter((t) => SUNULAN.includes(t.bicim));
const dis = T.filter((t) => !SUNULAN.includes(t.bicim));
console.log(`talep ${T.length}  pencere ${GUN} gun  ekip ${EKIP.length}  elle kurulum ` +
  `${ELLE_SAAT} saat, ${KAPASITE}/gun  havuz ${HAVUZ} es zamanli  uretim ${URETIM_SAAT} saat`);
const A = olc("talep kuyrugu (hep)", kuyruk(T));
const B = olc("istek uzerine (ic)", istekUzerine(ic));
const C = olc("altin yol disinda", kendiKuran(dis));
console.log(`havuzun dolu oldugu gun ${B.dolu}/${GUN}; havuz doluyken gelen talep bekliyor,` +
  ` ${B.dolu ? "gizlenen kapasite geri siziyor" : "sizma yok"}`);
console.log(`altin yol disinda ${dis.length}/${T.length} talep, tek gerekce alan-donanimli bicim` +
  ` (${[...new Set(dis.map((t) => t.ekip))].join(", ")}); platform hizmetinden hicbiri yararlanmiyor`);
console.log(`insan emegi: kuyruk ${A.n * ELLE_SAAT} saat   platform ${C.n * ELLE_SAAT} saat` +
  ` (yalnizca dis yol)   kurtulan ${(A.n - C.n) * ELLE_SAAT} saat`);
talep 90  pencere 90 gun  ekip 5  elle kurulum 6 saat, 1/gun  havuz 16 es zamanli  uretim 0.5 saat
talep kuyrugu (hep)  teslim 83  teslimsiz 7  bekleme  83.2 saat  ortam-gun 3528  bosta 3133 (%89)  unutulan 73
istek uzerine (ic)   teslim 60  teslimsiz 3  bekleme  10.1 saat  ortam-gun  877  bosta  580 (%66)  unutulan 12
altin yol disinda    teslim 27  teslimsiz 0  bekleme   6.0 saat  ortam-gun 1212  bosta 1090 (%90)  unutulan 22
havuzun dolu oldugu gun 16/90; havuz doluyken gelen talep bekliyor, gizlenen kapasite geri siziyor
altin yol disinda 27/90 talep, tek gerekce alan-donanimli bicim (saha); platform hizmetinden hicbiri yararlanmiyor
insan emegi: kuyruk 498 saat   platform 162 saat (yalnizca dis yol)   kurtulan 336 saat

Bekleme farkı en görünür sayıdır: kuyruk yolunda ortalama 83,2 saat, istek üzerine yolda 10,1 saat. Kuyruk yolunda 90 talebin 7’si pencere kapandığında hâlâ sıradadır. Ama beklemeyi düşüren şey tek başına otomasyon değildir; kuyruk yolunun kapasitesi günde bir ortamdır ve talep günde bir taleptir, yani kuyruk zaten doygunluk sınırında çalışır. Devredilen karar şudur: ortamın ne zaman var olacağına ve ne zaman yok olacağına insan değil, ekip kendi karar verir.

İkinci sayı ilkinden daha ilginçtir. Kuyruk yolunda 3.528 ortam-günün 3.133’ü boştadır, yani ortamlar ömürlerinin yüzde 89’unda kullanılmamaktadır. Nedeni beklemededir: ortam almak günler sürdüğü için kimse aldığı ortamı geri vermez, ve 83 ortamın 73’ü unutulan ortama dönüşür. Bekleme süresi ile boşta duran kaynak birbirinden bağımsız iki sorun değildir; biri diğerini üretir.

Ömür Sınırı: Kısa Ömrün Karşılığı

// omur.mjs — omur siniri taranir: maliyet, yeniden kurma, veri kaybi; sonra esik hesaplanir.
import { talepler, GUN, EKIP, SUNULAN } from "./veri.mjs";

const HAVUZ = 16, ELLE_SAAT = 6, UNUT = 7, KURULUM = 320, ISLETME_AY = 8, AY = 3;
const T = talepler(), ic = T.filter((t) => SUNULAN.includes(t.bicim));

const tara = (omur) => {                   // omur dolunca ortam silinir, is bitmediyse geri istenir
  const bekleyen = [], acik = [];
  let gunToplam = 0, uretilen = 0, yeniden = 0, kayip = 0, unutulan = 0;
  for (let g = 0; g < GUN; g++) {
    for (let i = acik.length - 1; i >= 0; i--) {
      const o = acik[i], yas = g - o.acilis, bitti = o.kalan === 0 && !o.unutuldu;
      if (!bitti && yas < omur) continue;
      acik.splice(i, 1);
      gunToplam += yas;
      if (yas - (o.kullanim - o.kalan) >= UNUT) unutulan++;
      if (o.kalan > 0) { yeniden++; kayip += o.durumlu ? 1 : 0; bekleyen.push(o); }
    }
    bekleyen.push(...ic.filter((t) => t.gun === g).map((t) => ({ ...t, kalan: t.kullanim,
      unutuldu: (t.gun * 7 + t.kullanim) % 4 === 0 })));
    while (bekleyen.length && acik.length < HAVUZ) {
      acik.push({ ...bekleyen.shift(), acilis: g }); uretilen++;
    }
    for (const o of acik) if (o.kalan > 0) o.kalan--;
  }
  for (const o of acik) {                           // pencere sonunda hala acik olanlar
    gunToplam += GUN - o.acilis;
    if (GUN - o.acilis - (o.kullanim - o.kalan) >= UNUT) unutulan++;
  }
  return { gunToplam, uretilen, yeniden, kayip, unutulan, teslimsiz: bekleyen.length };
};

console.log("omur   ortam-gun  uretilen  yeniden kurma  veri kaybi  unutulan  teslimsiz");
for (const s of [1, 2, 3, 5, 7, 14, 90]) {
  const r = tara(s);
  console.log(`${(s === 90 ? "yok" : s + " gun").padEnd(7)}${String(r.gunToplam).padStart(6)}` +
    `${String(r.uretilen).padStart(10)}${String(r.yeniden).padStart(15)}` +
    `${String(r.kayip).padStart(12)}${String(r.unutulan).padStart(10)}${String(r.teslimsiz).padStart(11)}`);
}

const fayda = Object.fromEntries(EKIP.map((e) =>               // ekip basina kurtulan insan-saat
  [e, ic.filter((t) => t.ekip === e).length * ELLE_SAAT]));
const bedel = KURULUM + ISLETME_AY * AY;
let k = 0, esik = 0;
const yigin = EKIP.map((e) => { k += fayda[e]; if (k >= bedel && !esik) esik = EKIP.indexOf(e) + 1;
  return `${e} ${fayda[e]} (${k})`; });
console.log(`\nplatform bedeli ${bedel} insan-saat (kurulum ${KURULUM} + ${AY} ay isletme)` +
  `   bes ekibin toplam kazanci ${k} insan-saat`);
console.log(`ekip basina kurtulan (yigisik): ${yigin.join("  ")}`);
console.log(`esik ${esik ? esik + ". ekipte asiliyor" : "bu donemde asilmiyor"}` +
  `; katki veren ekip ${EKIP.filter((e) => fayda[e] > 0).length}/${EKIP.length}`);
omur   ortam-gun  uretilen  yeniden kurma  veri kaybi  unutulan  teslimsiz
1 gun     314       314            251         113         0          0
2 gun     322       175            112          50         0          0
3 gun     331       127             64          27         0          0
5 gun     343        90             27          12         0          0
7 gun     355        76             13           8         0          0
14 gun    425        63              0           0        10          0
yok       877        60              0           0        12          3

platform bedeli 344 insan-saat (kurulum 320 + 3 ay isletme)   bes ekibin toplam kazanci 378 insan-saat
ekip basina kurtulan (yigisik): sayac-okuma 174 (174)  dogrulama 78 (252)  faturalama 90 (342)  saha 0 (342)  raporlama 36 (378)
esik 5. ekipte asiliyor; katki veren ekip 4/5

Tarama iki eğrinin farklı hızda gittiğini gösterir. Ömür sınırı yokken 877 ortam-gün harcanır; sınır on dört güne çekildiğinde bu sayı 425’e, yani yarısının altına iner ve karşılığında hiçbir yeniden kurma doğmaz. Buradan sonrası aynı ucuz değildir: on dört günden yedi güne inmek maliyeti yalnızca 425’ten 355’e çeker, ama 13 yeniden kurma ve 8 veri kaybı olayı üretir. Bir güne inmek maliyeti 314’e indirir — yedi güne göre yüzde on iki kazanç — ve karşılığında 251 yeniden kurma ile 113 veri kaybı doğurur. Maliyet eğrisi düzleşirken yeniden kurma eğrisi dikleşir.

Sınırın görülmeyen bir yararı da vardır. Ömür sınırı yokken 3 talep hiç karşılanamaz, çünkü unutulan ortamlar havuzu doldurur; sınır konduğu anda teslimsiz talep sıfırlanır. Kullanılmayan ortamın maliyeti yalnız hesapta değil, başka ekiplerin beklemesinde ödenir.

Gizlenen Katmanın Bedeli

Ölçü Talep kuyruğu İstek üzerine Altın yol dışında
ortalama bekleme 83,2 saat 10,1 saat 6,0 saat
teslim / teslimsiz 83 / 7 60 / 3 27 / 0
ortam-gün 3.528 877 1.212
boşta ortam-günü 3.133 (%89) 580 (%66) 1.090 (%90)
unutulan ortam 73 12 22
ortam başına insan emeği 6 saat 0 saat 6 saat

Gizlenen katman ortamın kurulum adımlarıdır ve kazanç 336 insan-saattir: kuyruk yolunda 498 saat harcanan iş, platform yolunda 162 saate iner. Eşik de aynı hesaptan çıkar. Platformun bir çeyrekteki bedeli 344 insan-saat, beş ekibin toplam kazancı 378 insan-saattir; eşik ancak beşinci ekipte aşılır ve o eşiği aşan ekip yıllık talebi en düşük olan raporlama ekibidir. Üç ekiple aynı platform kendini ödemez. Sayı tek yöne bakmaz: aynı model, az sayıda ekibin çalıştığı bir ağda platformun kurulmaması gerektiğini de söyler.

Soyutlama iki noktada sızar. Birincisi havuzdur: 90 günün 16’sında havuz doludur ve o günlerde bekleme kuyruk yolundaki gibi geri gelir — ekip istediği anda ortam alacağını sanır, gerçekte alt katmanın kapasitesine çarpar. İkincisi ömür sınırıdır: ortamın kalıcı olmadığı bilgisi ekibe ancak veri kaybı olayında görünür, ve o bilgi belge okuyarak değil, çalışma kaybederek öğrenilir.

Dışına çıkanlar tek bir gerekçeyle çıkar. Alan donanımlı ortam isteyen 27 talebin tamamı saha ekibindendir ve bu ekip platform hizmetinin hiçbirinden yararlanmaz: ortamını kendi kurar, ömür sınırı işlemez, ortam-gününün yüzde 90’ı boşta durur ve 22 ortamı unutulur. Kısmi yararlanma yoktur; bir talebin biçimi sunulan iki biçime oturmuyorsa o talep bütün yaşam döngüsünü platformun dışında geçirir.

Özet

  • Aynı 90 talep kuyruk yolunda ortalama 83,2 saat, istek üzerine yolda 10,1 saat bekledi; kuyruk yolunda 7 talep pencere kapanana kadar hiç karşılanmadı.
  • Bekleme boşta duran kaynağı üretti: kuyruk yolunda 3.528 ortam-gününün %89’u kullanılmadı ve 83 ortamın 73’ü unutulan ortama dönüştü.
  • Ömür sınırı 14 güne çekilince maliyet 877 ortam-gününden 425’e indi ve hiç yeniden kurma doğmadı; 1 güne çekilince maliyet yalnız 314’e indi ama 251 yeniden kurma ve 113 veri kaybı olayı çıktı.
  • Ömür sınırı havuzu da boşalttı: sınırsız yolda karşılanamayan 3 talep, sınır konduğunda sıfırlandı.
  • Platformun çeyreklik bedeli 344 insan-saat, beş ekibin kazancı 378 insan-saat; eşik ancak beşinci ekipte aşıldı ve saha ekibi bu kazanca hiç katkı vermedi.
  • Soyutlama iki yerden sızdı: 90 günün 16’sında havuz doldu ve bekleme geri geldi; ömür sınırının varlığı ekibe ancak veri kaybıyla göründü.

Sonraki Adım

Ortam artık istendiği anda var oluyor, ama içine konacak şey hâlâ elle yazılıyor. Ölçüm ağına altıncı bir servis eklenmesi gerektiğinde ekip boş bir dizinle başlıyor ve kütük biçiminden sağlık ucuna, derleme adımından ölçüt yayınına kadar her kararı yeniden veriyor — üstelik beş ekip bu kararları birbirinden habersiz veriyor. Bir sonraki ders yeni servis başlatma akışını ele alır: gerçek dosyalar üretilir, elle yazılanla üretilen karşılaştırılır, ve üretimden sonra şablon güncellendiğinde kaç servisin geride kaldığı sayılır.

İ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