---
title: 'Sunucusuz ve Kenar Bilişim'
source: 'https://academia.sh/tr/kurslar/sunucusuz'
language: tr
updated: '2026-08-17T04:39:02+00:00'
license: 'CC BY-SA 4.0'
lessons: 20
outcomes:
    - 'İşlev tabanlı hesaplamanın sınırlarını sayıyla verir'
    - 'Olay güdümlü yönetilen servislerle eşzamansız tümleştirme kurar'
    - 'Kenar çalışma zamanının kısıtlarını tasarım kararına çevirir'
---

# Sunucusuz ve Kenar Bilişim

Sürekli çalışan sunucunun da devredilmesi: kapasite yönetiminin bırakılması, eşzamanlı, eşzamansız ve akış tabanlı çağırma modelleri, soğuk başlangıcın gecikme kaynağı ve azaltma yolları, tasarımı kısıtlayan kaynak ve süre eşikleri, sürümleme ve takma adlarla aşamalı yayın, paylaşılan katmanlarla paket boyutu yönetimi, sunucusuzun uygun olmadığı durumlar, olay veri yolu, kuyruk ve konu servisleri, adım tabanlı iş akışı orkestrasyonu, zamanlanmış tetikleme, uç nokta yönetimi, bildirim servisleri, kenar çalışma zamanı modeli, kenarda istek işleme, kenar depolama, dayanıklı durum nesneleri, kenar kuyrukları, bildirimsel bağlamalar ve kenar sınırları.

## İşlev Tabanlı Hesaplama

Kapasite yönetiminin devredilmesi: eşzamanlı, eşzamansız ve akış tabanlı çağırma modellerinin gecikme ve yeniden deneme farkı, soğuk başlangıcın nereden geldiği ve azaltma yollarının bedeli, bellek, süre ve eşzamanlılık eşiklerinin tasarımı kısıtlaması, sürümleme ve takma adlarla aşamalı yayın, paylaşılan katmanlarla paket boyutu yönetimi ve sunucusuzun uzun süren, durum yoğun işlerde neden uygun olmadığı.

### Sunucusuz Kavramı

Source: https://academia.sh/tr/kurslar/sunucusuz/sunucusuz-kavrami

Aynı günün iş yükü iki düzende koşturulur: sürekli çalışan örnek ile isteğe göre çağrılan işlev; boşta geçen kapasite, tepe anında karşılanan istek ve gece işinin bittiği saat yan yana sayılır, taban yük sıfırdan altmış beş bine taranarak başabaş yük düzeyi çıkarılır ve devredilen on karar ile karşılığında gelen sekiz sayılı kısıt tek defterde toplanır.

Önceki kurs makineyi, ağı ve veriyi tek tek kiraladı. Her kiralamada aynı şey oldu: bir karar
sağlayıcıya geçti, karşılığında bir kısıt geldi. Ama üç kursun sonunda bile altta duran şey
değişmedi — kiralanan kapasite **sürekli çalışan bir sunucudur** ve iş gelmediği saatlerde de
sayaç işler. Bu kursun sorusu odur: kapasitenin kendisi de isteğe göre kiralanabilir mi.

Ölçü tek eksende ilerler: aynı gün, aynı iş yükü, iki düzen. Birincide örnek sayısına karar veren
taraf elde kalır, ikincide o karar sağlayıcıdadır. Fark yalnız faturada değildir — boşta duran
kapasite, tepede karşılanan istek ve gece işinin bittiği saat de değişir.

**IH1.** Bölgesel ölçüm ağı, su sayaçlarından okuma toplayan, okumaları doğrulayan, fatura üreten
ve saha ekiplerine bildirim gönderen **kurgu** bir yazılımdır; bütün süreler, sayılar ve fiyatlar
kurgudur. **IH2.** Bir okuma doğrulaması 400 ms tutar; sürekli çalışan bir örnek aynı anda dört
doğrulama taşır: dakikada 600 istek. **IH3.** Fiyatlar kurgu bir ölçüyle — **birim** —
yazılır ve gerçek para birimi değildir: örnek-dakika 0,6 birim, işlev çağrısı 0,0005 birim, 400 ms
işlem 0,001 birim. **IH4.** Günün trafiği kendi yazılan bir üreteçle kurulur ve tohum
20260802'dir. **IH5.** Sürekli düzende örnek sayısı gün boyu sabittir; kapasiteyi aşan istek
düşmez, kuyrukta bekler. **IH6.** İşlev düzeninde her istek geldiği dakikada çalışır ve hesap
düzeyindeki eşzamanlılık sınırı 200'dür.

#### Aynı Günün İki Düzeni

Ölçüm ağının günü düz değildir: okumalar gece toplu işlenir, fatura sabaha karşı üretilir,
doğrulama trafiği gündüz akar, saha bildirimi hiç durmaz. Aşağıdaki model günü dakika dakika kurar.

```js
// olcum-agi/iki-duzen.mjs — ayni gunun yuku iki duzende: surekli ornek ve istege gore islev (model)

// Butun birimler kurgudur; "birim" hayali bir olcu, gercek para degildir.
export const DK = 1440, ISLEM_MS = 400, ESZAMAN = 4;
export const ORNEK_KAP = 60000 * ESZAMAN / ISLEM_MS;      // bir ornek dakikada 600 istek
export const ORNEK_DK = 0.6, CAGRI = 0.0005, SURE = 0.001; // birim
export const ISTEK_BIRIM = CAGRI + SURE;

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; }; };

// Bolgesel olcum aginin kurgu gunu: gece toplu okuma islemesi, sabah fatura, gunduz dogrulama.
export const trafik = (taban = 0, tohum = 20260802) => {
  const r = uretec(tohum), y = new Array(DK).fill(0);
  for (let d = 0; d < DK; d++) {
    let v = taban + 60;                                        // saha bildirimi: her dakika akar
    if (d >= 360 && d < 1320) v += 700 * (0.75 + 0.5 * r());   // okuma dogrulama trafigi
    if (d >= 120 && d < 145) v += 22000;                       // gece toplu okuma islemesi
    if (d >= 300 && d < 310) v += 6000;                        // fatura uretimi
    y[d] = Math.round(v);
  }
  return y;
};

export const saat = (d) => `${String(Math.floor(d / 60)).padStart(2, "0")}:${String(d % 60).padStart(2, "0")}`;

// Surekli duzen: ornek sayisi gun boyu sabit; asan istek kuyrukta bekler.
export const surekli = (y, ornek) => {
  const kap = ornek * ORNEK_KAP;
  let kuyruk = 0, enUzun = 0, bitis = -1;
  for (let d = 0; d < DK; d++) {
    kuyruk += y[d] - Math.min(kuyruk + y[d], kap);
    if (kuyruk > enUzun) enUzun = kuyruk;
    if (d >= 145 && kuyruk === 0 && bitis < 0) bitis = d;
  }
  const toplam = y.reduce((a, b) => a + b, 0);
  return { ad: `surekli ${ornek} ornek`, maliyet: ornek * DK * ORNEK_DK,
    yuva: ornek * DK * ORNEK_KAP, kullanim: toplam / (ornek * DK * ORNEK_KAP),
    tepede: Math.min(Math.max(...y), kap), enUzun, devreden: kuyruk, bitis };
};

// Islev duzeni: kapasite karari devredildi; her istek geldigi dakikada calisir.
export const islev = (y) => {
  const toplam = y.reduce((a, b) => a + b, 0), tepe = Math.max(...y);
  return { ad: "islev", maliyet: toplam * ISTEK_BIRIM, yuva: toplam, kullanim: 1,
    tepede: tepe, enUzun: 0, devreden: 0, bitis: 144,
    eszaman: Math.ceil(tepe * (ISLEM_MS / 1000) / 60) };
};

if (import.meta.url === `file://${process.argv[1]}`) {
  const y = trafik(), toplam = y.reduce((a, b) => a + b, 0), tepe = Math.max(...y);
  console.log(`gun: ${toplam} istek, tepe ${tepe} istek/dk, ortalama ${Math.round(toplam / DK)} istek/dk, ` +
    `tepe/ortalama ${(tepe / (toplam / DK)).toFixed(1)}`);
  const duzenler = [surekli(y, Math.ceil(tepe / ORNEK_KAP)), surekli(y, 12), surekli(y, 2), islev(y)];
  console.log("\n" + "duzen".padEnd(20) + "maliyet".padEnd(11) + "bosta yuva".padEnd(13) +
    "bosta oran".padEnd(12) + "tepede karsilanan".padEnd(19) + "en uzun kuyruk".padEnd(16) + "gece isi biter");
  for (const d of duzenler)
    console.log(d.ad.padEnd(20) + d.maliyet.toFixed(0).padEnd(11) +
      (d.yuva - toplam).toFixed(0).padEnd(13) +
      `%${((1 - d.kullanim) * 100).toFixed(1)}`.padEnd(12) +
      `${d.tepede}/${tepe}`.padEnd(19) + d.enUzun.toFixed(0).padEnd(16) +
      (d.bitis < 0 ? `bitmiyor (${d.devreden} devreden)` : saat(d.bitis + 1)));
  const t = duzenler[0], i = duzenler[3];
  console.log(`\ntepeye gore boyutlandirma islevden ${(t.maliyet / i.maliyet).toFixed(1)} kat pahali; ` +
    `islev duzeninde tepede gereken eszamanlilik ${i.eszaman}`);
}
```

```
gun: 1370625 istek, tepe 22060 istek/dk, ortalama 952 istek/dk, tepe/ortalama 23.2

duzen               maliyet    bosta yuva   bosta oran  tepede karsilanan  en uzun kuyruk  gece isi biter
surekli 37 ornek    31968      30597375     %95.7       22060/22060        0               02:26
surekli 12 ornek    10368      8997375      %86.8       7200/22060         371500          03:18
surekli 2 ornek     1728       357375       %20.7       1200/22060         521500          18:48
islev               2056       0            %0.0        22060/22060        0               02:25

tepeye gore boyutlandirma islevden 15.5 kat pahali; islev duzeninde tepede gereken eszamanlilik 148
```

Sürekli düzenin üç satırı üç ayrı kötü seçenektir. Tepeye göre boyutlandırma her isteği zamanında
karşılar ve karşılığında günün **%95,7'sinde boş duran** 30,6 milyon istek yuvası ödetir; 37 örnek
gün boyu ayaktadır, oysa yirmi beş dakika dışında ikisi yeterlidir. Ortalamaya göre boyutlandırma
faturayı 31.968 birimden 1.728 birime indirir — ama gece 02:25'te başlayan toplu işleme akşam
**18:48'de** biter ve gün boyunca 521.500 kayıt kuyrukta bekler. Aradaki 12 örnek uzlaşmadır:
maliyet 10.368, gece işi 03:18'de biter, boşta oran hâlâ %86,8'dir.

İşlev satırı üçünün hiçbirine benzemez. Boşta yuva sıfırdır, çünkü boşta duran bir şey yoktur;
tepedeki 22.060 isteğin hepsi karşılanır ve gece işi geldiği dakikada — 02:25'te — biter. Fatura
tepeye göre boyutlandırmanın **on beşte biridir**. Fark bir verimlilik hilesi değil, ölçünün yer
değiştirmesidir: orada ayakta durma süresi ücretlendirilir, burada yapılan iş.

Son satır kısıtın ilk sayısını verir: tepede 148 eşzamanlı çağrı gerekir, hesap sınırı 200'dür.
Örnek sayısına karar verilmez, ama 200 verilmiş bir tavandır ve trafik %35 artsa tepe ona dayanır.

#### Yük Profili Taraması

Yukarıdaki gün seyrek ve anidir: tepe, ortalamanın 23,2 katıdır. Böyle bir profilde işlevin
kazanması şaşırtıcı değildir. Asıl soru profil düzleştikçe ne olduğudur. Aşağıdaki tarama günün
üzerine sürekli bir taban yük ekler ve iki düzeni her düzeyde yeniden fiyatlandırır.

```js
// olcum-agi/yuk-taramasi.mjs — surekli taban yuk artarken basabas noktasi nerede (model)
import { DK, ORNEK_KAP, ORNEK_DK, ISTEK_BIRIM, trafik, surekli, islev } from "./iki-duzen.mjs";

export const nokta = (taban) => {
  const y = trafik(taban), toplam = y.reduce((a, b) => a + b, 0), tepe = Math.max(...y);
  const ornek = Math.ceil(tepe / ORNEK_KAP), s = surekli(y, ornek), i = islev(y);
  return { taban, tepe, ortalama: toplam / DK, oran: tepe / (toplam / DK), ornek,
    kullanim: s.kullanim, s: s.maliyet, i: i.maliyet };
};

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log("taban yuk".padEnd(12) + "tepe/ortalama".padEnd(15) + "ornek".padEnd(8) +
    "kullanim".padEnd(11) + "surekli".padEnd(10) + "islev".padEnd(10) + "islev/surekli".padEnd(15) + "kazanan");
  for (const t of [0, 2000, 5000, 10000, 20000, 30000, 40000, 50000, 65000]) {
    const n = nokta(t);
    console.log(`${t}`.padEnd(12) + n.oran.toFixed(1).padEnd(15) + String(n.ornek).padEnd(8) +
      `%${(n.kullanim * 100).toFixed(1)}`.padEnd(11) + n.s.toFixed(0).padEnd(10) +
      n.i.toFixed(0).padEnd(10) + (n.i / n.s).toFixed(2).padEnd(15) + (n.i < n.s ? "islev" : "surekli"));
  }
  let a = 0, b = 65000;
  for (let k = 0; k < 24; k++) { const o = (a + b) / 2; (nokta(Math.round(o)).i < nokta(Math.round(o)).s) ? a = o : b = o; }
  const bb = nokta(Math.round(a));
  console.log(`\nbasabas taban yuk: ${Math.round(a)} istek/dk — bu noktada tepe/ortalama ${bb.oran.toFixed(2)}, ` +
    `kullanim %${(bb.kullanim * 100).toFixed(1)}`);
  console.log(`kuramsal esik: bir ornegin istek basina bedeli ${(ORNEK_DK / ORNEK_KAP).toFixed(6)} birim, ` +
    `islevin ${ISTEK_BIRIM.toFixed(6)} birim — orani %${((ORNEK_DK / ORNEK_KAP) / ISTEK_BIRIM * 100).toFixed(1)}`);
}
```

```
taban yuk   tepe/ortalama  ornek   kullanim   surekli   islev     islev/surekli  kazanan
0           23.2           37      %4.3       31968     2056      0.06           islev
2000        8.2            41      %12.0      35424     6376      0.18           islev
5000        4.5            46      %21.6      39744     12856     0.32           islev
10000       2.9            54      %33.8      46656     23656     0.51           islev
20000       2.0            71      %49.2      61344     45256     0.74           islev
30000       1.7            87      %59.3      75168     66856     0.89           islev
40000       1.5            104     %65.6      89856     88456     0.98           islev
50000       1.4            121     %70.2      104544    110056    1.05           surekli
65000       1.3            146     %75.3      126144    142456    1.13           surekli

basabas taban yuk: 42248 istek/dk — bu noktada tepe/ortalama 1.49, kullanim %66.7
kuramsal esik: bir ornegin istek basina bedeli 0.001000 birim, islevin 0.001500 birim — orani %66.7
```

Tarama tek bir kural gösterir: işlevin kazanması trafiğin **büyüklüğüne** değil **biçimine**
bağlıdır. Taban yük sıfırken işlev on altı kat ucuzdur, 42.248 istek/dk'da iki düzen eşitlenir,
ötesinde sürekli düzen kazanır. Başabaş kullanım oranı %66,7'dir ve rastgele değildir — son satır
aynı oranı fiyattan türetir: bir örnek istek başına 0,001, işlev 0,0015 birim tutar.

Kural bir tercihe değil bir ölçüme dayanır: **kapasitenin üçte ikisi sürekli dolu değilse**
kapasiteyi kendi yönetmek pahalıdır. Tepe/ortalama sütunu aynı sınırı ikinci bir açıdan verir;
oran 1,5'in altına indiğinde işlevin üstünlüğü biter.

#### Devredilen Kararın Defteri

Fatura tablonun yalnız bir sütunudur. Asıl değişen, kararların kimde durduğudur.

```js
// olcum-agi/karar-defteri.mjs — hangi karar devredildi, karsiliginda hangi sayi geldi (model)
import { ISLEM_MS, ORNEK_DK, trafik, islev } from "./iki-duzen.mjs";

// [karar, surekli duzende, islev duzeninde, gelen kisit (kurgu sayi)]
export const KARAR = [
  ["ornek sayisi", "sende", "saglayicida", "eszamanlilik siniri 200"],
  ["olcekleme esigi", "sende", "saglayicida", "olcekleme adimi 60 ornek/dk"],
  ["makine boyutu", "sende", "saglayicida", "bellek kademesi 128-3008"],
  ["bir isin ust suresi", "sende", "saglayicida", "sure siniri 900 sn"],
  ["yerel disk", "sende", "saglayicida", "gecici alan 512 birim"],
  ["paket icerigi", "sende", "kismen sende", "paket boyutu 250 birim"],
  ["calisma zamani surumu", "sende", "kismen sende", "destek penceresi 24 ay"],
  ["isletim sistemi yamasi", "sende", "saglayicida", "yama takvimi gorunmez"],
  ["yerlestirme", "sende", "saglayicida", "bolge secilir, makine secilmez"],
  ["ornegin ne kadar yasayacagi", "sende", "saglayicida", "bosta 300 sn sonra geri alinir"],
  ["istek basina fiyat", "saglayicida", "saglayicida", "—"],
];

// [kisit, kisitin etrafindan dolasma yolu]
export const DOLASMA = [["sure siniri 900 sn", "isi parcala"],
  ["eszamanlilik siniri 200", "pay rezerve et"],
  ["bosta 300 sn sonra geri alinir", "onceden isit"],
  ["gecici alan 512 birim", "durumu disari al"]];

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log("karar".padEnd(30) + "surekli duzen".padEnd(16) + "islev duzeni".padEnd(16) + "karsiligindaki kisit");
  for (const [a, s, i, k] of KARAR) console.log(a.padEnd(30) + s.padEnd(16) + i.padEnd(16) + k);
  const say = (j) => KARAR.filter((x) => x[j].includes("sende")).length;
  const sayili = KARAR.filter((x) => x[2] !== "sende" && /\d/.test(x[3])).length;
  console.log(`\nsurekli duzende ${say(1)} karar elde, islev duzeninde ${say(2)} karar tam ya da kismen elde; ` +
    `${say(1) - say(2)} karar bastan devredildi, ${sayili} kisit bir sayiyla geri geldi`);

  const y = trafik(), gece = y.slice(120, 145).reduce((a, b) => a + b, 0);
  const tek = gece * (ISLEM_MS / 1000), isit = 8, bosta = isit * 1440, ez = islev(y).eszaman;
  const BEDEL = [
    `${gece} kayitlik gece isi tek parcada ${Math.round(tek)} sn; sinira sigmasi icin ${Math.ceil(tek / 900)} cagri`,
    `tepede gereken ${ez} rezerve edilirse otekilere ${200 - ez} eszamanlilik kalir`,
    `${isit} ornek surekli sicak tutulursa gunde ${bosta} bosta ornek-dakika, ${(bosta * ORNEK_DK).toFixed(0)} birim`,
    `her cagri durumu disaridan okur: ${y.reduce((a, b) => a + b, 0)} ek okuma-yazma cifti`];
  console.log("\n" + "kisit".padEnd(32) + "dolasma yolu".padEnd(20) + "bedeli");
  DOLASMA.forEach(([k, yol], j) => console.log(k.padEnd(32) + yol.padEnd(20) + BEDEL[j]));
}
```

```
karar                         surekli duzen   islev duzeni    karsiligindaki kisit
ornek sayisi                  sende           saglayicida     eszamanlilik siniri 200
olcekleme esigi               sende           saglayicida     olcekleme adimi 60 ornek/dk
makine boyutu                 sende           saglayicida     bellek kademesi 128-3008
bir isin ust suresi           sende           saglayicida     sure siniri 900 sn
yerel disk                    sende           saglayicida     gecici alan 512 birim
paket icerigi                 sende           kismen sende    paket boyutu 250 birim
calisma zamani surumu         sende           kismen sende    destek penceresi 24 ay
isletim sistemi yamasi        sende           saglayicida     yama takvimi gorunmez
yerlestirme                   sende           saglayicida     bolge secilir, makine secilmez
ornegin ne kadar yasayacagi   sende           saglayicida     bosta 300 sn sonra geri alinir
istek basina fiyat            saglayicida     saglayicida     —

surekli duzende 10 karar elde, islev duzeninde 2 karar tam ya da kismen elde; 8 karar bastan devredildi, 8 kisit bir sayiyla geri geldi

kisit                           dolasma yolu        bedeli
sure siniri 900 sn              isi parcala         551500 kayitlik gece isi tek parcada 220600 sn; sinira sigmasi icin 246 cagri
eszamanlilik siniri 200         pay rezerve et      tepede gereken 148 rezerve edilirse otekilere 52 eszamanlilik kalir
bosta 300 sn sonra geri alinir  onceden isit        8 ornek surekli sicak tutulursa gunde 11520 bosta ornek-dakika, 6912 birim
gecici alan 512 birim           durumu disari al    her cagri durumu disaridan okur: 1370625 ek okuma-yazma cifti
```

On bir kararın onu sürekli düzende eldedir; işlev düzeninde elde kalan iki tanedir ve ikisi de
yalnız kısmen — paketin içeriği paket boyutu sınırına, çalışma zamanının sürümü destek penceresine
takılır. Sekiz karar baştan devredilir ve **sekizi de bir sayıyla geri döner**. Devretmek kararı
ortadan kaldırmaz; kararı bir tavana çevirir.

Alt tablo o tavanların etrafından dolaşma yollarını fiyatlandırır. Gece toplu işi tek parçada
220.600 saniye tutar; 900 saniyelik sınıra sığması için **246 ayrı çağrıya** bölünmesi gerekir ve
246 çağrı, tek işin sürdürmediği bir ilerleme kaydı ile kısmi başarı sorusu demektir. Tepedeki 148
eşzamanlılık rezerve edilirse ölçüm ağının öteki bütün işlevlerine 52 kalır: bir işlevi korumak
ötekileri aç bırakır. Sekiz örneği sürekli sıcak tutmak günde 11.520 boşta örnek-dakika, yani
6.912 birim eder — kaçınılan boşta kapasitenin küçük ölçekte geri alınması.

Dört satırın ortak biçimi şudur: kısıt bir sayıdır, dolaşma yolu vardır ve **dolaşmanın bedeli
kısıtın ölçüldüğü birimde değildir**. Süre sınırından çağrı sayısına, eşzamanlılık sınırından öteki
işlevlerin payına, örnek ömründen boşta kapasiteye geçilir; her kısıt kendi cinsinden ödenir.

#### Özet

- Tepeye göre boyutlandırılmış sürekli düzen 31.968 birim ve %95,7 boşta kapasite, işlev düzeni
  2.056 birim ve sıfır boşta kapasite ödetti — on beş kat fark.
- Ucuzlatmak için örnek sayısını 2'ye indirmek faturayı 1.728 birime çekti ama 02:25'te başlayan
  gece işini 18:48'e taşıdı ve 521.500 kaydı kuyrukta bıraktı; ucuzluk gecikmeyle ödendi.
- Taban yük taraması başabaş noktasını 42.248 istek/dk'da buldu: kullanım %66,7 ve tepe/ortalama
  1,49. Kapasitenin üçte ikisi sürekli dolu değilse kapasiteyi kendi yönetmek pahalıdır.
- On bir kararın onu sürekli düzende elde, işlev düzeninde yalnız ikisi kısmen elde kaldı; sekiz
  devredilen kararın sekizi de sayılı bir kısıt olarak geri geldi.
- Dolaşmanın bedeli hep başka bir birimdedir: süre sınırı 246 çağrıya, örnek ömrü günde 11.520
  boşta örnek-dakikaya, eşzamanlılık sınırı ötekilere kalan 52 paya çevrilir.

#### Sonraki Adım

Bu ders işlevi tek bir biçimde çağırdı: istek geldi, işlev çalıştı, sonuç döndü. Oysa gece toplu
işlemesiyle saha bildirimi aynı yolla çağrılmak zorunda değildir — biri sonucu bekleyen bir
istemcinin ucundadır, öteki bir kuyruğun.

Sonraki ders aynı doğrulama işini üç çağırma modelinde koşturur ve dört şeyi ayrı sayar: çağıranın
gördüğü gecikme, hatanın çağırana görünüp görünmediği, yeniden denemenin kimde olduğu ve aynı
kaydın iki kez işlenme riski. Ardından toplu okuma boyutu taranır: boy büyüdükçe verim artarken tek
bozuk kaydın kaç sağlam kaydı birlikte durdurduğu ölçülür.

### İşlev Çağırma Modelleri

Source: https://academia.sh/tr/kurslar/sunucusuz/islev-cagirma-modelleri

Aynı doğrulama işi üç çağırma modelinde koşturulur ve dört şey ayrı ayrı sayılır: çağıranın gördüğü gecikme, hatayı kimin gördüğü, yeniden denemenin kimde olduğu ve yinelenen işleme oranı; ardından akış tabanlı modelde toplu okuma boyu birden iki bin beş yüze taranarak çağrı sayısı, fazladan işleme, ölü mektup kutusuna eş düşen sağlam kayıt ve süre sınırına sığmayan toplu iş çıkarılır.

Önceki ders işlevi tek bir biçimde çağırdı: istek geldi, işlev çalıştı, sonuç döndü. Ama ağın işleri aynı ucun üzerinde durmaz: saha ekibine giden bildirimin yanıtını kimse beklemez;
gece toplu işlemesi bir sıradan okunur; geçit üzerinden gelen doğrulama isteği bir istemcinin
ucundadır.

Çağırma modeli dört ayrı sayının aynı anda değiştiği bir seçimdir: gecikme, hatayı kimin gördüğü,
yeniden denemenin kimde olduğu ve aynı kaydın kaç kez işlendiği. Bu ders dördünü de sayar.

**IH7.** Bölgesel ölçüm ağının — **kurgu** bir yazılımın — gece toplu işlemesine giren 20.000 sayaç
okuması ölçülür; kayıt sınıfları kendi yazılan bir üreteçle dağıtılır, tohum 20260803'tür. **IH8.** Bir doğrulama 400 ms, çağrı başına
sabit yük 250 ms, eşzamansız kabul yanıtı 5 ms tutar. **IH9.** Geçici hata ikinci denemede geçer,
zehirli kayıt hiç geçmez. **IH10.** Eşzamanlı modelde çağıran bir kez yeniden dener;
eşzamansız ve akış tabanlı modelde yeniden denemeyi altyapı üstlenir, üç deneme ve 60 saniye ara
ile. **IH11.** Akış tabanlı modelde toplu iş bölünmez: tek kayıt hata verirse toplu işin tamamı
yeniden okunur, üçüncü denemeden sonra tamamı ölü mektup kutusuna gider; kayıtlar saniyede 250
varır. **IH12.** Fiyatlar kurgu birimle yazılır (çağrı başına 0,0005, işlem milisaniyesi başına
0,0000025) ve süre sınırı 900 saniyedir.

#### Aynı İş, Üç Çağırma Yolu

```js
// olcum-agi/cagirma-modelleri.mjs — ayni dogrulama isi uc cagirma modelinde (model)

// Kurgu sayilar: bir okuma dogrulamasi 400 ms, cagri basina sabit yuk 250 ms, kabul yaniti 5 ms.
export const N = 20000, ISLEM = 400, SABIT = 250, KABUL = 5, BEKLE = 60000;
export const CAGRI_B = 0.0005, MS_B = 0.0000025;   // kurgu birim: cagri basina ve ms basina

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; }; };

// Gece toplu islemesine giren 20000 sayac okumasi: cogu temiz, kimi gecici hatali, kimi zehirli.
export const kayitlar = (tohum = 20260803) => {
  const r = uretec(tohum);
  return Array.from({ length: N }, () => { const v = r();
    return v < 0.001 ? "zehirli" : v < 0.021 ? "gecici" : "temiz"; });
};

const yuzde = (a, p) => [...a].sort((x, y) => x - y)[Math.floor(a.length * p)];
const ort = (a) => a.reduce((x, y) => x + y, 0) / a.length;

// Eszamanli: cagiran yaniti bekler, hatayi gorur, yeniden denemeyi kendi yapar.
export const eszamanli = (k) => {
  let cagri = 0, yeniden = 0; const bitis = [];
  for (const d of k) {
    const deneme = d === "temiz" ? 1 : 2;
    cagri += deneme; yeniden += deneme - 1;
    bitis.push(deneme * (SABIT + ISLEM) + (deneme - 1) * 200);
  }
  return { ad: "eszamanli", bitis, cagri, yeniden, islenen: cagri, sure: cagri * (SABIT + ISLEM),
    oluMektup: 0, esDusen: 0, hataGoren: "cagiran", denemeKimde: "cagiran" };
};

// Eszamansiz: cagiran kabul yanitini alip cikar; yeniden denemeyi altyapi yapar.
export const eszamansiz = (k) => {
  let cagri = 0, yeniden = 0, olu = 0; const bitis = [];
  for (const d of k) {
    const deneme = d === "temiz" ? 1 : d === "gecici" ? 2 : 3;
    cagri += deneme; yeniden += deneme - 1;
    bitis.push(deneme * (SABIT + ISLEM) + (deneme - 1) * BEKLE);
    if (d === "zehirli") olu++;
  }
  return { ad: "eszamansiz", bek: KABUL, bitis, cagri, yeniden, islenen: cagri,
    sure: cagri * (SABIT + ISLEM), oluMektup: olu, esDusen: 0,
    hataGoren: "hic kimse", denemeKimde: "altyapi" };
};

// Akis tabanli: kayitlar sirali okunur, toplu is tek cagridir, tek hata butun toplu isi tekrarlatir.
export const akis = (k, boy, varis = 250) => {
  let cagri = 0, islenen = 0, olu = 0, esDusen = 0; const bitis = [];
  for (let i = 0; i < k.length; i += boy) {
    const t = k.slice(i, i + boy);
    const zehirli = t.filter((d) => d === "zehirli").length;
    const deneme = zehirli ? 3 : t.some((d) => d === "gecici") ? 2 : 1;
    const sure = deneme * (SABIT + t.length * ISLEM) + (deneme - 1) * BEKLE;
    cagri += deneme; islenen += deneme * t.length;
    if (zehirli) { olu += t.length; esDusen += t.length - zehirli; }
    for (let j = 0; j < t.length; j++) bitis.push(t.length / varis * 1000 + sure);
  }
  return { ad: `akis tabanli (boy ${boy})`, bek: KABUL, bitis, cagri, islenen,
    yeniden: islenen - N, sure: cagri * SABIT + islenen * ISLEM,
    oluMektup: olu, esDusen, hataGoren: "hic kimse", denemeKimde: "altyapi" };
};

export const olc = (m) => ({ ...m, bekOrt: m.bek ?? ort(m.bitis), bitOrt: ort(m.bitis),
  bit99: yuzde(m.bitis, 0.99), maliyet: m.cagri * CAGRI_B + m.sure * MS_B });

if (import.meta.url === `file://${process.argv[1]}`) {
  const k = kayitlar(), say = (d) => k.filter((x) => x === d).length;
  console.log(`${N} kayit: ${say("temiz")} temiz, ${say("gecici")} gecici hatali, ${say("zehirli")} zehirli`);
  const m = [eszamanli(k), eszamansiz(k), akis(k, 100)].map(olc);
  console.log("\n" + "model".padEnd(24) + "cagiranin gordugu".padEnd(19) +
    "is biter (ort)".padEnd(16) + "is biter (99)".padEnd(15) + "islem cagrisi".padEnd(15) +
    "fazladan isleme".padEnd(17) + "olu mektup".padEnd(12) + "maliyet");
  for (const x of m)
    console.log(x.ad.padEnd(24) + `${x.bekOrt.toFixed(0)} ms`.padEnd(19) +
      `${(x.bitOrt / 1000).toFixed(1)} sn`.padEnd(16) + `${(x.bit99 / 1000).toFixed(1)} sn`.padEnd(15) +
      String(x.cagri).padEnd(15) + String(x.yeniden).padEnd(17) + String(x.oluMektup).padEnd(12) +
      x.maliyet.toFixed(2));
  console.log("\n" + "model".padEnd(24) + "hatayi goren".padEnd(15) + "yeniden deneme kimde".padEnd(22) +
    "100 kayda dusen fazladan isleme");
  for (const x of m)
    console.log(x.ad.padEnd(24) + x.hataGoren.padEnd(15) + x.denemeKimde.padEnd(22) +
      (x.yeniden / N * 100).toFixed(1));
  const a = m[2];
  console.log(`\nolu mektup kutusuna dusen ${a.oluMektup} kaydin ${a.esDusen} tanesi saglamdi: ` +
    `zehirli kayit basina ${(a.esDusen / say("zehirli")).toFixed(1)} saglam kayit es dustu`);
}
```

```
20000 kayit: 19551 temiz, 436 gecici hatali, 13 zehirli

model                   cagiranin gordugu  is biter (ort)  is biter (99)  islem cagrisi  fazladan isleme  olu mektup  maliyet
eszamanli               669 ms             0.7 sn          1.5 sn         20449          449              0           43.45
eszamansiz              5 ms               2.1 sn          61.3 sn        20462          462              13          43.48
akis tabanli (boy 100)  5 ms               130.9 sn        241.2 sn       380            18000            1300        38.43

model                   hatayi goren   yeniden deneme kimde  100 kayda dusen fazladan isleme
eszamanli               cagiran        cagiran               2.2
eszamansiz              hic kimse      altyapi               2.3
akis tabanli (boy 100)  hic kimse      altyapi               90.0

olu mektup kutusuna dusen 1300 kaydin 1287 tanesi saglamdi: zehirli kayit basina 99.0 saglam kayit es dustu
```

Birinci tablonun iki sütunu ters yönde hareket eder. Çağıranın gördüğü gecikme 669 ms'den 5 ms'ye
iner: eşzamansız modelde çağıran işin bitmesini değil, kabul edilmesini bekler. Ama işin bittiği an
0,7 saniyeden 2,1 saniyeye, yüzde doksan dokuzuncu dilim 61,3 saniyeye çıkar. Kazanılan gecikme yok
olmaz; **çağıranın göremediği bir yere taşınır.**

İkinci tablo asıl devri gösterir. Eşzamanlı modelde hatayı çağıran görür ve yeniden denemeye o
karar verir; on üç zehirli kaydın on üçü de bildirilir. Öteki iki modelde hatayı **hiç kimse
görmez**: altyapı üç kez dener, kaydı ölü mektup kutusuna bırakır, çağıran çoktan gitmiştir.
Yeniden deneme sorumluluğunu devretmek onu ortadan kaldırmaz, hatanın görünürlüğünü kaldırır.

Son sütun devrin bedelini verir. İlk iki modelde her yüz kayda 2,2 fazladan işleme düşer; akış
tabanlı modelde 90. Neden toplu işin bölünmemesidir: yüz kayıtlık bir toplu işte tek geçici hata
yüz kaydın hepsini yeniden işletir. Aynı bölünmezlik ölü mektup kutusunda da geçerlidir — 1.300
kaydın 1.287'si sağlamdır ve tek suçları zehirli bir kayıtla aynı toplu işe düşmektir.

#### Toplu Okuma Boyutu

Toplu boy tek bir sayıdır ama üç şeyi birden belirler: çağrı sayısını, yeniden işleme miktarını ve
bir kaydın sonucuna ne zaman ulaşıldığını.

```js
// olcum-agi/toplu-tarama.mjs — akis tabanli modelde toplu okuma boyu taranir (model)
import { N, ISLEM, SABIT, kayitlar, akis, olc } from "./cagirma-modelleri.mjs";

export const SINIR = 900;                          // kurgu sure siniri, saniye
export const BOY = [1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500];

if (import.meta.url === `file://${process.argv[1]}`) {
  const k = kayitlar(), zehirli = k.filter((x) => x === "zehirli").length;
  console.log("boy".padEnd(7) + "cagri".padEnd(9) + "islenen kayit".padEnd(15) +
    "fazladan".padEnd(11) + "toplam sure".padEnd(14) + "maliyet".padEnd(10) +
    "kaydin gecikmesi".padEnd(18) + "olu mektup".padEnd(12) + "es dusen".padEnd(10) + "toplu is / sinir");
  const satir = BOY.map((b) => olc(akis(k, b)));
  for (let i = 0; i < BOY.length; i++) {
    const x = satir[i], toplu = (SABIT + BOY[i] * ISLEM) / 1000;
    console.log(String(BOY[i]).padEnd(7) + String(x.cagri).padEnd(9) + String(x.islenen).padEnd(15) +
      `%${(x.yeniden / N * 100).toFixed(0)}`.padEnd(11) + `${(x.sure / 1000).toFixed(0)} sn`.padEnd(14) +
      x.maliyet.toFixed(2).padEnd(10) + `${(x.bitOrt / 1000).toFixed(1)} sn`.padEnd(18) +
      String(x.oluMektup).padEnd(12) + String(x.esDusen).padEnd(10) +
      `${toplu.toFixed(0)}/${SINIR} sn` + (toplu > SINIR ? " — sigmiyor" : ""));
  }
  const ucuz = satir.reduce((a, b) => (b.maliyet < a.maliyet ? b : a));
  const hizli = satir.reduce((a, b) => (b.sure < a.sure ? b : a));
  console.log(`\nen ucuz boy: ${ucuz.ad} — ${ucuz.maliyet.toFixed(2)} birim; ` +
    `en kisa toplam sure: ${hizli.ad} — ${(hizli.sure / 1000).toFixed(0)} sn`);
  const b1 = satir[0], b500 = satir[8];
  console.log(`boy 1'den 500'e: cagri ${b1.cagri} -> ${b500.cagri} (${(b1.cagri / b500.cagri).toFixed(0)} kat az), ` +
    `islenen kayit ${b1.islenen} -> ${b500.islenen} (${(b500.islenen / b1.islenen).toFixed(1)} kat cok)`);
  console.log(`${zehirli} zehirli kayit boy 1'de ${b1.esDusen} saglam kaydi, boy 500'de ${b500.esDusen} ` +
    `saglam kaydi birlikte olu mektup kutusuna dusurdu`);
}
```

```
boy    cagri    islenen kayit  fazladan   toplam sure   maliyet   kaydin gecikmesi  olu mektup  es dusen  toplu is / sinir
1      20462    20462          %2         13300 sn      43.48     2.1 sn            13          0         1/900 sn
2      10456    20912          %5         10979 sn      32.68     3.8 sn            26          13        1/900 sn
5      4440     22200          %11        9990 sn       27.20     9.1 sn            65          52        2/900 sn
10     2420     24200          %21        10285 sn      26.92     17.8 sn           130         117       4/900 sn
25     1166     29150          %46        11952 sn      30.46     42.5 sn           325         312       10/900 sn
50     684      34200          %71        13851 sn      34.97     77.4 sn           650         637       20/900 sn
100    380      38000          %90        15295 sn      38.43     130.9 sn          1300        1287      40/900 sn
250    172      43000          %115       17243 sn      43.19     285.5 sn          3000        2987      100/900 sn
500    91       45500          %127       18223 sn      45.60     534.1 sn          5500        5487      200/900 sn
1000   49       49000          %145       19612 sn      49.06     1071.6 sn         9000        8987      400/900 sn
2500   23       57500          %188       23006 sn      57.53     2998.2 sn         17500       17487     1000/900 sn — sigmiyor

en ucuz boy: akis tabanli (boy 10) — 26.92 birim; en kisa toplam sure: akis tabanli (boy 5) — 9990 sn
boy 1'den 500'e: cagri 20462 -> 91 (225 kat az), islenen kayit 20462 -> 45500 (2.2 kat cok)
13 zehirli kayit boy 1'de 0 saglam kaydi, boy 500'de 5487 saglam kaydi birlikte olu mektup kutusuna dusurdu
```

Maliyet sütunu bir çukur çizer: boy 1'de 43,48, boy 10'da 26,92, boy 2500'de 57,53 birim. Sol
yamaç çağrı başına sabit yükten gelir — her çağrı 250 ms kurulum ister ve bu yirmi bin kez ödenir.
Sağ yamaç yeniden işlemeden gelir: boy büyüdükçe bir toplu işte hatalı kayıt bulunma olasılığı
artar ve boy 2500'de kayıtların **%188'i fazladan** işlenir. En ucuz nokta en hızlı nokta değildir:
en kısa süre boy 5'te, en düşük maliyet boy 10'dadır.

Üçüncü kuvvet gecikmedir ve tek yönde artar: bir kaydın sonucuna ulaşma süresi boy 1'de 2,1 saniye,
boy 500'de 534 saniyedir; kayıt, kendisiyle ilgisi olmayan 499 kaydın işlenmesini bekler. Dördüncüsü
bir eşiktir: boy 2500'de toplu işin kendisi 1.000 saniye tutar ve 900 saniyelik süre sınırına
**sığmaz**. Satır yazılır ama seçilemez.

Eş düşen sütunu bölünmezliğin bedelini tek sayıya indirir: on üç zehirli kayıt boy 1'de hiçbir
sağlam kaydı götürmez, boy 500'de 5.487 sağlam kaydı ölü mektup kutusuna düşürür. Toplu boyu
büyütmek verimle birlikte **hata yarıçapını da büyütür**.

#### Yinelenen İşlemenin Bedeli

Fazladan işleme bir maliyet kalemi olarak sayıldı; asıl soru aynı kaydı iki kez işlemenin zararsız
olup olmadığıdır. Doğrulama için zararsızdır, fatura satırı için değildir.

```js
// olcum-agi/tekillestirme.mjs — yinelenen islemenin bedeli ve tekillestirmenin bedeli (model)
import { N, MS_B, kayitlar, eszamanli, eszamansiz, akis, olc } from "./cagirma-modelleri.mjs";

export const OKU = 15, YAZ = 10, PENCERE = 24 * 3600;   // ms, ms, saniye (kurgu)
export const SURME_GECIKMESI = 3 * 24 * 3600;           // olu mektup kutusu elle 3 gun sonra surulur

if (import.meta.url === `file://${process.argv[1]}`) {
  const k = kayitlar();
  const m = [eszamanli(k), eszamansiz(k), akis(k, 10)].map(olc);
  console.log("model".padEnd(23) + "fazladan isleme".padEnd(17) + "fazla fatura satiri".padEnd(21) +
    "tekillestirme eki".padEnd(19) + "ek maliyet".padEnd(12) + "pencere disi yineleme");
  for (const x of m) {
    const ek = x.islenen * OKU + N * YAZ;
    console.log(x.ad.padEnd(23) + String(x.yeniden).padEnd(17) + String(x.yeniden).padEnd(21) +
      `${(ek / 1000).toFixed(0)} sn`.padEnd(19) + (ek * MS_B).toFixed(2).padEnd(12) +
      String(x.oluMektup));
  }
  const a = m[2], oran = (a.islenen * OKU + N * YAZ) / a.sure;
  console.log(`\ntekillestirme penceresi ${PENCERE / 3600} saat; olu mektup kutusu ${SURME_GECIKMESI / 3600} saat ` +
    `sonra surulur — pencere kapali, ${a.oluMektup} kayit ikinci kez islenir`);
  console.log(`akis tabanli (boy 10) icin tekillestirme is suresinin %${(oran * 100).toFixed(1)}'i kadar ek yuk getirir; ` +
    `karsiliginda ${a.yeniden} fazla fatura satiri onlenir`);
}
```

```
model                  fazladan isleme  fazla fatura satiri  tekillestirme eki  ek maliyet  pencere disi yineleme
eszamanli              449              449                  507 sn             1.27        0
eszamansiz             462              462                  507 sn             1.27        13
akis tabanli (boy 10)  4200             4200                 563 sn             1.41        130

tekillestirme penceresi 24 saat; olu mektup kutusu 72 saat sonra surulur — pencere kapali, 130 kayit ikinci kez islenir
akis tabanli (boy 10) icin tekillestirme is suresinin %5.5'i kadar ek yuk getirir; karsiliginda 4200 fazla fatura satiri onlenir
```

Tekilleştirmenin bedeli küçüktür: iş süresinin %5,5'i ve 1,41 birim. Karşılığında 4.200 fazla
fatura satırı önlenir; bu kıyas tekilleştirmeyi bir seçenek olmaktan çıkarır.

Son sütun tekilleştirmenin de bir kısıtla geldiğini gösterir. Anahtar sonsuza kadar saklanmaz,
pencere 24 saattir; ölü mektup kutusu ise elle, 72 saat sonra sürülür. Sürülen 130 kaydın
tekilleştirme kaydı çoktan silinmiştir ve hepsi ikinci kez işlenir. Önlemin **kendi penceresi**,
önlemin kapsamadığı bir yol açar.

#### Özet

- Çağıranın gördüğü gecikme 669 ms'den 5 ms'ye iner ama işin bittiği an 0,7 saniyeden 2,1 saniyeye,
  yüzde doksan dokuzuncu dilim 61,3 saniyeye çıkar; gecikme yok olmaz, görünmez olur.
- Eşzamanlı modelde on üç zehirli kaydı çağıran görür; öteki ikisinde hatayı hiç kimse görmez —
  deneme sorumluluğunu devretmek onu kaldırmaz, görünürlüğü kaldırır.
- Toplu boy taramasında maliyet çukur çizer: boy 1'de 43,48, boy 10'da 26,92, boy 2500'de 57,53
  birim. En kısa süre boy 5'te, en düşük maliyet boy 10'dadır ve boy 2500 süre sınırına sığmaz.
- Toplu iş bölünmediği için hata yarıçapı boyla büyür: on üç zehirli kayıt boy 1'de hiçbir sağlam
  kaydı, boy 500'de 5.487 sağlam kaydı ölü mektup kutusuna düşürür.
- Tekilleştirme iş süresine %5,5 ekleyip 4.200 fazla fatura satırını önler, ama 24 saatlik penceresi
  vardır; 72 saat sonra sürülen 130 kayıt pencerenin dışında kalır ve ikinci kez işlenir.

#### Sonraki Adım

Üç modelin gecikme sayıları da tek bir varsayımın üzerine kuruldu: çağrı geldiğinde işlevi
çalıştıracak bir örnek hazırdır. Sabit yük olarak yazılan 250 ms o hazır durumun bedelidir.

Hazır örnek her zaman yoktur. Kapasite kararı devredildiği için örnekler istek geldikçe yaratılır,
boşta kalınca geri alınır. Sonraki ders bir sıcak havuz modeli koşturur ve havuz ömrü ile trafik
profili değiştikçe soğuk çağrı oranını, gecikmeye eklenen süreyi ve kuyruğun ne zaman oluştuğunu
sayar; ardından üç azaltma yolunu ayrı ayrı ölçer.

### Soğuk Başlangıç

Source: https://academia.sh/tr/kurslar/sunucusuz/soguk-baslangic

Bir sıcak havuz modeli koşturularak isteğin örnek bulup bulamadığı sayılır: üç kurgu trafik profilinde soğuk çağrı oranı, gecikmeye eklenen süre ve kuyruğa giren istek ölçülür; havuz ömrü sıfırdan bin sekiz yüz saniyeye taranarak soğuk oranın düştüğü eşik ile karşılığında boşta duran örnek-saniye çıkarılır ve üç azaltma yolu ayrı ayrı fiyatlandırılır.

Önceki iki dersin gecikme sayıları tek bir varsayıma yaslandı: çağrı geldiğinde işlevi
çalıştıracak bir örnek hazır bekliyordu. Kapasite kararı devredildiği için bu her zaman doğru
değildir. Örnekler istek geldikçe yaratılır, boşta kalınca geri alınır; hazır örnek bulamayan istek **soğuk
başlangıç** yaşar — çalışma zamanının kurulması, paketin açılması ve başlatma kodu istek yolunun
içine girer.

M23/K02 aynı dengeyi — imaja gömülen kalemle açılışta kalan iş — saniye ölçeğinde ölçtü; o ölçüm
tekrarlanmaz. Burada ölçek milisaniye, nesne imaj değil pakettir. Sorulan tek bir orandır: **kaç
çağrı soğuk başlıyor**, bu neye bağlı ve azaltmanın bedeli ne.

**IH13.** Ölçüm penceresi 1800 saniyedir; bölgesel ölçüm ağının üç **kurgu** trafik profili kendi
yazılan bir üreteçle kurulur, tohum 20260804'tür. **IH14.** Sıcak çağrı 400 ms tutar, soğuk çağrıya 900 ms eklenir; bu
ek gecikmeye girer, faturaya girmez. **IH15.** Profiller: saha bildirimi seyrek (ortalama 90 sn
ara), okuma doğrulaması düzenli (ortalama 250 ms ara), gece toplu işlemesi ani (600 saniyede bir,
60 saniyelik patlama, 25 ms ara). **IH16.** Havuz ömrü, bir örneğin boşta kalıp geri alınmadan önce
beklediği süredir; taban değer 300 saniyedir. **IH17.** İşlevin eşzamanlılık payı 40'tır; havuz
dolduğunda gelen istek kuyruğa girer, düşmez. **IH18.** Fiyatlar kurgu birimle yazılır: çağrı
0,0005, işlem milisaniyesi 0,0000025, önceden ısıtılan örnek-saniye 0,0002 birim.

#### Havuzda Örnek Var mı

Model tek kural üzerinedir: havuzda boşta örnek varsa çağrı sıcaktır; yoksa ve pay dolmamışsa
yeni örnek yaratılır; pay da dolmuşsa istek kuyruğa girer.

```js
// olcum-agi/sicak-havuz.mjs — istek geldiginde havuzda ornek varsa sicak, yoksa soguk cagri (model)

export const PENCERE = 1800000, ISLEM = 400, SOGUK = 900;   // ms: olcum penceresi, isleme, soguk ek
export const OMUR = 300000, SINIR = 40;                     // ms bosta tutma, islevin eszamanlilik payi
export const CAGRI_B = 0.0005, MS_B = 0.0000025, ISIT_B = 0.0002;   // kurgu birim

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; }; };

// Uc kurgu trafik profili: saha bildirimi seyrek, dogrulama duzenli, gece toplu islemesi ani.
export const PROFIL = {
  seyrek: { ara: 90000, pencereler: [[0, PENCERE]] },
  duzenli: { ara: 250, pencereler: [[0, PENCERE]] },
  ani: { ara: 25, pencereler: [[0, 60000], [600000, 660000], [1200000, 1260000]] },
};

export const varislar = (ad, tohum = 20260804) => {
  const r = uretec(tohum), p = PROFIL[ad], v = [];
  for (const [bas, son] of p.pencereler) {
    let t = bas;
    while (t < son) { t += -Math.log(1 - r()) * p.ara; if (t < son) v.push(t); }
  }
  return v;
};

const yuzde = (a, p) => [...a].sort((x, y) => x - y)[Math.floor(a.length * p)];
const bosta = (o, son) => Math.max(0, son - o.dogum - o.mesgul) / 1000;

// Havuz: her ornek bosaldigi anda "bos" damgasi alir; damga uzerinden omur dolarsa geri alinir.
export const kos = (varis, { omur = OMUR, sinir = SINIR, soguk = SOGUK, islem = ISLEM,
  isit = 0, ekCagri = 0 } = {}) => {
  const havuz = [];
  for (let i = 0; i < isit; i++) havuz.push({ bos: 0, dogum: 0, mesgul: 0, sabit: true });
  let sogukSayi = 0, kuyrukta = 0, enUzunBekleme = 0, bostaSn = 0, enCok = havuz.length, isSuresi = 0;
  const gecikme = [];
  for (const t of varis) {
    for (let i = havuz.length - 1; i >= 0; i--) {
      const o = havuz[i];
      if (!o.sabit && o.bos + omur < t) { bostaSn += bosta(o, o.bos + omur); havuz.splice(i, 1); }
    }
    let ornek = havuz.find((o) => o.bos <= t), bas = t, ek = 0, bekleme = 0;
    if (!ornek && havuz.length < sinir) {
      ornek = { bos: 0, dogum: t, mesgul: 0, sabit: false };
      havuz.push(ornek); ek = soguk; sogukSayi++;
    } else if (!ornek) {
      ornek = havuz.reduce((a, b) => (b.bos < a.bos ? b : a));
      bekleme = ornek.bos - t; bas = ornek.bos; kuyrukta++;
      if (bekleme > enUzunBekleme) enUzunBekleme = bekleme;
    }
    const sure = ek + islem + ekCagri;
    ornek.bos = bas + sure; ornek.mesgul += sure; isSuresi += sure;
    gecikme.push(bekleme + sure);
    if (havuz.length > enCok) enCok = havuz.length;
  }
  for (const o of havuz) bostaSn += bosta(o, o.sabit ? PENCERE : Math.min(PENCERE, o.bos + omur));
  return { cagri: varis.length, soguk: sogukSayi, oran: sogukSayi / varis.length,
    ortGecikme: gecikme.reduce((a, b) => a + b, 0) / gecikme.length, g99: yuzde(gecikme, 0.99),
    kuyrukta, enUzunBekleme, enCok, bostaSn,
    maliyet: varis.length * CAGRI_B + isSuresi * MS_B + isit * (PENCERE / 1000) * ISIT_B };
};

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log(`pencere ${PENCERE / 1000} sn, isleme ${ISLEM} ms, soguk ek ${SOGUK} ms, ` +
    `omur ${OMUR / 1000} sn, pay ${SINIR}`);
  console.log("\n" + "profil".padEnd(10) + "cagri".padEnd(9) + "soguk".padEnd(8) + "soguk oran".padEnd(12) +
    "ort gecikme".padEnd(14) + "99. dilim".padEnd(12) + "kuyruga giren".padEnd(15) +
    "en uzun bekleme".padEnd(17) + "en cok ornek".padEnd(14) + "bosta ornek-sn");
  for (const ad of Object.keys(PROFIL)) {
    const s = kos(varislar(ad));
    console.log(ad.padEnd(10) + String(s.cagri).padEnd(9) + String(s.soguk).padEnd(8) +
      `%${(s.oran * 100).toFixed(2)}`.padEnd(12) + `${s.ortGecikme.toFixed(0)} ms`.padEnd(14) +
      `${s.g99.toFixed(0)} ms`.padEnd(12) + String(s.kuyrukta).padEnd(15) +
      `${s.enUzunBekleme.toFixed(0)} ms`.padEnd(17) + String(s.enCok).padEnd(14) + s.bostaSn.toFixed(0));
  }
  const a = kos(varislar("ani"));
  console.log(`\nani profilde soguk cagrilar gecikmeye ${(a.soguk * SOGUK / 1000).toFixed(0)} sn ekliyor; ` +
    `sicak cagri ${ISLEM} ms, soguk cagri ${ISLEM + SOGUK} ms — ${((ISLEM + SOGUK) / ISLEM).toFixed(2)} kat`);
}
```

```
pencere 1800 sn, isleme 400 ms, soguk ek 900 ms, omur 300 sn, pay 40

profil    cagri    soguk   soguk oran  ort gecikme   99. dilim   kuyruga giren  en uzun bekleme  en cok ornek  bosta ornek-sn
seyrek    18       2       %11.11      500 ms        1300 ms     0              0 ms             1             1722
duzenli   7242     9       %0.12       401 ms        400 ms      0              0 ms             8             10510
ani       7241     120     %1.66       419 ms        1300 ms     135            539 ms           40            38159

ani profilde soguk cagrilar gecikmeye 108 sn ekliyor; sicak cagri 400 ms, soguk cagri 1300 ms — 3.25 kat
```

Üç profil üç ayrı davranış gösterir. Düzenli trafikte soğuk oran %0,12'dir: istekler 250 ms arayla
gelir, havuz sekiz örnekte oturur ve yalnız dokuz çağrı soğuk başlar. Seyrek trafikte oran
%11,11'dir ve bu oran yükten değil çağrı seyrekliğinden gelir. Ani trafikte oran %1,66'dır ama asıl
sayı başka sütundadır: **135 istek kuyruğa girer**, en uzun bekleme 539 ms.

Kuyruk soğuk başlangıcın ikinci yüzüdür. Patlama başladığında havuz boştur; her yeni istek yeni bir
örnek ister ve her örnek 900 ms kurulum harcar. Pay 40'a dayanınca istekler beklemeye başlar. Soğuk
çağrı yalnız kendi gecikmesini artırmaz, havuzun dolmasını yavaşlatarak **arkasındaki isteklere
kuyruk oluşturur**: ortalama 419 ms görünür, yüzde doksan dokuzuncu dilim 1.300 ms'dir.

#### Havuz Ömrü Taraması

Havuz ömrü devredilmiş bir karardır: bir örneğin ne kadar boşta tutulacağına sağlayıcı karar verir.
Tarama ömrü sıfırdan 1800 saniyeye çıkarır.

```js
// olcum-agi/omur-taramasi.mjs — havuz omru ve trafik profili degistikce soguk cagri orani (model)
import { PROFIL, varislar, kos } from "./sicak-havuz.mjs";

export const OMURLER = [0, 15, 30, 60, 120, 300, 600, 1800];   // saniye
export const ADLAR = Object.keys(PROFIL);

if (import.meta.url === `file://${process.argv[1]}`) {
  const varis = Object.fromEntries(ADLAR.map((a) => [a, varislar(a)]));
  console.log("havuz omru".padEnd(12) + ADLAR.map((a) => `${a}: soguk / bosta`.padEnd(24)).join("") +
    "ani: kuyruk / ort gecikme");
  const tablo = {};
  for (const o of OMURLER) {
    const s = Object.fromEntries(ADLAR.map((a) => [a, kos(varis[a], { omur: o * 1000 })]));
    tablo[o] = s;
    console.log(`${o} sn`.padEnd(12) +
      ADLAR.map((a) => `%${(s[a].oran * 100).toFixed(2)} / ${s[a].bostaSn.toFixed(0)}`.padEnd(24)).join("") +
      `${s.ani.kuyrukta} / ${s.ani.ortGecikme.toFixed(0)} ms`);
  }
  console.log("");
  for (const a of ADLAR) {
    const iyi = OMURLER.find((o) => tablo[o][a].oran < 0.01);
    const sifir = tablo[0][a], en = tablo[1800][a];
    console.log(`${a.padEnd(9)} omur 0'da %${(sifir.oran * 100).toFixed(1)} soguk ve ${sifir.bostaSn.toFixed(0)} bosta ornek-sn; ` +
      `omur 1800'de %${(en.oran * 100).toFixed(2)} ve ${en.bostaSn.toFixed(0)}; ` +
      (iyi === undefined ? "hicbir omurde %1'in altina inmiyor" : `%1'in altina ${iyi} sn omurde iniyor`));
  }
}
```

```
havuz omru  seyrek: soguk / bosta   duzenli: soguk / bosta  ani: soguk / bosta      ani: kuyruk / ort gecikme
0 sn        %100.00 / 0             %100.00 / 0             %49.99 / 0              3621 / 969 ms
15 sn       %88.89 / 266            %1.35 / 7651            %1.78 / 3819            135 / 420 ms
30 sn       %77.78 / 489            %0.65 / 8493            %1.73 / 5713            135 / 419 ms
60 sn       %72.22 / 895            %0.33 / 9208            %1.66 / 9359            135 / 419 ms
120 sn      %38.89 / 1364           %0.18 / 9883            %1.66 / 16559           135 / 419 ms
300 sn      %11.11 / 1722           %0.12 / 10510           %1.66 / 38159           135 / 419 ms
600 sn      %5.56 / 1781            %0.11 / 10873           %0.59 / 57609           47 / 407 ms
1800 sn     %5.56 / 1781            %0.11 / 10873           %0.55 / 69047           47 / 406 ms

seyrek    omur 0'da %100.0 soguk ve 0 bosta ornek-sn; omur 1800'de %5.56 ve 1781; hicbir omurde %1'in altina inmiyor
duzenli   omur 0'da %100.0 soguk ve 0 bosta ornek-sn; omur 1800'de %0.11 ve 10873; %1'in altina 30 sn omurde iniyor
ani       omur 0'da %50.0 soguk ve 0 bosta ornek-sn; omur 1800'de %0.55 ve 69047; %1'in altina 600 sn omurde iniyor
```

Tarama üç ayrı eğri verir. Düzenli trafikte 15 saniyelik ömür soğuk oranı %100'den %1,35'e indirir;
ötesi kazandırmaz ama boşta örnek-saniyeyi 7.651'den 10.873'e çıkarır. Ani
trafikte oran 15 saniyeden 300 saniyeye kadar **hiç değişmez** — %1,66'da takılır — ve 600
saniyede aniden %0,59'a düşer. Eşik tesadüf değildir: patlamalar arasındaki boşluk 540 saniyedir,
ömür o boşluğu geçtiği anda havuz iki patlama arasında yaşar. Kuyruğa giren istek de aynı satırda
135'ten 47'ye iner.

Eşiğin fiyatı aynı satırdadır: boşta örnek-saniye 38.159'dan 57.609'a çıkar. Soğuk çağrıyı üçte
bire indirmek boşta kapasiteyi **yarı yarıya artırmakla** ödenir.

Seyrek profil hiçbir ömürde %1'in altına inmez; 1800 saniyede bile oran %5,56'dır, çünkü on sekiz
çağrının biri pencerenin ilkidir ve öncesinde havuz yoktur. Seyrek trafikte soğuk başlangıç bir
ayar sorunu değil, trafiğin kendi özelliğidir.

#### Üç Azaltma Yolu

```js
// olcum-agi/azaltma.mjs — soguk baslangici azaltmanin uc yolu ve her yolun bedeli (model)
import { SOGUK, ISLEM, PENCERE, varislar, kos } from "./sicak-havuz.mjs";

// [ad, kos secenekleri, bedelin cinsi]
export const YOL = [
  ["azaltma yok", {}, "—"],
  ["onceden isitma (16)", { isit: 16 }, "16 ornek 1800 sn bosta durur"],
  ["paket kucultme", { soguk: 350 }, "bagimliliklarin 3'u disari alinir"],
  ["baslatma tasinmasi", { soguk: 500, ekCagri: 40 }, "her cagriya 40 ms tembel yukleme"],
  ["kucultme + isitma", { soguk: 350, isit: 16 }, "ikisinin bedeli birlikte"],
];

if (import.meta.url === `file://${process.argv[1]}`) {
  const v = varislar("ani"), taban = kos(v);
  console.log(`ani profil, ${v.length} cagri, havuz omru 300 sn; sicak cagri ${ISLEM} ms`);
  console.log("\n" + "yol".padEnd(22) + "soguk".padEnd(8) + "soguk oran".padEnd(12) +
    "ort gecikme".padEnd(14) + "99. dilim".padEnd(12) + "kuyruga giren".padEnd(15) +
    "bosta ornek-sn".padEnd(16) + "maliyet".padEnd(10) + "gecikme kazanci");
  for (const [ad, sec] of YOL) {
    const s = kos(v, sec);
    console.log(ad.padEnd(22) + String(s.soguk).padEnd(8) + `%${(s.oran * 100).toFixed(2)}`.padEnd(12) +
      `${s.ortGecikme.toFixed(1)} ms`.padEnd(14) + `${s.g99.toFixed(0)} ms`.padEnd(12) +
      String(s.kuyrukta).padEnd(15) + s.bostaSn.toFixed(0).padEnd(16) + s.maliyet.toFixed(2).padEnd(10) +
      `${(taban.ortGecikme - s.ortGecikme).toFixed(1)} ms`);
  }
  console.log("\n" + "yol".padEnd(22) + "bedeli".padEnd(38) + "kazanilan ms basina ek maliyet");
  for (const [ad, sec, bedel] of YOL.slice(1)) {
    const s = kos(v, sec), kazanc = taban.ortGecikme - s.ortGecikme;
    console.log(ad.padEnd(22) + bedel.padEnd(38) +
      (kazanc > 0 ? ((s.maliyet - taban.maliyet) / kazanc).toFixed(3) : "kazanc yok"));
  }
  const esik = 40 / (SOGUK - 500);
  console.log(`baslatma tasinmasi ancak soguk oran %${(esik * 100).toFixed(0)}'un ustundeyse kazandirir: ` +
    `40 ms her cagriya, kazanilan 400 ms yalniz soguk cagriya duser — bu profilde oran %1.66`);
  const i = kos(v, { isit: 16 });
  console.log(`\nonceden isitma bostada gecen kapasiteyi ${taban.bostaSn.toFixed(0)} ornek-sn'den ` +
    `${i.bostaSn.toFixed(0)} ornek-sn'ye cikariyor; ${PENCERE / 1000} sn'lik pencerede ` +
    `${(i.maliyet - taban.maliyet).toFixed(2)} birim ek — soguk ekin kendisi ${SOGUK} ms`);
}
```

```
ani profil, 7241 cagri, havuz omru 300 sn; sicak cagri 400 ms

yol                   soguk   soguk oran  ort gecikme   99. dilim   kuyruga giren  bosta ornek-sn  maliyet   gecikme kazanci
azaltma yok           120     %1.66       418.9 ms      1300 ms     135            38159           11.13     0.0 ms
onceden isitma (16)   49      %0.68       406.1 ms      400 ms      0              42736           16.73     12.8 ms
paket kucultme        111     %1.53       405.4 ms      750 ms      0              35500           10.96     13.5 ms
baslatma tasinmasi    120     %1.66       448.5 ms      940 ms      22             38229           11.74     -29.7 ms
kucultme + isitma     43      %0.59       402.1 ms      400 ms      0              40933           16.66     16.8 ms

yol                   bedeli                                kazanilan ms basina ek maliyet
onceden isitma (16)   16 ornek 1800 sn bosta durur          0.438
paket kucultme        bagimliliklarin 3'u disari alinir     -0.013
baslatma tasinmasi    her cagriya 40 ms tembel yukleme      kazanc yok
kucultme + isitma     ikisinin bedeli birlikte              0.329
baslatma tasinmasi ancak soguk oran %10'un ustundeyse kazandirir: 40 ms her cagriya, kazanilan 400 ms yalniz soguk cagriya duser — bu profilde oran %1.66

onceden isitma bostada gecen kapasiteyi 38159 ornek-sn'den 42736 ornek-sn'ye cikariyor; 1800 sn'lik pencerede 5.60 birim ek — soguk ekin kendisi 900 ms
```

Üç yol üç ayrı cinsten bedel öder. Önceden ısıtma soğuk oranı %0,68'e, kuyruğu sıfıra indirir ve
yüzde doksan dokuzuncu dilimi 1.300 ms'den 400 ms'ye çeker: havuzda hep on altı örnek beklediği
için patlamanın ilk saniyesi soğuk değildir. Bedeli birinci dersin kaçındığı şeydir — boşta
örnek-saniye 42.736'ya, fatura 11,13 birimden 16,73 birime çıkar, yani **%50 artar**.

Paket küçültme tek bedavaya benzeyen yoldur: soğuk ek 900 ms'den 350 ms'ye inince hem gecikme hem
maliyet düşer. Ama bedel tabloda değildir — üç bağımlılık paketten çıkarılmıştır ve bir yerde
karşılanması gerekir. Kısıtın etrafından dolaşmanın en sessiz biçimi budur.

Üçüncü yol zarar eder. Başlatma işinin taşınması soğuk eki 500 ms'ye indirir ama her çağrıya 40 ms
tembel yükleme ekler; ortalama gecikme **29,7 ms artar** ve yirmi iki istek kuyruğa girer. Son satır
eşiği verir: 40 ms bütün çağrılara, kazanılan 400 ms yalnız soğuk çağrılara düşer, yani yol ancak
soğuk oran %10'un üstündeyse kazandırır. Bu profilde oran %1,66, seyrek profilde %11,11'dir.

#### Özet

- Soğuk çağrı 1.300 ms, sıcak çağrı 400 ms tutar: 3,25 kat. Ani profilde oran %1,66 olsa da 135
  istek kuyruğa girer, en uzun bekleme 539 ms olur.
- Havuz ömrü taramasında eşik trafiğin biçiminden çıkar: ani profilde oran 15–300 saniye arasında
  %1,66'da takılır, 600 saniyede %0,59'a iner, çünkü patlamalar arasındaki boşluk 540 saniyedir.
  Eşiğin bedeli aynı satırda yazılıdır: boşta örnek-saniye 38.159'dan 57.609'a çıkar.
- Önceden ısıtma kuyruğu sıfıra indirir ve faturayı %50 artırır; paket küçültme ikisini de düşürür
  ama üç bağımlılığı paketten çıkarmayı ister.
- Başlatma işinin taşınması bu profilde gecikmeyi 29,7 ms artırır; ancak soğuk oran %10'un
  üstündeyse kazandırır — azaltma yolunun kendisi bir eşiğe bağlıdır.

#### Sonraki Adım

Bu derste eşzamanlılık payı 40 sabit bir sayıydı ve kuyruğun nereden çıktığını açıkladı. Oysa tek
başına duran bir sayı değildir: bellek seçimi işlemci payını, işlemci payı işlem süresini, işlem
süresi de aynı payla kaç iş yapılacağını belirler.

Sonraki ders üç eşiği — bellek, süre ve eşzamanlılık — bir iş kümesine uygular ve kaç işin
sığmadığını sayar. Bellek taranır, süre ile birim maliyetin ters yönde değiştiği ve en ucuz
noktanın ortada çıktığı gösterilir. Eşzamanlılık sınırı aşıldığında kısma ile arkadaki kuyruk
sayılır; sınırın hesap düzeyinde paylaşılması bir örnekle ölçülür.

### Kaynak ve Süre Sınırları

Source: https://academia.sh/tr/kurslar/sunucusuz/kaynak-ve-sure-sinirlari

Üç 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.

Üç 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 İş

```js
// 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.

```js
// 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.

```js
// 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.

### Sürümleme ve Takma Adlar

Source: https://academia.sh/tr/kurslar/sunucusuz/surumleme-ve-takma-adlar

Takma ad üzerinden ağırlık kaydırma ölçülür: sürüm değişmez kalır, takma ad taşınır. Her adımda etkilenen istek ve fark etme turu sayılır; soğuk başlangıcın kanarya ölçümüne karışması ile geri almanın tek anahtar çevirme oluşu ayrı ayrı çıkarılır.

Eşikler sayıldı: süre sınırı, bellek sınırı, eşzamanlılık tavanı. Hangi işin bu eşiklerin içine
sığmadığı yazıldı. Sığan işin ne olacağı ise hiç sorulmadı — o işlev yazıldıktan sonra çalışan
sisteme nasıl girecek?

Aşamalı yayının kalıp tarafı — kararın hangi ölçütle, hangi pencereyle, hangi eşikle verildiği —
ölçülmüş bir konudur ve tekrarlanmıyor. Buranın sorusu daha dardır: bu merdiven **takma ad** denen
tek bir işaretçi üzerinden yürür ve mekanizmanın kendine ait iki olgusu vardır. Geri alma tek bir
yazmadır; soğuk başlangıç ise yeni sürümde sıfırdan başlar.

- **IH25.** Kurgusal bölgesel ölçüm ağının doğrulama işlevi dakikada dokuz yüz istek alır; günün
  saatine göre değişim modellenmiyor. Ağ da rakamlar da kurgudur.
- **IH26.** Sıcak örnekte işlem iki yüz yirmi milisaniye sürer; soğuk başlangıç bin sekiz yüz
  milisaniye ekler. Paket boyutunun etkisi dersin dışındadır.
- **IH27.** Boşta kalan örnek dört dakika sonra düşürülür. **Havuz sürüm başına ayrıdır**: takma ad
  taşınsa da iki sürümün havuzu birleşmez.
- **IH28.** Kapı tek kalem okur: yeni sürümün ortalama gecikmesi. Taban ağırlık sıfırken ölçülür,
  eşik tabanın bir virgül iki beş katıdır.
- **IH29.** İstekler üstel aralıklarla gelir; üreteç kendi yazılmıştır, tohum görünürdür. Her
  ağırlık adımı beş adet iki dakikalık tur içerir.
- **IH30.** Takma ad yazması, yayılma ve yeniden yayım süreleri kurgudur.

#### Sürüm Değişmez, Takma Ad Taşınır

Ölçülen şey gerçek bir çalışma ortamı değil, `node` ile kurulan bir modeldir. İki nesne vardır:
**sürüm**, özeti değişmeyen donmuş bir kayıt; **takma ad**, bu sürümlerden birini gösteren ve
üzerine yazılabilen bir işaretçi. Sürüm başına ayrı bir sıcak havuz tutulur.

```js
// takmaad.mjs — surum, takma ad ve sicak havuz modeli; gercek bir calisma ortami degil, modeldir
export const TOHUM = 20260420, ISTEK_DK = 900;   // kurgu: dogrulama islevine dakikada gelen istek
export const HIZMET_MS = 220, SOGUK_EK_MS = 1800, BOSTA_MS = 240000;  // sicak, soguk ek, bosta omru
export const TUR_DK = 2, TUR = 5, KAPI = 1.25, GERILEME_MS = 120;
export const AGIRLIKLAR = [1, 2, 5, 25, 100];

export function uretec(tohum) {                  // dogrusal eslesik uretec, tohum gorunur
  let x = tohum >>> 0;
  return () => { x = (Math.imul(x, 1664525) + 1013904223) >>> 0; return x / 4294967296; };
}

// Surum dondurulmustur: ozeti bir daha degismez. Takma ad ise uzerine yazilabilen bir isaretcidir.
export const surum = (etiket, ozet) => Object.freeze({ etiket, ozet });
export const takmaAd = (ad, hedef) => ({ ad, hedef, yazma: 0 });
export const tasi = (t, hedef) => Object.assign(t, { hedef, yazma: t.yazma + 1 });

// Havuz surum basinadir: bosta ornek bulunursa sicak calisir, bulunmazsa yeni ornek acilir.
export const havuz = () => ({ ornekler: [], soguk: 0 });
export const ayakta = (h, t) => h.ornekler.filter((o) => o.son + BOSTA_MS > t).length;
export function cagir(h, t, ekMs) {
  h.ornekler = h.ornekler.filter((o) => o.son + BOSTA_MS > t);
  const o = h.ornekler.find((x) => x.mesgul <= t), sure = HIZMET_MS + ekMs + (o ? 0 : SOGUK_EK_MS);
  if (o) { o.mesgul = t + sure; o.son = t + sure; }
  else { h.soguk += 1; h.ornekler.push({ mesgul: t + sure, son: t + sure }); }
  return sure;
}

// Bir adim: istekler ustel araliklarla gelir, agirliga gore eski ya da yeni surume dusurulur.
export function adim(rnd, hE, hY, agirlik, ekMs, t0, tur = TUR, turDk = TUR_DK) {
  const lam = ISTEK_DK / 60000, turlar = [];
  let t = t0 - Math.log(1 - rnd()) / lam;
  for (let k = 0; k < tur; k += 1) {
    const son = t0 + (k + 1) * turDk * 60000;
    let ny = 0, ne = 0, sy = 0, se = 0, s0 = hY.soguk;
    while (t < son) {
      if (rnd() * 100 < agirlik) { sy += cagir(hY, t, ekMs); ny += 1; } else { se += cagir(hE, t, 0); ne += 1; }
      t -= Math.log(1 - rnd()) / lam;
    }
    turlar.push({ ny, ortY: ny ? sy / ny : 0, ortE: ne ? se / ne : 0, soguk: hY.soguk - s0 });
  }
  return turlar;
}

// Merdiven: once agirlik sifirken taban okunur, sonra agirlik buyur. Havuzlar adimlar arasi
// tasinir: yeni surumun havuzu yalnizca ilk adimda bostur.
export function merdiven(tohum, ekMs, agirliklar = AGIRLIKLAR, isit = 0) {
  const rnd = uretec(tohum), hE = havuz(), hY = havuz();
  const taban = adim(rnd, hE, hY, 0, 0, 0, TUR).reduce((x, y) => x + y.ortE, 0) / TUR;
  const satirlar = [];
  let t = TUR * TUR_DK * 60000, etkilenen = 0;
  for (let i = 0; i < isit; i += 1) cagir(hY, t - 30000, 0);   // es zamanli yapay isitma cagrilari
  for (const a of agirliklar) {
    const turlar = adim(rnd, hE, hY, a, ekMs, t, TUR);
    t += TUR * TUR_DK * 60000;
    etkilenen += turlar.reduce((x, y) => x + y.ny, 0);
    satirlar.push({ agirlik: a, turlar, etkilenen });
  }
  return { taban, satirlar };
}

export const imza = (x) => `${x < 0 ? '' : '+'}${Math.round(x)}`;
export const satir = (g, ...x) => x.map((v, i) => String(v).padEnd(g[i])).join('');
```

Devredilen karar burada görünür: hangi isteğin hangi sürüme gideceği, kaç örnek açılacağı
yazılmıyor — yerine tek bir sayı yazılıyor. Kısıt da aynı yerdedir: havuz sürüm başına ayrı olduğu
için yeni sürüm ısınmasını sıfırdan yapar.

#### Her Adımda İki Sayı

```js
// kosum1.mjs — takma ad agirligi adim adim kaydirilir; her adimda soguk cagri, gecikme ve kapi okunur
import { merdiven, surum, takmaAd, tasi, imza, satir, TOHUM, ISTEK_DK, HIZMET_MS,
  SOGUK_EK_MS, KAPI, GERILEME_MS, AGIRLIKLAR } from './takmaad.mjs';

const v7 = surum('v7', 'e3bb1237'), v8 = surum('v8', 'd8bb00e6'), canli = takmaAd('canli', v7);
try { v7.ozet = 'ustune-yazildi'; } catch { /* donmus kayda yazma reddedilir */ }
console.log(`tohum ${TOHUM} | ${ISTEK_DK} istek/dk | sicak ${HIZMET_MS} ms | soguk ek ${SOGUK_EK_MS} ms`);
console.log(`takma ad "${canli.ad}" -> ${canli.hedef.etiket}, tasindi -> ${tasi(canli, v8).hedef.etiket}` +
  ` | yazma ${canli.yazma} | ozet ${v7.ozet} (ustune yazilamadi)`);

const G = [9, 11, 12, 10, 10, 11, 11, 11];
for (const [ad, ek, goster] of [['temiz surum', 0, AGIRLIKLAR],
  [`kusurlu surum (+${GERILEME_MS} ms gercek gerileme)`, GERILEME_MS, [1]]]) {
  const { taban, satirlar } = merdiven(TOHUM, ek);
  console.log(`\n${ad} | merdiven ${AGIRLIKLAR.join('-')} | taban ${Math.round(taban)} ms | kapi esigi ${Math.round(taban * KAPI)} ms`);
  console.log(satir(G, 'agirlik', 'istek/tur', 'tur1 soguk', 'tur1 ort', 'tur2 ort',
    'tur1 fark', 'tur2 fark', 'ilk temiz') + 'etkilenen');
  for (const s of satirlar.filter((x) => goster.includes(x.agirlik))) {
    const [a, b] = s.turlar, t = s.turlar.findIndex((x) => x.ortY <= taban * KAPI);
    console.log(satir(G, `%${s.agirlik}`, a.ny, a.soguk, Math.round(a.ortY), Math.round(b.ortY),
      imza(a.ortY - taban), imza(b.ortY - taban), t < 0 ? 'hicbiri' : `tur ${t + 1}`) + s.etkilenen);
  }
}
```

```
tohum 20260420 | 900 istek/dk | sicak 220 ms | soguk ek 1800 ms
takma ad "canli" -> v7, tasindi -> v8 | yazma 1 | ozet e3bb1237 (ustune yazilamadi)

temiz surum | merdiven 1-2-5-25-100 | taban 226 ms | kapi esigi 283 ms
agirlik  istek/tur  tur1 soguk  tur1 ort  tur2 ort  tur1 fark  tur2 fark  ilk temiz  etkilenen
%1       21         2           391       220       +165       -6         tur 2      85
%2       38         1           267       220       +41        -6         tur 1      266
%5       99         1           238       220       +12        -6         tur 1      717
%25      468        2           228       220       +1         -6         tur 1      2968
%100     1823       7           227       220       +1         -6         tur 1      11969

kusurlu surum (+120 ms gercek gerileme) | merdiven 1-2-5-25-100 | taban 226 ms | kapi esigi 283 ms
agirlik  istek/tur  tur1 soguk  tur1 ort  tur2 ort  tur1 fark  tur2 fark  ilk temiz  etkilenen
%1       21         2           511       340       +285       +114       hicbiri    85
```

İkinci satır dersin başlığını doğruluyor: takma ad `v7`'den `v8`'e taşındı — bir yazma — ve aynı
anda `v7`'nin özetine yazma girişimi reddedildi. Yayın, kayıtları değiştirmek değil, üzerine
yazılabilen tek bir alanı güncellemektir.

Etkilenen istek sütunu kaydırmanın kazancını yazıyor: yüzde bir adımının sonunda seksen beş, yüzde
yüze varıldığında on bir bin dokuz yüz altmış dokuz — yüz kırk kata yakın bir fark.

Fark etme turu sütunu ise beklenmedik bir yerde bozuluyor. Temiz sürümde yüzde bir adımının
**birinci turu kapıyı tetikliyor**: ortalama üç yüz doksan bir milisaniye, eşik iki yüz seksen üç.
Aynı sürüm ikinci turda iki yüz yirmiye iniyor; kusurlu sürümde fark her turda yüz on dört
milisaniye civarındadır. Ayırt edici olan farkın büyüklüğü değil, **sönüp sönmediği**dir.

Sebep havuzun sürüm başına ayrı olmasıdır: yeni sürüm ilk adıma boş havuzla girer, iki örnek açar
ve o örnekler merdivenin geri kalanında sıcak kalır. Soğuk başlangıç bedeli yalnızca ilk adıma
düşer — tanım gereği en küçük örneklemi olan adıma. Aritmetiği tek satırdır: kapının payı elli yedi
milisaniyedir, yüzde bir payda tura on sekiz istek düşer ve bin sekiz yüz milisaniyelik tek bir
soğuk çağrı ortalamaya yüz milisaniye ekler; yüzde ikide elli, yüzde beşte yirmi. Küçük pay hem
etkilenen isteği azaltıyor hem ölçümü soğuk başlangıca duyarlı kılıyor — ilki isteniyordu, ikincisi
kısıt olarak geldi.

#### Geri Alma Tek Anahtar Çevirmedir

```js
// kosum2.mjs — geri almanin iki yolu, tam gecisten sonra eski havuz, dolasma yollarinin bedeli
import { merdiven, uretec, havuz, adim, ayakta, imza, satir, TOHUM, ISTEK_DK,
  BOSTA_MS, TUR_DK, KAPI, AGIRLIKLAR } from './takmaad.mjs';

// Kurgu sureler: yazma 120, yayilma 900, paket yukleme (42 MB / 20 MB-sn) 2100, surum 3000 ms.
const YOLLAR = { 'takma ad cevirme': [120, 900], 'yeniden yayim': [2100, 3000, 120, 900] };
console.log(satir([20, 7, 11], 'geri alma yolu', 'adim', 'sure') + 'bu surede kusurlu surume dusen istek');
for (const [ad, a] of Object.entries(YOLLAR)) {
  const ms = a.reduce((x, y) => x + y, 0);
  console.log(satir([20, 7, 11], ad, a.length, `${(ms / 1000).toFixed(2)} sn`) + Math.round(ISTEK_DK / 60000 * ms));
}

// Tam gecisten sonra eski surumun havuzu bosalir; geri alma o havuzu yeniden acmak zorunda kalir.
function gecisVeGeriAl(beklemeDk) {
  const rnd = uretec(TOHUM), hE = havuz(), hY = havuz();
  adim(rnd, hE, hY, 0, 0, 0, 5, 1);                        // eski surum isinir
  const gecen = adim(rnd, hE, hY, 100, 0, 300000, beklemeDk, 1).reduce((x, y) => x + y.ny, 0);
  const t = 300000 + beklemeDk * 60000, kalan = ayakta(hE, t), s0 = hE.soguk;
  const geri = adim(rnd, hE, hY, 0, 0, t, 1, 1)[0];        // takma ad geri alindi: bir dakika okunur
  return { gecen, kalan, soguk: hE.soguk - s0, ort: Math.round(geri.ortE) };
}
const H = [9, 25, 26, 19];
console.log(`
tam gecisten (%100) sonra geri alma — bosta ornek ${BOSTA_MS / 60000} dk sonra dusuruluyor`);
console.log(satir(H, 'bekleme', 'yeni surume gitmis istek', 'eski havuzda kalan ornek', 'geri almada soguk') + 'ilk dk ort');
for (const b of [3, 4, 5]) {
  const g = gecisVeGeriAl(b);
  console.log(satir(H, `${b} dk`, g.gecen, g.kalan, g.soguk) + `${g.ort} ms`);
}

// Ilk adimin soguk baslangicindan kacmanin yollari; her yolun bedeli ayri bir kalemdir.
const pay = merdiven(TOHUM, 0).taban * (KAPI - 1), Y = [30, 16, 12, 10, 7, 12, 11];
console.log(`
ilk adimda soguk baslangictan kacmanin yollari — kapi payi ${Math.round(pay)} ms`);
console.log(satir(Y, 'yol', 'merdiven', 'karar turu', 'yayin dk', 'yapay', 'ilk turda', 'tur1 soguk') + 'karar turunda fark');
for (const [ad, ag, isit, kt] of [['tur1 at, tur2 ile karar ver', AGIRLIKLAR, 0, 2],
  ['1 es zamanli yapay cagri', AGIRLIKLAR, 1, 1], ['3 es zamanli yapay cagri', AGIRLIKLAR, 3, 1],
  ['ilk adimi %25 yap', [25, 100], 0, 1]]) {
  const { taban, satirlar } = merdiven(TOHUM, 0, ag, isit), t1 = satirlar[0].turlar[0];
  console.log(satir(Y, ad, ag.join('-'), kt, ag.length * kt * TUR_DK, isit, t1.ny, t1.soguk) +
    `${imza(satirlar[0].turlar[kt - 1].ortY - taban)} ms`);
}
```

```
geri alma yolu      adim   sure       bu surede kusurlu surume dusen istek
takma ad cevirme    2      1.02 sn    15
yeniden yayim       4      6.12 sn    92

tam gecisten (%100) sonra geri alma — bosta ornek 4 dk sonra dusuruluyor
bekleme  yeni surume gitmis istek eski havuzda kalan ornek  geri almada soguk  ilk dk ort
3 dk     2680                     12                        0                  220 ms
4 dk     3584                     4                         14                 247 ms
5 dk     4490                     0                         39                 296 ms

ilk adimda soguk baslangictan kacmanin yollari — kapi payi 57 ms
yol                           merdiven        karar turu  yayin dk  yapay  ilk turda   tur1 soguk karar turunda fark
tur1 at, tur2 ile karar ver   1-2-5-25-100    2           20        0      21          2          -6 ms
1 es zamanli yapay cagri      1-2-5-25-100    1           10        1      21          1          +79 ms
3 es zamanli yapay cagri      1-2-5-25-100    1           10        3      21          0          -6 ms
ilk adimi %25 yap             25-100          1           4         0      477         5          +13 ms
```

İlk tablo sürümün değişmez olmasının ne satın aldığını gösteriyor. Eski sürüm bir kayıt olarak
durduğu için geri alma iki adımdır — bir yazma ve yayılma — toplam bir virgül sıfır iki saniye ve
kusurlu sürüme düşen on beş istek. Sürüm saklanmasaydı yol dört adıma, altı virgül on iki saniyeye
ve doksan iki isteğe çıkardı; fark altı kattır.

İkinci tablo bu rahatlığın sınırını yazıyor. Ağırlık yüzde yüze çıkarıldıktan sonra eski sürüm hiç
istek almaz ve havuzu dört dakikada boşalır. Üç dakika sonra geri alındığında havuzda on iki örnek
duruyordu, hiç soğuk çağrı olmadı; beş dakika sonra sıfır örnek kalır ve ilk dakika otuz dokuz
soğuk çağrı ödeyerek ortalamayı iki yüz doksan altıya çıkarır. Geri alma hâlâ tek yazmadır, ama
bedeli işlemden değil aradan geçen süreden gelir.

Üçüncü tablo dolaşmanın faturasını yazıyor. Birinci turu atmak kararı temizler, yayını on dakikadan
yirmi dakikaya çıkarır. Önceden ısıtma süreyi korur ama tek yapay çağrı yetmez: tur içindeki
yığılma ikinci örneği açtırır ve fark yetmiş dokuz milisaniyede kalır. Üç eş zamanlı çağrı soğuk
sayısını sıfırlar; bedeli merdiven başına on beş yapay çağrıdır — ölçütlere karışan, gerçek
kullanıcıdan gelmeyen istekler. Merdiveni yukarıdan başlatmak en pahalısıdır: fark on üç
milisaniyeye iner ama ilk turda etkilenen istek yirmi birden dört yüz yetmiş yediye çıkar.

#### Özet

- Takma ad `v7`'den `v8`'e taşındı: tek bir yazma. Aynı anda sürümün özetine yazma girişimi
  reddedildi — yayın, kayıtları değiştirmek değil, bir işaretçiyi güncellemektir.
- Etkilenen istek yüzde bir adımının sonunda seksen beş, yüzde yüze varıldığında on bir bin dokuz
  yüz altmış dokuzdur.
- Temiz bir sürüm yüzde bir adımının ilk turunda kapıyı tetikledi: iki soğuk çağrı, üç yüz doksan
  bir milisaniye, eşik iki yüz seksen üç. İkinci turda iki yüz yirmiye indi; kusurlu sürümde fark
  hiçbir turda sönmedi.
- Yüzde bir payda tura on sekiz istek düşer ve tek soğuk çağrı ortalamaya yüz milisaniye ekler;
  kapı payı elli yedidir.
- Geri alma iki adım ve bir virgül sıfır iki saniyedir; sürüm saklanmasaydı dört adım, altı virgül
  on iki saniye ve doksan iki istek olurdu.
- Tam geçişten beş dakika sonra eski havuzda sıfır örnek kalır; geri almanın ilk dakikası otuz
  dokuz soğuk çağrı öder ve ortalama iki yüz doksan altıya çıkar.

#### Sonraki Adım

Ölçümün her yerinde aynı sayı sabit gibi duruyordu: soğuk başlangıcın eklediği bin sekiz yüz
milisaniye. Kanarya turunu bozan, geri almanın gecikmiş bedelini yazan ve önceden ısıtmayı gerekli
kılan oydu. Oysa o sayı sabit değildir — paket ne kadar büyükse indirilecek bayt o kadar çoktur.
Sonraki ders paketi ölçer: boyut ile soğuk başlangıç arasındaki ilişkiyi tarar, bağımlılıkları
paylaşılan bir katmana taşımanın neyi küçültüp neyi küçültmediğini sayar, sürüm sabitlemenin ve bir
katman güncellemesinin kaç işleve dokunduğunun hesabını çıkarır — ve kullanılmayan bir bağımlılığın
taşınan bayt olarak bedelini yazar.

### Paylaşılan Katmanlar ve Bağımlılıklar

Source: https://academia.sh/tr/kurslar/sunucusuz/paylasilan-katmanlar-ve-bagimliliklar

Paket boyutu ile soğuk başlangıç arasındaki ilişki taranır: bağımlılıklar paylaşılan bir katmana taşındığında paket küçülür ama çekilen bayt değişmez. Sürüm sabitlemenin depolama bedeli, katman güncellemesinin yarıçapı ve kullanılmayan bağımlılığın taşınan bayt karşılığı sayılır.

Sürüm kaydırma ölçümünde soğuk başlangıç bin sekiz yüz milisaniyelik bir sabit gibi davranıyordu.
Değildir. O sayı işlevin paketinden gelir: paket ne kadar büyükse çekilecek, açılacak ve yüklenecek
o kadar çok bayt vardır. Buranın sorusu şudur — paketi küçültmenin yolları nelerdir ve her yolun
faturası nedir?

Buradaki **katman**, bir konteyner imajının katmanıyla aynı sözcüğü paylaşır ama farklı bir
nesnedir: orada katman bir dosya sistemi anlık görüntüsüydü, burada işlevin paketine yayım
sırasında eklenen ortak bir bağımlılık kümesidir.

- **IH31.** Kurgusal bölgesel ölçüm ağının dokuz işlevi ve yedi kalemlik bir bağımlılık kataloğu
  vardır. Boyutlar, modül sayıları ve kullanım ilişkileri kurgudur.
- **IH32.** Soğuk başlangıç dört kalemin toplamıdır: boyuttan bağımsız yüz seksen milisaniyelik
  taban, saniyede yirmi megabayt çekme, megabayt başına on iki milisaniye açma ve modül başına
  sıfır virgül otuz beş milisaniye yükleme. Ağ değişkenliği ve sıkıştırma modellenmiyor.
- **IH33.** Bir bağımlılık en az dört işlevde geçiyorsa paylaşılan katmana alınır. Eşiğin kendisi
  bir tasarım kararıdır ve taranmıyor.
- **IH34.** Katman soğuk başlangıçta paketle birlikte çekilir. Ana makine önbelleği tek bir isabet
  oranıyla modellenir; isabet hâlinde katmanın bedeli sıfırdır.
- **IH35.** Her işlev günde kırk soğuk başlangıç yaşar. Trafiğin gün içine dağılımı modellenmiyor.
- **IH36.** Canlı katman sürümlerinin dağılımı kurgudur: dört sürüm, sırasıyla üç, iki, üç ve bir
  işleve sabitlenmiş.

#### Bir Soğuk Başlangıç Neyin Toplamı

Ölçülen şey gerçek bir yayım değil, `node` ile kurulan bir modeldir. Katalog, her bağımlılığın
boyutunu ve modül sayısını tutar; dokuz işlevin her biri gerçekten çağırdığı bağımlılıkları
listeler. Bir kalem hiçbir listede geçmez.

```js
// paket.mjs — paket boyutu, soguk baslangic ve paylasilan katman modeli; olcum degil, modeldir
export const BANT_MB_SN = 20;      // kurgu: paketi cekme bant genisligi
export const ACMA_MS_MB = 12;      // bir MB'i acmanin suresi
export const MODUL_MS = 0.35;      // modul basina yukleme suresi
export const TABAN_MS = 180;       // calisma zamani baslatma tabani, boyuttan bagimsiz
export const SOGUK_GUN = 40;       // kurgu: islev basina gunluk soguk baslangic sayisi
export const KATMAN_ESIK = 4;      // bu kadar islevde gecen bagimlilik paylasilan katmana alinir

// Kurgusal olcum aginin bagimlilik katalogu: boyut (MB) ve modul sayisi.
export const KATALOG = {
  oc: { ad: 'olcum cozumleyici', mb: 9.4, modul: 320 },
  sd: { ad: 'sema dogrulayici', mb: 4.8, modul: 210 },
  ve: { ad: 'veri erisim katmani', mb: 6.3, modul: 240 },
  ts: { ad: 'tarih-saat kitapligi', mb: 2.1, modul: 90 },
  sf: { ad: 'sifreleme yardimcilari', mb: 1.6, modul: 60 },
  rb: { ad: 'rapor bicimlendirici', mb: 14.2, modul: 540 },
  gu: { ad: 'gorsel uretici', mb: 21.5, modul: 760 },
};
export const KENDI = { mb: 1.2, modul: 45 };   // her islevin kendi kodu

// Dokuz islev ve gercekten cagirdigi bagimliliklar. 'gu' hicbir islevde gecmiyor.
export const ISLEVLER = {
  'okuma-dogrulama': ['oc', 'sd', 've', 'ts', 'sf'],
  'okuma-yazma': ['oc', 've', 'ts', 'sf'],
  'fatura-uretimi': ['oc', 'sd', 've', 'ts', 'sf', 'rb'],
  'fatura-gonderimi': ['ve', 'ts', 'sf', 'rb'],
  'saha-bildirimi': ['ve', 'ts', 'sf'],
  'gece-toplu-is': ['oc', 'sd', 've', 'ts', 'sf'],
  'sayac-kayit': ['sd', 've', 'ts', 'sf'],
  'tarife-guncelleme': ['sd', 've', 'sf'],
  'saglik-ucu': ['ve'],
};

export const kullanan = (k) => Object.values(ISLEVLER).filter((d) => d.includes(k)).length;
export const boyut = (ks) => ks.reduce((a, k) => ({ mb: a.mb + KATALOG[k].mb, modul: a.modul + KATALOG[k].modul }),
  { ...KENDI });

// Soguk baslangic: sabit taban + cekme + acma + modul yukleme. Bayt hem cekilir hem acilir.
export const soguk = (b) => TABAN_MS + (1000 * b.mb) / BANT_MB_SN + ACMA_MS_MB * b.mb + MODUL_MS * b.modul;

export const satir = (g, ...x) => x.map((v, i) => String(v).padEnd(g[i])).join('');
export const mb = (x) => `${x.toFixed(1)} MB`;
export const ek = (b) => soguk(b) - TABAN_MS;   // tabani cikarilmis cekme + acma + yukleme suresi
```

```js
// kosum1.mjs — paket boyutu ile soguk baslangic arasindaki iliski ve dort paketleme duzeni
import { KATALOG, ISLEVLER, KENDI, KATMAN_ESIK, SOGUK_GUN, BANT_MB_SN, ACMA_MS_MB, MODUL_MS,
  kullanan, boyut, soguk, satir, mb } from './paket.mjs';

const hepsi = Object.keys(KATALOG), n = Object.keys(ISLEVLER).length;
console.log(`${n} islev | cekme ${BANT_MB_SN} MB/sn | acma ${ACMA_MS_MB} ms/MB | modul ${MODUL_MS} ms`);
console.log(`kullanim sayisi: ${hepsi.map((k) => `${k} ${kullanan(k)}`).join(', ')} | katman esigi ${KATMAN_ESIK}`);

console.log('\npaket boyutu -> soguk baslangic (modul sayisi boyutla orantili varsayilir, 36 modul/MB)');
console.log(satir([10, 9, 12, 11, 11], 'boyut', 'modul', 'cekme ms', 'acma ms', 'yukleme ms') + 'soguk baslangic');
for (const x of [2, 8, 16, 26, 40, 61]) {
  const b = { mb: x, modul: Math.round(36 * x) };
  console.log(satir([10, 9, 12, 11, 11], mb(x), b.modul, Math.round(1000 * x / BANT_MB_SN),
    Math.round(ACMA_MS_MB * x), Math.round(MODUL_MS * b.modul)) + `${Math.round(soguk(b))} ms`);
}

// Dort paketleme duzeni. C ve D ayni icerigi tasir: fark yalnizca baytin nerede durdugudur.
const katmanKod = hepsi.filter((k) => kullanan(k) >= KATMAN_ESIK), katman = boyut(katmanKod);
katman.mb -= KENDI.mb; katman.modul -= KENDI.modul;          // katmanda kendi kod bulunmaz
const duzen = (ad, paketi, katmanli = false) => {
  const p = Object.values(ISLEVLER).map((d) => boyut(paketi(d)));
  const cekilen = p.map((x) => (katmanli ? { mb: x.mb + katman.mb, modul: x.modul + katman.modul } : x));
  const c = cekilen.map(soguk), boy = p.map((x) => x.mb);
  return { ad, enKucuk: Math.min(...boy), enBuyuk: Math.max(...boy),
    depo: boy.reduce((a, b) => a + b, 0) + (katmanli ? katman.mb : 0),
    sogukEnAz: Math.min(...c), sogukEnCok: Math.max(...c) };
};
const D = [46, 16, 16, 12];
console.log('\npaketleme duzenleri — dokuz islev');
console.log(satir(D, 'duzen', 'paket en kucuk', 'paket en buyuk', 'depolanan') + 'soguk baslangic araligi');
for (const r of [
  duzen('A. her islev katalogun tamamini paketler', () => hepsi),
  duzen('B. hic kullanilmayan ayiklanir', () => hepsi.filter((k) => kullanan(k) > 0)),
  duzen('C. her islev yalniz kullandigini paketler', (d) => d),
  duzen('D. esigi gecen bagimliliklar katmana tasinir', (d) => d.filter((k) => kullanan(k) < KATMAN_ESIK), true)]) {
  console.log(satir(D, r.ad, mb(r.enKucuk), mb(r.enBuyuk), mb(r.depo)) +
    `${Math.round(r.sogukEnAz)}-${Math.round(r.sogukEnCok)} ms`);
}

const gu = KATALOG.gu, tekSoguk = 1000 * gu.mb / BANT_MB_SN + ACMA_MS_MB * gu.mb + MODUL_MS * gu.modul;
console.log(`\nhic kullanilmayan "${gu.ad}" (${mb(gu.mb)}, ${gu.modul} modul) A duzeninde kalirsa:`);
console.log(`  her soguk baslangica ${Math.round(tekSoguk)} ms, gunde ${n * SOGUK_GUN} soguk baslangicta ` +
  `${(n * SOGUK_GUN * tekSoguk / 1000 / 60).toFixed(1)} dk ve ${(n * SOGUK_GUN * gu.mb / 1024).toFixed(1)} GB tasinan bayt`);
console.log(`  depolamada ${mb(n * gu.mb)}; ayiklanmasi paketi ${mb(gu.mb)} kucultur, kod degisikligi gerektirmez`);
```

```
9 islev | cekme 20 MB/sn | acma 12 ms/MB | modul 0.35 ms
kullanim sayisi: oc 4, sd 5, ve 9, ts 7, sf 8, rb 2, gu 0 | katman esigi 4

paket boyutu -> soguk baslangic (modul sayisi boyutla orantili varsayilir, 36 modul/MB)
boyut     modul    cekme ms    acma ms    yukleme ms soguk baslangic
2.0 MB    72       100         24         25         329 ms
8.0 MB    288      400         96         101        777 ms
16.0 MB   576      800         192        202        1374 ms
26.0 MB   936      1300        312        328        2120 ms
40.0 MB   1440     2000        480        504        3164 ms
61.0 MB   2196     3050        732        769        4731 ms

paketleme duzenleri — dokuz islev
duzen                                         paket en kucuk  paket en buyuk  depolanan   soguk baslangic araligi
A. her islev katalogun tamamini paketler      61.1 MB         61.1 MB         549.9 MB    4761-4761 ms
B. hic kullanilmayan ayiklanir                39.6 MB         39.6 MB         356.4 MB    3162-3162 ms
C. her islev yalniz kullandigini paketler     7.5 MB          39.6 MB         185.0 MB    745-3162 ms
D. esigi gecen bagimliliklar katmana tasinir  1.2 MB          15.4 MB         63.4 MB     2093-3162 ms

hic kullanilmayan "gorsel uretici" (21.5 MB, 760 modul) A duzeninde kalirsa:
  her soguk baslangica 1599 ms, gunde 360 soguk baslangicta 9.6 dk ve 7.6 GB tasinan bayt
  depolamada 193.5 MB; ayiklanmasi paketi 21.5 MB kucultur, kod degisikligi gerektirmez
```

İlk tarama soğuk başlangıcın nereden geldiğini ayırıyor. İki megabayttan altmış bire çıkıldığında
süre üç yüz yirmi dokuz milisaniyeden dört bin yedi yüz otuz bire gidiyor; aradaki farkın tamamı
boyuta bağlıdır. Megabayt başına düşen yük yetmiş dört virgül altı milisaniyedir: elli çekme, on
iki açma, on iki virgül altı modül yükleme. Sabit taban yüz seksende kalır — otuz megabaytlık bir
pakette soğuk başlangıcın yüzde doksanından fazlası baytın kendisidir.

#### Dört Paketleme Düzeni

İkinci tablo aynı dokuz işlevi dört farklı paketleme düzeniyle kuruyor. A düzeninde her işlev
kataloğun tamamını taşır; B'de hiç kullanılmayan kalem ayıklanır; C'de her işlev yalnız çağırdığını
paketler; D'de eşiği geçen bağımlılıklar paylaşılan katmana taşınır.

A'dan B'ye geçiş bedava bir kazançtır: kod değişmez, paket altmış bir virgül birden otuz dokuz
virgül altıya, soğuk başlangıç dört bin yedi yüz altmış birden üç bin yüz altmış ikiye iner. C, her
işleve kendi listesini vererek en küçük paketi yedi virgül beşe indirir ve soğuk başlangıç
aralığını yedi yüz kırk beş ile üç bin yüz altmış iki arasına açar.

D satırı ise dersin asıl sayısını yazıyor. Paket boyutu bir virgül iki megabayta kadar iner — C'nin
altıda biri — ama **soğuk başlangıcın alt ucu yedi yüz kırk beşten iki bin doksan üçe çıkar**.
Sebebi basittir: katmandaki yirmi dört virgül iki megabayt yok olmadı, yalnız paketin dışına
alındı; soğuk başlangıçta yine çekilir. Dahası, katmandaki her şeyi kullanmayan işlevler artık
kullanmadıkları baytı da çekmektedir. Paket boyutunu ölçüt almak burada yanıltır; ölçülecek olan
**çekilen bayttır**.

Son satırlar hiç kullanılmayan kalemin faturasını yazıyor. Yirmi bir virgül beş megabaytlık görsel
üretici her soğuk başlangıca bin beş yüz doksan dokuz milisaniye ekler; günde üç yüz altmış soğuk
başlangıçta dokuz virgül altı dakika ve yedi virgül altı gigabayt taşınan bayt eder.

#### Katman Baytı Yok Etmez, Yerini Değiştirir

```js
// kosum2.mjs — katman onbellegi, surum sabitleme ve bir katman guncellemesinin yaricapi
import { KATALOG, ISLEVLER, KENDI, KATMAN_ESIK, TABAN_MS, kullanan, boyut, soguk, ek, satir, mb } from './paket.mjs';

const hepsi = Object.keys(KATALOG), n = Object.keys(ISLEVLER).length;
const katmanKod = hepsi.filter((k) => kullanan(k) >= KATMAN_ESIK), katman = boyut(katmanKod);
katman.mb -= KENDI.mb; katman.modul -= KENDI.modul;
const paketC = Object.values(ISLEVLER).map((d) => boyut(d));
const paketD = Object.values(ISLEVLER).map((d) => boyut(d.filter((k) => kullanan(k) < KATMAN_ESIK)));
console.log(`paylasilan katman: ${katmanKod.join(', ')} = ${mb(katman.mb)}, ${katman.modul} modul`);

// Katman ana makinede onbelleklenirse soguk baslangicta yeniden cekilmez. Isabet orani taranir.
const O = [10, 20, 20, 18];
console.log(satir(O, 'isabet', 'D en kucuk islev', 'D en buyuk islev', 'D ortalama') + 'C ortalama');
const ortC = paketC.map(soguk).reduce((a, b) => a + b, 0) / n;
for (const h of [0, 0.25, 0.5, 0.75, 1]) {
  const d = paketD.map((p) => TABAN_MS + ek(p) + (1 - h) * ek(katman));
  console.log(satir(O, `%${h * 100}`, `${Math.round(Math.min(...d))} ms`, `${Math.round(Math.max(...d))} ms`,
    `${Math.round(d.reduce((a, b) => a + b, 0) / n)} ms`) + `${Math.round(ortC)} ms`);
}

// Katman surumlenir ve her islev bir surume sabitlenir. Kurgu dagilim: kac islev hangi surumde.
const SABITLEME = { v4: 3, v3: 2, v2: 3, v1: 1 };
const canli = Object.keys(SABITLEME).length;
console.log(`\nsurum sabitleme — ${canli} katman surumu canli tutuluyor`);
console.log(`  ${Object.entries(SABITLEME).map(([s, k]) => `${s}: ${k} islev`).join(' | ')}`);
console.log(`  toplam katman depolamasi ${mb(canli * katman.mb)} (tek surum varsayimi ${mb(katman.mb)}); ` +
  `tek surume inmek ${n - Math.max(...Object.values(SABITLEME))} islevin yeniden yayimini gerektirir`);

// Bir bagimlilik guncellemesinin iki maliyeti: kac yayim gerekir ve kac islevi ayni anda etkiler.
const Y = [40, 10, 22];
console.log('\nbir bagimlilik guncellemesi');
console.log(satir(Y, 'bagimlilik nerede duruyor', 'yayim', 'ayni anda etkilenen') + 'depolanan');
for (const [ad, yayim, yaricap, depo] of [
  ['C — her paketin icinde ayri ayri', n, 1, paketC.reduce((a, b) => a + b.mb, 0)],
  ['D — katmanda, surum sabitlenmis', n, 1, paketD.reduce((a, b) => a + b.mb, 0) + canli * katman.mb],
  ['D — katmanda, takma adi izliyor', 1, n, paketD.reduce((a, b) => a + b.mb, 0) + katman.mb]]) {
  console.log(satir(Y, ad, yayim, `${yaricap} islev`) + mb(depo));
}
```

```
paylasilan katman: oc, sd, ve, ts, sf = 24.2 MB, 920 modul
isabet    D en kucuk islev    D en buyuk islev    D ortalama        C ortalama
%0        2093 ms             3162 ms             2330 ms           1730 ms
%25       1637 ms             2706 ms             1875 ms           1730 ms
%50       1181 ms             2251 ms             1419 ms           1730 ms
%75       726 ms              1795 ms             963 ms            1730 ms
%100      270 ms              1340 ms             508 ms            1730 ms

surum sabitleme — 4 katman surumu canli tutuluyor
  v4: 3 islev | v3: 2 islev | v2: 3 islev | v1: 1 islev
  toplam katman depolamasi 96.8 MB (tek surum varsayimi 24.2 MB); tek surume inmek 6 islevin yeniden yayimini gerektirir

bir bagimlilik guncellemesi
bagimlilik nerede duruyor               yayim     ayni anda etkilenen   depolanan
C — her paketin icinde ayri ayri        9         1 islev               185.0 MB
D — katmanda, surum sabitlenmis         9         1 islev               136.0 MB
D — katmanda, takma adi izliyor         1         9 islev               63.4 MB
```

İlk tablo katmanın ne zaman kazandırdığını gösteriyor. Önbellek isabeti sıfırken D düzeninin
ortalaması iki bin üç yüz otuz, C'nin ortalaması bin yedi yüz otuz milisaniyedir — katman
**ortalamayı altı yüz milisaniye kötüleştirir**. Yüzde elli isabette D bin dört yüz on dokuza iner
ve C'yi geçer; başabaş nokta yüzde otuz üç civarındadır, tam isabette D beş yüz sekize düşer.
Katmanın değeri katmanın kendisinde değil, **ana makinenin onu ne sıklıkla elinde tuttuğunda**dır —
ve bu, işlevi yazanın kararı değildir.

#### Sürüm Sabitleme ve Güncellemenin Yarıçapı

Sürüm sabitleme tablosu ikinci bedeli yazıyor. Dokuz işlev dört ayrı katman sürümüne sabitlenmiştir
ve hiçbiri düşürülemez, çünkü her birinin kullanıcısı vardır. Depolanan katman baytı yirmi dört
virgül ikiden doksan altı virgül sekize çıkar; hepsini tek sürüme çekmek altı işlevin yeniden
yayımını gerektirir.

Son tablo devredilen kararın faturasını kesiyor. Bağımlılık her paketin içinde ayrı ayrı dururken
bir güncelleme dokuz yayım ister, ama her yayım tek bir işlevi etkiler: yarıçap birdir, aşamalı
yayılabilir. Katmana taşındığında ve sürüm sabitlendiğinde yayım sayısı **yine dokuzdur** —
sabitleme, katmanın "tek yerden güncelle" vaadini geri alır — kazanç yalnız depolamadadır, yüz
seksen beşten yüz otuz altı megabayta. Sabitleme bırakılıp katman bir takma adı izlediğinde yayım
bire iner; karşılığında yarıçap dokuza çıkar. Tek yazma dokuz işlevi aynı anda değiştirir ve
kusurlu bir katman sürümü dokuzunu birden bozar.

#### Özet

- Soğuk başlangıcın megabayt başına yükü yetmiş dört virgül altı milisaniyedir: elli çekme, on iki
  açma, on iki virgül altı modül yükleme.
- Hiç kullanılmayan kalemi ayıklamak paketi otuz dokuz virgül altı megabayta, soğuk başlangıcı üç
  bin yüz altmış iki milisaniyeye indirir ve kod değişikliği gerektirmez; taşınan bayt günde yedi
  virgül altı gigabayt azalır.
- Bağımlılıkları katmana taşımak paketi bir virgül iki megabayta düşürür ama soğuk başlangıcın alt
  ucunu yedi yüz kırk beşten iki bin doksan üç milisaniyeye çıkarır: bayt yok olmadı, yer değiştirdi.
- Katman ancak ana makine önbelleği yüzde otuz üçün üstünde isabet ettiğinde kazandırır; sıfır
  isabette ortalamayı altı yüz milisaniye kötüleştirir.
- Dört katman sürümü canlı tutulduğunda depolanan katman baytı dört katına çıkar; tek sürüme inmek
  altı işlevin yeniden yayımını ister.
- Bir güncelleme paket içinde dokuz yayım ve bir işlevlik yarıçap, sabitlenmiş katmanda yine dokuz
  yayım, takma adı izleyen katmanda tek yayım ve dokuz işlevlik yarıçap demektir.

#### Sonraki Adım

Paket ölçüldü, katman ölçüldü, soğuk başlangıcın hangi kaleminin nereden geldiği yazıldı. Bunların
hepsi bir varsayımı paylaşıyordu: iş, işleve uyuyor. Süre sınırına sığıyor, durumu dışarıda
tutulabiliyor, bir istek gelince başlayıp bir yanıtla bitiyor. Her iş böyle değildir. Sonraki ders
beş iş türünü süre, durum ve maliyet ekseninde yan yana koyar; her tür için eşiği aşan kalemi adıyla
yazar ve sığmayan işi parçalayarak sığdırmanın bedelini — adım sayısı, ara durum saklama, hata
yüzeyi — sayar. Sonunda tek bir tablo kalır: hangi iş sunucusuza uyar, hangisi uymaz ve neden.

### Sunucusuzun Uygun Olmadığı Durumlar

Source: https://academia.sh/tr/kurslar/sunucusuz/sunucusuzun-uygun-olmadigi-durumlar

Beş iş türü süre, durum ve maliyet ekseninde kıyaslanır: her tür için eşiği aşan kalem adıyla yazılır ve sığmayan işi parçalayarak sığdırmanın bedeli adım, ara durum ve hata noktası olarak sayılır. Konu, hangi işin sunucusuza uyduğunu ve hangisinin neden uymadığını gösteren bir tabloyla kapanır.

Bu konu boyunca ölçülen her şey aynı varsayımı paylaşıyordu: iş, işleve uyuyor. Bir istek geliyor,
sınırların içinde bitiyor, durumunu dışarıda tutuyor. Eşikler sayıldı, paket küçültüldü, yayın
kapıya bağlandı — hepsi o varsayımın içinde. Şimdi varsayımın kendisi ölçülüyor: hangi iş bu
sınırların içine sığar, hangisi sığmaz ve sığmayanı zorla sığdırmanın faturası nedir?

Soru "sunucusuz iyi mi kötü mü" değildir; kiralamanın karşılığında gelen kısıtların hangi iş
türünde ödenebilir, hangisinde ödenemez olduğudur. Cevabı bir görüş değil, üç eksende okunan bir
sayıdır: süre, durum, maliyet.

- **IH37.** Kurgusal bölgesel ölçüm ağının beş iş türü ölçülür. İş yükü sayıları da sınırlar da
  kurgudur ve tek bir çalıştırma ortamını temsil eder.
- **IH38.** Sınırlar sabittir: tek koşum dokuz yüz saniye, bellek üç bin yetmiş iki megabayt.
  Bağlantı istekten uzun yaşayamaz, yani aynı dokuz yüz saniye bağlantı ömrüdür.
- **IH39.** Maliyet **kurgu birimlerle** yazılır; gerçek para birimi kullanılmaz ve yalnız oranlar
  anlamlıdır. Sunucusuz çağrı başına ve gigabayt-saniye başına, kiralık makine saat başına ücretlenir.
- **IH40.** Bir kiralık makine kırk eş zamanlı iş ya da iki bin kalıcı bağlantı taşır. Yedeklilik,
  yük dengeleme ve işletim emeği maliyete katılmıyor — yani kiralık makine tarafı **eksik sayılıyor**.
- **IH41.** Parçalamada her sınırda ara durum yazılır ve okunur: on sekiz artı on iki saniye ve iki
  yüz kırk megabayt. Sınırın tamamı kullanılamaz; kullanılabilir pay taranan bir ayardır.
- **IH42.** Hata noktası, başarısız olup yeniden denenebilecek yer sayısıdır: adım sayısı artı
  adımlar arası geçiş sayısı. Kısmi başarıdan sonra telafi yolu modellenmiyor.

#### Beş İş Türü, Üç Eksen

```js
// isler.mjs — bes is turunu sure, durum ve maliyet ekseninde kiyaslayan model; olcum degil, modeldir
export const SURE_SINIRI = 900;    // kurgu ust sinir, saniye
export const BELLEK_TAVAN = 3072;  // kurgu bellek tavani, MB
export const BAGLANTI_OMRU = 900;  // baglanti istekten uzun yasayamaz: ayni sinir
export const AY_SN = 2592000;      // otuz gunluk ay, saniye

// Kurgu birimler — gercek para birimi degildir, yalnizca oranlar anlamlidir.
export const CAGRI = 0.0000002;    // cagri basina birim
export const GBSN = 0.000017;      // GB-saniye basina birim
export const MAKINE_SAAT = 0.096;  // surekli calisan kiralik makine, saat basina birim
export const MAKINE_ESZAMAN = 40;  // bir makinenin tasidigi es zamanli is
export const MAKINE_BAGLANTI = 2000;

// Bes is turu. `ay` aylik cagri sayisidir; surekli servislerde AY_SN / sn x es zamanli sayisi.
export const ISLER = {
  'kisa ve seyrek istek': { sn: 0.12, ay: 40000, mb: 256, eszaman: 1, baglanti: 0, durum: 'yok' },
  'gece toplu is': { sn: 2700, ay: 30, mb: 1024, eszaman: 1, baglanti: 0, durum: 'ara dosya' },
  'uzun suren donusturme': { sn: 4200, ay: 60, mb: 3072, eszaman: 1, baglanti: 0, durum: 'bellekte ara sonuc' },
  'kalici baglanti tutan servis': { sn: 1500, ay: 1382400, mb: 512, eszaman: 20, baglanti: 800, durum: 'oturum' },
  'yuksek ve surekli yuk': { sn: 0.09, ay: 1036800000, mb: 512, eszaman: 36, baglanti: 0, durum: 'yok' },
};

export const sunucusuzAy = (i) => i.ay * CAGRI + (i.ay * i.sn * i.mb) / 1024 * GBSN;
export const makineAy = (i) => Math.max(1, Math.ceil(i.eszaman / MAKINE_ESZAMAN),
  Math.ceil(i.baglanti / MAKINE_BAGLANTI)) * 730 * MAKINE_SAAT;

// Esigi asan kalem: hangi sinir once carpiyor. Sirasi onemlidir, ilk carpan yazilir.
export function asan(i) {
  const k = [];
  if (i.baglanti > 0 && i.sn > BAGLANTI_OMRU) k.push('baglanti omru');
  else if (i.sn > SURE_SINIRI) k.push('sure siniri');
  if (i.mb > BELLEK_TAVAN) k.push('bellek tavani');
  if (i.durum === 'bellekte ara sonuc' || i.durum === 'oturum') k.push('durum');
  if (sunucusuzAy(i) > makineAy(i)) k.push('birim maliyet');
  return k;
}

export const satir = (g, ...x) => x.map((v, i) => String(v).padEnd(g[i])).join('');
export const bir = (x) => (x >= 100 ? x.toFixed(0) : x >= 1 ? x.toFixed(2) : x.toFixed(4));

// Parcalayarak sigdirmanin kalemleri (kurgu): her sinirda ara durum yazilir ve sonra okunur.
export const ARA_YAZ = 18, ARA_OKU = 12, ARA_MB = 240;
export function parcala(sn, pay) {
  const kullanilabilir = SURE_SINIRI * pay - ARA_YAZ - ARA_OKU;
  if (kullanilabilir <= 0) return null;
  const adim = Math.ceil(sn / kullanilabilir);
  const ek = (adim - 1) * (ARA_YAZ + ARA_OKU);
  return { adim, ek, toplam: sn + ek, araMb: (adim - 1) * ARA_MB, hata: 2 * adim - 1,
    parcaSn: sn / adim + ARA_YAZ + ARA_OKU };
}
```

```js
// kosum1.mjs — bes is turu sure, durum ve maliyet ekseninde yan yana konur
import { ISLER, SURE_SINIRI, BELLEK_TAVAN, BAGLANTI_OMRU, MAKINE_ESZAMAN, sunucusuzAy,
  makineAy, asan, satir, bir } from './isler.mjs';

console.log(`sinirlar: sure ${SURE_SINIRI} sn | bellek ${BELLEK_TAVAN} MB | baglanti omru ${BAGLANTI_OMRU} sn`);
console.log(`kurgu birimler: makine ${MAKINE_ESZAMAN} es zamanli is tasir; asagidaki sayilar birimdir, para degil\n`);

const A = [30, 11, 13, 16, 10, 21];
console.log(satir(A, 'is turu', 'tek kosum', 'sinirin kati', 'aylik cagri', 'bellek', 'durum') + 'es zamanli');
for (const [ad, i] of Object.entries(ISLER)) {
  console.log(satir(A, ad, `${i.sn} sn`, `${(i.sn / SURE_SINIRI).toFixed(2)}x`,
    i.ay.toLocaleString('tr-TR'), `${i.mb} MB`, i.durum) + i.eszaman);
}

const B = [30, 14, 16, 9, 26];
console.log('\naylik maliyet ve esigi asan kalem');
console.log(satir(B, 'is turu', 'sunucusuz', 'kiralik makine', 'oran') + 'esigi asan kalem');
for (const [ad, i] of Object.entries(ISLER)) {
  const s = sunucusuzAy(i), m = makineAy(i), k = asan(i);
  console.log(satir(B, ad, bir(s), bir(m), `${(s / m).toFixed(2)}x`) + (k.length ? k.join(' + ') : 'yok'));
}
```

```
sinirlar: sure 900 sn | bellek 3072 MB | baglanti omru 900 sn
kurgu birimler: makine 40 es zamanli is tasir; asagidaki sayilar birimdir, para degil

is turu                       tek kosum  sinirin kati aylik cagri     bellek    durum                es zamanli
kisa ve seyrek istek          0.12 sn    0.00x        40.000          256 MB    yok                  1
gece toplu is                 2700 sn    3.00x        30              1024 MB   ara dosya            1
uzun suren donusturme         4200 sn    4.67x        60              3072 MB   bellekte ara sonuc   1
kalici baglanti tutan servis  1500 sn    1.67x        1.382.400       512 MB    oturum               20
yuksek ve surekli yuk         0.09 sn    0.00x        1.036.800.000   512 MB    yok                  36

aylik maliyet ve esigi asan kalem
is turu                       sunucusuz     kiralik makine  oran     esigi asan kalem
kisa ve seyrek istek          0.0284        70.08           0.00x    yok
gece toplu is                 1.38          70.08           0.02x    sure siniri
uzun suren donusturme         12.85         70.08           0.18x    sure siniri + durum
kalici baglanti tutan servis  17626         70.08           251.51x  baglanti omru + durum + birim maliyet
yuksek ve surekli yuk         1001          70.08           14.28x   birim maliyet
```

İkinci tablo asıl ayrımı yapıyor. Kısa ve seyrek istek sunucusuzun tam ortasındadır: aylık maliyet
sıfır virgül sıfır iki sekiz birim, kiralık makinenin iki bin dört yüzde biri. İş ayda kırk bin kez
ve yüz yirmi milisaniye çalışıyor; sürekli açık duran bir makine bu işin neredeyse tamamında boş
bekler. Devredilen kapasite kararının en açık kazandığı yer burasıdır.

Gece toplu iş ile uzun süren dönüştürme maliyet ekseninde de kazanır — biri kiralık makinenin
yüzde ikisi, öteki yüzde on sekizi — ama ikisi de **süre sınırını** aşar. Bu iki iş için soru
"pahalı mı" değil, "hiç çalışır mı"dır. Uzun süren dönüştürme ayrıca durumu bellekte tutar:
dört bin iki yüz saniyelik iş boyunca biriken ara sonuç, koşum bittiğinde yok olan bir yerde durur.

Son iki satır tersine dönüyor. Kalıcı bağlantı tutan servis üç kalemi birden aşıyor: bağlantı ömrü,
durum ve birim maliyet. Sunucusuz karşılığı kiralık makinenin **iki yüz elli bir katıdır**, çünkü
sekiz yüz bağlantının her biri boyunca çalışan bir çağrı gibi ücretlendirilir — beklerken de. Yüksek
ve sürekli yük ise yalnız maliyet ekseninde düşer: on dört kat pahalı.

#### Parçalayarak Sığdırmanın Bedeli

```js
// kosum2.mjs — sigmayan isi parcalamanin bedeli ve surekli yukte basabas noktasi
import { ISLER, SURE_SINIRI, AY_SN, ARA_YAZ, ARA_OKU, ARA_MB, GBSN, CAGRI, MAKINE_SAAT,
  MAKINE_ESZAMAN, parcala, sunucusuzAy, makineAy, satir, bir } from './isler.mjs';

const d = ISLER['uzun suren donusturme'];
console.log(`"uzun suren donusturme" ${d.sn} sn, sinir ${SURE_SINIRI} sn, ara durum ${ARA_MB} MB, ` +
  `sinir basina yazma ${ARA_YAZ} sn + okuma ${ARA_OKU} sn`);
const P = [12, 14, 8, 11, 13, 14, 14];
console.log(satir(P, 'sinir payi', 'parca suresi', 'adim', 'ek sure', 'toplam sure', 'ara durum', 'hata noktasi') + 'aylik birim');
for (const pay of [0.4, 0.6, 0.8, 0.95]) {
  const r = parcala(d.sn, pay);
  const maliyet = d.ay * r.adim * CAGRI + (d.ay * r.toplam * d.mb) / 1024 * GBSN;
  console.log(satir(P, `%${pay * 100}`, `${Math.round(r.parcaSn)} sn`, r.adim, `${r.ek} sn`,
    `${Math.round(r.toplam)} sn`, `${r.araMb} MB`, r.hata) + bir(maliyet));
}
console.log(`  parcalanmadan: 1 adim, 0 sn ek sure, 0 MB ara durum, 1 hata noktasi — ama tek kosum ` +
  `sinirin ${(d.sn / SURE_SINIRI).toFixed(2)} kati oldugu icin calismaz`);
const g = ISLER['gece toplu is'], rg = parcala(g.sn, 0.8);
console.log(`  ayni %80 payla "gece toplu is" (${g.sn} sn): ${rg.adim} adim, ${rg.ek} sn ek sure, ` +
  `${rg.araMb} MB ara durum, ${rg.hata} hata noktasi`);

// Kalici baglanti: is parcalanamaz, baglanti kopar. Bedeli yeniden baglanma sayisiyla olculur.
const b = ISLER['kalici baglanti tutan servis'];
const kopma = Math.ceil(AY_SN / SURE_SINIRI) * b.baglanti;
console.log(`\n"kalici baglanti tutan servis": ${b.baglanti} baglanti, ortalama omur ${b.sn} sn`);
console.log(`  sinir ${SURE_SINIRI} sn oldugundan her baglanti ayda ${Math.ceil(AY_SN / SURE_SINIRI)} kez kopar: ` +
  `${kopma.toLocaleString('tr-TR')} yeniden baglanma; oturum durumu her seferinde disaridan okunur`);

// Surekli yukte basabas: hangi istek/sn'de kiralik makine ucuzlar.
const y = ISLER['yuksek ve surekli yuk'];
const Y = [12, 14, 14, 14, 10];
console.log('\nsurekli yukte basabas — istek/sn taranir');
console.log(satir(Y, 'istek/sn', 'es zamanli is', 'sunucusuz/ay', 'makine/ay', 'makine') + 'hangisi ucuz');
for (const r of [1, 10, 28, 100, 400]) {
  const i = { ...y, ay: Math.round(r * AY_SN), eszaman: Math.ceil(r * y.sn) };
  const s = sunucusuzAy(i), m = makineAy(i);
  console.log(satir(Y, r, i.eszaman, bir(s), bir(m), Math.max(1, Math.ceil(i.eszaman / MAKINE_ESZAMAN))) +
    (s < m ? 'sunucusuz' : 'kiralik makine'));
}
```

```
"uzun suren donusturme" 4200 sn, sinir 900 sn, ara durum 240 MB, sinir basina yazma 18 sn + okuma 12 sn
sinir payi  parca suresi  adim    ek sure    toplam sure  ara durum     hata noktasi  aylik birim
%40         353 sn        13      360 sn     4560 sn      2880 MB       25            13.95
%60         497 sn        9       240 sn     4440 sn      1920 MB       17            13.59
%80         630 sn        7       180 sn     4380 sn      1440 MB       13            13.40
%95         730 sn        6       150 sn     4350 sn      1200 MB       11            13.31
  parcalanmadan: 1 adim, 0 sn ek sure, 0 MB ara durum, 1 hata noktasi — ama tek kosum sinirin 4.67 kati oldugu icin calismaz
  ayni %80 payla "gece toplu is" (2700 sn): 4 adim, 90 sn ek sure, 720 MB ara durum, 7 hata noktasi

"kalici baglanti tutan servis": 800 baglanti, ortalama omur 1500 sn
  sinir 900 sn oldugundan her baglanti ayda 2880 kez kopar: 2.304.000 yeniden baglanma; oturum durumu her seferinde disaridan okunur

surekli yukte basabas — istek/sn taranir
istek/sn    es zamanli is sunucusuz/ay  makine/ay     makine    hangisi ucuz
1           1             2.50          70.08         1         sunucusuz
10          1             25.01         70.08         1         sunucusuz
28          3             70.04         70.08         1         sunucusuz
100         9             250           70.08         1         kiralik makine
400         36            1001          70.08         1         kiralik makine
```

Parçalama taraması şunu söylüyor: **parçalamanın bedeli işi yavaşlatmak değildir**. En kötü ayarda
bile toplam süre dört bin iki yüzden dört bin beş yüz altmış saniyeye çıkıyor, yüzde sekiz virgül
altı. Asıl fatura öteki üç sütunda. Sınır payı yüzde kırka çekildiğinde adım sayısı on üçe, ara
durum iki bin sekiz yüz seksen megabayta, hata noktası yirmi beşe çıkıyor; yüzde doksan beşte
bunlar altı adıma, bin iki yüz megabayta ve on bir hata noktasına iner — ama sınıra yaklaşmak,
süresi biraz uzayan bir parçanın sınırı aşması demektir.

Yani parçalama, tek hata noktalı bir işi on bir ile yirmi beş hata noktalı bir işe çevirir ve
aradaki her noktada bir ara durumun yazılıp okunmasına, dolayısıyla kalıcı bir depoya bağımlı hale
getirir. Aynı yüzde seksen ayarında gece toplu iş dört adım, doksan saniye ek süre, yedi yüz yirmi
megabayt ara durum ve yedi hata noktası ödüyor. Bunlar sunucusuzun kısıtından doğan, işin kendisinde
bulunmayan kalemlerdir.

Kalıcı bağlantı satırı parçalamanın sınırını gösteriyor. Bu iş **parçalanamaz**: sınıra gelindiğinde
kesilen şey hesaplama değil bağlantıdır. Sekiz yüz bağlantı ayda iki milyon üç yüz dört bin kez
kopar ve her koptuğunda oturum durumu dışarıdan yeniden okunur. Buradaki bedel bir yavaşlama değil,
bir tasarım değişikliğidir.

Başabaş taraması son ekseni bir sayıya bağlıyor. Saniyede yirmi sekiz isteğe kadar sunucusuz
ucuzdur; sonrasında kiralık makine ucuzlar ve dört yüz istekte fark on dört kata çıkar. Bu sayı
yedekliliği ve işletim emeğini saymıyor, yani gerçek başabaş noktası yirmi sekizin üstündedir.
Ölçünün söylediği şudur: sunucusuzun maliyet avantajı **doluluk oranıyla ters orantılıdır**.

#### Hangi İş Uyar, Hangisi Uymaz

| İş türü | Uyar mı | Eşiği aşan kalem | Dolaşmanın bedeli |
|---|---|---|---|
| Kısa ve seyrek istek | **Uyar** | yok | yok — aylık 0,03 birim, makinenin 2.400'de biri |
| Gece toplu iş | **Parçalanırsa uyar** | süre sınırı: 2.700 sn, sınırın 3 katı | 4 adım, 90 sn, 720 MB ara durum, 7 hata noktası |
| Uzun süren dönüştürme | **Zorlanır** | süre sınırı: 4.200 sn, sınırın 4,67 katı + bellekte durum | 7 adım, 180 sn, 1.440 MB ara durum, 13 hata noktası |
| Kalıcı bağlantı tutan servis | **Uymaz** | bağlantı ömrü 900 sn < 1.500 sn + oturum durumu + maliyet 251 kat | parçalanamaz; ayda 2.304.000 yeniden bağlanma |
| Yüksek ve sürekli yük | **Uymaz** | birim maliyet: 28 istek/sn üstünde makine ucuzlar, 400'de 14 kat | yok — kısıt maliyettir, tasarımla dolaşılamaz |

#### Özet

- Kısa ve seyrek istek sunucusuzda aylık sıfır virgül sıfır iki sekiz birim tutar, kiralık makinenin
  iki bin dört yüzde biri; sürekli açık makine bu işin neredeyse tamamında boş bekler.
- Gece toplu iş ve uzun süren dönüştürme maliyette kazanır ama süre sınırını üç ve dört virgül
  altmış yedi kat aşar; dönüştürme ayrıca durumu bellekte tutar.
- Kalıcı bağlantı tutan servis üç kalemi birden aşar ve sunucusuz karşılığı kiralık makinenin iki
  yüz elli bir katıdır; bağlantı beklerken de ücretlendirilir.
- Parçalamanın bedeli süre değildir: toplam süre en fazla yüzde sekiz virgül altı uzar. Bedel adım
  sayısı, ara durum ve hata noktasıdır — dönüştürmede altı ile on üç adım, bin iki yüz ile iki bin
  sekiz yüz seksen megabayt ve on bir ile yirmi beş hata noktası.
- Kalıcı bağlantı parçalanamaz: sınırda kesilen hesaplama değil bağlantıdır, ayda iki milyon üç yüz
  dört bin yeniden bağlanma demektir.
- Sürekli yükte başabaş noktası saniyede yirmi sekiz istektir; üstünde kiralık makine ucuzlar, dört
  yüz istekte fark on dört kat. Sunucusuzun maliyet avantajı doluluk oranıyla ters orantılıdır.

#### Sonraki Adım

İşlevin sınırları sayıldı: süresi, belleği, eşzamanlılığı, paketi, yayını, geri alması ve nerede
kullanılamayacağı. Bu konu boyunca ölçülen her şey **tek bir işleve** aitti — bir istek girdi, bir
yanıt çıktı, arada bir sınır vardı. Oysa ölçüm ağının hiçbir işi tek işlevle bitmiyor: okuma gelince
doğrulama tetikleniyor, doğrulama bitince fatura üretiliyor, fatura üretilince bildirim gidiyor. Bu
zincirin kendisi hiç ölçülmedi. İşlevler birbirine nasıl bağlanacak — biri ötekini doğrudan mı
çağıracak, yoksa aralarına bir şey mi girecek? Sonraki konu bağlantının kendisini ölçer.

## Olay Güdümlü Yönetilen Servisler

İşlevleri birbirine bağlayan katman: olay veri yolunun yönlendirme ve süzme kuralları, kuyruk ile konu servislerinin teslim garantisi farkı, adım tabanlı durum makineleriyle iş akışı orkestrasyonu, zamanlanmış tetiklemenin kaçırılan koşum ve üst üste binme davranışı, uç nokta yönetimi ve yetkilendirme yapan geçit servisi ile gönderim itibarını yöneten bildirim servisleri.

### Olay Veri Yolu

Source: https://academia.sh/tr/kurslar/sunucusuz/olay-veri-yolu

Yönlendirme kararının veri yoluna devredilmesi: aynı iki bin olaylık akışta kural kümesi genişledikçe hiçbir kurala uymayan ve birden çok hedefe giden olay sayısının taranması, süzgecin kuralda mı hedefte mi durduğunun taşınan olay sayısına etkisi ve yeni bir kuralın hiçbir sayıyı bozmadan trafik almasının ölçülmesi.

Önceki ders işlevin sınırlarını saydı ve nerede kullanılamayacağını yazdı. Geriye tek bir soru
kaldı: işlevler birbirine nasıl bağlanacak? Bir işlev kendi başına hiçbir şey yapmaz; bir şeyin
onu uyandırması gerekir. Uyandıran taraf çağıran işlevse, çağıranın hedefi bilmesi gerekir —
adresi, sürümü, kaç tane olduğu. Üretici sayısı arttıkça bu bilgi her üreticide ayrı ayrı
çoğalır.

**Olay veri yolu** (event bus) bu bağı tersine çevirir. Üretici olayı yazar ve kime gideceğini
bilmez; hedefi **kural** (rule) seçer. Karar üreticiden alınıp veri yoluna devredilmiştir. Bu
ders devredilen kararın karşılığında ne geldiğini sayar.

#### Devredilen Karar: Kimin Uyanacağı

Doğrudan çağrıda hedef listesi kodun içindedir: kim kimi çağırıyor, çağrı yığınından okunur.
Kural tabanlı yönlendirmede hedef listesi kodun dışındadır — kural bir **veri** kalemidir.
Karşılığında gelen kısıt buradan doğar: yönlendirme artık kaynak deposundaki farkta görünmez,
işlevin çağrı çizgesinde durmaz ve bir olayın nereye gittiği ancak kural kümesi okunarak
bilinir.

Devredilen kararın ilk karşılığı bağ sayısındadır. Ölçüm ağında olay üreten altı bileşen ve
olayla iş yapan dokuz hedef var. Doğrudan çağrıda her üretici ilgilendiği hedefleri bilmek
zorundadır: en kötü durumda 54 bağ, her biri iki tarafta da tutulan bir adres ve bir sürüm.
Veri yolunda üretici tek bir yere yazar, hedefler tek bir yerden okur — 6 + 9 = 15 kayıt ve
aralarında bir kural kümesi. Bağ sayısı çarpımdan toplama iner. Kısıt de aynı yerden gelir:
54 bağın hepsi kodda görünürdü, kural kümesindeki hiçbir kalem kodda değildir.

İkinci kısıt eşleşmenin kendisindedir. Bir olay hiçbir kurala uymazsa veri yolunun öntanımlı
davranışı onu **düşürmektir**; hata üretmez, kimseyi uyandırmaz, geriye iz bırakmaz. Üçüncüsü
tersidir: bir olay birden çok kurala uyarsa her kural kendi hedefini uyandırır ve aynı olay
birden çok kez işlenir. İkisi de kural kümesinin genişliğine bağlıdır, ikisi de bir sayıdır.

Ölçüm, ders boyunca sürecek kurgu bir düzenek üzerinde yapılır: **bölgesel ölçüm ağı** —
sayaçların okumalarını gönderdiği, okumaların doğrulandığı, fatura üretilen ve saha ekiplerine
iş atanan bir sistem. Ağ da, olay adları da kurgudur.

- **OS1.** Akış 2.000 olaydır; olay türleri dokuz kalemdir ve türlerin payı sabittir.
- **OS2.** Her olayın üç alanı vardır: tür, bölge (dört bölge), öncelik (1–3).
- **OS3.** Kural, nokta ile ayrılmış bir tür deseni ve isteğe bağlı alan koşullarıdır; desendeki
  `*` o bölümden sonrasını serbest bırakır.
- **OS4.** Bir olay aynı hedefe iki kuraldan uyarsa tek teslim sayılır; teslim hedef başınadır.
- **OS5.** Rastgelelik gerektiren yerlerde üreteç kendi yazılır ve tohum görünürdür.
- **OS6.** Model yalnız yönlendirme kararını kurar; taşıma gecikmesi ve sıra ölçülmez.

#### Kural Kümesi Genişledikçe

Aşağıdaki kod bir veri yolu değil, yönlendirme kararının sayılabilir bir modelidir. Aynı akış
üç kural kümesinden geçirilir: dört kurallı **dar**, yedi kurallı **orta**, on kurallı ve bir
yakala-tümü kuralı içeren **geniş**.

```js
// kural-motoru.mjs — olay veri yolu modeli: kurallar deseni tutan olaylari hedeflere yonlendirir
// Model: gercek bir veri yolu degil, yonlendirme kararinin sayilabilir bicimde yeniden kurulmasi.

const TOHUM = 20260415;                       // uretec tohumu: kosum tekrarlanabilir
let durum = TOHUM;
const rastgele = () => (durum = (durum * 1103515245 + 12345) % 2147483648) / 2147483648;

const TURLER = [["olcum.okuma.alindi", 46], ["olcum.okuma.eksik", 9],
  ["olcum.dogrulama.basarisiz", 7], ["fatura.taslak.olustu", 12], ["fatura.kesinlesti", 6],
  ["cihaz.pil.dusuk", 8], ["cihaz.baglanti.koptu", 5], ["saha.ekip.atandi", 4],
  ["saha.ariza.kapandi", 3]];
const BOLGELER = ["kuzey", "dogu", "bati", "merkez"];

function olaylar(n) {
  const liste = [];
  for (let i = 0; i < n; i++) {
    let p = rastgele() * 100, tur = TURLER[0][0];
    for (const [ad, agirlik] of TURLER) { if ((p -= agirlik) < 0) { tur = ad; break; } }
    liste.push({ tur, bolge: BOLGELER[Math.floor(rastgele() * 4)],
                 oncelik: 1 + Math.floor(rastgele() * 3) });
  }
  return liste;
}

// Desen: nokta ile ayrilmis bolumler; "*" o bolumden sonrasini serbest birakir.
function tutuyor(desen, tur) {
  const d = desen.split("."), t = tur.split(".");
  for (let i = 0; i < d.length; i++) {
    if (d[i] === "*") return true;
    if (d[i] !== t[i]) return false;
  }
  return d.length === t.length;
}
const uyuyor = (k, o) => tutuyor(k.desen, o.tur) &&
  (k.bolge === undefined || k.bolge === o.bolge) &&
  (k.enAz === undefined || o.oncelik >= k.enAz);

const K = {
  dar: [
    { ad: "K1", desen: "olcum.okuma.alindi", hedef: "dogrulama" },
    { ad: "K2", desen: "fatura.*", hedef: "fatura" },
    { ad: "K3", desen: "cihaz.pil.dusuk", hedef: "bakim" },
    { ad: "K4", desen: "saha.*", hedef: "saha" }],
};
K.orta = [...K.dar,
  { ad: "K5", desen: "olcum.*", hedef: "arsiv" },
  { ad: "K6", desen: "cihaz.*", hedef: "izleme" },
  { ad: "K7", desen: "olcum.dogrulama.basarisiz", bolge: "kuzey", hedef: "uyari" }];
K.genis = [...K.orta,
  { ad: "K8", desen: "*", hedef: "denetim" },
  { ad: "K9", desen: "fatura.kesinlesti", hedef: "muhasebe" },
  { ad: "K10", desen: "olcum.okuma.alindi", enAz: 3, hedef: "oncelikli" }];

const AKIS = olaylar(2000);

function tara(kurallar) {
  let eslesmeyen = 0, tek = 0, cok = 0, teslim = 0;
  for (const o of AKIS) {
    const h = new Set(kurallar.filter((k) => uyuyor(k, o)).map((k) => k.hedef));
    teslim += h.size;
    if (h.size === 0) eslesmeyen++; else if (h.size === 1) tek++; else cok++;
  }
  return { eslesmeyen, tek, cok, teslim };
}

console.log("kume    kural  eslesmeyen  tek hedef  cok hedef  toplam teslim");
for (const ad of ["dar", "orta", "genis"]) {
  const s = tara(K[ad]);
  console.log(ad.padEnd(8) + String(K[ad].length).padStart(5) +
    String(s.eslesmeyen).padStart(12) + String(s.tek).padStart(11) +
    String(s.cok).padStart(11) + String(s.teslim).padStart(15));
}
console.log("olay sayisi: " + AKIS.length + ", tohum: " + TOHUM);
```

```sh
node kural-motoru.mjs
```

```
kume    kural  eslesmeyen  tek hedef  cok hedef  toplam teslim
dar         4         433       1567          0           1567
orta        7           0        881       1119           3119
genis      10           0          0       2000           5551
olay sayisi: 2000, tohum: 20260415
```

İlk satır sessiz düşmeyi gösteriyor. Dört kural iki bin olayın 1.567'sini bir hedefe verdi;
**433 olay hiçbir kurala uymadı** ve düşürüldü. Bu olaylar eksik okuma, doğrulama hatası ve
kopan bağlantı bildirimleridir — yani en çok bakılması gereken üç türden ikisi. Düşme bir hata
değildir; veri yolu için "eşleşme yok" olağan bir sonuçtur. Üretici tarafında da bir belirti
yoktur: olay yazıldı, kabul edildi, iş bitti.

İkinci satır kısıtın öbür ucudur. Üç kural eklenince eşleşmeyen sıfıra indi, ama **1.119 olay
birden çok hedefe** gitti ve toplam teslim 1.567'den 3.119'a çıktı. Aynı okuma hem doğrulama
hem arşiv hedefini uyandırıyor. İki hedef ayrı iş yapıyorsa bu doğrudur; ikisi de fatura
kalemi yazıyorsa aynı kalem iki kez yazılır. Kural kümesi bu farkı bilmez.

Bu iki satır arasındaki geçiş, kural kümesi genişletilirken izlenen olağan yoldur: eşleşmeyen
bir olay fark edilir, desen genişletilir, eşleşmeyen sayısı düşer. Düşen tek şey o değildir —
her genişletme, daha önce tek hedefe giden olayları da yeni kurala uygun hale getirir. Dört
kuralda hiçbir olay çok hedefli değilken, üç kural eklendikten sonra akışın yüzde 56'sı çok
hedeflidir. Genişletmenin etkisi yalnız hedeflenen türle sınırlı kalmaz; desen, hedeflenmeyen
türleri de kapsar.

Üçüncü satırda yakala-tümü kuralı eşleşmeyeni sıfırda tutuyor, ama artık **her olay çok
hedefli**: 2.000 olay 5.551 teslime, olay başına 2,78 uyandırmaya dönüştü. Sessiz düşmeden
kaçmanın bedeli üç kat teslimdir ve teslim, işlev tarafında çağrı demektir.

#### Süzgecin Yeri

Yönlendirme kararı devredilince ikinci bir karar da devredilebilir: **süzme**. Doğrulama hedefi
gerçekte yalnız kuzey bölgesinin öncelikli okumalarıyla ilgilenir. Bu koşul ya kuralın içine
yazılır ya da hedefin ilk satırlarına. İkisi de aynı işi yapar; taşınan olay sayısı aynı
değildir.

```js
// suzgec-yeri.mjs — ayni akis, suzgec kuralda ve hedefte; sonra gorunmeyen bir kural eklenir
const TOHUM = 20260415;                       // ilk kosumla ayni tohum, ayni akis
let durum = TOHUM;
const rastgele = () => (durum = (durum * 1103515245 + 12345) % 2147483648) / 2147483648;
const TURLER = [["olcum.okuma.alindi", 46], ["olcum.okuma.eksik", 9],
  ["olcum.dogrulama.basarisiz", 7], ["fatura.taslak.olustu", 12], ["fatura.kesinlesti", 6],
  ["cihaz.pil.dusuk", 8], ["cihaz.baglanti.koptu", 5], ["saha.ekip.atandi", 4],
  ["saha.ariza.kapandi", 3]];
const BOLGELER = ["kuzey", "dogu", "bati", "merkez"];
const AKIS = [];
for (let i = 0; i < 2000; i++) {
  let p = rastgele() * 100, tur = TURLER[0][0];
  for (const [ad, agirlik] of TURLER) { if ((p -= agirlik) < 0) { tur = ad; break; } }
  AKIS.push({ tur, bolge: BOLGELER[Math.floor(rastgele() * 4)],
              oncelik: 1 + Math.floor(rastgele() * 3) });
}

const ilgili = (o) => o.bolge === "kuzey" && o.oncelik >= 2;   // hedefin gercekten istedigi
const okuma = AKIS.filter((o) => o.tur === "olcum.okuma.alindi");
const BIRIM = 1000;                            // kurgu birim: her 1000 teslim 1 tasima birimi

console.log("suzgecin yeri".padEnd(16) + "tasinan".padStart(8) +
  "bosa uyandirma".padStart(16) + "tasima birimi".padStart(15));
for (const [yer, tasinan] of [["suzgec kuralda", okuma.filter(ilgili)], ["suzgec hedefte", okuma]]) {
  const bosa = tasinan.length - tasinan.filter(ilgili).length;
  console.log(yer.padEnd(16) + String(tasinan.length).padStart(8) + String(bosa).padStart(16) +
    (tasinan.length / BIRIM).toFixed(2).padStart(15));
}

// Gorunmeyen kural: mevcut hedefin sayilarina dokunmadan ayni olaylari ikinci bir hedefe verir.
const oncesi = okuma.filter(ilgili).length;
const golge = AKIS.filter((o) => o.tur.startsWith("olcum.okuma.")).length;
console.log("\nkural eklemeden once  dogrulama hedefi: " + oncesi + ", toplam teslim: " + oncesi);
console.log("K11 eklendikten sonra dogrulama hedefi: " + oncesi + ", toplam teslim: " +
  (oncesi + golge) + ", hata: 0");
```

```sh
node suzgec-yeri.mjs
```

```
suzgecin yeri    tasinan  bosa uyandirma  tasima birimi
suzgec kuralda       145               0           0.14
suzgec hedefte       926             781           0.93

kural eklemeden once  dogrulama hedefi: 145, toplam teslim: 145
K11 eklendikten sonra dogrulama hedefi: 145, toplam teslim: 1257, hata: 0
```

Süzgeç kuralda durunca 145 olay taşındı ve hepsi işlendi. Hedefte durunca 926 olay taşındı,
**781'i ilk satırda elendi**: işlev uyandı, olayı okudu, ilgisiz olduğunu gördü, döndü. Aynı
işin görünen maliyeti taşıma tarafında 0,14 birime karşı 0,93 birim — 6,4 kat. Birim kurgudur;
oran kural kümesinden çıkar.

Boşa uyandırmanın bedeli yalnız taşıma değildir. 781 çağrı eşzamanlılık havuzundan pay alır,
soğuk başlangıç ihtimalini taşır ve işlev tarafındaki her ölçüte gürültü olarak girer: çağrı
sayısı, hata oranı, ortalama süre. Süzgeci kurala taşımanın bedeli ise koşulun kod
incelemesinden çıkıp yapılandırmaya geçmesidir — bir sonraki bölümün konusu.

Kaynakta süzmenin bir sınırı var ve bu sınır ölçümün dışında kalan asıl kısıttır: süzgeç yalnız
olayın kendi alanlarına bakabilir. Doğrulama hedefi "yalnız sözleşmesi askıya alınmış
aboneliklerin okumaları" isteseydi, bu koşul olayda taşınan üç alandan hiçbiriyle
yazılamazdı — aboneliğin durumu başka bir yerde tutulur. O durumda tek yol, koşulu ilgilendiren
alanı olaya eklemektir; bedeli, üreticinin artık tüketicinin ihtiyacını bilmesi, yani devredilen
bağın bir ucundan geri gelmesidir. Alan eklenemiyorsa 781 boşa uyandırma kaçınılmazdır ve
seçim, süzgecin yeri değil, hangi maliyetin kabul edileceğidir.

#### Kuralın Görünmezliği Bir Yüzeydir

Çıktının son iki satırı tek bir şey gösteriyor. Kural kümesine, doğrulama hedefine dokunmayan
yeni bir kural eklendi: `olcum.okuma.*` desenli K11, olayları ikinci bir hedefe veriyor.
Doğrulama hedefinin teslim sayısı **145'te kaldı**, hata sayısı sıfır kaldı, hiçbir ölçüt
kıpırdamadı.
Toplam teslim ise 145'ten 1.257'ye çıktı — akıştaki bütün okuma olayları artık ikinci bir yere
de gidiyor.

Bu, yönlendirmeyi devretmenin en pahalı kısıtıdır. Kural bir veri kalemi olduğu için:

- Kaynak deposundaki farkta görünmez; işlev kodunda tek satır değişmez.
- Var olan hedeflerin ölçütlerini bozmaz, dolayısıyla hiçbir uyarı eşiğini aşmaz.
- Yeni hedefe giden olayların içeriği üreticinin niyetinden bağımsızdır: üretici okumayı
  doğrulama için yazmıştı, kural onu başka bir yere de verdi.

Aynı görünmezlik ters yönde de çalışır. Bir kural silindiğinde ya da deseni daraltıldığında
hedef trafik almayı bırakır; işlev hata vermez, çünkü hiç çağrılmaz. Çağrı sayısı sıfıra iner
ve sıfır, bir arıza belirtisi gibi değil, "bu saatte iş yok" gibi okunur. Birinci ölçümdeki
433 sessiz düşme ile bu durum arasında hiçbir gözlemsel fark yoktur: ikisinde de olay yazılmış,
kabul edilmiş ve hiçbir yere gitmemiştir. Aradaki farkı görebilmenin tek yolu, üretilen olay
sayısı ile teslim edilen olay sayısını ayrı ayrı sayıp aralarındaki farkı izlemektir.

Kısıtın etrafından dolaşmanın üç yolu var ve üçü de sayılabilir bir bedel ister. Birincisi,
kural kümesini kaynak deposunda tutup değişiklikleri kod gibi incelemektir; bedeli, her kural
değişikliğinin yayın hattına girmesi ve dakikalar süren bir işlemin saatlere yayılmasıdır.
İkincisi hedef başına teslim sayacı tutmaktır; K11 eklendiğinde toplam teslimin 145'ten
1.257'ye çıkması ancak böyle görülür ve bedeli, on kurallı bir kümede on ayrı sayaç ile bunları
okuyan bir eşik kümesidir. Üçüncüsü desen genişliğini yasaklamaktır — yakala-tümü kuralı
kaldırılır, `*` yalnız son bölümde kullanılır. Bunun bedeli birinci ölçümdeki ilk satırdır:
desen daraldıkça eşleşmeyen olay sayısı yeniden yükselir ve 433 olay sessizce düşer.

Üçü arasında seçim yapılırken bakılacak sayı, düşen olayın maliyeti ile fazladan teslimin
maliyetinin karşılaştırılmasıdır. Ölçüm ağında düşen bir doğrulama hatası faturaya yanlış
tüketim olarak yansır; fazladan bir arşiv teslimi yalnız depolama yazar. Bu ağda kural kümesi
geniş, süzgeç kuralda, sayaç hedef başınadır.

#### Özet

- Olay veri yolu yönlendirme kararını üreticiden alır: üretici hedefi bilmez, hedefi kural
  seçer. Karşılığında kural bir veri kalemi olur ve kod incelemesinin dışına çıkar.
- Aynı 2.000 olaylık akışta dört kurallı küme 433 olayı hiçbir hedefe vermedi ve bunu hata
  üretmeden yaptı; sessiz düşme veri yolunun öntanımlı davranışıdır.
- Kural sayısı yediye çıkınca eşleşmeyen sıfırlandı ama 1.119 olay çok hedefli oldu; on kurallı
  kümede toplam teslim 5.551'e, olay başına 2,78 uyandırmaya çıktı.
- Süzgeç kuralda 145 olay taşıdı, hedefte 926 olay taşıdı ve bunların 781'i işlevi boşuna
  uyandırdı; taşıma tarafındaki fark 0,14 birime karşı 0,93 kurgu birimdir.
- Yeni bir kural, var olan hedefin teslim sayısını 145'te bırakıp toplam teslimi 1.257'ye
  çıkardı ve hiçbir hata üretmedi; kuralın görünmezliği bu yüzden bir yüzeydir.
- Sessiz düşme ile silinmiş kural aynı belirtiyi verir: her ikisinde de çağrı sayısı sıfırdır.
  Aradaki farkı ayırt etmenin yolu, üretilen olay sayısı ile teslim sayısını ayrı saymaktır.

#### Sonraki Adım

Yönlendirme kararı verildi: hangi olayın kimi uyandıracağı artık kural kümesinde yazılı. Ama
bu ölçümde bir şey hiç sorulmadı — hedef uyandığında **ayakta değilse** ne olur? Model her
teslimi başarılı saydı; oysa işlev kısılabilir, hata verebilir, eşzamanlılık sınırına çarpabilir.
Olayı tutan, yeniden deneyen ve tüketici hazır olana kadar bekleten bir katman gerekir. Sonraki
ders bu katmanı hizmet olarak ölçer: kuyruk ve konu servisleri devralındığında hangi kararlar
elden çıkar, görünürlük süresi hangi eşikte çift işleme, hangi eşikte gecikme üretir.

### Kuyruk ve Konu Servisleri

Source: https://academia.sh/tr/kurslar/sunucusuz/kuyruk-ve-konu-servisleri

Kuyruğun hizmet olarak alınmasının getirdiği kısıtlar: geriye kalan beş yapılandırma kaleminin sayılması, görünürlük süresinin altı değerde taranarak kısa sürenin ürettiği çift işleme ile uzun sürenin ürettiği kurtarma gecikmesinin ölçülmesi, ölü mektup kutusuna düşme süresinin türetilmiş bir sayı olması ve kuyruk ile konu arasındaki fan-out farkının teslim ve yapılandırma kalemi cinsinden karşılaştırılması.

Önceki ders olayları kurallara göre hedeflere yönlendirdi ve her teslimi başarılı saydı. Gerçek
akışta bu varsayım tutmaz: hedef kısılmış olabilir, hata verebilir, hiç ayakta olmayabilir.
Aradaki tamponu **kuyruk servisi** kurar — olayı tutar, tüketici hazır olana kadar bekletir,
başarısız işi yeniden görünür kılar.

Kuyruğun mekaniği yeni değildir. Eşzamansız İşleme kursunun Teslim Semantiği dersi onay ile
etkinin sırasını ölçtü ve en az bir kez ile tekilleştirmenin farkını sayılarla gösterdi; o ölçüm
burada tekrarlanmaz ve sonuçları veri olarak alınır. Bu dersin sorusu başkadır: kuyruk kendi
işlettiğin bir aracı değil de **bir hizmet** olduğunda ne değişir?

#### Devredilen Kararlar ve Geriye Kalan Yüzey

Hizmet olarak alınan bir kuyrukta şu kararlar elden çıkar: kaç düğüm çalışacağı, iletinin kaç
kopyayla saklanacağı, diskin nereye yazacağı, sürümün ne zaman yükseltileceği, kuyruk derinliği
arttığında kaç tüketicinin ekleneceği. Sonuncusu en önemlisidir; kuyruk servisi işlev
çalıştırma ortamına bağlandığında ölçekleme kararı da devredilir — derinlik arttıkça örnek
eklenir, azaldıkça silinir.

Devredilen ölçekleme kararının bedeli, artışın **hızının** da elden çıkmasıdır. Kuyruğa bir
anda 400 ileti düştüğünde kaç örneğin ne kadar sürede ekleneceğini belirleyen kural hizmetin
içindedir; dışarıdan görünen tek şey bir tavan sayısıdır. Bu, iki yönlü bir kısıt üretir. Artış
yavaşsa gece toplu işi beklenenden geç biter ve kuyruk derinliği saatlerce yüksek kalır. Artış
hızlıysa aynı anda uyanan yüzlerce örnek, arkadaki veritabanının bağlantı havuzunu tüketir —
kuyruk kendi ölçeğini bulur, ama bulduğu ölçek aşağı akıştaki bir kısıtı aşar. Kuyruk
derinliğine bakan bir tüketici sayısını kendi ayarlamak bu ikisini de çözerdi; devredilen
kararla birlikte o kol da gitmiştir. Geriye kalan tek denetim, tavanın kendisini düşürmektir ve
bunun bedeli birinci durumun kalıcı hale gelmesidir.

Geriye kalan yüzey küçüktür ve sayılabilir. Bu derste kullanılan modelde kuyruk başına beş
kalem vardır: **görünürlük süresi**, **azami teslim sayısı**, **ölü mektup kutusu**, **saklama
süresi**, **yığın boyu**. Beş kalem, devredilen onca kararın karşılığında elde kalan tüm
denetimdir. Kısıt buradadır: ayarlanamayan hiçbir şey düzeltilemez de. Saklama süresi dolan
ileti silinir ve bu silme, önceki dersteki eşleşmeyen olay gibi, sessizdir.

Ölçüm yine kurgu **bölgesel ölçüm ağı** üzerinde yapılır: sayaç okumaları bir kuyruğa yazılır,
doğrulama işlevi kuyruktan okur, doğrulanan okuma fatura akışına girer.

- **OS7.** İş yükü 400 iletidir; işleme süresi üç kümede toplanır — olağan doğrulama 2–6 birim,
  toplu okuma 12–31 birim, gecikmiş yığın 40–69 birim.
- **OS8.** İletilerin 12'si zehirlidir (her denemede başarısız), 16'sında tüketici işi
  bitirmeden ölür; iki küme çakışmaz ve konum olarak sabittir.
- **OS9.** Azami teslim sayısı 5'tir; bu sayıya ulaşan ileti ölü mektup kutusuna taşınır.
- **OS10.** Görünürlük süresi dolduğunda ileti yeniden görünür olur; hâlâ çalışan tüketici
  durdurulmaz, yani ikinci tüketici işi **koşut olarak** yeniden yapar.
- **OS11.** Süre birimi kurgudur; ölçülen şey oranlardır, saniye değildir.
- **OS12.** Model yalnız tek bir kuyruğu kurar; sıra, bölümleme ve taşıma gecikmesi ölçülmez.

#### Görünürlük Süresi

**Görünürlük süresi** (visibility timeout), bir tüketici iletiyi aldıktan sonra iletinin
kuyrukta ne kadar gizli kalacağıdır. Tüketici bu süre içinde işi bitirip iletiyi silerse iş
biter; bitiremezse ileti yeniden görünür olur ve başka bir tüketici onu alır. Tek sayıdır ve
iki ayrı şeyi birden belirler: yavaş işin ne zaman ikinci kez başlatılacağını ve ölü tüketicinin
elindeki işin ne zaman kurtarılacağını. Bu iki gereksinim ters yönlere çeker; aşağıdaki tarama
ikisini de aynı iş yükü üzerinde sayar.

```js
// gorunurluk.mjs — kuyruk servisi modeli: gorunurluk suresi degisince ne olur
// Model: gercek bir kuyruk degil, hizmetin tek ayarinin sonuclarinin sayilmasi.
const TOHUM = 20260518;                        // uretec tohumu: kosum tekrarlanabilir
let d = TOHUM;
const r = () => (d = (d * 1103515245 + 12345) % 2147483648) / 2147483648;

const N = 400, AZAMI = 5;                      // AZAMI teslimden sonra ileti olu mektup kutusuna
const ILETI = [];
for (let i = 0; i < N; i++) {
  const p = r();
  const sure = p < 0.88 ? 2 + Math.floor(r() * 5)        // olagan dogrulama: 2-6 birim
             : p < 0.97 ? 12 + Math.floor(r() * 20)      // toplu okuma: 12-31 birim
             : 40 + Math.floor(r() * 30);                // gecikmis yigin: 40-69 birim
  ILETI.push({ sure, zehirli: i % 33 === 7, coken: i % 25 === 3 });   // ikisi hic cakismaz
}
const ZEHIRLI = ILETI.filter((i) => i.zehirli).length;
const COKEN = ILETI.filter((i) => i.coken).length;

function kosum(T) {
  let teslim = 0, cift = 0, bekleme = 0;
  for (const i of ILETI) {
    if (i.zehirli) { teslim += AZAMI; continue; }         // her denemede yeniden basarisiz
    if (i.coken) { teslim += 2; bekleme += T; continue; } // tuketici oldu: T kadar gizli kalir
    const tur = Math.ceil(i.sure / T);                    // T dolmadan bitmeyen is yeniden gorunur
    teslim += tur;
    if (tur > 1) cift++;
  }
  return { teslim, cift, bekleme: bekleme / COKEN, olu: AZAMI * T };
}

console.log("gorunurluk".padEnd(12) + "cift isleme".padStart(12) + "toplam teslim".padStart(15) +
  "kurtarma gecikmesi".padStart(20) + "olu kutuya dusme".padStart(18));
for (const T of [5, 10, 20, 30, 60, 120]) {
  const s = kosum(T);
  console.log(String(T).padEnd(12) + String(s.cift).padStart(12) + String(s.teslim).padStart(15) +
    s.bekleme.toFixed(0).padStart(20) + String(s.olu).padStart(18));
}
const ENUZUN = Math.max(...ILETI.map((i) => i.sure));
console.log(`ileti: ${N}, zehirli: ${ZEHIRLI}, tuketicisi coken: ${COKEN}, ` +
  `en uzun is: ${ENUZUN} birim, tohum: ${TOHUM}`);
```

```sh
node gorunurluk.mjs
```

```
gorunurluk   cift isleme  toplam teslim  kurtarma gecikmesi  olu kutuya dusme
5                    102            745                   5                25
10                    40            562                  10                50
20                    28            505                  20               100
30                    11            480                  30               150
60                     5            469                  60               300
120                    0            464                 120               600
ileti: 400, zehirli: 12, tuketicisi coken: 16, en uzun is: 69 birim, tohum: 20260518
```

İlk satır kısa sürenin bedelini gösteriyor. Görünürlük süresi 5 birimken **102 ileti çift
işlendi** ve 400 iletilik iş yükü 745 teslime çıktı. Buradaki çift işleme, yeniden denemeden
farklı bir şeydir: birinci tüketici hâlâ çalışırken ileti yeniden görünür olur ve ikinci
tüketici aynı işi **aynı anda** yapar. Ölçüm ağında bu, aynı sayaç okumasının iki kez
doğrulanması ve fatura akışına iki kez girmesi demektir.

Son satır uzun sürenin bedelidir. 120 birimde çift işleme sıfıra iner, ama tüketicisi ölen 16
ileti ortalama **120 birim gizli bekler** — o süre boyunca kuyrukta görünmezdir, hiçbir tüketici
alamaz, hiçbir ölçüt bir şey göstermez. Zehirli iletinin ölü mektup kutusuna düşmesi ise 600
birim sürer.

Bu ayrımın pratik sonucu, koşut çift işlemenin tekilleştirme bekçisini de zorlamasıdır. Bekçi
"bu ileti daha önce işlendi mi" sorusunu sorar; koşut koşumda ikinci tüketici bu soruyu, birinci
tüketici sonucunu henüz yazmadan sorar ve yanıt "hayır" olur. Sıralı yeniden denemede işe
yarayan bekçi burada iki koşumu da geçirir. Çift işlemeyi kapatan şey bekçinin varlığı değil,
bekçinin yazma anındaki tekillik kısıtına dayanmasıdır.

Aradaki kural çıktının son satırından okunur: **en uzun iş 69 birimdir.** Çift işlemenin sıfıra
inmesi için görünürlük süresinin en uzun işi aşması gerekir; 60 birimde hâlâ 5 ileti çift
işleniyor, 120'de sıfır. Yani işleme süresinin kuyruğu, kurtarma gecikmesinin alt sınırını
belirler. Tek bir uzun iş türü, bütün kuyruğun kurtarma davranışını aşağı çeker.

Kısıtın etrafından dolaşmanın yolu, iş sürerken görünürlük süresini uzatmaktır: tüketici
çalıştığını düzenli aralıklarla bildirir, servis de sayacı ileri alır. Bedeli iki kalemdir.
Birincisi, 10 birimlik bir süreyle 69 birimlik bir işi tamamlamak için altı uzatma çağrısı
gerekir — tek iletilik iş yedi isteğe çıkar ve istek başına ücretlendirilen bir hizmette bu
doğrudan faturadır. İkincisi, tüketici artık işini yapmakla kalmaz, kendi ömrünü de yönetir;
uzatmayı unutan ya da uzatma çağrısı hata alan tüketici birinci satırdaki çift işlemeye geri
düşer.

#### Ölü Mektup Kutusunun Otomatikliği

Tablodaki son sütun, hiç kimsenin doğrudan ayarlamadığı bir sayıdır. Zehirli iletinin ölü
mektup kutusuna düşmesi için geçen süre, azami teslim sayısı ile görünürlük süresinin
çarpımıdır: 5 × 30 = 150, 5 × 120 = 600. İki ayrı kalem ayrı gerekçelerle seçilir, üçüncü bir
sayı kendiliğinden ortaya çıkar. Kısıtın en sinsi biçimi budur — ayarlanan şeyle ölçülen şey
aynı değildir.

Hizmet olmanın buradaki kazancı gerçektir: zehirli ileti elle ayıklanmaz, beşinci teslimden
sonra otomatik olarak taşınır ve ana kuyruğu tıkamaz. Modelde 12 zehirli ileti, hangi
görünürlük süresi seçilirse seçilsin, toplam 60 teslim harcayıp yoldan çekilir. Bunun
karşılığında gelen kısıt şudur: **ölü mektup kutusu öntanımlı olarak tüketicisi olmayan bir
kuyruktur.** İleti oraya taşınır, saklanır ve saklama süresi dolunca silinir. Kimse okumazsa
sonuç, önceki dersteki sessiz düşmenin makbuzlu biçimidir — kayıp aynı kayıptır, yalnız bir
yerde yazılıdır.

Kutuyu boşaltmanın yolu iletileri ana kuyruğa geri basmaktır ve bunun da bir sayısı vardır.
Nedeni düzeltilmeden geri basılan 12 ileti yeniden beş kez teslim edilir; 60 teslim daha
harcanır ve iletiler aynı kutuya döner. Geri basma bu yüzden bir onarım değil, bir sınamadır:
önce zehirlenmenin nedeni bulunur, sonra kutu boşaltılır.

Saklama süresi de aynı biçimde bir üst sınırdır. Tüketici tarafı saklama süresinden uzun bir
kesinti yaşarsa kuyruktaki iletiler tek tek silinmeye başlar ve kesinti bittiğinde kuyruk boş
görünür. Ölçüm ağında bu, kesinti penceresine denk gelen sayaç okumalarının hiç faturalanmaması
demektir. Kısıtın etrafından dolaşmanın yolu saklama süresini üst sınırına çekmektir; bedeli,
kuyruğun bir yedekleme katmanı gibi kullanılmaya başlaması ve derinlik ölçütü izlenmiyorsa
kaybın ancak fatura döneminde fark edilmesidir.

#### Kuyruk ile Konu Arasındaki Fark

İkinci servis türü aynı iletiyi birden çok tarafa verir. Fark tek cümleyle yazılır: kuyruk işi
**paylaştırır**, konu iletiyi **çoğaltır**.

```js
// fanout.mjs — ayni 400 olay iki servisten gecerse: kuyruk servisi ve konu servisi
const N = 400;
const KUYRUK_KALEM = 5;   // gorunurluk suresi, azami teslim, olu mektup kutusu, saklama, yigin boyu
const KONU_KALEM = 2;     // konunun kendi kalemleri: ad ve erisim kurali

console.log("tuketici".padEnd(10) + "kuyruk teslim".padStart(14) + "kuyruk kalem".padStart(14) +
  "konu teslim".padStart(13) + "konu kalem".padStart(12));
for (const k of [1, 2, 3, 4]) {
  const konuKalem = KONU_KALEM + k * (KUYRUK_KALEM + 1);  // her abonelik kendi kuyrugu + suzgeci
  console.log(String(k).padEnd(10) + String(N).padStart(14) + String(KUYRUK_KALEM).padStart(14) +
    String(N * k).padStart(13) + String(konuKalem).padStart(12));
}
console.log("tuketici basina is: kuyrukta " + N / 4 + ", konuda " + N + " (dort tuketicide)");
```

```sh
node fanout.mjs
```

```
tuketici   kuyruk teslim  kuyruk kalem  konu teslim  konu kalem
1                    400             5          400           8
2                    400             5          800          14
3                    400             5         1200          20
4                    400             5         1600          26
tuketici basina is: kuyrukta 100, konuda 400 (dort tuketicide)
```

Kuyruk sütunu düzdür: tüketici sayısı ne olursa olsun teslim 400'de kalır, tüketici başına iş
dörtte bire iner, yapılandırma kalemi beşte sabit durur. Tüketici eklemek bir ölçekleme
kararıdır ve maliyeti değiştirmez.

Konu sütunu doğrusal artar. Dördüncü aboneyle teslim 1.600'e, yapılandırma kalemi 26'ya çıkar.
Abone eklemek bir ölçekleme kararı değil, yeni bir iş kolu açmaktır: her abone iletinin kendi
kopyasını alır, kendi görünürlük süresini, kendi azami teslim sayısını, kendi ölü mektup
kutusunu ve kendi süzgecini taşır. 26 kalem, yanlış ayarlanabilecek 26 yerdir ve bunların
altısı her yeni aboneyle gelir.

Bu artışın önceki derste ölçülen şeyle aynı yüzey olduğuna dikkat edilmeli. Abone eklemek
üreticide tek satır değiştirmez, var olan abonelerin sayılarını bozmaz ve hiçbir hata üretmez —
kuralın görünmezliği burada aboneliğin görünmezliği olarak geri gelir. Fark şudur: kuralda
fazladan teslimin bedeli çağrıydı, konuda bedel çağrı artı 400 kopyanın saklanmasıdır.

İki servis birbirinin alternatifi olmak zorunda da değildir. Yaygın düzen, konunun her
aboneliğini bir kuyruğa bağlamaktır: konu çoğaltır, her kuyruk kendi tarafında paylaştırır.
Modeldeki 26 kalemin yapısı zaten budur — konunun iki kalemi ile abone başına beş kuyruk kalemi
ve bir süzgeç. Bu düzende önceki dersin süzgeç ölçümü doğrudan geçerlidir: süzgeç abonelikte
durursa ilgisiz olay kuyruğa hiç yazılmaz, tüketicide durursa yazılır, saklanır, teslim edilir
ve elenir. Fark bu kez üç kalemde birden görünür — teslim sayısı, saklanan ileti sayısı ve
tüketicinin boşa uyanması.

Konu servisinin devrettiği karar da kendi başına bir kalemdir: yayıncı abone listesini tutmaz.
Kaç abonenin olduğu, birinin eklenip eklenmediği, birinin sürekli hata verip vermediği yayıncı
tarafında görünmez. Bir abonenin ölü mektup kutusu dolarken konu sağlıklı çalışmayı sürdürür ve
öteki üç abone hiçbir şey fark etmez. Yalıtım budur ve iki yönlüdür: bir abonenin arızası
ötekileri durdurmaz, ama bir abonenin arızası da kimseye bildirilmez.

Seçim ölçütü işin niteliğidir. Aynı işi bölüşecek tüketiciler için kuyruk, aynı olaydan farklı
işler türetecek taraflar için konu kullanılır. Ölçüm ağında doğrulanmış okuma tek bir işe
girer — fatura kalemine dönüşür — ve bu iş bölüştürülür: kuyruk. Aynı okumadan hem fatura hem
arşiv hem tüketim eğrisi üretilecekse üç ayrı iş vardır: konu.

#### Özet

- Kuyruğun hizmet olarak alınması düğüm sayısı, kopya sayısı, sürüm yükseltmesi ve tüketici
  ölçekleme kararlarını devreder; geriye ayarlanabilir beş kalem kalır.
- Görünürlük süresi 5 birimken 400 iletilik iş yükü 745 teslime çıktı ve 102 ileti koşut olarak
  çift işlendi; 120 birimde çift işleme sıfırlandı ama tüketicisi ölen 16 ileti ortalama 120
  birim gizli bekledi.
- En uzun iş 69 birim olduğu için çift işlemenin sıfırlanması ancak 120 birimde gerçekleşti:
  işleme süresinin kuyruğu, kurtarma gecikmesinin alt sınırını belirler.
- Ölü mektup kutusuna düşme süresi ayarlanan bir kalem değil, azami teslim ile görünürlük
  süresinin çarpımıdır: 5 × 120 = 600 birim. Kutunun kendisi öntanımlı olarak tüketicisizdir.
- Kuyrukta teslim tüketici sayısından bağımsız olarak 400'de kaldı ve yapılandırma beş kalemde
  durdu; konuda dört aboneyle teslim 1.600'e, yapılandırma kalemi 26'ya çıktı. Kuyruk işi
  paylaştırır, konu iletiyi çoğaltır.
- Görünürlük süresini iş sürerken uzatmak çift işlemeyi kapatır ama 10 birimlik süreyle 69
  birimlik bir işi bitirmek altı uzatma çağrısı ister: tek iletilik iş yedi isteğe çıkar ve
  tüketici kendi ömrünü yönetmek zorunda kalır.

#### Sonraki Adım

Kuyruk iki işlevi güvenle birbirine bağlıyor: biri yazıyor, öteki alıyor, arada hata olursa
ileti geri geliyor. Ama ölçüm ağındaki fatura üretimi iki adım değil; okuma doğrulanır, tüketim
hesaplanır, tarife uygulanır, fatura yazılır, bildirim gönderilir. Beş adımın dördüncüsü hata
verdiğinde ilk üçünün ne olacağı hiçbir kuyrukta yazılı değildir — kuyruk yalnız kendi iletisini
bilir, akışın tamamını bilmez. Sonraki ders bu boşluğu ölçer: adım tabanlı bir durum makinesi
koşturulur, adım başına yeniden deneme ile telafi yolu sayılır ve akışın durumunun nerede
tutulduğu sorulur.

### İş Akışı Orkestrasyonu

Source: https://academia.sh/tr/kurslar/sunucusuz/is-akisi-orkestrasyonu

Beş adımlı bir fatura akışının durum makinesi olarak koşturulması: adım başına yeniden deneme ve telafi adımı sayısının ölçülmesi, akış durumunun orkestratöre taşınmasının getirdiği kısıtlar ve aynı akışı işlev içinde kurmakla orkestratöre vermek arasındaki farkın ücret ile kilitlenen eşzamanlılık cinsinden sayılması.

Kuyruk iki işlevi güvenle bağlar: biri yazar, öteki okur, hata olursa ileti geri gelir. Ölçüm
ağındaki fatura üretimi ise iki adım değil beş adımdır — okuma doğrulanır, tüketim hesaplanır,
tarife uygulanır, fatura yazılır, bildirim gönderilir. Dördüncü adım kalıcı olarak hata
verdiğinde ilk üçünün ne olacağı hiçbir kuyrukta yazılı değildir; kuyruk yalnız kendi iletisini
bilir.

Telafi işlemleriyle yürüyen dağıtık iş akışı — **saga** kalıbı — daha önce ölçüldü. O kalıp
burada tekrarlanmaz, yalnız adıyla anılır. Bu dersin sorusu şudur: akışın tamamı bir **iş akışı
orkestratörüne** verildiğinde hangi karar devredilir ve karşılığında hangi sayı gelir.

#### Akışı Kim Tutuyor

Beş adımı tek bir işlevin içine yazmak en kısa yoldur: bir işlev, beş çağrı, aralarında `if`
bloklarıyla hata yönetimi. Akışın durumu o işlevin yerel değişkenlerindedir. Bu, akış bitene
kadar sorun çıkarmaz — çıktığında ise geriye hiçbir şey kalmaz. Üçüncü adımda ölen bir işlevin
hangi adıma kadar geldiği, hangi adımın yan etkisini bıraktığı hiçbir yerde yazılı değildir.

Orkestratör bu durumu işlevin dışına alır. Her adımın başlangıcı, bitişi, girdisi, çıktısı ve
deneme sayısı orkestratörün kaydına yazılır; işlev yalnız tek bir adımı yapar ve sonucu döner.
Devredilen karar budur: **akışın nerede olduğunu bilme sorumluluğu.** Karşılığında gelen ilk
kısıt aynı yerden çıkar — adımlar arasında geçen her veri o kayıttan geçer, dolayısıyla bir
boyut sınırına tabidir ve büyük gövdeler adımlar arasında taşınamaz, ancak bir depoya yazılıp
anahtarı taşınabilir.

Devredilen ikinci karar yeniden denemenin kendisidir. İşlev içinde yazılan bir akışta kaç kez
deneneceği, ne kadar bekleneceği ve hangi hatanın yeniden denenebilir sayılacağı koddadır;
orkestratörde bunlar adım tanımının yanında duran bir politikadır. Kazanç, politikanın koddan
ayrılıp tek yerde görülmesidir. Kısıt ise akış tanımının önceki dersteki kuralla aynı yere
düşmesidir: tanım bir yapılandırma kalemi olduğu için kod incelemesinden geçmez, bir adımın
yeniden deneme sayısı üçten beşe çıkarıldığında hiçbir işlev değişmez ve fark yalnız faturada
ve gecikmede görünür.

Ölçüm yine kurgu bölgesel ölçüm ağı üzerindedir.

- **OS13.** Akış beş adımdır ve adım süreleri kurgu birimdir: 2, 3, 2, 4, 1.
- **OS14.** Her adımın kendi hata oranı vardır; yeniden deneme politikası üç deneme ve denemeler
  arasında artan beklemedir (2 ve 4 birim).
- **OS15.** 200 akışın on yedide birinde fatura yazımı kalıcı olarak çatışır; bu akışlar üç
  denemeyi de tüketir ve başarısız biter.
- **OS16.** Telafi yalnız yan etkisi olan adımlar için tanımlıdır: tarife-uygula 1 birim,
  fatura-yaz 2 birim. İlk iki adımın telafisi yoktur.
- **OS17.** Geçiş sayısı, adım denemeleri ile telafi adımlarının toplamıdır.
- **OS18.** Model tek bir akışın içini kurar; akışlar arası eşzamanlılık ve sıra ölçülmez.

#### Durum Makinesi

```js
// akis.mjs — is akisi orkestratoru modeli: adimlar, yeniden deneme politikasi, telafi yolu
// Model: gercek bir orkestrator degil, adim tabanli durum makinesinin sayilabilir kurulumu.
const TOHUM = 20260603;                       // uretec tohumu: kosum tekrarlanabilir
let d = TOHUM;
const r = () => (d = (d * 1103515245 + 12345) % 2147483648) / 2147483648;

const ADIM = [                                // sure ve telafi: kurgu birim
  { ad: "okuma-dogrula", sure: 2, hata: 0.06, telafi: 0 },
  { ad: "tuketim-hesapla", sure: 3, hata: 0.04, telafi: 0 },
  { ad: "tarife-uygula", sure: 2, hata: 0.10, telafi: 1 },
  { ad: "fatura-yaz", sure: 4, hata: 0.08, telafi: 2 },
  { ad: "bildirim-gonder", sure: 1, hata: 0.15, telafi: 0 },
];
const AZAMI = 3, BEKLE = [2, 4];              // 3 deneme; denemeler arasi artan bekleme
const N = 200;
const KALICI = (n) => n % 17 === 5;           // bu akislarda fatura yazimi her denemede catisir

const s = { deneme: ADIM.map(() => 0), hata: ADIM.map(() => 0), basarili: 0, telafi: 0,
            telafiAdim: 0, is: 0, duvar: 0, gecis: 0, enUzun: 0 };

for (let n = 0; n < N; n++) {
  const bitti = [], basi = s.duvar;
  let kesildi = false;
  for (let a = 0; a < ADIM.length && !kesildi; a++) {
    let deneme = 0, tamam = false;
    while (deneme < AZAMI) {
      deneme++; s.deneme[a]++; s.gecis++; s.is += ADIM[a].sure; s.duvar += ADIM[a].sure;
      const kalici = KALICI(n) && ADIM[a].ad === "fatura-yaz";
      if (!kalici && r() >= ADIM[a].hata) { tamam = true; break; }
      s.hata[a]++;
      if (deneme < AZAMI) s.duvar += BEKLE[deneme - 1];   // bekleme: is yok, sure var
    }
    if (tamam) { bitti.push(a); continue; }
    for (const t of bitti.reverse()) {                    // telafi: ters sirada geri alma
      if (ADIM[t].telafi === 0) continue;
      s.gecis++; s.is += ADIM[t].telafi; s.duvar += ADIM[t].telafi; s.telafiAdim++;
    }
    s.telafi++; kesildi = true;
  }
  if (!kesildi) s.basarili++;
  s.enUzun = Math.max(s.enUzun, s.duvar - basi);        // tek akisin en uzun duvar suresi
}

console.log("adim".padEnd(18) + "deneme".padStart(8) + "hata".padStart(7) +
  "deneme/akis".padStart(13));
ADIM.forEach((a, i) => console.log(a.ad.padEnd(18) + String(s.deneme[i]).padStart(8) +
  String(s.hata[i]).padStart(7) + (s.deneme[i] / N).toFixed(2).padStart(13)));
console.log(`\nakis: ${N}, basarili: ${s.basarili}, telafiye giden: ${s.telafi}, ` +
  `telafi adimi: ${s.telafiAdim}`);
console.log(`is suresi: ${s.is} birim, duvar suresi: ${s.duvar} birim, gecis: ${s.gecis}`);
console.log(`en uzun tek akis: ${s.enUzun} birim, tohum: ${TOHUM}`);
```

```sh
node akis.mjs
```

```
adim                deneme   hata  deneme/akis
okuma-dogrula          213     13         1.06
tuketim-hesapla        211     11         1.05
tarife-uygula          229     29         1.15
fatura-yaz             234     46         1.17
bildirim-gonder        220     32         1.10

akis: 200, basarili: 188, telafiye giden: 12, telafi adimi: 12
is suresi: 2685 birim, duvar suresi: 2967 birim, gecis: 1119
en uzun tek akis: 31 birim, tohum: 20260603
```

Adım tablosu, yeniden denemenin nereye yığıldığını gösteriyor. Beş adımın her biri ilk denemede
geçseydi 200 akış 1.000 deneme yapardı; ölçümde 1.107 deneme var. Fark, hata veren adımların
ikinci ve üçüncü denemeleridir. En yüklü adım fatura yazımıdır: 234 deneme, 46 hata. Bu 46'nın 36'sı kalıcı
çatışan on iki akıştan gelir; kalan 10'u geçici hatadır ve yeniden denemeyle kapanmıştır.

Son satırdaki sayı ilk bakışta ters görünüyor: bildirim gönderme adımının hata oranı en yüksek
olduğu halde akış başına denemesi 1,10, yani tarife adımından düşük. Nedeni paydadır — bu adıma
yalnız 188 akış ulaştı, çünkü 12 akış bir önceki adımda kesildi. Aynı sayı ulaşan akışa
bölündüğünde 1,17 çıkar. Adım ölçütleri akış sayısına değil, **o adıma ulaşan akış sayısına**
bölünmelidir; yoksa akışın sonuna doğru bütün hata oranları olduğundan küçük görünür.

Telafi yolu iki sayı üretti: 12 akış telafiye gitti ve toplam 12 telafi adımı koştu. Oran akış
başına birdir, çünkü fatura yazımı başarısız olduğunda geri alınacak tek yan etki tarife
uygulamasıdır; ilk iki adımın telafisi tanımlı değildir. Bu, telafi tasarımının asıl sorusunu
gösterir: geri alınacak adım sayısı, başarısız olan adımın **kaçıncı** olduğuna bağlıdır.
Başarısızlık ne kadar geç olursa geri alma o kadar uzundur ve son adımda başarısız olan bir
akışın telafisi, akışın kendisinden pahalı olabilir.

Yeniden deneme politikasının kendisi de bu sayıların içindedir. Azami deneme üç yerine beş
olsaydı, kalıcı çatışan 12 akış fatura yazımında 36 değil 60 deneme harcardı: 24 fazladan
deneme, 96 birim fazladan iş ve — beklemeler artan olduğu için — telafinin başlamasından önce
akış başına daha uzun bir gecikme. Kalıcı hatada yeniden deneme hiçbir şeyi kurtarmaz, yalnız
başarısızlığın kabul edilmesini geciktirir. Politikayı gevşetmenin bedeli buradan okunur;
sıkılaştırmanın bedeli ise ters yöndedir — üç yerine iki deneme, tarife adımındaki 29 geçici
hatanın bir bölümünü kalıcı başarısızlığa çevirir ve telafiye giden akış sayısını yükseltir.

#### Uzun Süren Akışın Ücretlendirilmesi

Toplam iş süresi 2.685 birim, duvar süresi 2.967 birim. Aradaki 282 birim, yeniden denemeler
arasındaki beklemedir — hiçbir iş yapılmayan, ama akışın açık olduğu süre. Bu ölçümde bekleme
toplamın yüzde 10'u kadardır, çünkü politikadaki bekleme değerleri küçük tutuldu. Onay bekleyen
ya da dış bir servisin yanıtını bekleyen akışlarda oran tersine döner ve bekleme iş süresinin
katlarına çıkar. Aşağıdaki hesap bu farkı bir çarpanla tarar; her satırda aynı 200 akış, yalnız
beklemenin ağırlığı değişir. Farkın kime yazılacağı, akışın nerede kurulduğuna bağlıdır.

```js
// akis-ucret.mjs — ayni 200 akis: akis islevin icinde mi, orkestratorde mi kuruluyor
// Sayilar ilk kosumdan okundu. Ucret birimi kurgudur; oran korunur, para birimi yoktur.
const N = 200, IS = 2685, DUVAR = 2967, GECIS = 1119;
const BEKLEME = DUVAR - IS;                   // adimlar arasi bekleme: is yapilmayan sure
const SURE_UCRET = 1;                         // kurgu birim: calisan sure birimi basina
const GECIS_UCRET = 0.25;                     // kurgu birim: orkestratorde durum gecisi basina

console.log("bekleme carpani".padEnd(17) + "islev icinde".padStart(14) +
  "orkestratorde".padStart(15) + "kilitlenen (islev)".padStart(20) +
  "kilitlenen (ork.)".padStart(19));
for (const k of [1, 5, 20, 100]) {
  const bekleme = BEKLEME * k;
  const islev = (IS + bekleme) * SURE_UCRET;               // islev bekleme boyunca da ayakta
  const ork = IS * SURE_UCRET + GECIS * GECIS_UCRET;       // bekleme ucretsiz, gecis ucretli
  console.log(String(k).padEnd(17) + islev.toFixed(0).padStart(14) + ork.toFixed(0).padStart(15) +
    String(IS + bekleme).padStart(20) + String(IS).padStart(19));
}
console.log(`akis: ${N}, is: ${IS} birim, bekleme (carpan 1): ${BEKLEME} birim, gecis: ${GECIS}`);
```

```sh
node akis-ucret.mjs
```

```
bekleme carpani    islev icinde  orkestratorde  kilitlenen (islev)  kilitlenen (ork.)
1                          2967           2965                2967               2685
5                          4095           2965                4095               2685
20                         8325           2965                8325               2685
100                       30885           2965               30885               2685
akis: 200, is: 2685 birim, bekleme (carpan 1): 282 birim, gecis: 1119
```

İlk satır dürüst bir sonuçtur: bekleme kısayken iki düzenin ücreti neredeyse aynıdır — 2.967'ye
karşı 2.965. Orkestratörün geçiş başına aldığı 1.119 × 0,25 = 280 birim, işlevin bekleme boyunca
ödediği 282 birimi tam olarak karşılıyor. Adım başına ücretlendirme bedavaya gelmez; adım sayısı
arttıkça geçiş ücreti de artar ve çok adımlı, hızlı biten akışlarda orkestratör pahalı kalabilir.

Bu ücret biçiminin bir yan etkisi, akışın **tanecikliğini** fiyatlandırmasıdır. Beş adımın her
biri üçe bölünse — her adım kendi doğrulaması, kendi işi ve kendi yazması olarak ayrılsa — iş
süresi değişmez ama geçiş sayısı 1.119'dan üç katına çıkar ve geçiş ücreti 280 birimden 840
birime yükselir. Adım sınırlarını nereye koyduğu, orkestratörde çalışan bir akışın maliyetini
doğrudan belirler. Ters yönde de aynı şey geçerlidir: iki adımı tek adımda birleştirmek geçiş
ücretini düşürür, ama birleşen adımın yeniden denemesi artık ikisini birden koşturur ve
başarısızlık noktası kabalaşır.

Fark bekleme uzadıkça açılır. Çarpan 100'de — onay bekleyen, dış servisin yanıtını bekleyen ya
da ertesi güne kadar duran bir akışta — işlev içindeki düzen 30.885 birime çıkarken orkestratör
2.965'te kalır: **10,4 kat.** Kesişme noktası ölçümden okunabilir; bekleme, geçiş ücretinin
toplamını aştığı anda orkestratör ucuzlar.

Son iki sütun daha sert bir kısıtı gösteriyor. Kilitlenen süre, eşzamanlılık havuzundan
tutulan yerdir. İşlev içinde kurulan akış bekleme boyunca da bir yuva işgal eder; çarpan 100'de
30.885 birimlik yuva-süresi kilitlenir. Orkestratörde bu sayı 2.685'te sabit kalır, çünkü
bekleme sırasında ayakta hiçbir işlev yoktur. Eşzamanlılık sınırı olan bir ortamda bu fark
ücretten önce **kapasiteye** çarpar: bekleyen akışlar, yeni gelen okumaların işlenmesini
engeller.

#### Görünürlük, Yeniden Başlatılabilirlik, Sınır

Ücret ve kapasite dışında üç fark daha var ve üçü de ölçümdeki sayılardan okunur.

**Görünürlük.** Orkestratör her geçişi kaydettiği için 1.119 geçişin tamamı sorgulanabilir bir
kayıttır: hangi akış hangi adımda, kaçıncı denemede, ne kadar bekledi. Aynı akış işlev içinde
kurulduğunda bu bilgi yalnız günlük satırlarında bulunur ve akış bazında birleştirilmesi ayrı
bir iş olur. Devredilen karar burada bir kazanç olarak geri döner.

**Yeniden başlatılabilirlik.** Telafiye giden 12 akış, orkestratörde başarısız adımdan itibaren
yeniden başlatılabilir; ilk üç adımın sonucu kayıtta durur ve tekrar koşmaz. İşlev içindeki
düzende yeniden başlatma baştan başlamaktır — 12 akış için üç adım daha, yani 12 × 7 = 84 birim
fazladan iş. Kalıcı hatanın nedeni giderildikten sonra bu fark doğrudan sayılır.

**Sınır.** En uzun tek akış 31 birim sürdü. Bu sayı, işlev içindeki düzenin can alıcı kısıtıdır:
akışın duvar süresi işlev çalıştırma ortamının süre sınırını aşamaz. 31 birim makul bir sınırın
altında kalır, ama duvar süresi bekleme çarpanıyla birlikte büyür; onay bekleyen ya da ertesi
güne kalan bir akış hiçbir işlev süre sınırına sığmaz. Orkestratörde böyle bir sınır yoktur, çünkü bekleme sırasında çalışan bir şey
yoktur.

Bunun karşılığında orkestratörün kendi sınırları gelir ve bunlar süre değil **sayı**
cinsindendir: bir akışın alabileceği azami adım sayısı, tutabileceği kayıt boyutu, saklanan
geçmişin ömrü. Ölçümdeki akış beş adımlı ve akış başına ortalama 5,6 geçişli olduğu için hiçbir
sınıra yaklaşmıyor; ama adım sayısı akışın veri büyüklüğüne bağlıysa — örneğin her sayaç için
bir adım açan bir toplu akış — sınır tasarımı doğrudan imkânsız kılar. O durumda tek yol akışı
sabit adımlı bir dış döngüye çevirmek, yani her yinelemede yeni bir akış başlatmaktır; bedeli,
akış sayısının ve dolayısıyla geçiş ücretinin veriyle birlikte büyümesidir.

Kısıtın etrafından dolaşmanın yolu akışı ikiye bölmektir: kısa ve sıkı adımlar işlev içinde,
bekleme içeren geçişler orkestratörde. Bedeli, akışın iki yerde birden tanımlı olmasıdır —
görünürlük yeniden bölünür ve hangi adımın nerede koştuğu ayrı bir bilgi haline gelir.

#### Özet

- Akışın durumunu tutma sorumluluğu orkestratöre devredilir; karşılığında adımlar arasında geçen
  her veri orkestratörün kaydından geçer ve bir boyut sınırına tabi olur.
- 200 akış 1.107 adım denemesi üretti; en yüklü adım 234 deneme ve 46 hatayla fatura yazımıdır,
  bu hataların 36'sı kalıcı çatışan 12 akıştan gelir.
- Adım ölçütleri akış sayısına değil o adıma ulaşan akış sayısına bölünmelidir: son adımın
  denemesi 200'e bölününce 1,10, ulaşan 188 akışa bölününce 1,17 çıkar.
- Telafiye giden 12 akış 12 telafi adımı koştu; geri alınacak adım sayısı, başarısızlığın
  akışın kaçıncı adımında olduğuna bağlıdır.
- Bekleme kısayken iki düzenin ücreti eşittir (2.967'ye karşı 2.965); bekleme yüz katına
  çıktığında işlev içindeki akış 30.885, orkestratördeki 2.965 birimdir ve kilitlenen
  eşzamanlılık 30.885'e karşı 2.685 yuva-süresidir.
- Geçiş başına ücretlendirme akışın tanecikliğini fiyatlandırır: adımlar üçe bölünürse geçiş
  ücreti 280 birimden 840 birime çıkar, iş süresi ise değişmez.

#### Sonraki Adım

Bu akışın tamamı bir olayla başladı: okuma geldi, doğrulama tetiklendi, zincir yürüdü. Ölçüm
ağının işlerinin bir bölümünde ise böyle bir olay yoktur. Gece toplu faturalama, günlük mutabakat
ve haftalık sayaç sağlık taraması hiçbir okumanın gelişine bağlı değildir; onları başlatan tek
şey saattir. Saati de bir hizmet tutar. Sonraki ders bu tetiklemeyi ölçer: hizmetin verdiği
garantinin türü, aynı dakikada iki kez tetiklenmenin faturaya ne yaptığı ve kaçırılan bir
koşumun neden kendiliğinden telafi edilmediği.

### Zamanlanmış Tetikleme

Source: https://academia.sh/tr/kurslar/sunucusuz/zamanlanmis-tetikleme

Saatin bir hizmete devredilmesinin getirdiği garanti türü: otuz gecelik toplu faturalama koşumunda aynı dakikada gelen iki tetiklemenin ürettiği yinelenen fatura sayısının ölçülmesi, etkisizlik anahtarının bunu kapatırken kaçırılan koşumu kapatmaması ve iş penceresinin tetikleme anından türetilmesiyle veriden türetilmesi arasındaki farkın saat kayması altında sayılması.

Önceki dersteki akışın tamamı bir olayla başlıyordu: okuma geldi, doğrulama tetiklendi, zincir
yürüdü. Ölçüm ağının işlerinin bir bölümünde ise böyle bir olay yoktur. Gece toplu faturalama,
günlük mutabakat ve haftalık sayaç sağlık taraması hiçbir okumanın gelişine bağlı değildir;
onları başlatan tek şey saattir.

Zamanlanmış işin kendisi yeni değildir; kaçırılan koşum ve üst üste binme politikaları daha önce
ölçüldü ve o karşılaştırma burada tekrarlanmaz. Bu dersin sorusu dardır: saati **bir hizmet**
tuttuğunda ne değişir?

#### Devredilen Karar ve Garantinin Türü

Kendi işlettiği bir zamanlayıcıda saat, belirli bir makinede çalışan belirli bir süreçtir. O
makine ölürse tetikleme olmaz; iki makine birden çalışırsa tetikleme iki kez olur. İkisi de
görülebilir, ikisi de düzeltilebilir — çünkü saati tutan şey elin altındadır.

Hizmet olarak alınan bir zamanlayıcıda bu sorumluluk devredilir. Karşılığında gelen kısıt bir
cümleyle yazılır ve bu dersin ekseni odur: **garanti en az bir kezdir.** Hizmet tetiklemenin
gerçekleşeceğini üstlenir, bir kez gerçekleşeceğini üstlenmez. Aynı dakikada iki tetikleme
olabilir; bu bir arıza değil, ilan edilmiş davranıştır. İşin etkisiz olması bu yüzden iyi bir
uygulama değil, hizmetin ön koşuludur.

Devredilenler sayılabilir: saati tutan sürecin ayakta kalması, o sürecin tek örnekli olması,
makine değiştiğinde zamanlamanın kaybolmaması, tetikleme kaydının tutulması. Geriye kalan yüzey
yine küçüktür — zamanlama ifadesi, saat dilimi, hedef, hedefe geçilecek girdi ve tetikleme
başarısız olursa uygulanacak yeniden deneme politikası: beş kalem. Önceki derslerdeki kuyruk
yapılandırmasıyla aynı büyüklükte bir yüzey, aynı türden bir kısıt.

Saat dilimi kalemi tek başına bir örnektir. Zamanlama yerel saate göre yazıldığında yılda iki
gece 24 saat sürmez; biri 23, öteki 25 saattir. Günde bir kez koşan bir iş o gecelerin birinde
iki kez, ötekinde hiç koşmayabilir. Yani ölçümdeki iki kusur — çift koşum ve kaçırılan koşum —
saat diliminin kendisinden de doğar ve bunun tetiklemenin doğruluğuyla ilgisi yoktur.

İkinci kısıt tersidir. Tetikleme anında hedef ayakta değilse — işlev kısılmışsa, hesap
sınırındaysa, dağıtım yarıdaysa — o koşum **kaçırılır ve telafi edilmez**. Zamanlayıcı yalnız
"şimdi"yi bilir; geçmiş bir anı yeniden üretmez. İki kısıt birlikte tuhaf bir çift oluşturur:
aynı iş bazen iki kez koşar, bazen hiç koşmaz.

Ölçüm kurgu bölgesel ölçüm ağının gece toplu faturalama işi üzerindedir.

- **OS19.** Otuz gecelik koşum; her gece 1.200 abone faturalanır, beklenen toplam 36.000 fatura.
- **OS20.** On birde bir gecede tetikleme aynı dakikada iki kez gelir, on üçte bir gecede hiç
  gelmez; günler sabittir, modelde rastgelelik yoktur.
- **OS21.** Etkisizlik anahtarı dönem ile abone kimliğinden türetilir; anahtar varsa ikinci
  yazma atlanır.
- **OS22.** Tetikleme anı hedeflenen andan −60 ile +60 birim arasında kayar; kayma güne göre
  belirlidir.
- **OS23.** Gün 1.440 birimdir ve okumalar gün içine eşit dağılır.
- **OS24.** Model üst üste binen koşumların iç kilitlenmesini kurmaz; yalnız yazılan fatura ve
  işlenen okuma sayılır.

#### Aynı Dakikada İki Tetikleme

```js
// tetikleme.mjs — zamanlanmis tetikleme modeli: en az bir kez garantisi ve kacirilan kosum
// Model: gercek bir zamanlayici degil, garanti turunun fatura sayisina etkisinin sayilmasi.
const GUN = 30, ABONE = 1200;
const CIFT = (g) => g % 11 === 4;      // bu gecelerde tetikleme ayni dakikada iki kez geldi
const KACAN = (g) => g % 13 === 9;     // bu gecelerde tetikleme hic gelmedi

function kosum(anahtarVar) {
  const yazilan = new Set();
  let fatura = 0, yinelenen = 0, eksik = 0, tetikleme = 0;
  for (let g = 0; g < GUN; g++) {
    if (KACAN(g)) { eksik += ABONE; continue; }        // telafi yok: gun bir daha gelmez
    for (let t = 0; t < (CIFT(g) ? 2 : 1); t++) {
      tetikleme++;
      for (let a = 0; a < ABONE; a++) {
        const anahtar = `d${g}:a${a}`;                 // etkisizlik anahtari: donem + abone
        if (anahtarVar && yazilan.has(anahtar)) continue;
        yazilan.add(anahtar); fatura++;
        if (t > 0) yinelenen++;
      }
    }
  }
  return { tetikleme, fatura, yinelenen, eksik };
}

console.log("etkisizlik anahtari".padEnd(21) + "tetikleme".padStart(11) +
  "yazilan fatura".padStart(16) + "yinelenen".padStart(11) + "eksik".padStart(8));
for (const [ad, v] of [["yok", false], ["var", true]]) {
  const s = kosum(v);
  console.log(ad.padEnd(21) + String(s.tetikleme).padStart(11) + String(s.fatura).padStart(16) +
    String(s.yinelenen).padStart(11) + String(s.eksik).padStart(8));
}
console.log(`gun: ${GUN}, abone: ${ABONE}, beklenen fatura: ${GUN * ABONE}`);
```

```sh
node tetikleme.mjs
```

```
etkisizlik anahtari    tetikleme  yazilan fatura  yinelenen   eksik
yok                           31           37200       3600    2400
var                           31           33600          0    2400
gun: 30, abone: 1200, beklenen fatura: 36000
```

Tablo aynı otuz geceyi iki kez işler; tek fark, yazma sırasında etkisizlik anahtarının
sorulup sorulmamasıdır. Otuz gece için 31 tetikleme geldi. Sayı otuz değil, çünkü iki gece hiç tetikleme olmadı ve üç
gecede ikişer tetikleme geldi: 28 + 3. Tek başına bu sayı zararsız görünüyor; faturaya
yansıması ilk satırdadır.

Etkisizlik anahtarı olmadan **3.600 yinelenen fatura** yazıldı. Üç gecenin her birinde 1.200
abone iki kez faturalandı. Ölçüm ağında bunun anlamı şudur: üç bin altı yüz aboneye aynı dönem
için ikinci bir fatura çıktı, ikinci bir borç kaydı oluştu ve — önceki derslerdeki zincir
düşünülürse — muhtemelen ikinci bir bildirim gitti. Hiçbir yerde hata yoktur; iki koşum da
başarıyla bitmiştir.

Yinelenen faturanın yanında ikinci bir sayı daha var: 3.600 fazladan işlev çağrısı. Abone başına
bir çağrı sayıldığında üç gece boyunca yapılan iş iki katına çıkar, eşzamanlılık havuzundan iki
kat yer tutulur ve faturalama penceresi uzar. Üstelik iki koşum aynı dakikada başladığı için
üst üste binerler; aynı abonenin kaydına iki koşum aynı anda yazar. Yazmanın kendisi bir tekillik
kısıtına dayanmıyorsa, tabloda iki satır birden oluşur ve ikisi de "başarılı" sayılır. Çift
tetiklemenin bedeli bu yüzden yalnız yinelenen kayıt değil, aynı zamanda kayıt düzeyinde bir
yarıştır.

İkinci satır anahtarın ne yaptığını gösteriyor. Tetikleme sayısı **yine 31'dir** — anahtar
tetiklemeyi tekilleştirmez, hizmet ikinci tetiklemeyi göndermeye devam eder. Değişen şey
yazmadır: dönem ile abone kimliğinden türetilen anahtar zaten yazılmışsa ikinci yazma atlanır
ve yinelenen fatura sıfıra iner. Bu, teslim semantiği ölçümünde kurulan ayrımın aynısıdır —
tekilleştirilen şey teslim değil, etkidir.

Anahtarın neyden türetildiği burada belirleyicidir. Ölçümde anahtar dönem ile abone
kimliğinden yapıldı; ikinci tetikleme aynı dönemi getirdiği için aynı anahtarı üretti ve yazma
atlandı. Anahtar koşum kimliğinden türetilseydi — her tetikleme kendi kimliğiyle geldiği için —
iki koşum iki ayrı anahtar üretir ve tablodaki ilk satıra geri dönülürdü. Anahtar, tekrarın
hangi ölçüte göre "aynı iş" sayılacağını tanımlar; zamanlanmış işte bu ölçüt her zaman **işin
kapsamıdır**, koşumun kendisi değil. Ölçüm ağında kapsam "hangi dönem, hangi abone"dir; aynı
dönem iki kez faturalanamaz, çünkü ikinci fatura yeni bir olgu değil, birincinin kopyasıdır.

#### Anahtarın Kapatmadığı Sütun

Tablonun son sütunu iki satırda da aynıdır: **2.400 eksik fatura.** Etkisizlik anahtarı bu
sayıya dokunmaz, çünkü anahtar yalnız "bu iş daha önce yapıldı mı" sorusunu yanıtlar; hiç
yapılmamış bir iş için sorulacak bir soru yoktur.

Eksik sütununun asıl güçlüğü fark edilme süresidir. Yinelenen fatura kendini gösterir: abone
ikinci bildirimi alır, borç iki kez düşer, çağrı merkezine bir soru gelir. Eksik fatura hiçbir
belirti üretmez — üretilmeyen fatura kimseyi rahatsız etmez. 2.400 fatura, otuz günlük dönemin
yüzde 6,7'sidir ve bu fark ancak dönem sonu mutabakatında, gelir beklentisiyle karşılaştırma
yapıldığında görünür. Ölçümdeki iki eksik gecenin maliyeti bu yüzden yalnız 2.400 fatura değil,
o faturaların bir ay geç kesilmesidir.

Kaçırılan koşum, hizmetin garantisinin öteki yüzüdür ve düzeltilmesi tetikleme tarafında değil
**iş tanımı** tarafındadır. Aradaki fark tek cümlede durur: iş "bugünü faturala" diye
yazılırsa kaçan gün bir daha gelmez; "faturalanmamış dönemleri faturala" diye yazılırsa ertesi
gece iki günü birden kapatır. İkinci biçim aynı zamanda çift tetiklemeye de dayanıklıdır,
çünkü ikinci koşum faturalanmamış dönem bulamaz.

Bu biçimin bedeli iki kalemdir. Birincisi, işin artık kendi kapsamını bulması gerekir: her
koşumda "hangi dönemler işlenmedi" sorgusu çalışır ve bu sorgu, koşum ne kadar seyrek kaçarsa
o kadar sık boşuna koşar. İkincisi, kaçan gün sayısı arttıkça tek bir koşumun iş yükü
katlanır — iki gün üst üste kaçarsa üçüncü gece 3.600 fatura yazılır ve bu, işlev süre
sınırının içinde bitmek zorundadır. Kapsam tabanlı iş, kaçırma sorununu bir süre sınırı
sorununa çevirir.

Üçüncü bir seçenek, koşumun gerçekleştiğini ayrı bir yerde işaretleyip eksik günleri arayan bir
denetçi kurmaktır. Bu, kaçırmayı **görünür** kılar ama kendisi de zamanlanmış bir iştir ve aynı
garantiye tabidir; denetçinin kaçırdığı koşumu bulacak bir üçüncü katman yoktur.

Üç seçenek arasındaki tercih, işin doğasına bakılarak yapılır. Faturalama gibi kapsamı veriden
okunabilen işlerde ikinci biçim doğrudan uygulanır. Kapsamı olmayan işlerde — örneğin bir
önbelleği ısıtan ya da geçici dosyaları silen bir koşumda — kaçan bir gecenin telafi edilecek
bir karşılığı da yoktur; orada kaçırma bir kusur değil, kabul edilmiş bir durumdur. Ayrımı
yapmanın ölçütü tek sorudur: koşum kaçtığında geriye eksik bir **kayıt** kalıyor mu? Kalıyorsa
kapsam tabanlı yazım zorunludur; kalmıyorsa zamanlayıcının garantisi olduğu gibi kabul edilir.

#### Saat Kayması ve Pencerenin Kaynağı

Tetiklemenin bir de anı vardır. Hizmet "her gece belirli bir dakikada" der, ama gerçekleşen an
o dakikanın etrafında kayar: sıra beklemesi, ölçekleme gecikmesi, saat eşitleme farkı. Kayma
küçüktür; sorun kaymanın büyüklüğü değil, **işin penceresini nereden aldığıdır.** Aşağıdaki
koşum aynı otuz geceyi iki pencere tanımıyla işler: biri pencereyi tetikleme anından geriye
sayar, öteki bir önceki koşumun bıraktığı yerden başlatır. Kayma ikisinde de aynıdır.

```js
// kayma.mjs — saat kaymasi: is penceresi tetikleme aninin mi, verinin mi uzerine kuruluyor
const GUN = 30, GUNLUK = 1200, DAKIKA = 1440;
const kayma = (g) => ((g * 37) % 121) - 60;      // -60..+60 birim, gune gore belirli
const tetik = (g) => (g + 1) * DAKIKA + kayma(g);

const OKUMA = [];                                 // okumalar gun icine esit dagilir
for (let g = 0; g < GUN; g++)
  for (let i = 0; i < GUNLUK; i++) OKUMA.push(g * DAKIKA + Math.floor((i * DAKIKA) / GUNLUK));

function kosum(kapsamli) {
  const sayac = new Map(OKUMA.map((z, i) => [i, 0]));
  let son = 0;
  for (let g = 0; g < GUN; g++) {
    const T = tetik(g);
    const bas = kapsamli ? son : T - DAKIKA;      // kapsamli: son islenen andan itibaren
    OKUMA.forEach((z, i) => { if (z >= bas && z < T) sayac.set(i, sayac.get(i) + 1); });
    son = T;
  }
  let hic = 0, cift = 0;
  for (const n of sayac.values()) { if (n === 0) hic++; else if (n > 1) cift += n - 1; }
  return { hic, cift };
}

console.log("pencere".padEnd(22) + "hic islenmeyen".padStart(16) + "cift islenen".padStart(14));
for (const [ad, k] of [["tetikleme anindan", false], ["son islenen andan", true]]) {
  const s = kosum(k);
  console.log(ad.padEnd(22) + String(s.hic).padStart(16) + String(s.cift).padStart(14));
}
console.log(`okuma: ${OKUMA.length}, kayma araligi: -60..+60 birim`);
```

```sh
node kayma.mjs
```

```
pencere                 hic islenmeyen  cift islenen
tetikleme anindan                  648           560
son islenen andan                    0             0
okuma: 36000, kayma araligi: -60..+60 birim
```

Pencere tetikleme anından geriye sayıldığında 36.000 okumanın **648'i hiç işlenmedi**, 560'ı
**iki kez işlendi**. Ne bir hata oluştu ne de tetikleme kaçtı; her gece iş koştu ve başarıyla
bitti. Kayan tek şey pencerenin iki ucuydu. Bir gece erken, ertesi gece geç tetiklendiğinde
aradaki dilim iki pencerede birden kalır; tersi durumda hiçbir pencereye girmez.

648 okuma, 36.000'in yüzde 1,8'idir ve bu oran yanıltıcıdır — kayıp rastgele dağılmaz. Kaçan
dilim her zaman gün sınırının etrafındadır, yani hep aynı saatlerde okuma gönderen sayaçlara
denk gelir. Sabit saatte rapor eden bir sayaç filosunda bu, her ay aynı abone kümesinin eksik
faturalanması demektir; yüzde 1,8'lik bir genel kayıp değil, bir avuç abonede yüzde yüze yakın
bir kayıptır. Çift işlenen 560 okuma da aynı kümededir ve iki hata birbirini gizler: toplam
tüketim rakamına bakan bir denetim, 648 eksikle 560 fazlanın birbirini kısmen götürdüğünü görüp
sapmayı küçük sanır.

İkinci satır aynı kaymayla sıfır üretiyor. Fark tek satırdır: pencere `T - 1440` yerine **son
işlenen andan** başlıyor. Pencere artık saatten değil, işin kendi ilerlemesinden türetiliyor;
kayma pencerenin sonunu oynatsa da başlangıcı bir önceki koşumun bıraktığı yerdir, dolayısıyla
ne boşluk ne örtüşme kalır.

Buradan dersin kuralı çıkar: zamanlanmış tetikleme **işin ne zaman başlayacağını** söyler,
**neyi işleyeceğini** söylememelidir. Neyi işleyeceği veriden okunur. Bu ayrım kurulduğunda üç
kısıt birden kapanır — çift tetikleme yeni iş bulamaz, kaçırılan koşum ertesi koşumda kapanır
ve saat kayması pencereyi bozmaz. Bedeli, her koşumun kendi ilerleme işaretini kalıcı olarak
yazması ve bu yazmanın işle aynı sınırda kesinleşmesi gereğidir; işaret işten önce yazılırsa
kaçan dilim sessizce atlanır, sonra yazılırsa aynı dilim ikinci kez işlenir.

#### Özet

- Zamanlanmış tetikleme hizmet olarak alındığında garanti en az bir kezdir: aynı dakikada iki
  tetikleme olabilir ve bu bir arıza değil, ilan edilmiş davranıştır.
- Otuz gecede 31 tetikleme geldi; etkisizlik anahtarı olmadan 3.600 yinelenen fatura yazıldı ve
  iki koşum da hatasız bitti.
- Anahtar eklendiğinde tetikleme sayısı yine 31 kaldı ama yinelenen fatura sıfırlandı:
  tekilleştirilen şey tetikleme değil, yazmadır.
- Kaçırılan koşum telafi edilmez; 2.400 eksik fatura iki satırda da aynı kaldı. Bunu kapatan
  şey anahtar değil, işin "bugünü faturala" yerine "faturalanmamış dönemleri faturala" diye
  yazılmasıdır.
- Pencere tetikleme anından türetildiğinde 36.000 okumanın 648'i hiç işlenmedi, 560'ı iki kez
  işlendi; pencere son işlenen andan türetildiğinde aynı kaymayla iki sayı da sıfır oldu. Kayıp
  rastgele de değildir: kaçan dilim hep gün sınırındadır, yani hep aynı saatte rapor eden
  sayaçlara denk gelir ve toplam üzerinden bakan bir denetimde 648 eksikle 560 fazla birbirini
  kısmen götürür.
- Zamanlanmış tetikleme işin ne zaman başlayacağını söyler; neyi işleyeceğini veriden okumak
  çift tetiklemeyi, kaçırılan koşumu ve saat kaymasını aynı anda kapatır.

#### Sonraki Adım

Buraya kadar işlevleri uyandıran her şey içeriden geldi: bir kural, bir kuyruk, bir akış adımı,
bir saat. Ölçüm ağının bir de dışarıya bakan yüzü var — saha ekiplerinin uygulaması, şube
ekranları ve abonelerin kendi tüketimini sorguladığı arayüz. Bu istekler doğrudan işleve
ulaşamaz; arada kimliği doğrulayan, yolu eşleyen ve kısan bir katman durur. Sonraki ders bu
katmanı hizmet olarak ölçer: yapılandırma kalemi sayısı, istek başına ücret, yetkilendirmenin
geçitte yapılmasının işlev çağrısı sayısına etkisi ve geçidin soğuk başlangıç konusunda ne
yapıp ne yapmadığı.

### API Ağ Geçidi Servisi

Source: https://academia.sh/tr/kurslar/sunucusuz/api-ag-gecidi-servisi

Geçidin hizmet olarak alınmasının sayıları: on iki uç noktalık bir yüzeyin yapılandırma kalemi sayısı, yetkilendirmenin geçitte yapılmasının işlev çağrısı sayısına etkisi ve başabaş önbellek isabet oranı, geçidin soğuk başlangıcı gizlemediğinin zaman aşımı eşiği taranarak gösterilmesi ve zaman aşımına uğrayan isteklerin işlevde tamamlanmayı sürdürmesi.

Buraya kadar işlevleri uyandıran her şey içeriden geldi: bir kural, bir kuyruk, bir akış adımı,
bir saat. Ölçüm ağının bir de dışarıya bakan yüzü var — saha ekiplerinin uygulaması, şube
ekranları ve abonelerin kendi tüketimini sorguladığı arayüz. Bu istekler işleve doğrudan
ulaşamaz; arada yolu eşleyen, kimliği doğrulayan ve kısan bir katman durur.

Geçidin görevleri daha önce ölçüldü; yol eşleme, kimlik doğrulama ve kısma o derslerin
konusuydu ve buradaki ölçüm onları tekrarlamaz. Bu dersin sorusu yine dardır: geçit **bir
hizmet** olduğunda hangi karar devredilir ve karşılığında hangi sayı gelir.

#### Yapılandırma Yüzeyi

Devredilen kararlar tanıdıktır: geçidin kendisini işleten makineler, o makinelerin ölçeği,
sertifika yenilemesi, sürüm yükseltmesi. Karşılığında gelen kısıt bu kez bir sınır değil, bir
**hacimdir.** Geçit servisinde her uç nokta kendi yapılandırma kümesini taşır: yol deseni,
yöntem, tümleştirme hedefi, yetkilendirici, istek eşlemesi, kısma sınırı, önbellek anahtarı,
günlükleme. Sekiz kalem, uç nokta başına.

Ölçüm ağının dışarıya açılan yüzü on iki uç noktadır. Toplam yapılandırma kalemi 12 × 8 + 6 =
**102**. Bu sayı bir maliyet değil, bir yüzeydir: 102 yerin her biri yanlış ayarlanabilir ve
hiçbiri işlev kodunda görünmez. Önceki derslerdeki kuralla, akış tanımıyla ve zamanlama
ifadesiyle aynı türden bir yüzeydir; farkı büyüklüğüdür.

Yüzeyin tehlikeli yanı, kalemlerin **birbirinden bağımsız** olmasıdır. On üçüncü uç nokta
eklendiğinde sekiz kalem daha açılır ve bunlardan biri — yetkilendirici — boş bırakılabilir. Boş
bırakılmış bir yetkilendirici hata üretmez; uç nokta çalışır, yanıt döner, ölçütler yeşil kalır.
Tek fark, o uç noktanın kimlik sormamasıdır. Önceki derste kuralın görünmezliği bir yüzeydi;
burada aynı görünmezlik doğrudan bir erişim kararına dokunuyor. Kısıtın etrafından dolaşmanın
yolu, uç nokta tanımlarını tek bir şablondan üretip yetkilendirici alanını zorunlu kılmaktır;
bedeli, geçit yapılandırmasının artık elle düzenlenememesi ve her değişikliğin üretim hattından
geçmesidir.

- **OS25.** Günlük istek karışımı 50.000'dir ve üç kurgu kaynaktan gelir: saha uygulaması
  12.000, şube ekranı 18.000, abone arayüzü 20.000.
- **OS26.** Ret nedeni yetkilendirmedir — süresi geçmiş belirteç, eksik kapsam, belirteçsiz
  istek; ret oranları kaynağa göre 0,03 ile 0,31 arasındadır.
- **OS27.** Ücret kurgu birimdir: istek başına 0,002 geçit payı, işlev çağrısı başına 0,010.
- **OS28.** Yapılandırma sayımı 12 uç nokta × 8 kalem artı geçit düzeyinde 6 kalemdir.
- **OS29.** Soğuk başlangıcın ek süresi 90 birim, geçidin kendi payı 4 birimdir; soğuk çağrılar
  sabit aralıklarla dağıtılır.
- **OS30.** İstemci yeniden denemesi tek sefer sayılır; kısma ve yanıt önbelleği ölçülmez.

#### Yetkilendirme Nerede Yapılıyor

Geçitte reddedilen bir istek işlevi hiç uyandırmaz. Bu cümle doğrudur, ama tek başına eksiktir —
reddin kendisi de bir işlem gerektirir ve o işlemin nerede yapıldığı sayıyı değiştirir. Aşağıdaki
model aynı günlük istek karışımını dört düzende işler ve her düzende kaç işlev çağrısı
yapıldığını sayar.

```js
// gecit.mjs — gecit servisi modeli: yetkilendirme nerede yapiliyor, islev kac kez uyaniyor
// Model: gercek bir gecit degil, yetkilendirme yerinin cagri sayisina etkisinin sayilmasi.
const KAYNAK = [                                  // kurgu olcum agindan gunluk istek karisimi
  { ad: "saha uygulamasi", istek: 12000, ret: 0.06 },
  { ad: "sube ekrani", istek: 18000, ret: 0.03 },
  { ad: "abone arayuzu", istek: 20000, ret: 0.31 },
];
const ISTEK = KAYNAK.reduce((t, k) => t + k.istek, 0);
const RET = KAYNAK.reduce((t, k) => t + Math.round(k.istek * k.ret), 0);
const GECEN = ISTEK - RET;
const ONBELLEK = 0.85;                            // yetkilendirici sonucunun isabet orani

const GECIT_UCRET = 0.002, CAGRI_UCRET = 0.010;   // kurgu birim: istek basina ve cagri basina
const duzen = [
  ["yetkilendirme islevde", ISTEK, 0],
  ["gecitte, onbelleksiz", GECEN, ISTEK],
  ["gecitte, onbellekli", GECEN, Math.round(ISTEK * (1 - ONBELLEK))],
  ["gecitte, yerlesik dogrulama", GECEN, 0],
];

console.log("duzen".padEnd(29) + "is cagrisi".padStart(12) + "yetkilendirici".padStart(16) +
  "toplam cagri".padStart(14) + "ucret".padStart(9));
for (const [ad, is, yetki] of duzen) {
  const ucret = ISTEK * GECIT_UCRET + (is + yetki) * CAGRI_UCRET;
  console.log(ad.padEnd(29) + String(is).padStart(12) + String(yetki).padStart(16) +
    String(is + yetki).padStart(14) + ucret.toFixed(1).padStart(9));
}
console.log(`istek: ${ISTEK}, reddedilen: ${RET}, gecen: ${GECEN}`);
console.log(`yapilandirma: 12 uc nokta x 8 kalem + gecit duzeyi 6 kalem = ${12 * 8 + 6}`);
```

```sh
node gecit.mjs
```

```
duzen                          is cagrisi  yetkilendirici  toplam cagri    ucret
yetkilendirme islevde               50000               0         50000    600.0
gecitte, onbelleksiz                42540           50000         92540   1025.4
gecitte, onbellekli                 42540            7500         50040    600.4
gecitte, yerlesik dogrulama         42540               0         42540    525.4
istek: 50000, reddedilen: 7460, gecen: 42540
yapilandirma: 12 uc nokta x 8 kalem + gecit duzeyi 6 kalem = 102
```

İlk satır yetkilendirmenin işlevde yapıldığı düzendir: 50.000 isteğin tamamı işlevi uyandırır.
Bunların **7.460'ı yalnız "hayır" demek için** uyanır — belirteci doğrular, geçersiz bulur,
yanıt döner. İş yapılmamıştır ama çağrı yapılmıştır; eşzamanlılık havuzundan yer alınmış, soğuk
başlangıç ihtimali göze alınmıştır.

İkinci satır beklenenin tersini gösteriyor. Yetkilendirme geçide taşındığında iş çağrısı
42.540'a indi, ama geçidin çağırdığı yetkilendirici işlev her istek için bir kez koştuğundan
toplam çağrı **92.540'a**, ücret 1.025,4 birime çıktı. Reddi işlevden almak, reddi yapan şeyin
kendisi bir işlevse çağrı sayısını azaltmaz; artırır.

Üçüncü satır sınırdır: yetkilendirici sonucu yüzde 85 isabetle önbelleklendiğinde toplam çağrı
50.040, ücret 600,4 birim olur — birinci satırla neredeyse aynı. Başabaş isabet oranı basit bir
eşitlikten çıkar: 50.000 × (1 − h) = 7.460, yani h = **yüzde 85,1.** Bu oranın altında geçitte
yetkilendirme pahalıdır, üstünde ucuzdur ve kazanç isabet oranına birebir bağlıdır.

Dördüncü satır asıl kazancın nerede olduğunu söylüyor: geçit belirteci **kendi doğrulayabildiğinde**
araya hiçbir işlev girmez. Toplam çağrı 42.540, ücret 525,4 — birinci satıra göre yüzde 12,4
düşük. Ölçünün sonucu tek cümledir: "geçitte reddedilen istek işlevi uyandırmaz" ancak reddin
kendisi bir işlev çağrısı değilse bir kazançtır.

Reddedilen isteklerin dağılımı da kendi başına bir bulgudur. 7.460 reddin **6.200'ü** tek bir
kaynaktan, abone arayüzünden gelir; oran orada yüzde 31'dir çünkü tarayıcı oturumu kısadır ve
belirteç sık sık süresini doldurur. Kalan iki kaynak birlikte 1.260 ret üretir. Yani reddin
yüzde 83,1'i tek bir istemcinin belirteç yenileme davranışından doğuyor. Bu, geçit
yapılandırmasıyla çözülecek bir şey değildir; istemci belirteci süresi dolmadan yenilediğinde
sayı kendiliğinden düşer. Ölçünün buradaki dersi, çağrı sayısını azaltmanın her zaman geçit
tarafında bir ayar olmadığıdır.

Ücretin bir ayrıntısı da bu satırlarda gizli. Geçit payı dört düzende de aynıdır: 50.000 ×
0,002 = 100 birim. Reddedilen 7.460 istek işlevi uyandırmasa bile geçide ulaşmıştır ve 14,9
birim ücretlendirilmiştir. Geçitte reddetmek çağrıyı önler, isteği önlemez; yetkisiz bir
istek seli hiçbir işlev çalıştırmadan fatura üretir ve bunu durduracak şey geçidin kendisi
değil, önündeki kısma sınırıdır.

Çağrı sayısının ötesinde bir kazanç daha var ve o sayıya girmiyor. Dört düzenin üçünde iş
işlevi hiçbir zaman yetkisiz bir istek görmez; yetkilendirme kodu tek yerde, 12 uç noktanın
hepsi için aynı biçimde durur. Birinci düzende aynı denetim on iki işlevde ayrı ayrı yazılıdır
ve birinde unutulması sessiz bir açıktır. Bu, 102 kalemlik yapılandırma yüzeyinin karşılığında
alınan şeydir.

Dördüncü düzende geçit payı toplam ücretin 100 / 525,4'ü, yani yüzde 19'udur. Bu oran isteğin
ne kadar iş yaptığından bağımsızdır: geçit isteği sayar, süreyi saymaz. Uzun süren bir rapor
sorgusunda geçit payı toplamın küçük bir dilimi kalır; birkaç alan döndüren kısa bir uç noktada
ise geçit, işlevin kendisinden pahalı olabilir. Uç nokta ne kadar ince olursa geçidin payı o
kadar büyür ve bu, çok sayıda küçük uç nokta tasarlamanın görünmeyen bir maliyetidir. Aynı işi
tek bir uç noktada toplamak payı düşürür; bedeli, yetkilendirme ve kısma sınırlarının artık uç
nokta düzeyinde ayrışamamasıdır.

#### Geçit Soğuk Başlangıcı Gizlemez

Geçit isteği alır, yönlendirir ve yanıtı bekler. Beklerken yapabileceği tek şey vardır: bir
süre sonra vazgeçmek. İşlevin ısınmasını bekleyip isteği tutamaz, ısınana kadar başka bir yere
gönderemez. Bu yüzden soğuk başlangıcın gecikmesi doğrudan istemciye geçer ve geçidin zaman
aşımı eşiği, kimin hata alacağını belirler. Aşağıdaki tarama aynı 42.540 çağrıyı dört farklı
eşikte işler; çağrıların gecikmesi ve hangilerinin soğuk olduğu bütün satırlarda aynıdır,
değişen tek şey geçidin ne kadar beklediğidir.

```js
// zaman-asimi.mjs — gecit servisi soguk baslangici gizlemez: zaman asimi esigi taranir
const TOHUM = 20260714;                       // uretec tohumu: kosum tekrarlanabilir
let d = TOHUM;
const r = () => (d = (d * 1103515245 + 12345) % 2147483648) / 2147483648;

const N = 42540, GECIT = 4, SOGUK_EK = 90;    // kurgu birim: gecidin kendi payi ve soguk ek
const CAGRI = [];
for (let i = 0; i < N; i++) {
  const is = r() < 0.88 ? 10 + Math.floor(r() * 31)    // olagan sorgu: 10-40 birim
                        : 60 + Math.floor(r() * 81);   // rapor sorgusu: 60-140 birim
  const soguk = i % 47 === 3;                          // soguk cagrilar sabit araliklarla
  CAGRI.push({ gecikme: GECIT + is + (soguk ? SOGUK_EK : 0), soguk });
}
const SOGUK = CAGRI.filter((c) => c.soguk).length;

console.log("zaman asimi".padEnd(13) + "asan istek".padStart(12) + "bunlarin sogugu".padStart(17) +
  "istemci yeniden denerse".padStart(25));
for (const T of [60, 120, 200, 300]) {
  const asan = CAGRI.filter((c) => c.gecikme > T);
  console.log(String(T).padEnd(13) + String(asan.length).padStart(12) +
    String(asan.filter((c) => c.soguk).length).padStart(17) +
    String(N + asan.length).padStart(25));
}
console.log(`cagri: ${N}, soguk cagri: ${SOGUK}, gecit payi: ${GECIT} birim, tohum: ${TOHUM}`);
```

```sh
node zaman-asimi.mjs
```

```
zaman asimi    asan istek  bunlarin sogugu  istemci yeniden denerse
60                   5929              906                    48469
120                  1864              455                    44404
200                    39               39                    42579
300                     0                0                    42540
cagri: 42540, soguk cagri: 906, gecit payi: 4 birim, tohum: 20260714
```

En alt satır rahatlatıcı görünüyor: 300 birimlik zaman aşımında hiçbir istek aşmıyor. Bir üst
satır asıl bulguyu veriyor. 200 birimlik eşikte 39 istek zaman aşımına uğradı ve **39'unun da
tamamı soğuk çağrıydı.** Sıcak çağrıların hiçbiri o eşiği aşamaz, çünkü sıcak yolun en kötü
durumu 144 birimdir; soğuk yolun en kötü durumu 234'tür. Eşik ikisinin arasına düştüğünde hata
alan istemci kümesi tam olarak soğuk başlangıca denk gelen kümedir.

Geçidin kendi payı olan 4 birim küçük görünür, ama nerede göründüğü önemlidir: işlevin süre
ölçütünde görünmez. İşlev 30 birimde bittiğini bildirirken istemci 34 birim bekler; soğuk
çağrıda işlev yine 30 birim bildirir, istemci 124 birim bekler. İki tarafın gördüğü sayı
arasındaki bu fark, geçit hizmetinin gizli kısıtıdır — gecikme şikâyeti geldiğinde işlev
ölçütlerine bakan taraf hiçbir anormallik bulamaz. Farkı görebilmenin yolu, geçidin kendi erişim
kaydındaki toplam süreyi işlevin bildirdiği süreyle yan yana koymaktır; iki kaynağın
birleştirilmesi ayrı bir iştir ve geçidin hizmet olmasının bedellerinden biridir.

60 birimlik eşikte tablo başka bir şey söylüyor: 906 soğuk çağrının **hepsi** aşıyor. Soğuk
başlangığın süresi tek başına eşiği aştığı için, o çağrının ne kadar iş yaptığı önemsizdir.
Geçidin zaman aşımını sıkmak, soğuk başlangıcı bir gecikme sorunundan bir **hata** sorununa
çevirir.

Son sütun bedelin ikinci yarısıdır. Zaman aşımı geçidin kararıdır; işlev bundan haberdar
değildir ve çalışmayı sürdürür. İstemci hata alıp yeniden denediğinde 60 birimlik eşikte çağrı
sayısı 42.540'tan 48.469'a çıkar — yüzde 13,9 fazladan çağrı. Daha kötüsü, ilk çağrı işini
tamamlayıp yazmıştır; ikinci çağrı artık sıcak bir örneğe düşer, hızla biter ve aynı yazmayı
ikinci kez yapar. Bu, önceki iki derste ölçülen yinelenen etkinin geçit yüzeyindeki
biçimidir ve çözümü de aynıdır: yazma bir etkisizlik anahtarına dayanmalıdır.

Geçidin bu noktada yapamadıklarını saymak, hizmetin sınırını çizer. Geçit isteği kuyruğa
almaz — kuyruk servisi ayrı bir şeydir ve araya girmesi için isteğin eşzamansıza çevrilmesi
gerekir. Geçit kendiliğinden yeniden denemez; denese bile bu, zaman aşımına uğrayan çağrının
üstüne ikinci bir çağrı bindirmek olurdu ve son sütundaki 48.469 sayısı istemci yerine geçitten
gelirdi. Geçit yanıtı ısınana kadar bekletmez, çünkü hangi işlevin ne zaman ısınacağını bilmez.
Yaptığı üç şey vardır: yolu eşler, belirteci doğrular, süreyi keser. Bu üçünün dışında kalan her davranış ya
istemcide ya işlevde kurulur; geçidin hizmet olması bu sınırı genişletmez, yalnız üç işi
işletme yükünden kurtarır.

Kısıtın etrafından dolaşmanın üç yolu var. Zaman aşımını yükseltmek 39 hatayı sıfırlar ama
bağlantıyı daha uzun tutar ve gerçekten takılmış bir isteğin fark edilmesini geciktirir. İşlevi
sıcak tutmak soğuk çağrı sayısını düşürür ama boşta çağrı üretir; 906 soğuk çağrının bedeli ile
sıcak tutmanın bedeli karşılaştırılmalıdır. Üçüncüsü, ağır uç noktaları eşzamansıza çevirmektir:
istek kuyruğa yazılır, geçit hemen yanıt döner, sonuç ayrıca sorulur — bedeli, istemci
tarafında iki adımlı bir akış ve sonucun nerede tutulacağı sorusudur.

Ölçüm ağında seçim uç noktanın türüne göre yapılır. Şube ekranının tüketim sorgusu kısadır ve
sıcak yolda en kötü 44 birim sürer; orada 300 birimlik bir eşik fazlasıyla yeterlidir. Rapor
sorgusu ise soğuk yolda 234 birime çıkabilir ve istemcinin bu kadar beklemesi anlamlı değildir;
o uç nokta eşzamansıza çevrilir. Aynı geçit, aynı yapılandırma yüzeyi, iki farklı zaman aşımı
kalemi. Bu da 102 kalemin neden 102 olduğunu gösteriyor — kalemler uç nokta başına ayrı
tutuluyor, çünkü tek bir eşik bütün uç noktalar için doğru olamaz.

#### Özet

- Geçit servisinde on iki uç noktalık bir yüzey 102 yapılandırma kalemi taşır; kalemlerin hiçbiri
  işlev kodunda görünmez.
- Yetkilendirme işlevde yapıldığında 50.000 isteğin tamamı işlevi uyandırdı ve 7.460 çağrı
  yalnız reddetmek için koştu.
- Yetkilendirme geçide taşınıp reddi bir yetkilendirici işlev yaptığında toplam çağrı 92.540'a
  çıktı; yüzde 85 önbellek isabetiyle 50.040'a indi ve ücret birinci düzenle eşitlendi. Başabaş
  isabet oranı yüzde 85,1'dir.
- Geçidin belirteci kendi doğrulaması tek kazançlı düzendir: 42.540 çağrı, yüzde 12,4 daha az
  ücret. "Geçitte reddedilen istek işlevi uyandırmaz" ancak red bir işlev çağrısı değilse
  kazançtır.
- 200 birimlik zaman aşımında aşan 39 isteğin tamamı soğuk çağrıydı; 60 birimde 906 soğuk
  çağrının hepsi aştı. Geçit soğuk başlangıcı gizlemez, yalnız onu gecikme yerine hata olarak
  gösterir.
- Zaman aşımına uğrayan istekte işlev çalışmayı sürdürür; istemci yeniden denediğinde çağrı
  sayısı 48.469'a çıkar ve aynı yazma ikinci kez yapılır.

#### Sonraki Adım

Geçit dışarıdan gelen isteği içeri alıyor. Ölçüm ağının dışarıya **gönderdiği** bir akış daha
var: doğrulama başarısız olduğunda saha ekibine giden iş bildirimi, fatura kesildiğinde aboneye
giden ileti. Bu gönderimler de bir hizmete devredilir ve o hizmetin kısıtı buraya kadar
görülenlerin hiçbirine benzemez — gönderimin başarısı gönderenin elinde değildir, alan tarafın
verdiği karara bağlıdır. Sonraki ders bu kısıtı ölçer: geri dönen ileti ve şikâyet birer olay
olarak geri gelir, bu geri bildirim akışı işlenmezse ne olduğu sayılır.

### Bildirim ve E-posta Servisleri

Source: https://academia.sh/tr/kurslar/sunucusuz/bildirim-ve-e-posta-servisleri

Gönderimin bir hizmete devredilmesinin kısıtı: geri dönen ileti ile şikâyetin birer olay olarak geri gelmesi, bu geri bildirim akışının işlenme oranı taranarak otuz günün sonundaki itibar puanı, kısılan gün sayısı ve teslim edilen ileti sayısının ölçülmesi ve işlemenin maliyetiyle işlememenin bedelinin karşılaştırılması.

Geçit dışarıdan gelen isteği içeri alıyordu. Ölçüm ağının dışarıya **gönderdiği** bir akış daha
var: doğrulama başarısız olduğunda saha ekibine giden iş bildirimi, fatura kesildiğinde aboneye
giden ileti, sayaç arızasında şube sorumlusuna giden uyarı. Bu gönderimler de bir hizmete
devredilir.

Teslim edilebilirliğin kendisi daha önce ölçüldü ve o ölçüm burada tekrarlanmaz. Bu dersin
sorusu şudur: gönderimi bir hizmete devretmek hangi kısıtı geri getirir? Yanıt, buraya kadar
görülen bütün kısıtlardan farklı bir yerden gelir — **gönderimin başarısı gönderenin elinde
değildir.**

#### Devredilen Karar ve Elde Kalmayan Şey

Devredilenler tanıdık: gönderim sunucusunu işletmek, adres kayıtlarını tutmak, yeniden deneme
kuyruğunu yönetmek, alan adı doğrulama kayıtlarını yenilemek. Devredilmeyen, ama zaten hiç
kimsenin elinde olmayan bir şey var: alan tarafın kararı. Bir ileti kabul edilir, geri
çevrilir, sessizce bir klasöre atılır ya da şikâyet olarak işaretlenir; bu kararı veren, gönderen
değildir.

Hizmet bu kararı ölçer ve gönderene bir **itibar** olarak yansıtır. Karşılığında gelen kısıt
buradan doğar: gönderim kotası itibara bağlıdır. İtibar düşünce kota düşer, kota düşünce
gönderilebilecek ileti sayısı düşer. Buraya kadarki derslerde kısıt bir ayardı — görünürlük
süresi, azami teslim, zaman aşımı. Burada kısıt **kazanılan bir sayıdır** ve doğrudan
ayarlanamaz; ancak davranışla yükseltilir.

Kısıtın bir de başlangıç hali vardır. Yeni bir gönderim akışının geçmişi yoktur, dolayısıyla
itibarı da yoktur; hizmet bu durumda hacmi baştan açmaz, geçmiş biriktikçe açar. Bunun pratik
sonucu, gönderim kapasitesinin **anlık olarak ölçeklenememesidir.** Buraya kadarki bütün
hizmetlerde ölçek talep edildiği anda geliyordu — kuyruk derinliği artınca örnek eklendi, istek
sayısı artınca geçit taşıdı. Gönderimde böyle olmaz: bir günde 8.000 iletiden 80.000'e çıkmak
teknik bir sınır değil, kazanılmamış bir izindir. Ölçüm ağının yeni bir bölgeyi devreye alması
planlanıyorsa, gönderim hacminin o tarihten haftalar önce kademeli olarak yükseltilmesi gerekir.

Hizmetin bu kararı ilettiği yol da tanıdıktır. Geri dönen ileti ve şikâyet, gönderene birer
**olay** olarak geri gelir; tıpkı bu konunun ilk dersindeki olaylar gibi bir veri yoluna ya da
konuya yazılırlar. Buradan doğrudan bir sonuç çıkar: o olayları alacak bir kural yoksa, hiçbir
hata üretmeden düşerler. İlk derste ölçülen 433 sessiz düşme burada bir liste hijyeni sorununa
dönüşür.

Ölçüm kurgu bölgesel ölçüm ağının saha bildirimleri üzerindedir; adresler `ornek.gecersiz`
biçiminde kurgu adlardır.

- **OS31.** Liste 12.000 alıcıdır; başlangıçta 480'i geçersizdir (kapanmış hesap, hatalı alan
  adı).
- **OS32.** Günlük taban kota 8.000 iletidir; gerçekleşen kota itibarla orantılıdır ve itibar
  60'ın altına inince ayrıca yarıya düşer.
- **OS33.** İtibar 100'den başlar; günlük geri dönme oranı 0,02'yi aşarsa 6 puan, şikâyet oranı
  0,001'i aşarsa 3 puan iner, ikisi de eşiğin altındaysa 2 puan çıkar.
- **OS34.** Şikâyet eden alıcı listeden çıkarılmazsa listede kalır ve sonraki gönderimlerde
  yeniden şikâyet eder.
- **OS35.** Geri bildirim işleme oranı, o gün gelen geri dönen ve şikâyet olaylarının kaçının
  listeye yansıdığıdır.
- **OS36.** Model tek bir gönderim akışı kurar; içerik, konu satırı ve gönderim saati etkileri
  ölçülmez. Modelde rastgelelik yoktur.

#### İşleme Oranı ile Teslim Arasındaki Bağ

```js
// itibar.mjs — bildirim servisi modeli: geri bildirim islenmezse teslim ne oluyor
// Model: gercek bir gonderim degil, geri bildirim isleme orani ile teslimin baglanmasi.
const GUN = 30, LISTE = 12000, TABAN = 8000;
const GECERSIZ0 = 480;                         // kapanmis ya da hatali adres (kurgu liste)

function kosum(p) {                            // p: geri bildirim isleme orani
  let gecersiz = GECERSIZ0, sikayetci = 0, itibar = 100;
  let teslim = 0, donenTop = 0, sikTop = 0, kisilanGun = 0;
  for (let g = 0; g < GUN; g++) {
    const kisik = itibar < 60;                 // itibar esigin altina inince gonderim kisilir
    const kota = Math.round(TABAN * (itibar / 100) * (kisik ? 0.5 : 1));
    if (kisik) kisilanGun++;
    const gonderim = Math.min(kota, LISTE);
    const donen = Math.round(gonderim * (gecersiz / LISTE));
    const sik = Math.round(gonderim * (0.0006 + sikayetci / LISTE));
    teslim += gonderim - donen; donenTop += donen; sikTop += sik;
    const dOran = donen / gonderim, sOran = sik / gonderim;
    if (dOran > 0.02) itibar -= 6;
    if (sOran > 0.001) itibar -= 3;
    if (dOran < 0.01 && sOran < 0.0005) itibar += 2;
    itibar = Math.max(0, Math.min(100, itibar));
    gecersiz = Math.max(0, gecersiz - Math.round(donen * p));      // islenen geri bildirim
    sikayetci = Math.max(0, sikayetci + Math.round(gonderim * 0.0006) - Math.round(sik * p));
  }
  return { itibar, teslim, donenTop, sikTop, kisilanGun };
}

console.log("isleme orani".padEnd(14) + "30. gun itibar".padStart(16) + "teslim".padStart(9) +
  "geri donen".padStart(12) + "sikayet".padStart(9) + "kisilan gun".padStart(13));
for (const p of [0, 0.25, 0.5, 0.9, 1]) {
  const s = kosum(p);
  console.log(p.toFixed(2).padEnd(14) + String(s.itibar).padStart(16) +
    String(s.teslim).padStart(9) + String(s.donenTop).padStart(12) +
    String(s.sikTop).padStart(9) + String(s.kisilanGun).padStart(13));
}
console.log(`gun: ${GUN}, liste: ${LISTE}, gunluk taban kota: ${TABAN}, ` +
  `baslangictaki gecersiz adres: ${GECERSIZ0}`);
```

```sh
node itibar.mjs
```

```
isleme orani    30. gun itibar   teslim  geri donen  sikayet  kisilan gun
0.00                         0    40743        1697       65           25
0.25                         7    62990        1450       84           24
0.50                        88   211687         953      207            0
0.90                        94   225548         532      150            0
1.00                        94   225600         480      150            0
gun: 30, liste: 12000, gunluk taban kota: 8000, baslangictaki gecersiz adres: 480
```

İlk satır geri bildirimin hiç işlenmediği durumdur. Otuzuncu günün sonunda itibar **sıfırdır**,
otuz günün **25'inde gönderim kısılmıştır** ve toplam teslim 40.743'te kalmıştır. Hiçbir şey
bozulmadı: gönderim isteği her gün kabul edildi, hizmet hata döndürmedi, geri bildirim olayları
düzgün biçimde yayınlandı. Yalnız kimse onları okumadı.

Son satır aynı listenin, aynı içeriğin ve aynı otuz günün öteki ucudur. Geri bildirim tam
işlendiğinde itibar 94'te kalır, hiçbir gün kısılmaz ve teslim **225.600'e** çıkar. Aradaki
fark 184.857 iletidir — beş buçuk kat. İki koşum arasında değişen tek şey, geri dönen olayların
listeye yansıtılmasıdır.

Geri dönen sütunu bu mekanizmayı açıklıyor. Tam işlemede toplam geri dönen **480'dir**, yani
listedeki geçersiz adres sayısına eşittir: her geçersiz adres bir kez geri döner, işlenir,
listeden çıkar ve bir daha denenmez. İşleme yokken aynı 480 adres otuz gün boyunca yeniden
denenir ve 1.697 geri dönme üretir. Geri dönme oranı böylece hiç düşmez, eşiğin üstünde kalır ve
itibarı her gün aşağı çeker.

Kısılan gün sütunu bu düşüşün nasıl hızlandığını gösteriyor. İtibar 60'ın altına indiği anda
kota ayrıca yarıya iner; ilk satırda otuz günün 25'i bu durumdadır. Kısılma yalnız teslimi
azaltmaz, geri bildirim akışını da inceltir — daha az gönderim, daha az geri dönme, dolayısıyla
temizlenecek adresin bulunması da yavaşlar. Kısıt kendi düzelmesini geciktirir.

Şikâyet sütunu ilk bakışta ters görünüyor: işleme oranı yükseldikçe şikâyet sayısı 65'ten 150'ye
çıkıyor. Bunun nedeni paydadır — işlenmeyen koşumda kota çöktüğü için zaten çok az ileti
gönderilmiştir. Şikâyet **oranı** işlemeyle düşer, sayısı ise gönderim arttığı için yükselir.
Mutlak sayıya bakan bir gösterge burada tam ters yönde yorumlanır.

#### Eşik Nerede

Tabloda asıl bulgu ikinci ile üçüncü satır arasındadır. İşleme oranı 0,25'te itibar 7,
teslim 62.990; 0,50'de itibar 88, teslim 211.687. Doğrusal bir ilişki yoktur — iki katına çıkan
işleme oranı teslimi üç buçuk katına çıkarır. Bunun nedeni eşik mantığıdır: geri dönme oranı
0,02'nin altına indiği anda ceza durur ve itibar kendini toplamaya başlar. Bu eşiği geçecek
kadar temizlik yapmak yetiyor; ondan sonrası kendiliğinden geliyor.

Bu yüzden "geri bildirimin yarısını işliyoruz" cümlesi bir eksiklik değil, sınırın hangi
tarafında durulduğu sorusudur. 0,25 ile 0,50 arasında bir yerde sistem iki kararlı durumdan
birine yerleşir: ya oran eşiğin altına iner ve teslim tavana yürür, ya eşiğin üstünde kalır ve
kota dibe iner. Ara bir denge yoktur, çünkü kısılan kota geri bildirim hacmini de düşürür ve
temizlenecek adres daha yavaş bulunur.

#### Geri Bildirimi Yanlış İşlemek

İlk ölçüm işlemenin faydasını gösterdi, ama tek bir işleme biçimi varsaydı: geri dönen adres
listeden çıkar. Gerçek geri bildirim akışı tek türlü değildir. Bir bölümü kalıcı hatadır —
adres yok, alan adı yok, hesap kapanmış. Bir bölümü geçicidir: kutu dolu, alan sunucu meşgul,
geçici bir sınıra takılmış. İkisi aynı olay akışından, çoğu zaman benzer biçimde gelir.

```js
// tur-ayrimi.mjs — geri bildirim turu ayirt edilmezse listeden kimler siliniyor
const GUN = 30, LISTE = 12000, KOTA = 8000;
const GECERSIZ0 = 480;          // kalici hata: adres yok, alan adi yok
const GECICI = 0.03;            // gecici hata: kutu dolu, alici sunucu mesgul

function kosum(ayrimVar) {
  let gecerli = LISTE - GECERSIZ0, gecersiz = GECERSIZ0, yanlis = 0, teslim = 0;
  for (let g = 0; g < GUN; g++) {
    const liste = gecerli + gecersiz;
    const gonderim = Math.min(KOTA, liste);
    const kalici = Math.round(gonderim * (gecersiz / liste));
    const gecici = Math.round((gonderim - kalici) * GECICI);
    teslim += gonderim - kalici - gecici;
    gecersiz = Math.max(0, gecersiz - kalici);          // kalici hata her iki modda silinir
    if (!ayrimVar) { gecerli -= gecici; yanlis += gecici; }   // gecici hata da silinirse
  }
  return { liste: gecerli + gecersiz, yanlis, teslim };
}

console.log("mod".padEnd(22) + "30. gun liste".padStart(15) + "yanlis silinen".padStart(16) +
  "teslim".padStart(9));
for (const [ad, v] of [["tur ayrimi yok", false], ["yalniz kalici silinir", true]]) {
  const s = kosum(v);
  console.log(ad.padEnd(22) + String(s.liste).padStart(15) + String(s.yanlis).padStart(16) +
    String(s.teslim).padStart(9));
}
console.log(`gun: ${GUN}, baslangic listesi: ${LISTE}, gunluk kota: ${KOTA}`);
```

```sh
node tur-ayrimi.mjs
```

```
mod                     30. gun liste  yanlis silinen   teslim
tur ayrimi yok                   5025            6495   210020
yalniz kalici silinir           11520               0   232334
gun: 30, baslangic listesi: 12000, gunluk kota: 8000
```

Tür ayırt edilmediğinde otuz günde **6.495 geçerli alıcı** listeden silindi ve liste 12.000'den
5.025'e indi. Silinenlerin hiçbirinde bir sorun yoktu; yalnız o gün kutuları doluydu. İkinci
satırda liste 11.520'de kalır — bu, başlangıçtaki 480 geçersiz adresin çıkarılmış halidir.

Buradaki kusur birinci ölçümdekinin tersidir. Orada geri bildirim işlenmiyordu ve itibar
düşüyordu; burada işleniyor, hem de fazlasıyla ve teslim yine düşüyor: 232.334 yerine 210.020.
Geri bildirim akışını işlemek tek başına yeterli değildir; olayın **türünü** okumak gerekir.
Fark, olayı alan işlevin iki satırındadır ve iki satırın maliyeti 6.495 alıcıdır. Kalıcı ile
geçici arasındaki sınırı yanlış çizmenin bedeli, akışı hiç işlememenin bedeliyle aynı yöne
bakar.

#### İşlemenin Maliyeti, İşlememenin Bedeli

Geri bildirim akışını işlemek bu konudaki en ucuz işlerden biridir. Tam işleme koşumunda otuz
günde 480 geri dönen ve 150 şikâyet olayı gelir: toplam 630 olay. Her olay bir işlev çağrısıyla
işlense ve önceki dersteki çağrı ücreti kullanılsa, otuz günün maliyeti 630 × 0,010 = **6,3
kurgu birimdir.** İşlememenin bedeli 184.857 teslim edilmemiş iletidir.

Oran bu kadar keskin olduğu halde bu akışın işlenmeden kalması olağandır ve nedeni ilk dersteki
ölçümde yazılıdır. Geri bildirim olayları bir konuya yazılır; o konunun abonesi yoksa olaylar
sessizce düşer. Ne hata sayacı artar ne bir eşik aşılır — abonesi olmayan bir konu, boş bir
kuyruğa benzer, sağlıklı görünür. Belirti, otuz gün sonra teslim sayısının düşmesiyle ortaya
çıkar ve o zaman da neden olarak gönderim hizmeti değil, "iletiler gitmiyor" gibi bir sonuç
görülür.

Bu akışın nasıl kurulacağı da bu konuda ölçülmüş parçalardan çıkar. Geri bildirim olayları bir
konuya yazılır, konunun bir aboneliği bir kuyruğa bağlanır, kuyruk bir işlevi uyandırır ve işlev
listeye yazar. Kuyruğun görünürlük süresi buradaki iş için kısa tutulabilir, çünkü liste yazması
birkaç birim sürer. Aynı geri dönme olayının iki kez teslim edilebileceği ise ikinci dersin
sonucudur; adresi listeden çıkarmak zaten etkisiz bir iştir, ama şikâyet sayacı tutuluyorsa o
sayacın dördüncü dersteki gibi bir etkisizlik anahtarına dayanması gerekir. Konu kapanırken
görülen şey budur: gönderim hizmetinin geri bildirim akışı, bu konudaki beş dersin hepsini aynı
anda kullanan tek örnektir.

Kısıtın etrafından dolaşmanın yolları vardır ve hepsinin kendi bedeli sayılabilir. Listeyi elle
temizlemek geri bildirimi işlemenin yerini tutar ama gecikmelidir: haftada bir yapılan temizlik,
tabloda 0,25 ile 0,50 arasındaki bölgeye denk düşer. Gönderimi ikiye ayırmak — işlemsel
bildirimler bir akıştan, toplu duyurular başka bir akıştan — birinin itibarını ötekinden korur;
bedeli iki ayrı yapılandırma yüzeyi ve iki ayrı geri bildirim akışıdır. Kotayı yükseltmek için
başvurmak ise kısıtı hiç kaldırmaz: kota itibarın sonucudur, girdisi değil. Bu, konu boyunca
sayılan kısıtların en katısıdır — görünürlük süresi değiştirilebilir, zaman aşımı yükseltilebilir,
adım sınırı yeniden çizilebilir; itibar yalnız kazanılır.

#### Özet

- Gönderim hizmete devredildiğinde geriye alınamayan şey alan tarafın kararıdır; hizmet bu
  kararı itibar olarak yansıtır ve kota itibara bağlanır. Kısıt bu kez ayarlanan değil,
  kazanılan bir sayıdır.
- Geri dönen ileti ve şikâyet gönderene birer olay olarak döner; bu olayları alacak bir kural
  ya da abonelik yoksa hiçbir hata üretmeden düşerler.
- Geri bildirim hiç işlenmediğinde otuz günün 25'inde gönderim kısıldı, itibar sıfıra indi ve
  teslim 40.743'te kaldı; tam işlendiğinde itibar 94, kısılan gün 0, teslim 225.600 oldu —
  aradaki fark 184.857 iletidir.
- Tam işlemede toplam geri dönen 480'dir, yani listedeki geçersiz adres sayısına eşittir;
  işleme yokken aynı 480 adres 1.697 geri dönme üretir. İlişki doğrusal da değildir: işleme
  oranı 0,25'ten 0,50'ye çıkınca teslim 62.990'dan 211.687'ye çıkar, çünkü geri dönme oranı
  eşiğin altına indiği anda ceza durur.
- Olayın türünü okumamak ters yönde aynı zararı verir: kalıcı ile geçici hata ayırt edilmediğinde
  otuz günde 6.495 geçerli alıcı silindi ve teslim 232.334'ten 210.020'ye indi.
- 630 geri bildirim olayını işlemenin maliyeti 6,3 kurgu birimdir; işlememenin bedeli 184.857
  teslim edilmemiş iletidir.

#### Sonraki Adım

Bu konu boyunca işlevler birbirine bağlandı. Olaylar kurallarla yönlendirildi, kuyruklar ve
konular araya tampon koydu, çok adımlı akışlar bir durum makinesine verildi, saatle başlayan
işler etkisiz kılındı, dışarıdan gelen istekler bir geçitten geçirildi ve dışarıya giden
iletiler bir geri bildirim akışına bağlandı. Her birinde aynı hesap tekrarlandı: bir karar
devredildi, karşılığında sayılabilir bir kısıt geldi.

Bütün bu düzeneğin ortak bir özelliği var ve şimdiye kadar hiç sorulmadı: hepsi **tek bir
bölgede** koşuyor. Kural motoru, kuyruk, orkestratör, zamanlayıcı, geçit ve gönderim hizmeti aynı
yerde duruyor; şube ekranındaki bir sorgu da, saha uygulamasındaki bir istek de o tek yere
gidiyor. Kullanıcıya yakın olan tek şey önbellekti — ve önbellek yalnız daha önce hesaplanmış
bir yanıtı saklayabilir. Sonraki konu bu sınırı ele alıyor: hesaplamanın kendisi kullanıcıya
yaklaştığında ne kazanılır, karşılığında hangi çalışma zamanı kısıtları kabul edilir.

## Kenar Bilişim

Hesaplamanın kullanıcıya taşınması: yalıtılmış çalışma birimleriyle kenar çalışma zamanı modeli, kenarda istek işleme ve yönlendirme, anahtar değer ile nesne bağlantılarıyla kenar depolama, kenarda eşgüdümlü durum tutan dayanıklı nesneler, eşzamansız işlemenin kenara taşınması ve işlem süresi, bellek ile uyumluluk kısıtlarının tasarımı belirlemesi.

### Kenar Çalışma Zamanı Modeli

Source: https://academia.sh/tr/kurslar/sunucusuz/kenar-calisma-zamani-modeli

Yalıtılmış çalışma birimi, konteyner ve sanal makineyle aynı ölçütlerde karşılaştırılır: başlangıç gecikmesi ve bellek tabanı mertebe olarak, sunulan arayüz genişliği kalem kalem. Soğuk başlangıcın kaybolması sayılır, karşılığında gelen yedi eksik kalem ve dolaşma bedeli de.

Olaylar yönlendirildi, akışlar kuruldu, uzun süren işler adım adım koşturuldu. Ama bütün bu
düzenek hâlâ **tek bir bölgede** duruyor. Kurgudaki **bölgesel ölçüm ağında** saha ekipleri ve
şube uçları bölgeye dağılmıştır; kullanıcıya yakın olan tek şey önbellekti ve önbellek yalnız
daha önce üretilmiş bir yanıtı saklar. Yeni bir yanıt üretmek gerektiğinde istek yine bölgeye
gidiyor.

Bu kurs hesabın kendisini uca taşır. İlk soru şudur: uçta ne koşar? Bölgede koşan şey bir
konteynerdir ve konteynerin bedeli ölçülmüştür. Aynı bedel yüzlerce uç noktada, her uçta
onlarca farklı uygulama için ödenemez. Uçta koşan şeyin adı **yalıtılmış çalışma birimidir** ve
bu ders onu bilinen ölçeğe ekler.

**KE1.** Bütün sayılar model girdisidir, ölçülmüş bir kurulumdan gelmez; anlamlı olan iki düzey
arasındaki **mertebe farkıdır**. **KE2.** Arayüz kalemleri ikili değer alır: sunulur ya da
sunulmaz; kısıtlı biçimde sunulan bir kalem "sunulmaz" sayılır. **KE3.** Konteyner ve sanal
makine satırlarının başlangıç ve bellek değerleri önceki ölçümün girdileridir; bu ders onları
yeniden ölçmez, yalnız üçüncü satırı ekler.

#### Ölçeğin Ucundaki Satır

Yalıtım düzeyleri daha önce beş ölçütle karşılaştırıldı ve bedeli üç kalemde ödendi. Çalışma
birimi o ölçeğin bir alt basamağıdır: kendi çekirdeğini taşımaz, kendi dosya sistemini de
taşımaz. Ayırdığı şey tek bir dildeki **yorumlayıcı bağlamıdır** — değişken uzayı, yığın ve
nesne kümesi ayrıdır, altındaki süreç ortaktır. Yeni ölçüt bu yüzden **sunulan arayüz
genişliğidir**: çalışma zamanının uygulamaya kaç kalem sunduğu.

```js
// olcum-agi/birim.mjs — yalitilmis calisma biriminin uc duzeyli olcege eklenmesi
// MODEL: butun sayilar bildirilen model girdisidir. Anlamli olan iki duzey
// arasindaki mertebe farkidir, tek bir hucredeki deger degil.

export const DUZEY = {
  "sanal makine": { baslangicMs: 25_000, bellekTabaniMB: 512 },
  "konteyner": { baslangicMs: 300, bellekTabaniMB: 12 },
  "calisma birimi": { baslangicMs: 3, bellekTabaniMB: 3 },
};

// Calisma zamaninin uygulamaya sundugu arayuz kalemleri ve hangi duzeyde var.
export const ARAYUZ = {
  "istek/yanit isleme":      ["sanal makine", "konteyner", "calisma birimi"],
  "zamanlayici":             ["sanal makine", "konteyner", "calisma birimi"],
  "giden ag istegi":         ["sanal makine", "konteyner", "calisma birimi"],
  "sifreleme temelleri":     ["sanal makine", "konteyner", "calisma birimi"],
  "akis isleme":             ["sanal makine", "konteyner", "calisma birimi"],
  "bellek ici veri yapisi":  ["sanal makine", "konteyner", "calisma birimi"],
  "dosya sistemi":           ["sanal makine", "konteyner"],
  "yerel disk kaliciligi":   ["sanal makine", "konteyner"],
  "uzun sureli surec":       ["sanal makine", "konteyner"],
  "alt surec baslatma":      ["sanal makine", "konteyner"],
  "ham yuva":                ["sanal makine", "konteyner"],
  "yerel ikili eklenti":     ["sanal makine", "konteyner"],
  "cekirdek ayari":          ["sanal makine"],
};

export const ADLAR = Object.keys(DUZEY);
export const KALEM = Object.keys(ARAYUZ);
export const sunulan = (d) => KALEM.filter((k) => ARAYUZ[k].includes(d));
const mertebe = (n) => "10^" + Math.round(Math.log10(n));

if (import.meta.main) {
console.log("bedel ve arayuz genisligi (model girdisi)");
console.log("duzey".padEnd(16) + "baslangic".padEnd(11) + "mertebe".padEnd(9) +
  "bellek tabani".padEnd(15) + "mertebe".padEnd(9) + "arayuz");
for (const d of ADLAR) {
  const v = DUZEY[d];
  console.log(d.padEnd(16) + `${v.baslangicMs} ms`.padEnd(11) + mertebe(v.baslangicMs).padEnd(9) +
    `${v.bellekTabaniMB} MB`.padEnd(15) + mertebe(v.bellekTabaniMB).padEnd(9) +
    `${sunulan(d).length}/${KALEM.length}`);
}

console.log("\narayuz kalemi (+ sunulur, - sunulmaz)");
console.log("kalem".padEnd(24) + ADLAR.map((d) => d.padEnd(16)).join(""));
for (const k of KALEM)
  console.log(k.padEnd(24) + ADLAR.map((d) => (ARAYUZ[k].includes(d) ? "+" : "-").padEnd(16)).join(""));

const eksik = KALEM.filter((k) => !ARAYUZ[k].includes("calisma birimi"));
console.log(`\ncalisma biriminde eksik olan ${eksik.length} kalem:`);
for (const k of eksik) console.log("  - " + k);
}
```

```
bedel ve arayuz genisligi (model girdisi)
duzey           baslangic  mertebe  bellek tabani  mertebe  arayuz
sanal makine    25000 ms   10^4     512 MB         10^3     13/13
konteyner       300 ms     10^2     12 MB          10^1     12/13
calisma birimi  3 ms       10^0     3 MB           10^0     6/13

arayuz kalemi (+ sunulur, - sunulmaz)
kalem                   sanal makine    konteyner       calisma birimi  
istek/yanit isleme      +               +               +               
zamanlayici             +               +               +               
giden ag istegi         +               +               +               
sifreleme temelleri     +               +               +               
akis isleme             +               +               +               
bellek ici veri yapisi  +               +               +               
dosya sistemi           +               +               -               
yerel disk kaliciligi   +               +               -               
uzun sureli surec       +               +               -               
alt surec baslatma      +               +               -               
ham yuva                +               +               -               
yerel ikili eklenti     +               +               -               
cekirdek ayari          +               -               -               

calisma biriminde eksik olan 7 kalem:
  - dosya sistemi
  - yerel disk kaliciligi
  - uzun sureli surec
  - alt surec baslatma
  - ham yuva
  - yerel ikili eklenti
  - cekirdek ayari
```

Başlangıç mertebeleri iki basamaklı adımlarla iner: 10^4, 10^2, 10^0. Sanal makineden konteynere
geçerken iki mertebe, konteynerden çalışma birimine geçerken yine iki mertebe kazanılır. Bellek
tabanı da 10^3, 10^1, 10^0 sırasını izler. Buraya kadar tablo tanıdıktır — daha ucuz bir yalıtım
düzeyi eklenmiştir.

Üçüncü sütun tabloyu tersine çevirir. Arayüz genişliği 13/13, 12/13 ve **6/13**'tür. Sanal
makine her kalemi sunar; konteynerin kaybettiği tek kalem çekirdek ayarıdır, çünkü çekirdek
paylaşılır. Çalışma birimi ise on üç kalemden yedisini birden kaybeder. Bu, ölçek üzerinde
sürekli bir azalma değil, bir **kırılmadır**: konteyner bir mertebe ucuzlarken bir kalem verir,
çalışma birimi iki mertebe ucuzlarken yedi kalem verir.

#### Soğuk Başlangıcın Ortadan Kalkması

Başlangıç gecikmesinin 10^0 mertebesine inmesi tek bir şeyi değiştirir ve o şey büyüktür.
Sunucusuz bir işlevin en tanıdık kusuru, sıfırdan başlayan bir örneğin ilk çağrıyı geciktirmesidir.
O gecikme uygulama süresinin yanında bir gürültü değil, **onu bastıran** bir kalemdir. Aşağıdaki
koşum aynı çağrı dizisini üç düzeyde koşturur ve gecikmenin yüzdelik dilimlere nasıl düştüğünü
sayar.

**KE4.** Soğuk çağrı oranı %6'dır ve deseni sabittir; rastgelelik yoktur. **KE5.** Uygulamanın
kendi işlem süresi 12 ms'dir ve düzeye göre değişmez; ağ gecikmesi bu modele girmez. **KE6.**
Dolaşma bedeli istek başına eklenen **ağ turu** sayısıyla ölçülür; bir turun kaç milisaniye
ettiği sonraki dersin konusudur.

```js
// olcum-agi/kazanc.mjs — baslangic gecikmesinin yuzdelik dilime yansimasi ve
// eksik arayuzun is yukune cevrilmesi. MODEL: cagri dagilimi deterministiktir.
import { DUZEY, ADLAR, sunulan } from "./birim.mjs";

const CAGRI = 10_000, SOGUK_YUZDE = 6, ISLEM_MS = 12, ESIK_MS = 100;
const soguk = (i) => (i * SOGUK_YUZDE) % 100 < SOGUK_YUZDE;   // desen: tohumsuz, sabit
const dilim = (a, p) => a[Math.min(a.length - 1, Math.ceil((p / 100) * a.length) - 1)];

console.log(`${CAGRI} cagri, %${SOGUK_YUZDE} soguk, islem ${ISLEM_MS} ms (model)`);
console.log("duzey".padEnd(16) + "p50".padEnd(11) + "p95".padEnd(11) + "p99".padEnd(11) +
  "ortalama ek".padEnd(14) + `${ESIK_MS} ms asan`);
for (const d of ADLAR) {
  const g = [];
  for (let i = 0; i < CAGRI; i++) g.push(ISLEM_MS + (soguk(i) ? DUZEY[d].baslangicMs : 0));
  g.sort((x, y) => x - y);
  const ek = g.reduce((t, v) => t + v - ISLEM_MS, 0) / CAGRI;
  console.log(d.padEnd(16) + `${dilim(g, 50)} ms`.padEnd(11) + `${dilim(g, 95)} ms`.padEnd(11) +
    `${dilim(g, 99)} ms`.padEnd(11) + `${ek.toFixed(1)} ms`.padEnd(14) +
    String(g.filter((v) => v > ESIK_MS).length));
}

// Soguk orani sifira indirmek: onceden isitilmis ornek tutmanin bellek bedeli.
const SICAK = 40;
console.log(`\nsoguk orani sifirlamak icin ${SICAK} ornek sicak tutulursa`);
for (const d of ADLAR)
  console.log("  " + d.padEnd(16) + `${String(DUZEY[d].bellekTabaniMB * SICAK).padStart(6)} MB bos duran taban`);

const IS = {
  "istek yonlendirme":    ["istek/yanit isleme"],
  "baslik duzenleme":     ["istek/yanit isleme"],
  "oturum dogrulama":     ["istek/yanit isleme", "sifreleme temelleri"],
  "okuma bicim cevirimi": ["istek/yanit isleme", "akis isleme"],
  "gecelik toplu isleme": ["uzun sureli surec", "dosya sistemi", "yerel disk kaliciligi"],
  "fatura belgesi":       ["dosya sistemi", "yerel ikili eklenti"],
  "gunluk arsivleme":     ["yerel disk kaliciligi", "dosya sistemi"],
  "cihaz kalici baglantisi": ["ham yuva", "uzun sureli surec"],
};
const kosar = (is, d) => IS[is].every((k) => sunulan(d).includes(k));

console.log("\nis yuku duzeyde kosar mi");
console.log("is yuku".padEnd(26) + ADLAR.map((d) => d.padEnd(16)).join(""));
for (const is of Object.keys(IS))
  console.log(is.padEnd(26) + ADLAR.map((d) => (kosar(is, d) ? "kosar" : "kosmaz").padEnd(16)).join(""));
for (const d of ADLAR)
  console.log("  " + d.padEnd(16) + `${Object.keys(IS).filter((is) => kosar(is, d)).length}/${Object.keys(IS).length} is yuku`);

// Eksik kalemin etrafindan dolasmanin bedeli: istek basina eklenen ag turu.
const DOLASMA = {
  "dosya sistemi": [1, "okuma/yazma nesne deposuna cikar"],
  "yerel disk kaliciligi": [1, "durum dis anahtar-deger deposunda tutulur"],
  "uzun sureli surec": [3, "is parcalanir, her parca durumu disaridan okur"],
  "alt surec baslatma": [2, "cagri bolgedeki bir uca devredilir"],
  "ham yuva": [2, "baglanti bolgede sonlanir, kenar yalniz yonlendirir"],
  "yerel ikili eklenti": [0, "saf dil karsiligi yazilir, islem suresi artar"],
  "cekirdek ayari": [0, "ayar yok; is bu duzeyde tutulamaz"],
};
console.log("\neksik kalemin etrafindan dolasma (istek basina ek ag turu)");
let toplam = 0;
for (const [k, [tur, yol]] of Object.entries(DOLASMA)) {
  toplam += tur;
  console.log("  " + k.padEnd(24) + `+${tur} tur   ` + yol);
}
console.log(`  ${"yedi kalemin toplami".padEnd(24)}+${toplam} tur`);
```

```
10000 cagri, %6 soguk, islem 12 ms (model)
duzey           p50        p95        p99        ortalama ek   100 ms asan
sanal makine    12 ms      25012 ms   25012 ms   1500.0 ms     600
konteyner       12 ms      312 ms     312 ms     18.0 ms       600
calisma birimi  12 ms      15 ms      15 ms      0.2 ms        0

soguk orani sifirlamak icin 40 ornek sicak tutulursa
  sanal makine     20480 MB bos duran taban
  konteyner          480 MB bos duran taban
  calisma birimi     120 MB bos duran taban

is yuku duzeyde kosar mi
is yuku                   sanal makine    konteyner       calisma birimi  
istek yonlendirme         kosar           kosar           kosar           
baslik duzenleme          kosar           kosar           kosar           
oturum dogrulama          kosar           kosar           kosar           
okuma bicim cevirimi      kosar           kosar           kosar           
gecelik toplu isleme      kosar           kosar           kosmaz          
fatura belgesi            kosar           kosar           kosmaz          
gunluk arsivleme          kosar           kosar           kosmaz          
cihaz kalici baglantisi   kosar           kosar           kosmaz          
  sanal makine    8/8 is yuku
  konteyner       8/8 is yuku
  calisma birimi  4/8 is yuku

eksik kalemin etrafindan dolasma (istek basina ek ag turu)
  dosya sistemi           +1 tur   okuma/yazma nesne deposuna cikar
  yerel disk kaliciligi   +1 tur   durum dis anahtar-deger deposunda tutulur
  uzun sureli surec       +3 tur   is parcalanir, her parca durumu disaridan okur
  alt surec baslatma      +2 tur   cagri bolgedeki bir uca devredilir
  ham yuva                +2 tur   baglanti bolgede sonlanir, kenar yalniz yonlendirir
  yerel ikili eklenti     +0 tur   saf dil karsiligi yazilir, islem suresi artar
  cekirdek ayari          +0 tur   ayar yok; is bu duzeyde tutulamaz
  yedi kalemin toplami    +9 tur
```

Üç düzeyin p50 değeri aynıdır: 12 ms. Ortanca çağrı sıcak bir örneğe düşer ve başlangıç
gecikmesini hiç görmez. Fark p95'te ortaya çıkar, çünkü soğuk çağrılar %6'lık dilimi doldurur ve
en yavaş %6 orada başlar. Sanal makinede p95 **25.012 ms**, konteynerde **312 ms**, çalışma
biriminde **15 ms**'dir. Ortalama ek gecikme sırasıyla 1.500,0 / 18,0 / 0,2 ms'dir.

Son sütun kararı verir. 100 ms'lik bir eşik konduğunda sanal makine ve konteyner aynı sayıyı
üretir: 600 çağrı. İki düzey arasında 80 kat fark olmasına karşın **ikisi de eşiği aşar**; soğuk
başlangıç konteynerde küçülür ama ortadan kalkmaz. Çalışma biriminde eşiği aşan çağrı sayısı
**0**'dır. Soğuk başlangıç burada iyileştirilmemiş, **sorun olmaktan çıkmıştır** — 3 ms'lik bir
başlangıç, 12 ms'lik bir işlemin yanında ölçülmeye değmez.

Bu kazanç, konteynerde onu satın almanın bedeliyle birlikte okunur. Soğuk oranı sıfıra indirmenin
yolu örnekleri önceden ısıtmaktır ve kırk örnek sıcak tutulduğunda boş duran bellek tabanı sanal
makinede 20.480 MB, konteynerde 480 MB'dır. Çalışma biriminde bu satır anlamsızdır: ısıtma
yapılmaz, çünkü ısıtılacak bir şey yoktur.

#### Eksik Arayüz ve Etrafından Dolaşmanın Bedeli

Devredilen karar burada nettir: çalışma zamanının kurulumu, sürümü, kapasitesi ve yerleştirmesi
gitmiştir. Karşılığında gelen kısıt bir sayıdır — **13 kalemden 7'si yoktur**. Kalem kalem:
dosya sistemi yok, yerel disk kalıcılığı yok, uzun süreli süreç yok, alt süreç başlatma yok, ham
yuva yok, yerel ikili eklenti yok, çekirdek ayarı yok. Son madde en geniş sonucu doğurur: yerel
ikili eklentiye dayanan bir kütüphane bu düzeyde **çalışmaz**, uygulama onu doğrudan çağırmasa
bile bağımlılık zincirinin bir yerinde duruyorsa paket yüklenmez.

İş yükü tablosu bunu kurgudaki ağa çevirir. Sekiz iş yükünün dördü çalışma biriminde koşar:
istek yönlendirme, başlık düzenleme, oturum doğrulama, okuma biçim çevirimi. Dördü koşmaz:
gecelik toplu işleme, fatura belgesi üretimi, günlük arşivleme, cihazla kalıcı bağlantı. Oran
**4/8**'dir ve bu, aynı ağın işlerinin yarısının uçta duramayacağı anlamına gelir. Konteyner ve
sanal makine sekizini de koşturur; ayrım iş yükünün türünde değil, **hangi kalemi istediğindedir**
— koşan dört iş de yalnız istek işleme, şifreleme ve akış kalemlerine dokunur.

Kısıtın etrafından dolaşmak mümkündür ve bedeli son tabloda toplanır. Dosya sistemi yerine nesne
deposu kullanmak erişim başına **+1 ağ turu**, yerel disk yerine dış anahtar–değer deposu **+1
tur**, uzun süreli süreci parçalayıp durumu dışarıdan okumak **+3 tur**, alt süreç ve ham yuva
işini bölgeye devretmek ikişer tur ekler. Yedi kalemin toplamı **+9 turdur**. İki kalemde tur
sayısı sıfırdır ama bedel yok değildir: yerel ikili eklentinin saf dil karşılığı işlem süresini
uzatır, çekirdek ayarının ise karşılığı yoktur — o iş bu düzeyde tutulamaz.

Dokuz turun anlamı burada henüz eksiktir, çünkü bir turun kaç milisaniye ettiği uçtan nereye
gidildiğine bağlıdır. Uçtan uca yakın bir depoya gidilen tur ile bölgeye gidilen tur aynı kalem
değildir; ilk tablo kazanç olarak 300 ms'yi silerken, dolaşma turlarının her biri o kazancın bir
parçasını geri alabilir. Kenarda hesap yapmanın gerçek hesabı bu iki sayının farkıdır.

#### Özet

- Yalıtılmış çalışma birimi bilinen ölçeğin bir alt basamağıdır: başlangıç mertebeleri 10^4,
  10^2 ve 10^0; bellek tabanı mertebeleri 10^3, 10^1 ve 10^0. Ayırdığı şey çekirdek ya da dosya
  sistemi değil, tek bir dildeki yorumlayıcı bağlamıdır.
- Üçüncü ölçüt tabloyu tersine çevirir: sunulan arayüz genişliği 13/13, 12/13 ve 6/13'tür.
  Konteyner bir kalem verip bir mertebe kazanır, çalışma birimi yedi kalem verip iki mertebe.
- Soğuk başlangıç ortadan kalkar: p95 değeri 25.012, 312 ve 15 ms; 100 ms eşiğini aşan çağrı
  sayısı 600, 600 ve 0'dır. Sıcak havuz tutmanın kırk örneklik bedeli 20.480 ve 480 MB iken
  çalışma biriminde ısıtılacak bir şey yoktur.
- Karşılığında gelen kısıt kalem kalem yazılır: dosya sistemi, yerel disk, uzun süreli süreç,
  alt süreç, ham yuva, yerel ikili eklenti ve çekirdek ayarı yoktur. Kurgudaki sekiz iş yükünün
  yalnız 4'ü bu düzeyde koşar.
- Kısıtın etrafından dolaşmanın bedeli istek başına ağ turudur: yedi kalem için toplam +9 tur.
  İki kalemde tur eklenmez ama bedel işlem süresine ya da işin taşınmasına yazılır.

#### Sonraki Adım

Bu ders uçta ne koşabileceğini yazdı ama koşan şeyin **nerede durduğunu** hiç ölçmedi. Dört iş
yükü uçta koşabiliyorsa, aynı iş bölgede de kaynakta da koşabilir — üç yer arasındaki seçim neye
göre yapılır? Bir isteğin uçta karara bağlanmasıyla bölgeye taşınması arasındaki fark kaç ağ
turudur ve o turlar kaç milisaniye eder? Yönlendirme kararı uçta verildiğinde kaynağa hiç
gitmeyen isteklerin oranı ne olur, aynı karar kimlik doğrulaması ya da A/B ayrımı olduğunda bu
oran nasıl değişir? Sonraki ders bir istek kümesini üç yerde ayrı ayrı işletir, her yerleşimin
tur sayısını ve gecikmesini çıkarır ve uçta yapılamayan işi adıyla yazar.

### İstek İşleme ve Yönlendirme

Source: https://academia.sh/tr/kurslar/sunucusuz/istek-isleme-ve-yonlendirme

Aynı istek kümesi üç yerde işlenir — uçta, bölgede ve kaynakta — ve her yerleşimin kaç ağ turu, kaç milisaniye eklediği sayılır. Uçta yapılabilen dört iş türü için kaynağa hiç gitmeyen istek oranı çıkarılır, uçta yapılamayan iş adıyla yazılır.

Önceki ders uçta neyin koşabileceğini yazdı: on üç arayüz kaleminden altısı, kurgudaki sekiz iş
yükünden dördü. Ama koşabilmek bir yerleşim kararı değildir. Aynı dört iş **bölgede de koşar**,
**kaynakta da**. Kurgudaki **bölgesel ölçüm ağında** şube uçlarından gelen her istek bugün
bölgeye gidiyor; bir kısmının uçta karara bağlanabileceğini bilmek, hangisinin bağlanması
gerektiğini söylemez.

Bu dersin ölçüsü tek bir şeydir: bir kararın nerede verildiği, o isteğe kaç **ağ turu** ve kaç
milisaniye ekler. Turlar sayılınca yerleşim sorusu tercih olmaktan çıkar ve aritmetiğe döner.

**KE7.** Turlar tam tur (gidiş–dönüş) olarak sayılır; tek yönlü gecikme modellenmez. **KE8.**
Tur ve işlem süreleri model girdisidir; kurgudaki ağın uç, bölge ve kaynak üçlüsüne karşılık
gelir. **KE9.** Bir istek en fazla bir yerde işlenir; aynı iş iki yerde birden yapılmaz.

#### Üç Yer, Üç Tur

Yol üç bacaktan oluşur. İstemci ile uç arasındaki bacak kısadır, çünkü uç şubeye yakındır. Uç
ile bölge arasındaki bacak uzundur. Bölge ile kaynak arasındaki bacak yine kısadır, çünkü ikisi
aynı bölgededir. İstek nerede işlenirse, o noktaya kadar olan bütün bacaklar ödenir.

```js
// olcum-agi/yerlesim.mjs — ayni istegin uc yerde islenmesi: tur ve gecikme
// MODEL: tur sureleri bildirilen model girdisidir; tek yonlu degil, tam tur sayilir.

export const BACAK = { "istemci-kenar": 8, "kenar-bolge": 60, "bolge-kaynak": 20 };
export const YER = {
  "kenar":  { bacak: ["istemci-kenar"], islemMs: 2 },
  "bolge":  { bacak: ["istemci-kenar", "kenar-bolge"], islemMs: 6 },
  "kaynak": { bacak: ["istemci-kenar", "kenar-bolge", "bolge-kaynak"], islemMs: 15 },
};
export const YERLER = Object.keys(YER);
export const tur = (y) => YER[y].bacak.length;
export const gecikme = (y) =>
  YER[y].bacak.reduce((t, b) => t + BACAK[b], 0) + YER[y].islemMs;

// Dort is turu ve her birinin hangi yerde yapilabildigi.
export const IS = {
  "yonlendirme":      { yer: ["kenar", "bolge", "kaynak"], sonlandirir: true },
  "baslik duzenleme": { yer: ["kenar", "bolge", "kaynak"], sonlandirir: false },
  "kimlik dogrulama": { yer: ["kenar", "bolge", "kaynak"], sonlandirir: true },
  "a/b ayrimi":       { yer: ["kenar", "bolge", "kaynak"], sonlandirir: true },
  "iliskisel sorgu":  { yer: ["kaynak"], sonlandirir: false },
  "islemli yazma":    { yer: ["kaynak"], sonlandirir: false },
  "veri kumesi taramasi": { yer: ["bolge", "kaynak"], sonlandirir: false },
};

if (import.meta.main) {
console.log("bir istegin uc yerde islenmesi (model girdisi)");
console.log("yer".padEnd(10) + "ag turu".padEnd(10) + "ag suresi".padEnd(12) +
  "islem".padEnd(9) + "toplam".padEnd(10) + "kenara gore");
for (const y of YERLER) {
  const ag = YER[y].bacak.reduce((t, b) => t + BACAK[b], 0);
  console.log(y.padEnd(10) + String(tur(y)).padEnd(10) + `${ag} ms`.padEnd(12) +
    `${YER[y].islemMs} ms`.padEnd(9) + `${gecikme(y)} ms`.padEnd(10) +
    `+${gecikme(y) - gecikme("kenar")} ms`);
}
console.log("bacak basina eklenen tur: " +
  Object.entries(BACAK).map(([b, v]) => `${b} ${v} ms`).join(", "));

console.log("\nis turu nerede yapilabilir (+ yapilir, - yapilmaz)");
console.log("is turu".padEnd(24) + YERLER.map((y) => y.padEnd(10)).join("") + "uc sonlandirir");
for (const [ad, v] of Object.entries(IS))
  console.log(ad.padEnd(24) + YERLER.map((y) => (v.yer.includes(y) ? "+" : "-").padEnd(10)).join("") +
    (v.yer.includes("kenar") ? (v.sonlandirir ? "evet" : "hayir") : "-"));
const kenarda = Object.values(IS).filter((v) => v.yer.includes("kenar")).length;
console.log(`kenarda yapilabilen: ${kenarda}/${Object.keys(IS).length}`);
}
```

```
bir istegin uc yerde islenmesi (model girdisi)
yer       ag turu   ag suresi   islem    toplam    kenara gore
kenar     1         8 ms        2 ms     10 ms     +0 ms
bolge     2         68 ms       6 ms     74 ms     +64 ms
kaynak    3         88 ms       15 ms    103 ms    +93 ms
bacak basina eklenen tur: istemci-kenar 8 ms, kenar-bolge 60 ms, bolge-kaynak 20 ms

is turu nerede yapilabilir (+ yapilir, - yapilmaz)
is turu                 kenar     bolge     kaynak    uc sonlandirir
yonlendirme             +         +         +         evet
baslik duzenleme        +         +         +         hayir
kimlik dogrulama        +         +         +         evet
a/b ayrimi              +         +         +         evet
iliskisel sorgu         -         -         +         -
islemli yazma           -         -         +         -
veri kumesi taramasi    -         +         +         -
kenarda yapilabilen: 4/7
```

Tur sayısı 1, 2 ve 3'tür; gecikme 10, 74 ve 103 ms. Uçtan bölgeye geçmek **+64 ms**, bölgeden
kaynağa geçmek **+29 ms** ekler. İki adım eşit değildir ve nedeni bacak süreleridir: uzun bacak
uç ile bölge arasındadır. Yerleşim kararının ağırlığı bu yüzden ilk adımda toplanır — bir işi
bölgeden kaynağa taşımak yerinde bir ayrıntı, uçtan bölgeye taşımak ise gecikmenin yaklaşık üçte
ikisidir.

İşlem süreleri ters yönde çalışır ve kararı yumuşatmaz. Uçta 2 ms, bölgede 6 ms, kaynakta 15
ms'dir; en uzak yer aynı zamanda en yavaş işleyen yerdir, çünkü orada yapılan iş daha ağırdır.
Üç kalemin toplamında ağ süresi işlem süresini bastırır: kaynakta 88 ms ağ, 15 ms işlem.

Turların tam tur sayılması (KE7) sayının nasıl okunacağını da belirler. Bir yerleşimin maliyeti
tek yönlü mesafe değil, **yanıtın geri dönmesi** dahil edilmiş süredir; uçta verilen bir karar
kaynağa bir soru sorup beklemek zorunda kalırsa o bekleme aynı tabloya bir satır daha ekler.
Modelin dışarıda bıraktığı şey de burada görünür: art arda iki bağımsız veri isteği yapan bir iş,
tabloda tek satırla temsil edilemez, iki tur öder. Bu yüzden uçta tutulmaya en uygun iş türü,
karar için gereken her şeyi **isteğin kendisinde** taşıyan iştir.

İkinci tablo yedi iş türünü yerleştirir. Dördü üç yerde de yapılabilir. Bunların üçü **isteği
uçta sonlandırabilir**: yönlendirme bir yanıt üretir, kimlik doğrulama bir reddetme üretir, A/B
ayrımı hazır bir kopyayı döndürür. Başlık düzenleme uçta yapılır ama isteği sonlandırmaz —
başlık yazılır ve istek yoluna devam eder. Bu ayrım sonraki sayımın tamamını belirler: bir işin
uçta yapılabilmesi ile o işin **kaynağı ziyaret etmekten kurtarması** aynı şey değildir.

#### Uçta Sonlanan İstek

Şimdi bir istek kümesi bu dört işten sırayla geçirilir. Sıralı olması önemlidir: yönlendirme
aşamasında kapanan bir istek kimlik doğrulamaya hiç girmez, dolayısıyla aynı istek iki kez
sayılmaz.

**KE10.** Küme 10.000 istektir ve aşama başına uçta sonlanan istek sayısı model girdisidir.
**KE11.** A/B ayrımında uçta hazır bulunan kopya bir girdidir; önbellek isabeti bu derste
yeniden ölçülmez. **KE12.** Uçta işlenip geçen istek kaynak yoluna uç işlem süresini de ekler.

```js
// olcum-agi/suzgec.mjs — istek kumesi ucta sirali suzgecten gecirilir
// MODEL: asama basina ucta sonlanan istek sayisi bildirilen model girdisidir.
import { YER, YERLER, IS, tur, gecikme } from "./yerlesim.mjs";

const KUME = 10_000;
const ASAMA = [
  ["yonlendirme", 1_240, "eski adres ucta kalici yanitla kapanir"],
  ["kimlik dogrulama", 860, "gecersiz belirtec ucta reddedilir"],
  ["a/b ayrimi", 2_100, "varyant ucta secilir ve ucta hazir kopya doner"],
  ["baslik duzenleme", 0, "baslik yazilir, istek yoluna devam eder"],
];

console.log(`${KUME} istek, ucta sirali suzgec (model girdisi)`);
console.log("asama".padEnd(20) + "dokunulan".padEnd(12) + "ucta sonlanan".padEnd(16) +
  "kalan".padEnd(9) + "kume orani");
let kalan = KUME, sonlanan = 0;
for (const [ad, biten, _] of ASAMA) {
  const dokunulan = kalan;
  kalan -= biten; sonlanan += biten;
  console.log(ad.padEnd(20) + String(dokunulan).padEnd(12) + String(biten).padEnd(16) +
    String(kalan).padEnd(9) + `%${((biten / KUME) * 100).toFixed(1)}`);
}
console.log("kaynaga hic gitmeyen: " + sonlanan + `/${KUME}  ` +
  `%${((sonlanan / KUME) * 100).toFixed(1)}   kaynaga giden: ${kalan}`);

// Iki senaryonun agirlikli gecikmesi ve toplam ag turu.
const KENAR_EK = YER["kenar"].islemMs;
const senaryo = {
  "hepsi kaynakta": [[KUME, gecikme("kaynak"), tur("kaynak")]],
  "dort is ucta": [[sonlanan, gecikme("kenar"), tur("kenar")],
                   [kalan, gecikme("kaynak") + KENAR_EK, tur("kaynak")]],
};
console.log("\nagirlikli gecikme ve toplam ag turu");
const ort = {};
for (const [ad, satir] of Object.entries(senaryo)) {
  const ms = satir.reduce((t, [n, g]) => t + n * g, 0) / KUME;
  const turlar = satir.reduce((t, [n, , k]) => t + n * k, 0);
  ort[ad] = ms;
  console.log("  " + ad.padEnd(18) + `${ms.toFixed(1)} ms/istek   ` +
    `${turlar} tur   istek basina ${(turlar / KUME).toFixed(2)} tur`);
}
const fark = ort["hepsi kaynakta"] - ort["dort is ucta"];
console.log(`  ${"kazanc".padEnd(18)}${fark.toFixed(1)} ms/istek   ` +
  `%${((fark / ort["hepsi kaynakta"]) * 100).toFixed(1)}`);

// Bir kararin ucta degil daha uzakta verilmesinin marjinal bedeli.
console.log("\nayni karari bir basamak uzaga tasimanin bedeli");
for (let i = 1; i < YERLER.length; i++) {
  const [o, y] = [YERLER[i - 1], YERLER[i]];
  console.log("  " + `${o} -> ${y}`.padEnd(20) +
    `+${tur(y) - tur(o)} tur   +${gecikme(y) - gecikme(o)} ms/istek   ` +
    `kume basina +${(((gecikme(y) - gecikme(o)) * KUME) / 1000).toFixed(1)} sn`);
}

const NEDEN = {
  "iliskisel sorgu": "cok tabloyu birlestirir; veri kenarda yok",
  "islemli yazma": "kesin siralama ve geri alma ister; kenarda islem sinir yok",
  "veri kumesi taramasi": "girdi bellek tabanindan buyuk; kenarda disk yok",
};
console.log("\nkenarda yapilamayan is");
for (const [ad, v] of Object.entries(IS)) {
  if (v.yer.includes("kenar")) continue;
  console.log("  " + ad.padEnd(24) + `en yakin yer: ${v.yer[0].padEnd(8)}` + NEDEN[ad]);
}
```

```
10000 istek, ucta sirali suzgec (model girdisi)
asama               dokunulan   ucta sonlanan   kalan    kume orani
yonlendirme         10000       1240            8760     %12.4
kimlik dogrulama    8760        860             7900     %8.6
a/b ayrimi          7900        2100            5800     %21.0
baslik duzenleme    5800        0               5800     %0.0
kaynaga hic gitmeyen: 4200/10000  %42.0   kaynaga giden: 5800

agirlikli gecikme ve toplam ag turu
  hepsi kaynakta    103.0 ms/istek   30000 tur   istek basina 3.00 tur
  dort is ucta      65.1 ms/istek   21600 tur   istek basina 2.16 tur
  kazanc            37.9 ms/istek   %36.8

ayni karari bir basamak uzaga tasimanin bedeli
  kenar -> bolge      +1 tur   +64 ms/istek   kume basina +640.0 sn
  bolge -> kaynak     +1 tur   +29 ms/istek   kume basina +290.0 sn

kenarda yapilamayan is
  iliskisel sorgu         en yakin yer: kaynak  cok tabloyu birlestirir; veri kenarda yok
  islemli yazma           en yakin yer: kaynak  kesin siralama ve geri alma ister; kenarda islem sinir yok
  veri kumesi taramasi    en yakin yer: bolge   girdi bellek tabanindan buyuk; kenarda disk yok
```

Dört iş türünün kaynağa hiç gitmeyen istek oranları ayrı ayrı okunur: yönlendirme %12,4, kimlik
doğrulama %8,6, A/B ayrımı %21,0, başlık düzenleme %0,0. Toplamda **4.200 istek** kaynağı hiç
görmez — kümenin %42,0'si. Başlık düzenlemenin sıfır üretmesi onu değersiz kılmaz; yaptığı iş
kaynağın yükünü değil, kaynağın **kodunu** hafifletir. Ama tur sayımında karşılığı yoktur ve
tabloda öyle görünür.

İstek başına ağ turu 3,00'ten **2,16**'ya, ağırlıklı gecikme 103,0 ms'den **65,1 ms**'ye iner;
kazanç 37,9 ms, yani %36,8. Bu sayı doğrudan %42,0'nin karşılığıdır: kaynağa gitmeyen her istek
üç turluk yoldan tek turluk yola geçer. Kaynağa giden 5.800 istek ise **105 ms** öder, 103 değil;
uçta işlenip geçmenin 2 ms'lik bir bedeli vardır ve ortalamada görünür.

Süzgecin sırası da bir karardır ve "dokunulan" sütununda görünür. Kimlik doğrulama yönlendirmenin
ardında durduğu için 10.000 yerine 8.760 isteğe bakar; A/B ayrımı ikisinin ardında olduğu için
7.900'e bakar. Sıra tersine çevrilseydi uçta sonlanan toplam değişmezdi — 4.200 yine 4.200 olurdu
— ama A/B ayrımı, sonunda reddedilecek 860 istek için de varyant hesaplardı. Sıralı süzgeçte
kazanılan şey tur değil, uçta harcanan **işlem süresidir**; ucuz ve çok eleyen aşama öne alınır.

Marjinal tablo aynı kararı ters yönden okur. Uçta verilebilen bir kararı bölgeye taşımak istek
başına +64 ms, on bin istekte **640 saniye** eder. Bölgeden kaynağa taşımak +29 ms ve 290
saniyedir. Kurgudaki ağda bu, kimlik doğrulamasını uçta değil bölgede yapma kararının on bin
istekte on dakikadan fazla toplam bekleme yarattığı anlamına gelir — ve bu isteklerin 860'ı zaten
reddedilecektir.

#### Uçta Yapılamayan İş

Devredilen karar bu derste yerleştirmedir: isteğin hangi düğümde karşılandığını uygulama
seçmez. Karşılığında gelen kısıt yine bir sayıdır — **yedi iş türünden 3'ü uçta yapılamaz** ve
üçü de adıyla yazılır. **İlişkisel sorgu** birden çok tabloyu birleştirir; birleştirilecek veri
uçta yoktur. **İşlemli yazma** kesin sıralama ve geri alma ister; uçta işlem sınırı kurulamaz.
**Veri kümesi taraması** girdisi bellek tabanından büyüktür ve uçta disk yoktur. Son ikisi
önceki dersin eksik kalem listesinden doğrudan türer: yerel disk kalıcılığı yoktu, işlemli
yazmanın dayandığı kalıcı günlük de yoktu.

Bu üçünün en yakın yeri farklıdır ve fark bir tasarım kaldıracıdır. Veri kümesi taraması
bölgede yapılabilir, ilişkisel sorgu ve işlemli yazma yalnız kaynakta. Yani uçta yapılamayan
her iş aynı uzaklığa sürülmez: bir işi bölgede tutabilmek, kaynağa taşımaya göre istek başına 29
ms geri kazandırır. Kurgudaki ağda gecelik uzlaştırma bu yüzden bölgede kalır, fatura
kesinleştirme ise kaynağa iner; ikisi de uçtan çıkar ama aynı uzaklığa değil.

Kısıtın etrafından dolaşmanın yolu bu dersin ölçüsünde nettir ve bedeli de öyle. İlişkisel
sorgunun uca taşınabilmesi için sonucun önceden hesaplanıp uçta bir yerde durması gerekir; o
zaman soru sorgu olmaktan çıkar, **okuma** olur. İşlemli yazmanın uca taşınabilmesi için
sıralamayı garanti eden tek bir yazarın uçta durması gerekir. İki dolaşma yolu da aynı şeyi
ister: uçta duran, okunabilen ve yazılabilen bir **durum**. Bu dersin modeli o durumu hiç
varsaymadı — dört işin dördü de durumsuzdu.

#### Özet

- Üç yerleşim üç tur eder: uç 1 tur / 10 ms, bölge 2 tur / 74 ms, kaynak 3 tur / 103 ms. Uzun
  bacak uç ile bölge arasındadır, bu yüzden ilk adım +64 ms, ikinci adım +29 ms'dir.
- Yedi iş türünün 4'ü uçta yapılabilir; bunların 3'ü isteği uçta sonlandırır. Uçta yapılabilmek
  ile kaynağı ziyaret etmekten kurtarmak aynı şey değildir — başlık düzenleme bunun örneğidir.
- Kaynağa hiç gitmeyen istek oranları: yönlendirme %12,4, kimlik doğrulama %8,6, A/B ayrımı
  %21,0, başlık düzenleme %0,0. Toplamı 4.200/10.000, yani %42,0.
- İstek başına ağ turu 3,00'ten 2,16'ya, ağırlıklı gecikme 103,0 ms'den 65,1 ms'ye iner; kazanç
  %36,8. Uçta işlenip geçen istek kaynak yolunda 2 ms'lik ek öder.
- Uçta yapılamayan üç iş adıyla yazılır: ilişkisel sorgu, işlemli yazma, veri kümesi taraması.
  İkisinin en yakın yeri kaynak, birininki bölgedir; aradaki fark istek başına 29 ms'dir.

#### Sonraki Adım

Bu dersin dört işi de durumsuzdu: yönlendirme bir tabloya, kimlik doğrulama bir imzaya, A/B
ayrımı bir bölme kuralına bakıyordu. Uçta yapılamayan üç iş ise durum istiyor. O zaman soru şu
olur: uçta bir değer okunabilir mi, yazılabilir mi? Okuma uca yakınsa hızlıdır — peki yazma
nereye gider ve yazılan değer öbür uçlarda ne zaman görünür? İki uç aynı anahtarı okuduğunda ne
kadar süre farklı yanıt verirler ve bu süre içinde kaç okuma bayat çıkar? Uçtan büyük bir nesneye
erişmek kaç tur eder ve çıkış ücretini hangi yöne çevirir? Sonraki ders uçtaki depolamayı okuma
ve yazma eksenlerinde ayrı ayrı ölçer, yayılma penceresini tarar ve depoya konulabilecek değerin
sınırını bir kısıt olarak sayar.

### Kenar Depolama

Source: https://academia.sh/tr/kurslar/sunucusuz/kenar-depolama

Kenar anahtar–değer deposu okuma için hızlı, yazma için yavaştır ve tutarlılığı gecikmelidir. Yayılma penceresi taranıp her değerde bayat okuma sayılır, nesne deposuna erişimin tur sayısı ve çıkış ücreti kurgu birimle karşılaştırılır, deponun boyut sınırı bir kısıt olarak çıkarılır.

Önceki dersin dört işi de durumsuzdu: yönlendirme bir tabloya, kimlik doğrulama bir imzaya, A/B
ayrımı bir bölme kuralına bakıyordu. Uçta yapılamayan üç işin ortak yanı ise durum istemeleriydi.
Kurgudaki **bölgesel ölçüm ağında** şube uçlarının sık ihtiyaç duyduğu şeyler bellidir: şubenin
tarife tablosu, yapılandırması, bir oturumun geçerlilik özeti. Bunlar büyük değildir ve çoğunlukla
okunur.

Uçta bir depo vardır ve adı **kenar anahtar–değer deposudur**. Bu ders onu tek bir ölçüyle
tartmaz, çünkü tek bir sayı yanıltır: bu modeldeki depo okuma yönünde bölgedeki her şeyden hızlı,
yazma yönünde bölgedeki her şeyden yavaştır — gerçek kenar depolarının hepsi bu takası aynı
biçimde yapmaz, kimi yazmayı güçlü tutarlı sunar. Aradaki fark bir gecikme kalemi değil,
bir **tutarlılık
penceresidir**.

**KE13.** Yazma merkezde uygulanır; yazan uç yeni değeri hemen görür, öteki uçlar yayılma
penceresi boyunca eski değeri döndürür. **KE14.** Pencere sabittir ve sonunda bütün uçlar yeni
değeri görür; kısmi yayılma modellenmez. **KE15.** Olay akışı kendi üretecimizle üretilir ve
tohum görünürdür.

#### Okuma Ucuz, Yazma Pahalı

Okuma yolunun uzunluğu değerin uçta olup olmamasına bağlıdır. Değer uçta duruyorsa okuma hiç
ağa çıkmaz. Yazma yolunun uzunluğu ise değişmez: yazma her zaman merkeze gider, çünkü sıralamayı
belirleyen tek nokta orasıdır.

```js
// olcum-agi/yayilma.mjs — kenar anahtar-deger deposunda okuma/yazma asimetrisi
// ve yayilma penceresinde bayat okuma sayimi.
// MODEL: olay akisi kendi uretecimizle uretilir; tohum gorunurdur.

const TOHUM = 20_260_801;
let s = TOHUM % 2_147_483_647;
const rnd = () => (s = (s * 48_271) % 2_147_483_647) / 2_147_483_647;

const UC = 6, ANAHTAR = 40, OLAY = 20_000, YAZMA_YUZDE = 8;
const YOL = {
  "okuma (uctaki kopya)": { tur: 0, ms: 2 },
  "okuma (kopya yoksa)":  { tur: 1, ms: 62 },
  "yazma (merkeze)":      { tur: 1, ms: 64 },
};

console.log("okuma ve yazma ayni depoda ayni sey degil (model girdisi)");
for (const [ad, v] of Object.entries(YOL))
  console.log("  " + ad.padEnd(24) + `${v.tur} ek tur   ${String(v.ms).padStart(3)} ms`);
console.log("  yazma / okuma gecikme orani: " +
  (YOL["yazma (merkeze)"].ms / YOL["okuma (uctaki kopya)"].ms).toFixed(0) + "x");

const olay = [];
let t = 0;
for (let i = 0; i < OLAY; i++) {
  t += 1 + Math.floor(rnd() * 60);
  const uc = Math.floor(rnd() * UC), anahtar = Math.floor(rnd() * ANAHTAR);
  olay.push({ t, uc, anahtar, yaz: rnd() * 100 < YAZMA_YUZDE });
}
const yazma = olay.filter((o) => o.yaz).length;
console.log(`\n${OLAY} olay, ${UC} uc, ${ANAHTAR} anahtar, tohum ${TOHUM}`);
console.log(`  yazma ${yazma}   okuma ${OLAY - yazma}   akis suresi ${(t / 1000).toFixed(1)} sn`);

console.log("\nyayilma penceresi tarandiginda bayat okuma");
console.log("pencere".padEnd(12) + "pencere ici okuma".padEnd(20) +
  "bayat okuma".padEnd(14) + "okuma orani".padEnd(14) + "anahtar basina");
for (const pencere of [1_000, 5_000, 10_000, 30_000, 60_000]) {
  const son = new Array(ANAHTAR).fill(null);
  let ici = 0, bayat = 0, okuma = 0;
  for (const o of olay) {
    if (o.yaz) { son[o.anahtar] = o; continue; }
    okuma++;
    const y = son[o.anahtar];
    if (!y || o.t - y.t >= pencere) continue;
    ici++;
    if (y.uc !== o.uc) bayat++;
  }
  console.log(`${pencere} ms`.padEnd(12) + String(ici).padEnd(20) + String(bayat).padEnd(14) +
    `%${((bayat / okuma) * 100).toFixed(2)}`.padEnd(14) + (bayat / ANAHTAR).toFixed(1));
}
console.log("  pencere 0 ms olsaydi bayat okuma 0 olurdu; bedeli her okumanin merkeze gitmesidir");
```

```
okuma ve yazma ayni depoda ayni sey degil (model girdisi)
  okuma (uctaki kopya)    0 ek tur     2 ms
  okuma (kopya yoksa)     1 ek tur    62 ms
  yazma (merkeze)         1 ek tur    64 ms
  yazma / okuma gecikme orani: 32x

20000 olay, 6 uc, 40 anahtar, tohum 20260801
  yazma 1582   okuma 18418   akis suresi 609.8 sn

yayilma penceresi tarandiginda bayat okuma
pencere     pencere ici okuma   bayat okuma   okuma orani   anahtar basina
1000 ms     1154                957           %5.20         23.9
5000 ms     5019                4147          %22.52        103.7
10000 ms    8690                7230          %39.26        180.8
30000 ms    15466               12857         %69.81        321.4
60000 ms    17572               14621         %79.38        365.5
  pencere 0 ms olsaydi bayat okuma 0 olurdu; bedeli her okumanin merkeze gitmesidir
```

Asimetri ilk üç satırda okunur. Uçtaki kopyadan okuma **0 ek tur ve 2 ms**, kopya yoksa okuma 1
tur ve 62 ms, yazma her durumda 1 tur ve **64 ms**'dir. Yazmanın okumaya oranı **32 kat**tır. Bu
oran deponun ne için kurulduğunu söyler: değer bir kez yazılıp çok kez okunuyorsa depo yerindedir,
her istekte bir kez yazılıyorsa depo yanlış yerdedir.

#### Bayat Okumanın Sayısı

Tutarlılığın gecikmeli olması bir sıfat değildir; kaç okumanın eski değeri gördüğüyle ölçülür.
Aşağıdaki tarama pencereyi beş değerde tutar ve her değerde bayat okumayı sayar. Bayat sayılmanın
koşulu iki tanedir: okuma son yazmadan sonra pencere dolmadan gelmiş olacak **ve** okuyan uç
yazan uçtan farklı olacak.

Akışın kendisi de bir girdidir ve okunması gerekir: 20.000 olayın 1.582'si yazma, 18.418'i
okumadır ve 609,8 saniyeye yayılır. Yani karışım deponun tasarlandığı yöne uygundur — on bir
okumaya bir yazma düşer. Bayat okuma sayısının bu kadar yüksek çıkması bu yüzden yazmanın çok
olmasından değil, kırk anahtarın altı uca dağılmasından gelir: her yazma, öteki beş uçtaki
okumaları pencere boyunca eski değere bağlar.

Sayılar tek yönde ve hızlı büyür. 1.000 ms'lik pencerede bayat okuma **957**, okumaların
%5,20'si. 5.000 ms'de 4.147 ve %22,52. 10.000 ms'de 7.230 ve %39,26. 30.000 ms'de 12.857 ve
%69,81. 60.000 ms'de 14.621 ve %79,38. Pencere altmış kat büyürken bayat okuma on beş kat artar;
büyüme doğrusal değildir, çünkü pencere genişledikçe okumaların çoğu zaten bir yazmanın gölgesinde
kalır ve doyuma yaklaşır. Anahtar başına düşen bayat okuma 23,9'dan 365,5'e çıkar.

Kırk anahtarın her biri kurgudaki bir şubenin tarife tablosu sayılırsa, 30.000 ms'lik bir
pencerede anahtar başına 321,4 okuma eski tarifeyi görür. Bu sayının kabul edilebilir olup
olmadığı okumanın ne için yapıldığına bağlıdır: bir ekranda tarife göstermek için okunuyorsa
katlanılır, bir faturaya tutar yazmak için okunuyorsa katlanılmaz. Aynı depo aynı pencereyle iki
iş için iki ayrı yanıt verir.

Devredilen karar burada çoğaltmadır: değerin hangi uçlara, ne zaman kopyalanacağını uygulama
seçmez. Karşılığında gelen kısıt yayılma penceresidir ve bir sayıdır. Kısıtın etrafından
dolaşmanın yolu son satırda yazılıdır: pencere sıfıra indirilirse bayat okuma sıfır olur, ama o
zaman her okuma merkeze gider — okuma 2 ms'den 62 ms'ye, yani otuz bir kat yukarı çıkar. Depoyu
kullanmanın sebebi tam olarak o 2 ms olduğuna göre, bu dolaşma yolu deponun kendisini iptal eder.

#### Nesne Deposuna Uzanmak

Depoya sığmayan şeyler için uç, nesne deposuna uzanır. Uzanmanın iki ekseni vardır ve ters
yönde çalışırlar: tur sayısı ve çıkış ücreti.

**KE16.** Ücretler **kurgu birimdir**; gerçek bir para birimi ya da fiyat değildir. **KE17.**
Nesne boyutu 250 KB sabittir ve uçta tutulan kopyanın isabet oranı %70 girdidir.
**KE18.** Bu modelde değer
sınırı 25 KB, anahtar sınırı 512 bayttır — gerçek servislerde bu iki sınır çok farklı olabilir;
parçalama parçaların sırayla okunmasını varsayar.

```js
// olcum-agi/nesne.mjs — kenardan nesne deposuna erisimin turu ve cikis ucreti,
// ardindan kenar deposunun boyut siniri. MODEL: ucretler kurgu birimdir,
// gercek bir para birimi ya da fiyat degildir.

const ISTEK = 10_000, NESNE_KB = 250, GB = 1_048_576;   // KB cinsinden 1 GB
const UCRET = { "nesne->bolge": 0, "bolge->uc": 0, "nesne->uc": 2, "uc->istemci": 1 };
const YOL = {
  "bolge uzerinden": { tur: 2, ms: 80, bacak: ["nesne->bolge", "bolge->uc", "uc->istemci"] },
  "uctan dogrudan":  { tur: 1, ms: 45, bacak: ["nesne->uc", "uc->istemci"] },
  "ucta kopya":      { tur: 0, ms: 2,  bacak: ["uc->istemci"] },
};

const hacimGB = (n) => (n * NESNE_KB) / GB;
const ucret = (yol, n) => YOL[yol].bacak.reduce((t, b) => t + UCRET[b], 0) * hacimGB(n);

console.log(`${ISTEK} nesne istegi, nesne ${NESNE_KB} KB, ucretler kurgu birimdir`);
console.log("yol".padEnd(18) + "ag turu".padEnd(10) + "gecikme".padEnd(10) +
  "cikis kalemi".padEnd(14) + "birim/GB".padEnd(11) + "kume ucreti");
for (const [ad, v] of Object.entries(YOL)) {
  const birimGB = v.bacak.reduce((t, b) => t + UCRET[b], 0);
  console.log(ad.padEnd(18) + String(v.tur).padEnd(10) + `${v.ms} ms`.padEnd(10) +
    String(v.bacak.length).padEnd(14) + String(birimGB).padEnd(11) +
    `${ucret(ad, ISTEK).toFixed(2)} birim`);
}
console.log(`kume hacmi ${hacimGB(ISTEK).toFixed(2)} GB   ` +
  `bacak ucreti: ` + Object.entries(UCRET).map(([b, u]) => `${b} ${u}`).join(", "));

const ISABET = 70;
const kopya = Math.round((ISTEK * ISABET) / 100), dusen = ISTEK - kopya;
const karmaMs = (kopya * YOL["ucta kopya"].ms + dusen * YOL["bolge uzerinden"].ms) / ISTEK;
const karmaUcret = ucret("ucta kopya", kopya) + ucret("bolge uzerinden", dusen);
console.log(`\nkarma: %${ISABET} ucta kopya, kalani bolge uzerinden`);
console.log("  " + `${kopya} + ${dusen} istek`.padEnd(22) +
  `${karmaMs.toFixed(1)} ms/istek   ${karmaUcret.toFixed(2)} birim   ` +
  `dogrudan yola gore ${(ucret("uctan dogrudan", ISTEK) / karmaUcret).toFixed(2)}x ucuz`);

// Kenar anahtar-deger deposunun siniri: anahtar 512 bayt, deger 25 KB.
const DEGER_KB = 25, ANAHTAR_BAYT = 512;
const KAYIT = {
  "sube yapilandirmasi": 2,
  "tarife tablosu": 18,
  "oturum ozeti": 0.4,
  "gunluk okuma ozeti": 140,
  "aylik fatura belgesi": 900,
  "sayac ham gunlugu": 12_000,
};
console.log(`\nkenar deposu siniri: deger ${DEGER_KB} KB, anahtar ${ANAHTAR_BAYT} bayt`);
console.log("kayit".padEnd(24) + "boyut".padEnd(12) + "sigar".padEnd(9) + "dolasma");
let sigan = 0;
for (const [ad, kb] of Object.entries(KAYIT)) {
  const olur = kb <= DEGER_KB;
  if (olur) sigan++;
  const parca = Math.ceil(kb / DEGER_KB);
  console.log(ad.padEnd(24) + `${kb} KB`.padEnd(12) + (olur ? "evet" : "hayir").padEnd(9) +
    (olur ? "-" : `${parca} parca, okuma basina +${parca - 1} okuma  ya da nesne deposu (+2 tur)`));
}
console.log(`  ${sigan}/${Object.keys(KAYIT).length} kayit depoya sigar`);
```

```
10000 nesne istegi, nesne 250 KB, ucretler kurgu birimdir
yol               ag turu   gecikme   cikis kalemi  birim/GB   kume ucreti
bolge uzerinden   2         80 ms     3             1          2.38 birim
uctan dogrudan    1         45 ms     2             3          7.15 birim
ucta kopya        0         2 ms      1             1          2.38 birim
kume hacmi 2.38 GB   bacak ucreti: nesne->bolge 0, bolge->uc 0, nesne->uc 2, uc->istemci 1

karma: %70 ucta kopya, kalani bolge uzerinden
  7000 + 3000 istek     25.4 ms/istek   2.38 birim   dogrudan yola gore 3.00x ucuz

kenar deposu siniri: deger 25 KB, anahtar 512 bayt
kayit                   boyut       sigar    dolasma
sube yapilandirmasi     2 KB        evet     -
tarife tablosu          18 KB       evet     -
oturum ozeti            0.4 KB      evet     -
gunluk okuma ozeti      140 KB      hayir    6 parca, okuma basina +5 okuma  ya da nesne deposu (+2 tur)
aylik fatura belgesi    900 KB      hayir    36 parca, okuma basina +35 okuma  ya da nesne deposu (+2 tur)
sayac ham gunlugu       12000 KB    hayir    480 parca, okuma basina +479 okuma  ya da nesne deposu (+2 tur)
  3/6 kayit depoya sigar
```

Üç yol arasındaki ilişki ilk bakışta beklenenin tersidir. Uçtan doğrudan nesne deposuna gitmek
**en az turlu** yollardan biridir — 1 tur, 45 ms — ama küme ücreti **7,15 birimdir**, bölge
üzerinden gitmenin üç katı. Nedeni çıkış kalemidir: doğrudan yolda nesne, deponun ağından çıkıp
uca gelir ve bu bacak GB başına 2 birim yazar. Bölge üzerinden gidildiğinde nesne aynı ağın içinde
kalır; ücretlenen tek bacak uçtan istemciye olandır. Tur sayısını azaltmak burada ücreti üç katına
çıkarır.

Uçta kopya tutmak iki eksende de kazanır: 0 tur, 2 ms ve 2,38 birim. Ama bu satır bir varsayımla
gelir — kopyanın orada olması. Karma satır gerçek durumu verir: %70 isabetle ortalama **25,4
ms/istek** ve 2,38 birim; doğrudan yola göre 3,00 kat ucuz. Kopya oranı düştükçe gecikme 80 ms'ye
doğru kayar, ücret ise değişmez. Yani uçta kopya tutmanın kazandırdığı şey ücret değil, gecikmedir;
ücreti belirleyen tek şey trafiğin hangi bacaklardan geçtiğidir.

#### Depoya Ne Sığar

Son tablo deponun sınırını bir kısıt olarak sayar. Değer sınırı 25 KB'dır ve kurgudaki altı
kayıt türünün **3'ü sığar**: şube yapılandırması 2 KB, tarife tablosu 18 KB, oturum özeti 0,4 KB.
Üçü sığmaz: günlük okuma özeti 140 KB, aylık fatura belgesi 900 KB, sayaç ham günlüğü 12.000 KB.

Sığmayan bir değeri depoya sokmanın yolu parçalamaktır ve bedeli okuma tarafında toplanır. 140
KB'lık özet 6 parça eder; her tam okuma **+5 okuma** demektir. Fatura belgesi 36 parça ve +35
okuma, ham günlük 480 parça ve +479 okuma. Parçalama küçük bir aşımda makul, büyük bir aşımda
saçmadır: 25 KB sınırının dört yüz seksen katı olan bir değer için depo doğru araç değildir.
Alternatif satırda yazılıdır — nesne deposuna koymak ve +2 tur ödemek. Karar noktası tek okumada
kaç parça gerektiğidir; parça sayısı ikiyi üçü geçtiği anda nesne deposunun iki turu daha ucuza
gelir.

Anahtar sınırının 512 bayt olması ayrı bir tasarım kısıtıdır ve tabloda görünmez. Anahtarın kısa
olması, birleşik anahtarların — şube, sayaç, dönem üçlüsünün — tek bir dizgeye sığdırılmasını
gerektirir; bu da deponun aralık sorgusu yapamamasıyla birleşince veriyi anahtar tasarımına
gömmeye zorlar. Depo bir veritabanı değildir; anahtarla erişilen küçük ve çok okunan değerler
içindir.

#### Özet

- Aynı depo iki yönde iki ayrı şeydir: uçtaki kopyadan okuma 0 tur / 2 ms, yazma 1 tur / 64 ms.
  Yazmanın okumaya oranı 32 kattır; depo bir kez yazılıp çok okunan değerler içindir.
- Tutarlılık gecikmelidir ve bedeli sayılır: 1.000 / 5.000 / 10.000 / 30.000 / 60.000 ms'lik
  pencerelerde bayat okuma 957, 4.147, 7.230, 12.857 ve 14.621; okuma oranı %5,20'den %79,38'e
  çıkar, anahtar başına 23,9'dan 365,5'e.
- Pencereyi sıfırlamak bayat okumayı sıfırlar ama okumayı 2 ms'den 62 ms'ye taşır — deponun
  kullanılma sebebini iptal eder.
- Nesne deposuna üç yol vardır: bölge üzerinden 2 tur / 2,38 birim, uçtan doğrudan 1 tur / 7,15
  birim, uçta kopya 0 tur / 2,38 birim. Tur azaltmak ücreti üç katına çıkarabilir; %70 isabetli
  karma 25,4 ms/istek ve 2,38 birim eder.
- Değer sınırı 25 KB'dır ve altı kayıt türünün 3'ü sığar. Sığmayanlar 6, 36 ve 480 parça eder;
  parça sayısı birkaçı geçtiğinde nesne deposunun +2 turu daha ucuza gelir.

#### Sonraki Adım

Bu dersin deposu bir şeyi hiç çözmedi: iki uç aynı anahtarı **aynı anda** değiştirmek isterse ne
olur? Yayılma penceresi eski değeri okutuyordu; iki yazma yarışırsa biri diğerinin üzerine yazar
ve arada bir güncelleme kaybolur. Sayaç artırmak, bir odaya katılanları saymak, bir kaynağı tek
bir işleme kilitlemek — üçü de "oku, değiştir, yaz" adımını gerektirir ve üçü de bu depoda güvenli
değildir. Uçta eşgüdümlü durum tutmanın yolu, aynı anahtar için **tek bir yazarın** var olmasıdır.
Sonraki ders tek yazarlı bir nesne modelini koşturur, eşzamanlı isteklerde kayıp güncellemeyi
sayar ve karşılığında gelen iki kısıtı — tek örneğin darboğazı ile nesnenin coğrafi olarak
sabitlenmesi — ölçer.

### Dayanıklı Durum Nesneleri

Source: https://academia.sh/tr/kurslar/sunucusuz/dayanikli-durum-nesneleri

Aynı anahtar için tek yazarlı bir nesne modeli koşturulur: eşzamanlı isteklerde kayıp güncelleme sıfıra iner. Karşılığında gelen iki kısıt sayılır — tek örneğin istek başına sıraya girmesi ve nesnenin coğrafi olarak sabitlenmesi — ve sayaç, oda, kilit senaryolarında hangisinin uyduğu yazılır.

Önceki dersin deposu bir şeyi çözmeden bıraktı. Yayılma penceresi okumaları eski değere
bağlıyordu; iki uç aynı anahtarı aynı anda değiştirmek isterse ne olur? Kurgudaki **bölgesel
ölçüm ağında** bunun karşılığı somuttur: bir şubenin doğrulanmış okuma sayacı, aynı anda iki
farklı uçtan gelen kayıtla artırılmak isteniyor.

"Oku, değiştir, yaz" üç ayrı adımdır ve aralarına başkası girebilir. Bu dersin ölçtüğü şey bu
araya girmenin kaç güncelleme düşürdüğü ve onu sıfıra indiren modelin karşılığında ne istediğidir.
İki model aynı iş yüküyle koşar.

**KE19.** Paylaşılan depo modelinde okuma 20 ms, hesap 1 ms, yazma 64 ms sürer; üçü ayrı
adımdır. **KE20.** Varışlar deterministiktir; rastgelelik yoktur. **KE21.** Tek yazarlı nesnede
aynı anahtar tek bir örneğe yönlendirilir, istekler varış sırasına göre kuyruğa girer, durum
örneğin belleğinde tutulur ve istek başına işleme 6 ms'dir; koşut yürütme yoktur.

#### Aynı Anahtara İki Model

İlk model tanıdıktır: değer uzak bir depoda durur, her istemci okur, artırır, geri yazar. İkinci
modelde anahtar bir örneğe bağlanır — aynı anahtar için ağda tek bir örnek vardır ve bütün
istekler oraya sıraya girer. Adım artık üç değil, birdir.

```js
// olcum-agi/tekyazar.mjs — ayni anahtar iki modelde: paylasilan depo (oku-degistir-yaz)
// ve tek yazarli nesne (sirali isleme). MODEL: varislar ve sureler deterministiktir.

const ISTEMCI = 8, ADIM = 50, TOPLAM = ISTEMCI * ADIM;
const OKU_MS = 20, HESAP_MS = 1, YAZ_MS = 64;      // paylasilan depo yolu
const ISLEM_MS = 6;                                 // tek ornekte istek basina isleme

// --- 1. Paylasilan depo: her istemci sirayla oku-degistir-yaz yapar.
const islem = [];
for (let c = 0; c < ISTEMCI; c++) {
  let t = c * 3;
  for (let i = 0; i < ADIM; i++) {
    islem.push({ okuT: t, yazT: t + OKU_MS + HESAP_MS + YAZ_MS, okunan: 0 });
    t = t + OKU_MS + HESAP_MS + YAZ_MS;
  }
}
const olay = [];
for (const o of islem) { olay.push({ t: o.okuT, oku: true, o }); olay.push({ t: o.yazT, oku: false, o }); }
olay.sort((a, b) => a.t - b.t || (a.oku ? -1 : 1));
let deger = 0, ustuneYazilan = 0;
for (const e of olay) {
  if (e.oku) { e.o.okunan = deger; continue; }
  if (deger !== e.o.okunan) ustuneYazilan++;
  deger = e.o.okunan + 1;
}
console.log(`${ISTEMCI} istemci x ${ADIM} artirma = ${TOPLAM} istek, ayni anahtar (model)`);
console.log("paylasilan depo (oku-degistir-yaz)");
console.log(`  beklenen ${TOPLAM}   sayacin son degeri ${deger}   ` +
  `kayip guncelleme ${TOPLAM - deger}   %${(((TOPLAM - deger) / TOPLAM) * 100).toFixed(1)}`);
console.log(`  ustune yazilan yazma ${ustuneYazilan}   islem suresi ${OKU_MS + HESAP_MS + YAZ_MS} ms`);

// --- 2. Tek yazarli nesne: ayni anahtar tek ornege gider, istekler sirayla islenir.
function kuyruk(istemci, araMs) {
  const varis = [];
  for (let c = 0; c < istemci; c++)
    for (let i = 0; i < ADIM; i++) varis.push(c * 3 + i * araMs);
  varis.sort((a, b) => a - b);
  let bos = 0, sayac = 0, bekleme = [];
  for (const v of varis) {
    const basla = Math.max(v, bos);
    bekleme.push(basla - v);
    bos = basla + ISLEM_MS;
    sayac++;                                        // durum bellekte, adim atomik
  }
  bekleme.sort((a, b) => a - b);
  const p95 = bekleme[Math.ceil(0.95 * bekleme.length) - 1];
  const ort = bekleme.reduce((t, v) => t + v, 0) / bekleme.length;
  return { istek: varis.length, sayac, hiz: (istemci * 1000) / araMs, ort, p95,
           sure: (bos - varis[0]) / 1000 };
}
const TAVAN = 1000 / ISLEM_MS;
console.log(`\ntek yazarli nesne (istek basina ${ISLEM_MS} ms, tavan ${TAVAN.toFixed(1)} istek/sn)`);
console.log("yuk".padEnd(22) + "varis hizi".padEnd(14) + "kayip".padEnd(9) +
  "ort. bekleme".padEnd(15) + "p95 bekleme".padEnd(14) + "kuyruk");
for (const [istemci, ara] of [[4, 40], [6, 40], [8, 40]]) {
  const r = kuyruk(istemci, ara);
  console.log(`${istemci} istemci / ${ara} ms`.padEnd(22) +
    `${r.hiz.toFixed(0)}/sn`.padEnd(14) + String(r.istek - r.sayac).padEnd(9) +
    `${r.ort.toFixed(1)} ms`.padEnd(15) + `${r.p95} ms`.padEnd(14) +
    (r.hiz > TAVAN ? "doygun" : "akiyor"));
}
```

```
8 istemci x 50 artirma = 400 istek, ayni anahtar (model)
paylasilan depo (oku-degistir-yaz)
  beklenen 400   sayacin son degeri 45   kayip guncelleme 355   %88.8
  ustune yazilan yazma 355   islem suresi 85 ms

tek yazarli nesne (istek basina 6 ms, tavan 166.7 istek/sn)
yuk                   varis hizi    kayip    ort. bekleme   p95 bekleme   kuyruk
4 istemci / 40 ms     100/sn        0        4.5 ms         9 ms          akiyor
6 istemci / 40 ms     150/sn        0        7.5 ms         15 ms         akiyor
8 istemci / 40 ms     200/sn        0        206.5 ms       386 ms        doygun
```

Paylaşılan depoda 400 artırma isteği sayacı **45**'e taşır. Kayıp güncelleme **355**, yani
%88,8. Sayı bu kadar büyüktür çünkü işlem süresi 85 ms'dir ve sekiz istemci o 85 ms boyunca aynı
eski değeri okur; sekizinin yazması da aynı sonucu üretir, yedisi boşa gider. Bu, deponun bir
kusuru değildir — depo yazılan şeyi doğru yazmıştır. Kaybolan şey **araya girmenin görülmemiş
olmasıdır**.

Tek yazarlı nesnede aynı iş yükünde kayıp güncelleme üç yük düzeyinde de **0**'dır. Nedeni
modelin kendisidir: okuma, hesap ve yazma tek bir örneğin belleğinde art arda olur ve o örnek
aynı anda başka bir isteği işlemez. Sıfırın bir garanti olarak yazılabilmesi, adımın bölünemez
hâle gelmesinden gelir.

#### Karşılığında Gelen İki Kısıt

Sıfır bedava değildir. İlk bedel kuyruğa girmedir ve tabloda üç düzeyde okunur. Örnek başına
tavan **166,7 istek/sn**'dir. 100/sn varışta ortalama bekleme 4,5 ms, p95 9 ms. 150/sn varışta
7,5 ms ve 15 ms. 200/sn varışta ise ortalama bekleme **206,5 ms**, p95 **386 ms**'dir ve kuyruk
doygundur — varış tavanı aştığı için bekleme koşum boyunca büyümeye devam eder.

İki yük düzeyi arasındaki fark burada dikkat çeker: 150/sn ile 200/sn arasında varış %33 artarken
ortalama bekleme 7,5 ms'den 206,5 ms'ye, yani yaklaşık 28 kat çıkar. Tek örnek bir ölçekleme
birimidir ve tavanı aştığında yanıt vermeyi kesmez, **biriktirir**. Devredilen karar eşzamanlılığın
yönetimidir; karşılığında gelen kısıt tek bir sayıdır: istek başına 6 ms, saniyede 166,7 istek.

Kısıtın etrafından dolaşmanın yolu örneği çoğaltmak değildir — çoğaltmak tek yazarlığı, dolayısıyla
sıfırı iptal eder. Yol **anahtarı bölmektir**: bir sayaç yerine şube başına bir sayaç tutmak,
toplam yükü örnek sayısına böler. Bedeli, artık küresel bir toplamın tek bir yerde durmamasıdır;
toplam istendiğinde bütün örnekler okunur ve okuma sayısı örnek sayısı kadar artar.

#### Nesne Nerede Durur

İkinci bedel coğrafyadır. Nesne bir yerde durur; oradan uzaktaki istemci ona **uzaktan** erişir.
Uçta koşmanın bütün kazancı yakınlıktan geliyordu ve eşgüdümlü durum o yakınlığı tek bir noktaya
indirger.

**KE22.** Uzaklıklar tam turdur ve model girdisidir. **KE23.** Nesne koşum boyunca taşınmaz;
konum değişimi modellenmez. **KE24.** Senaryo hızları toplam istek hızıdır; örnek başına düşen
hız, anahtarın kaç örneğe bölündüğüne göre hesaplanır.

```js
// olcum-agi/senaryo.mjs — nesnenin cografi olarak sabitlenmesi ve senaryo uyumu
// MODEL: uzakliklar tam tur, model girdisidir; nesne kosum boyunca tasinmaz.

const ISLEM_MS = 6, TAVAN = 1000 / ISLEM_MS;
const UC = {
  "uc-1": { yuk: 2600, "en yogun ucta": 4,  "bolgede": 62, "sube basina": 4 },
  "uc-2": { yuk: 2100, "en yogun ucta": 40, "bolgede": 58, "sube basina": 4 },
  "uc-3": { yuk: 1800, "en yogun ucta": 55, "bolgede": 66, "sube basina": 4 },
  "uc-4": { yuk: 1500, "en yogun ucta": 70, "bolgede": 60, "sube basina": 4 },
  "uc-5": { yuk: 1200, "en yogun ucta": 88, "bolgede": 64, "sube basina": 4 },
  "uc-6": { yuk:  800, "en yogun ucta": 96, "bolgede": 70, "sube basina": 4 },
};
const YERLESIM = ["en yogun ucta", "bolgede", "sube basina"];
const TOPLAM = Object.values(UC).reduce((t, u) => t + u.yuk, 0);

console.log(`nesneye erisim turu, ${TOPLAM} istek uc uca dagilmis (model girdisi)`);
console.log("uc".padEnd(8) + "yuk".padEnd(9) + YERLESIM.map((y) => y.padEnd(16)).join(""));
for (const [ad, u] of Object.entries(UC))
  console.log(ad.padEnd(8) + String(u.yuk).padEnd(9) + YERLESIM.map((y) => `${u[y]} ms`.padEnd(16)).join(""));
console.log("agirlikli".padEnd(8) + "".padEnd(9) + YERLESIM.map((y) => {
  const ms = Object.values(UC).reduce((t, u) => t + u.yuk * u[y], 0) / TOPLAM;
  return `${ms.toFixed(1)} ms`.padEnd(16);
}).join(""));
console.log("en kotu uc".padEnd(8) + "".padEnd(9) +
  YERLESIM.map((y) => `${Math.max(...Object.values(UC).map((u) => u[y]))} ms`.padEnd(16)).join(""));
console.log("  esgudum istemeyen is ayni uctan 2 ms'de biter; fark sabitlenmenin bedelidir");

const SENARYO = {
  "sube sayaci":        { anahtar: "sube",    ornek: 6,   hiz: 480, uzunIsMs: 0 },
  "sube odasi":         { anahtar: "sube",    ornek: 6,   hiz: 600, uzunIsMs: 0 },
  "is emri kilidi":     { anahtar: "is emri", ornek: 120, hiz: 240, uzunIsMs: 0 },
  "kuresel sira sayaci":{ anahtar: "tek",     ornek: 1,   hiz: 900, uzunIsMs: 0 },
  "gecelik uzlastirma": { anahtar: "tek",     ornek: 1,   hiz: 5,   uzunIsMs: 40_000 },
};
console.log(`\nsenaryo uyumu (ornek basina tavan ${TAVAN.toFixed(1)} istek/sn)`);
console.log("senaryo".padEnd(22) + "anahtar".padEnd(10) + "ornek".padEnd(8) +
  "toplam hiz".padEnd(13) + "ornek basina".padEnd(14) + "sonuc");
for (const [ad, s] of Object.entries(SENARYO)) {
  const basina = s.hiz / s.ornek;
  const neden = s.uzunIsMs > 0
    ? `uymaz: ${s.uzunIsMs / 1000} sn'lik is ornegi kilitler, ` +
      `arkada ${Math.round((s.uzunIsMs / 1000) * s.hiz)} istek bekler`
    : basina > TAVAN
      ? `uymaz: ornek basina ${basina.toFixed(0)}/sn, tavanin ${(basina / TAVAN).toFixed(1)} kati`
      : `uyar: tavanin %${((basina / TAVAN) * 100).toFixed(0)}'i`;
  console.log(ad.padEnd(22) + s.anahtar.padEnd(10) + String(s.ornek).padEnd(8) +
    `${s.hiz}/sn`.padEnd(13) + `${basina.toFixed(0)}/sn`.padEnd(14) + neden);
}
const uyan = Object.values(SENARYO).filter((s) => s.uzunIsMs === 0 && s.hiz / s.ornek <= TAVAN).length;
console.log(`  ${uyan}/${Object.keys(SENARYO).length} senaryo tek yazarli nesneye uyar`);
```

```
nesneye erisim turu, 10000 istek uc uca dagilmis (model girdisi)
uc      yuk      en yogun ucta   bolgede         sube basina     
uc-1    2600     4 ms            62 ms           4 ms            
uc-2    2100     40 ms           58 ms           4 ms            
uc-3    1800     55 ms           66 ms           4 ms            
uc-4    1500     70 ms           60 ms           4 ms            
uc-5    1200     88 ms           64 ms           4 ms            
uc-6    800      96 ms           70 ms           4 ms            
agirlikli         48.1 ms         62.5 ms         4.0 ms          
en kotu uc         96 ms           70 ms           4 ms            
  esgudum istemeyen is ayni uctan 2 ms'de biter; fark sabitlenmenin bedelidir

senaryo uyumu (ornek basina tavan 166.7 istek/sn)
senaryo               anahtar   ornek   toplam hiz   ornek basina  sonuc
sube sayaci           sube      6       480/sn       80/sn         uyar: tavanin %48'i
sube odasi            sube      6       600/sn       100/sn        uyar: tavanin %60'i
is emri kilidi        is emri   120     240/sn       2/sn          uyar: tavanin %1'i
kuresel sira sayaci   tek       1       900/sn       900/sn        uymaz: ornek basina 900/sn, tavanin 5.4 kati
gecelik uzlastirma    tek       1       5/sn         5/sn          uymaz: 40 sn'lik is ornegi kilitler, arkada 200 istek bekler
  3/5 senaryo tek yazarli nesneye uyar
```

Nesne en yoğun ucun yanına konduğunda ağırlıklı erişim turu **48,1 ms**, bölgeye konduğunda
**62,5 ms**'dir. İlk seçenek ikinciyi ortalamada geçer ama en kötü ucu kötüleştirir: 96 ms'ye
karşı 70 ms. Yani nesneyi en yoğun ucun yanına almak, yükün %26'sını taşıyan uca 4 ms verirken
%8'ini taşıyan uca 96 ms yazar. Bölgeye koymak bu dağılımı düzleştirir; kimseye çok iyi, kimseye
çok kötü davranmaz.

Üçüncü sütun asıl kararı gösterir. Anahtar şube başına bölündüğünde her nesne kendi ucunda durur
ve ağırlıklı erişim turu **4,0 ms**'ye iner — en kötü uç da 4 ms'dir. Eşgüdüm istemeyen bir işin
aynı uçtan 2 ms'de bitmesiyle karşılaştırıldığında fark yalnız 2 ms'dir. Coğrafi sabitlenme
burada bir bedel olmaktan çıkar, çünkü nesne zaten kullanıldığı yerdedir. Sabitlenme, anahtar
coğrafyayla örtüşmediğinde bedel olur.

#### Hangi Kullanım Uyar

Son tablo beş senaryoyu aynı iki ölçütle tartar: örnek başına düşen hız ve işin süresi.
**Şube sayacı** 480/sn toplam yük taşır, altı örneğe bölünür, örnek başına 80/sn eder — tavanın
%48'i. **Şube odası** 600/sn ile örnek başına 100/sn ve tavanın %60'ı. **İş emri kilidi** 120
örneğe bölündüğü için örnek başına 2/sn, tavanın %1'i; kilit senaryosu tek yazarlı nesneye en
rahat oturan kullanımdır, çünkü anahtar doğal olarak çok sayıda ve her biri seyrektir.

İki senaryo uymaz ve nedenleri farklıdır. **Küresel sıra sayacı** bölünemez bir anahtar üzerinde
900/sn ister; bu, tavanın 5,4 katıdır ve tek örnek bunu karşılayamaz. Buradaki uyumsuzluk
hızdandır. **Gecelik uzlaştırma** ise yalnız 5/sn ister ama işin kendisi 40 saniye sürer ve o
süre boyunca örneği kilitler; arkasında **200 istek** bekler. Buradaki uyumsuzluk süredendir.
Aynı model iki ayrı eşikte reddeder: istek başına 6 ms'lik tavan ve isteğin bölünemez uzunluğu.

Beş senaryonun **3'ü uyar**. Kural tek cümleyle yazılır: tek yazarlı nesne, anahtarı çok sayıda
olan, her anahtarı seyrek dokunulan ve işlemleri kısa olan eşgüdüm işleri içindir. Üç koşuldan
biri bozulduğunda model reddeder ve reddi bir sayıyla yazar.

#### Özet

- Paylaşılan depoda 400 eşzamanlı artırma sayacı 45'e taşır: kayıp güncelleme 355, yani %88,8.
  Kaybolan şey deponun yanlış yazması değil, araya girmenin görülmemiş olmasıdır.
- Tek yazarlı nesnede aynı iş yükünde kayıp güncelleme üç yük düzeyinde de 0'dır; okuma, hesap ve
  yazma tek örneğin belleğinde bölünemez biçimde olur.
- Karşılığında gelen ilk kısıt tavandır: istek başına 6 ms, örnek başına 166,7 istek/sn. Varış
  100, 150 ve 200/sn iken ortalama bekleme 4,5, 7,5 ve 206,5 ms; %33'lük bir varış artışı beklemeyi
  yaklaşık 28 kat büyütür.
- İkinci kısıt coğrafi sabitlenmedir: ağırlıklı erişim turu en yoğun uçta 48,1 ms, bölgede 62,5
  ms, şube başına bölündüğünde 4,0 ms'dir. Bedel, anahtarın coğrafyayla örtüşmediği durumda doğar.
- Beş senaryonun 3'ü uyar: şube sayacı (tavanın %48'i), şube odası (%60), iş emri kilidi (%1).
  Küresel sıra sayacı hız yüzünden (tavanın 5,4 katı), gecelik uzlaştırma süre yüzünden (40 sn'de
  arkada 200 istek) uymaz.

#### Sonraki Adım

Bu dersin reddettiği iki senaryonun ortak yanı, isteğin **yanıtı beklemek zorunda olmasıdır**.
Gecelik uzlaştırma 40 saniye sürüyordu ve arkasında iki yüz istek biriktiriyordu; oysa o işin
sonucunu bekleyen kimse yoktu. Kurgudaki ağda uçtan gelen çoğu kayıt böyledir: sayaç okuması
alınır, alındığı onaylanır ve işlenmesi sonraya bırakılabilir. Uçta bir işi hemen yapmak yerine
bırakabilseydik, tek örneğin tavanı bir sınır olmaktan çıkar mıydı? Bırakılan iş nerede durur,
kaç kez denenir ve uçtaki çalışma zamanının süre sınırı bu bekleyişi nasıl keser? Sonraki ders
uçta işi sonraya bırakmanın yollarını ölçer: bırakılan işin nerede biriktiği, teslim garantisinin
ne olduğu ve uçta zamanlanmış bir tetiklemenin bölgedekinden nerede ayrıldığı.

### Kenar Kuyrukları ve Zamanlanmış İşler

Source: https://academia.sh/tr/kurslar/sunucusuz/kenar-kuyruklari-ve-zamanlanmis-isler

Aynı iş kümesi merkez ve kenar kuyruğunda işlenir; kuyruğa girme turu, işin koştuğu yer ve sonucun dönüş yolu ayrı sayılır. Kenar kuyruğunun dört kısıtı ile zamanlanmış işin tetiklendiği bölge ölçülür.

Bir önceki ders kenarda eşgüdümlü durumu tutmayı başardı: tek yazarlı nesne kendi anahtarına gelen
yazmaları sıraya koydu. Eşzamansız iş ise hâlâ merkezde koşuyor; doğrulama, fatura satırı ve saha
bildirimi merkez bölgedeki bir kuyruğa yazılıyor. Bu ders aynı iş kümesini iki yerde işletip üç şeyi
ayrı sayar: kuyruğa girme turu, işin koştuğu yer, sonucun dönüş yolu.

Ölçüm **bölgesel ölçüm ağının** altı şube ucu üzerindedir ve **kurgudur**; uçlar, iki kuyruk servisi
ve zamanlayıcı `node` ile kurulmuş bir **modeldir**. Gerçek bir ürün çağrılmaz.

**KE25.** Her uç için merkeze ve en yakın kenar konumuna tek yön gecikme, bir de gecelik okuma
sayısı yazılıdır.
**KE26.** Kuyruğa girme turu, tek yön gecikmenin iki katı artı kuyruğun sabit kabul süresidir.
**KE27.** Merkez kuyruğu 250'lik toplu okuma, 10 deneme, 14 gün saklama ve anahtar başına sıralama
sunar; kenar kuyruğu 25 ve 3 sunar, 4 gün saklar, sıralama vermez.
**KE28.** Tüketici her toplu okumada bir kez başlar: merkezde 40 ms, kenarda 6 ms. Okuma başına
işlem iki yolda da 12 ms'dir.
**KE29.** Sonuç, işin koştuğu yerdeki depoya yazılır. Merkez deposu merkez turu kadar uzaktır;
kenar anahtar–değer deposu yerel okunur, ama yazısının öteki uçlarda görünmesi 480 ms sürer.
**KE30.** Zamanlanmış tetikleme yalnız temel saati bilir; kenar zamanlayıcı tetikleme konumunu
kendi seçer ve seçim kayıt altında değildir.

#### Aynı İş Kümesi, İki Kuyruk

```js
// ag.mjs — kurgu olcum agi modeli: uclar, gecikmeler, iki kuyrugun kisitlari.
export const UCLAR = [                              // tek yon gecikme ms, serit temel saatten sapma
  { ad: "uc-bati",  merkez: 12, kenar: 5,  serit: 0, okuma: 610 },
  { ad: "uc-kuzey", merkez: 38, kenar: 7,  serit: 0, okuma: 520 },
  { ad: "uc-dogu",  merkez: 74, kenar: 9,  serit: 2, okuma: 430 },
  { ad: "uc-guney", merkez: 51, kenar: 6,  serit: 1, okuma: 350 },
  { ad: "uc-yayla", merkez: 96, kenar: 11, serit: 3, okuma: 280 },
  { ad: "uc-liman", merkez: 63, kenar: 8,  serit: 2, okuma: 210 },
];
export const TOPLAM = UCLAR.reduce((t, u) => t + u.okuma, 0);
export const KUYRUK = {                             // kalem kalem kisitlar
  merkez: { kabul: 9, toplu: 250, deneme: 10, saklama_gn: 14, baslatma: 40 },
  kenar:  { kabul: 3, toplu: 25,  deneme: 3,  saklama_gn: 4,  baslatma: 6 },
};
export const ISLEME = 12, YAYILMA = 480, DEPO_OKUMA = 5;   // isleme / kenar yayilmasi / depo yaniti, ms
export const tur = (yol, u) => 2 * u[yol] + KUYRUK[yol].kabul;
export const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 13 : 11)).join("").trimEnd());

export function uretec(tohum) {                     // tohum gorunur; kosumdan kosuma ayni dizi
  let s = tohum >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296;
}
export function isKumesi(tohum) {                   // okuma: sayac kimligi, artan sira, gereken deneme
  const r = uretec(tohum), sira = new Map(), kume = [];
  for (const u of UCLAR) for (let i = 0; i < u.okuma; i++) {
    const sayac = `s${String(Math.floor(r() * 900)).padStart(3, "0")}`;
    sira.set(sayac, (sira.get(sayac) ?? 0) + 1);
    kume.push({ uc: u.ad, sayac, sira: sira.get(sayac), deneme: 1 });
  }
  for (const i of kume) while (r() < 0.28 && i.deneme < 12) i.deneme++;
  return kume;
}
```

```js
// tur.mjs — ayni is kumesi iki yerde: kuyruga girme turu, isin kostugu yer, sonucun donus yolu.
import { UCLAR, TOPLAM, KUYRUK, ISLEME, YAYILMA, DEPO_OKUMA, tur, sut } from "./ag.mjs";

sut("uc", "okuma", "merkez turu", "kenar turu", "kazanc");
for (const u of UCLAR) sut(u.ad, u.okuma, `${tur("merkez", u)} ms`, `${tur("kenar", u)} ms`,
  `${(tur("merkez", u) / tur("kenar", u)).toFixed(1)}x`);
const agirlik = (yol) => UCLAR.reduce((t, u) => t + u.okuma * tur(yol, u), 0) / TOPLAM;
console.log(`${TOPLAM} okuma icin agirlikli kuyruga girme turu: ` +
  `merkez ${agirlik("merkez").toFixed(1)} ms, kenar ${agirlik("kenar").toFixed(1)} ms\n`);

for (const yol of ["merkez", "kenar"]) {            // tuketici: kac kez basliyor
  const k = KUYRUK[yol], cagri = Math.ceil(TOPLAM / k.toplu);
  const baslatma = cagri * k.baslatma, is = TOPLAM * ISLEME;
  console.log(`${yol.padEnd(7)}toplu okuma ${String(k.toplu).padStart(3)} -> ${String(cagri).padStart(3)} tuketici cagrisi; ` +
    `baslatma ${String(baslatma).padStart(4)} ms + isleme ${is} ms = ${baslatma + is} ms`);
}
console.log(`isin kostugu yer: merkez yolunda bilinen tek bolge; ` +
  `kenar yolunda platformun sectigi konum, secim kayitli degil\n`);

// donus yolu: merkez deposu uzak, kenar deposu yerel ama once yayilmali
const don = (yol) => UCLAR.reduce((t, u) => t + u.okuma * (2 * u[yol] + DEPO_OKUMA), 0) / TOPLAM;
console.log(`agirlikli donus turu: merkez ${don("merkez").toFixed(1)} ms, kenar ${don("kenar").toFixed(1)} ms`);
console.log(`sonuc hazir olana kadar: merkez ${don("merkez").toFixed(1)} ms, ` +
  `kenar ${(don("kenar") + YAYILMA).toFixed(1)} ms (yayilma ${YAYILMA} ms eklendi)`);
console.log(`uctan uca toplam: merkez ${(agirlik("merkez") + don("merkez")).toFixed(1)} ms, ` +
  `kenar ${(agirlik("kenar") + don("kenar") + YAYILMA).toFixed(1)} ms`);
```

```
uc         okuma        merkez turu  kenar turu   kazanc
uc-bati    610          33 ms        13 ms        2.5x
uc-kuzey   520          85 ms        17 ms        5.0x
uc-dogu    430          157 ms       21 ms        7.5x
uc-guney   350          111 ms       15 ms        7.4x
uc-yayla   280          201 ms       25 ms        8.0x
uc-liman   210          135 ms       19 ms        7.1x
2400 okuma icin agirlikli kuyruga girme turu: merkez 106.4 ms, kenar 17.5 ms

merkez toplu okuma 250 ->  10 tuketici cagrisi; baslatma  400 ms + isleme 28800 ms = 29200 ms
kenar  toplu okuma  25 ->  96 tuketici cagrisi; baslatma  576 ms + isleme 28800 ms = 29376 ms
isin kostugu yer: merkez yolunda bilinen tek bolge; kenar yolunda platformun sectigi konum, secim kayitli degil

agirlikli donus turu: merkez 102.4 ms, kenar 19.5 ms
sonuc hazir olana kadar: merkez 102.4 ms, kenar 499.5 ms (yayilma 480 ms eklendi)
uctan uca toplam: merkez 208.8 ms, kenar 517.0 ms
```

Birinci ölçüde kenar açık ara kazanır: ağırlıklı kuyruğa girme turu 106,4 milisaniyeden 17,5
milisaniyeye iner, en uzak uçta kazanç sekiz kata çıkar.

İkinci ölçüde tablo ters döner. Kenar tüketicisi altı milisaniyede başlar, merkez kırkta; ama
kenarın toplu okuma boyutu yirmi beş olduğu için 2400 ileti doksan altı çağrıya bölünür, merkezde
ona. **Çağrı başına daha ucuz olan başlangıç, dokuz kat daha sık başlandığı için toplamda daha
pahalıya gelir.** İşin koştuğu yer de belirsizleşir: merkezde bilinen tek bir bölge, kenarda
platformun seçtiği kayıtsız bir konum.

Üçüncü ölçü dönüş yoludur. Kenarın dönüş turu 19,5 milisaniyeyle kısadır, ama sonuç kenar deposuna
yazıldığı için kullanıcının ucunda görünmesi 480 milisaniyelik yayılmayı bekler: uçtan uca toplam
merkezde 208,8, kenarda 517,0 milisaniye. **Kuyruğa girmede kazanılan 89 milisaniye, sonucun
okunabilir olmasında kaybedilen 397 milisaniyeyi karşılamaz.**

#### Kenar Kuyruğunun Dört Kısıtı

```js
// kisit.mjs — kenar kuyrugunun dort kisiti ayni is kumesinde sayilir: deneme, saklama, sira, toplu.
import { TOPLAM, KUYRUK, isKumesi, uretec } from "./ag.mjs";

const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 15 : 17)).join("").trimEnd());
const kume = isKumesi(20260731);                    // tohum gorunur
sut("kisit", "merkez", "kenar", "olcum", "kenarin kaybi");

const olu = (k) => kume.filter((i) => i.deneme > k.deneme).length;   // deneme hakkini asan ileti
sut("yeniden deneme", KUYRUK.merkez.deneme, KUYRUK.kenar.deneme,
  `${TOPLAM} ileti`, `${olu(KUYRUK.kenar)} olu mektup (${(100 * olu(KUYRUK.kenar) / TOPLAM).toFixed(1)}%)`);

const KESINTI_GN = 6, GUNLUK = TOPLAM;              // tuketici alti gun durdu
const kalan = (k) => Math.min(KESINTI_GN, k.saklama_gn) * GUNLUK;
sut("saklama suresi", `${KUYRUK.merkez.saklama_gn} gn`, `${KUYRUK.kenar.saklama_gn} gn`,
  `${KESINTI_GN} gn kesinti`, `${KESINTI_GN * GUNLUK - kalan(KUYRUK.kenar)} ileti dustu`);

const r = uretec(770419), karisik = kume.map((i) => [r(), i]).sort((a, b) => a[0] - b[0]).map((x) => x[1]);
const uygula = (akis) => { const son = new Map(); for (const i of akis) son.set(i.sayac, i.sira); return son; };
const dogru = uygula([...kume].sort((a, b) => a.sira - b.sira)), bozuk = uygula(karisik);
const yanlis = [...dogru].filter(([s, n]) => bozuk.get(s) !== n).length;
sut("siralama", "anahtar basina", "yok", `${dogru.size} sayac`,
  `${yanlis} sayacta yanlis endeks (${(100 * yanlis / dogru.size).toFixed(1)}%)`);

const cagri = (k) => Math.ceil(TOPLAM / k.toplu);
sut("toplu okuma", KUYRUK.merkez.toplu, KUYRUK.kenar.toplu, `${TOPLAM} ileti`,
  `${cagri(KUYRUK.kenar) - cagri(KUYRUK.merkez)} fazla cagri`);

const cok = [...dogru.values()].filter((n) => n > 1).length, b = KUYRUK.kenar;
console.log("\ndolasmanin bedeli, kalem kalem:");
for (const s of [
  `deneme: ${olu(b)} olu mektup elle geri konur -> ${olu(b)} ek yazma; saklama sayaci sifirlanir, sira bastan gelir`,
  `saklama: ${KESINTI_GN * GUNLUK - kalan(b)} ileti icin ikinci dayanikli kopya; ${KESINTI_GN * GUNLUK} iletinin tamami iki yere yazilir`,
  `siralama: ${cok} cok okumali sayac icin tampon; ${TOPLAM} ek durum yazmasi, ileti basina 3000 ms bekleme`,
  `toplu okuma: ${cagri(b)} x ${b.baslatma} ms = ${cagri(b) * b.baslatma} ms, merkezin ${cagri(KUYRUK.merkez) * KUYRUK.merkez.baslatma} ms'sinden fazla`,
]) console.log("  " + s);
```

```
kisit            merkez         kenar          olcum          kenarin kaybi
yeniden deneme   10             3              2400 ileti     50 olu mektup (2.1%)
saklama suresi   14 gn          4 gn           6 gn kesinti   4800 ileti dustu
siralama         anahtar basina yok            842 sayac      438 sayacta yanlis endeks (52.0%)
toplu okuma      250            25             2400 ileti     86 fazla cagri

dolasmanin bedeli, kalem kalem:
  deneme: 50 olu mektup elle geri konur -> 50 ek yazma; saklama sayaci sifirlanir, sira bastan gelir
  saklama: 4800 ileti icin ikinci dayanikli kopya; 14400 iletinin tamami iki yere yazilir
  siralama: 667 cok okumali sayac icin tampon; 2400 ek durum yazmasi, ileti basina 3000 ms bekleme
  toplu okuma: 96 x 6 ms = 576 ms, merkezin 400 ms'sinden fazla
```

Dört kısıt dört ayrı sayı verir. Deneme hakkı ondan üçe inince aynı hata dağılımında 50 ileti ölü
mektup kutusuna düşer; merkez yolunda hepsi geçer. Saklama on dörtten dört güne inince, altı günlük
bir kesintide biriken 14400 iletinin **4800'ü kuyruktan düşer**; merkez kuyruğu hiçbirini kaybetmez.

En pahalı kalem sıralamadır. Garanti olmadığında 842 sayacın **438'i** yanlış endeksle biter: son
uygulanan okuma en büyük sıra numarası olmayabilir, fatura eksik ya da fazla çıkar. Bu,
ayarla düzeltilecek bir kalem değil, kuyruğun hiç sunmadığı bir garantidir.

Dolaşmanın bedeli son bloktadır. Ölü mektupları elle geri koymak 50 ek yazma demektir, ama geri konan
ileti yenidir: saklama sayacı sıfırlanır, sıra numarası baştan gelir. Uzun saklama ancak ikinci bir
dayanıklı kopyayla, sıralama da 667 sayaç adına tutulan tamponla sağlanır: 14400 iletinin tamamı iki
yere yazılır, 2400 ek durum yazması ve ileti başına üç saniye bekleme çıkar. **Üçü de kenarda
kazanılan 89 milisaniyeden büyüktür.**

#### Zamanlanmış İş Hangi Bölgede Tetiklenir

```js
// zaman.mjs — zamanlanmis is: hangi bolgede tetiklendigi ve saat dilimi karari kimde kaldi.
import { UCLAR, DEPO_OKUMA } from "./ag.mjs";

const TEMEL = 2, KAYMA_GUN = 217, KAYAN_SERIT = [2, 3];   // temel saat 02:00, mevsimlik kayma penceresi
const saat = (h) => `${String(((h % 24) + 24) % 24).padStart(2, "0")}:00`;
const gun = (h) => (h < 0 ? " (bir onceki gun)" : "");

const s1 = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 14 : 11)).join("").trimEnd());
s1("uc", "serit", "tek tetikleme", "yerel saat", "kayma penceresi");
for (const u of UCLAR) s1(u.ad, `+${u.serit}`, saat(TEMEL), saat(TEMEL + u.serit),
  KAYAN_SERIT.includes(u.serit) ? `${KAYMA_GUN} gun 60 dk` : "yok");

const yerel = new Set(UCLAR.map((u) => TEMEL + u.serit));
const seritler = [...new Set(UCLAR.map((u) => u.serit))].sort();
console.log(`\ntek tetikleme -> ${yerel.size} ayri yerel saat; ` +
  `${UCLAR.filter((u) => u.serit === 0).length}/${UCLAR.length} uc istenen ${saat(TEMEL)} saatini goruyor`);
console.log(`her ucta ${saat(TEMEL)} icin ${seritler.length} ayri tetikleme tanimi: ` +
  seritler.map((s) => `+${s} temel ${saat(TEMEL - s)}${gun(TEMEL - s)}`).join(", "));
const kayan = UCLAR.filter((u) => KAYAN_SERIT.includes(u.serit));
console.log(`mevsimlik kayma: ${kayan.length} uc x ${KAYMA_GUN} gun = ${kayan.length * KAYMA_GUN} uc-gun ` +
  `60 dk sapma; zamanlayici yalniz temel saati bilir, cevrimi islev kendi yapar\n`);

const OKUMA = 2400, PAKET = 100, tur = Math.ceil(OKUMA / PAKET);
const sure = (u) => tur * (2 * u.merkez + DEPO_OKUMA);
const l = UCLAR.map(sure), en_az = Math.min(...l), en_cok = Math.max(...l);
console.log(`gecelik is ${tur} tur x ${PAKET} okuma; tetikleme yeri secilemedigi icin sure ` +
  `${en_az}-${en_cok} ms araliginda, ortalama ${(l.reduce((a, b) => a + b) / l.length).toFixed(0)} ms ` +
  `(${(en_cok / en_az).toFixed(1)}x fark)`);
console.log(`sabitlemenin bedeli: is merkez bolgeye pinlenirse sure ${en_az} ms'de sabitlenir, ` +
  `ama kenarda kosma ozelligi bu is icin tumden birakilir`);
```

```
uc         serit         tek tetikleme yerel saat    kayma penceresi
uc-bati    +0            02:00         02:00         yok
uc-kuzey   +0            02:00         02:00         yok
uc-dogu    +2            02:00         04:00         217 gun 60 dk
uc-guney   +1            02:00         03:00         yok
uc-yayla   +3            02:00         05:00         217 gun 60 dk
uc-liman   +2            02:00         04:00         217 gun 60 dk

tek tetikleme -> 4 ayri yerel saat; 2/6 uc istenen 02:00 saatini goruyor
her ucta 02:00 icin 4 ayri tetikleme tanimi: +0 temel 02:00, +1 temel 01:00, +2 temel 00:00, +3 temel 23:00 (bir onceki gun)
mevsimlik kayma: 3 uc x 217 gun = 651 uc-gun 60 dk sapma; zamanlayici yalniz temel saati bilir, cevrimi islev kendi yapar

gecelik is 24 tur x 100 okuma; tetikleme yeri secilemedigi icin sure 696-4728 ms araliginda, ortalama 2792 ms (6.8x fark)
sabitlemenin bedeli: is merkez bolgeye pinlenirse sure 696 ms'de sabitlenir, ama kenarda kosma ozelligi bu is icin tumden birakilir
```

Gecelik işin "her şubede 02:00'de koşsun" isteği tek tetikleme tanımıyla karşılanamaz. Temel saate
kurulan tetikleme dört ayrı yerel saate düşer, altı uçtan yalnız ikisi istenen saati görür. Her uçta
02:00 için dört tanım gerekir ve şerit +3'ünki temel saat 23:00'e, yani **bir önceki güne** düşer.
İki şerit ayrıca yılın 217 gününde altmış dakika kayar: 651 uç-gün sapma. **Zamanlayıcı yalnız temel
saati bilir; yerel saate çevirme kararı devredilmez, işlevin kodunda kalır.**

Son iki satır tetiklemenin nerede koştuğunu sayar. Gecelik iş merkez deposunu yirmi dört turda okur;
koştuğu konum seçilemediği için aynı iş 696 ile 4728 milisaniye arasında, ortalama 2792 milisaniyede
biter — **6,8 katlık bir aralık ve hangi ucuna düşeceği bizim kararımız değil.** Süreyi sabitlemenin
tek yolu işi merkeze sabitlemektir; o zaman iş kenarda koşmaz.

#### Özet

- Kuyruğa girme turu kenarda 106,4 milisaniyeden 17,5 milisaniyeye indi, en uzak uçta kazanç 8 kata
  çıktı; ama toplu okuma 250'den 25'e indiği için 2400 ileti 10 yerine 96 çağrıya bölündü ve
  başlatma toplamı 400 yerine 576 milisaniye oldu.
- Sonuç kenar deposuna yazıldığı için 480 milisaniye yayılma bekledi; uçtan uca toplam merkezde
  208,8, kenarda 517,0 milisaniye çıktı. Kabul hızlandı, teslim yavaşladı.
- Dört kısıt dört sayı verdi: 3 deneme hakkı 50 ölü mektup, 4 gün saklama 6 günlük kesintide 4800
  ileti kaybı, sıralama garantisinin yokluğu 842 sayacın 438'inde yanlış endeks, 25'lik toplu okuma
  86 fazla çağrı. Dolaşmanın bedeli 50 ek yazma, 14400 iletiyi iki yere yazma, 2400 ek durum
  yazması ve 3000 milisaniye bekleme oldu.
- Tek tetikleme 4 ayrı yerel saate düştü, 6 uçtan 2'si istenen saati gördü; 651 uç-gün
  mevsimlik sapma çıktı ve gecelik iş tetiklendiği yere göre 696-4728 milisaniye sürdü.

#### Sonraki Adım

Kenar çalışma zamanı bir kuyruğa ve bir zamanlayıcıya erişti, ama erişimin nasıl kurulduğu
sorulmadı. Kaynak adresi ve kimlik bilgisi çalışma zamanında istemci kurularak da verilebilir,
dağıtım anında **bildirimsel bağlamayla** da. Bir sonraki ders aynı kaynağa iki yoldan erişip
dördünü sayar: kod satırı, açılış işi, kimlik bilgisinin yeri ve yanlış yapılandırmanın fark
edilme anı.

### Bağlamalar ve Servis Bağlantıları

Source: https://academia.sh/tr/kurslar/sunucusuz/baglamalar-ve-servis-baglantilari

Aynı kaynağa çalışma zamanında istemci kurarak ve bildirimsel bağlamayla erişilir; kod satırı, açılış işi, kimlik bilgisinin yeri ve hatanın görülme anı sayılır. Bağlamanın kapsam ve taşınabilirlik kısıtları da ölçülür.

Bir önceki ders kenarda kuyruk ve zamanlayıcı kullandı, ama bu kaynaklara erişimin nasıl kurulduğunu
hiç sormadı. İki yol vardır. Birincisinde işlev açılırken kaynağın adresini, kimlik bilgisini ve
ayarlarını okur, bir istemci kurar ve bağlanır. İkincisinde dağıtım tanımına bir **bağlama** yazılır
ve çalışma zamanı işleve hazır bir kol verir. Bu ders aynı beş kaynağa iki yoldan erişip dördünü
sayar: kod satırı, açılış işi, kimlik bilgisinin nerede durduğu ve yanlış yapılandırmanın ne zaman
fark edildiği.

Kaynağın nasıl **yaratıldığı** bu dersin konusu değildir; sağlayıcı arayüzü ve kaynak alanları **kod
olarak altyapı** kursunda ölçüldü. Buradaki soru sonrasıdır: çalışan koda o kaynak nasıl bağlanıyor.
Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; katalog, istemci ve bağlama kolu
`node` ile kurulmuş bir **modeldir**.

**KE31.** Kurgu katalogda dokuz kaynak ve dokuz tür vardır; her tür için istemcinin kurması gereken
alanlar yazılıdır.
**KE32.** Bildirimsel bağlama bu türlerden yalnız beşini destekler; kalan dördü çalışma zamanında
istemci kurularak erişilir.
**KE33.** İstemci yolu açılışta bütün bağlantıları kurar ve her bağlantının sabit bir kurma süresi
vardır; bağlama yolu açılışta hiçbir bağlantı kurmaz, kol ilk kullanımda bağlanır.
**KE34.** Kenar çalışma zamanının soğuk başlangıç tabanı 12 ms'dir; açılışta yapılan iş bu tabanın
üstüne eklenir.
**KE35.** Kimlik bilgisi istemci yolunda süreç ortamına yazılır ve ayar nesnesinden istemciye geçer;
bağlama yolunda koda hiç girmez. Metinde geçen gizli değer **kurgu bir yer tutucudur**.
**KE36.** Dağıtım anında bir doğrulayıcı manifestoyu katalogla karşılaştırıp yapısal hataları
yakalar; istemci yolunda böyle bir doğrulama yoktur, hata kaynağa ilk çağrıda görülür.

#### Aynı Kaynak, İki Erişim Yolu

```js
// kaynak.mjs — kurgu kaynak katalogu, iki erisim yolu ve kimlik tarayicisi (model).
export const TURLER = {                             // istemcinin kurmasi gereken alanlar
  veri_deposu:  { alan: ["adres", "kimlik", "zaman_asimi", "deneme", "havuz"], baglanabilir: true },
  kuyruk:       { alan: ["adres", "kimlik", "zaman_asimi", "toplu"], baglanabilir: true },
  nesne_deposu: { alan: ["adres", "kimlik", "bolge", "zaman_asimi"], baglanabilir: true },
  anahtar_deger:{ alan: ["adres", "kimlik", "zaman_asimi"], baglanabilir: true },
  konu:         { alan: ["adres", "kimlik", "zaman_asimi"], baglanabilir: true },
  iliskisel:    { alan: ["adres", "kimlik", "zaman_asimi", "havuz", "sema"], baglanabilir: false },
  dis_servis:   { alan: ["adres", "kimlik", "zaman_asimi", "deneme"], baglanabilir: false },
  dizin:        { alan: ["adres", "kimlik", "zaman_asimi"], baglanabilir: false },
  akis:         { alan: ["adres", "kimlik", "bolge", "zaman_asimi", "toplu"], baglanabilir: false },
};
export const KAYNAKLAR = [                          // acilis: baglanti kurma ms; ilk: dagitimdan ilk cagriya dk
  { ad: "olcum_deposu", tur: "veri_deposu", acilis: 34, ilk: 0.2 },
  { ad: "sayac_kuyrugu", tur: "kuyruk", acilis: 21, ilk: 0.2 },
  { ad: "arsiv_deposu", tur: "nesne_deposu", acilis: 27, ilk: 540 },
  { ad: "oran_sayaci", tur: "anahtar_deger", acilis: 8, ilk: 0.2 },
  { ad: "bildirim_konusu", tur: "konu", acilis: 15, ilk: 47 },
  { ad: "fatura_tablosu", tur: "iliskisel", acilis: 52, ilk: 540 },
  { ad: "saha_gecidi", tur: "dis_servis", acilis: 19, ilk: 47 },
  { ad: "kimlik_dizini", tur: "dizin", acilis: 23, ilk: 0.2 },
  { ad: "rapor_akisi", tur: "akis", acilis: 30, ilk: 540 },
];
export const BAGLANABILIR = KAYNAKLAR.filter((k) => TURLER[k.tur].baglanabilir);
export const SOGUK_TABAN = 12;                      // soguk baslangic tabani, ms
export const GIZLI = "KURGU-GIZLI-DEGER";           // kurgu yer tutucu; gercek bir kimlik bilgisi degil

export const istemciKodu = (k) => [                 // calisma zamaninda istemci kurma kodu
  `const ${k.ad}_ayar = {`,
  ...TURLER[k.tur].alan.map((a) => `  ${a}: ortam("${k.ad.toUpperCase()}_${a.toUpperCase()}"),`),
  `};`,
  `const ${k.ad} = istemciKur("${k.tur}", ${k.ad}_ayar);`,
  `await ${k.ad}.baglan();`,
];
export const baglamaSatiri = (k) => [`  { ad: "${k.ad}", tur: "${k.tur}", hedef: "${k.ad}-uretim" },`];
export const ORTAK = 12;                            // yardimci islevlerin satiri
export const SARMAL = 2;                            // manifestonun acilis ve kapanis satiri

export function istemciKur(tur, ayar) {             // kimlik ayar nesnesinde ve istemcide durur
  return { tur, ayar, baglan: () => true, cagir: (n) => `${tur}:${n}` };
}
export function baglamaKolu(k) {                    // baglama kolu: kimlik alani hic yok
  return { ad: k.ad, tur: k.tur, cagir: (n) => `${k.tur}:${n}` };
}
export function tara(nesne, yol = "kok", bulgu = []) {   // nesne grafinde kimlik alani arar
  for (const [a, d] of Object.entries(nesne)) {
    if (a === "kimlik") bulgu.push(`${yol}.${a}`);
    else if (d && typeof d === "object") tara(d, `${yol}.${a}`, bulgu);
  }
  return bulgu;
}
export function uretec(tohum) {                     // tohum gorunur; kosumdan kosuma ayni dizi
  let s = tohum >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296;
}
```

```js
// kod.mjs — ayni bes kaynak iki yolla: kod satiri ve acilis isi sayilir.
import { TURLER, KAYNAKLAR, BAGLANABILIR, SOGUK_TABAN, istemciKodu, baglamaSatiri,
  ORTAK, SARMAL, uretec } from "./kaynak.mjs";

const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 16 : 17)).join("").trimEnd());
sut("kaynak", "tur", "alan", "istemci satiri", "baglama satiri");
for (const k of BAGLANABILIR)
  sut(k.ad, k.tur, TURLER[k.tur].alan.length, istemciKodu(k).length, baglamaSatiri(k).length);
const istemciSatir = BAGLANABILIR.reduce((t, k) => t + istemciKodu(k).length, 0) + ORTAK;
const baglamaSatir = BAGLANABILIR.reduce((t, k) => t + baglamaSatiri(k).length, 0) + SARMAL;
console.log(`toplam: istemci ${istemciSatir} satir (${ORTAK} satir ortak yardimci dahil), ` +
  `baglama ${baglamaSatir} satir (${SARMAL} satir manifesto sarmali dahil); ` +
  `oran ${(istemciSatir / baglamaSatir).toFixed(1)}x\n`);

const acilis = BAGLANABILIR.reduce((t, k) => t + k.acilis, 0);
console.log(`istemci yolu acilista ${BAGLANABILIR.length} baglanti kurar: ${acilis} ms; ` +
  `soguk baslangic ${SOGUK_TABAN} ms -> ${SOGUK_TABAN + acilis} ms`);
console.log(`baglama yolu acilista hicbir baglanti kurmaz: 0 ms; ` +
  `soguk baslangic ${SOGUK_TABAN} ms -> ${SOGUK_TABAN} ms (kol ilk kullanimda baglanir)\n`);

const r = uretec(19870504), SOGUK = 40;             // kirk soguk baslangic
let istemciIs = 0, baglamaIs = 0, dokunan = 0;
for (let i = 0; i < SOGUK; i++) {
  const kume = BAGLANABILIR.filter(() => r() < 0.45);
  istemciIs += acilis;                              // hepsi kurulur, kullanilsin kullanilmasin
  baglamaIs += kume.reduce((t, k) => t + k.acilis, 0);
  dokunan += kume.length;
}
console.log(`${SOGUK} soguk baslangic, dokunulan kaynak ortalamasi ` +
  `${(dokunan / SOGUK).toFixed(2)}/${BAGLANABILIR.length}`);
console.log(`acilista yapilan is: istemci ${istemciIs} ms, baglama ${baglamaIs} ms ` +
  `(${(100 * (istemciIs - baglamaIs) / istemciIs).toFixed(1)}% daha az)`);

const disarida = KAYNAKLAR.filter((k) => !TURLER[k.tur].baglanabilir);
const disSatir = disarida.reduce((t, k) => t + istemciKodu(k).length, 0) + ORTAK;
console.log(`\nbaglamanin kapsami: ${BAGLANABILIR.length}/${KAYNAKLAR.length} kaynak turu; ` +
  `kalan ${disarida.length} kaynak (${disarida.map((k) => k.tur).join(", ")}) istemciyle kurulur`);
console.log(`karisik gercek: ${disSatir} satir istemci kodu ve ` +
  `${disarida.reduce((t, k) => t + k.acilis, 0)} ms acilis isi yerinde kalir`);
```

```
kaynak           tur             alan            istemci satiri  baglama satiri
olcum_deposu     veri_deposu     5               9               1
sayac_kuyrugu    kuyruk          4               8               1
arsiv_deposu     nesne_deposu    4               8               1
oran_sayaci      anahtar_deger   3               7               1
bildirim_konusu  konu            3               7               1
toplam: istemci 51 satir (12 satir ortak yardimci dahil), baglama 7 satir (2 satir manifesto sarmali dahil); oran 7.3x

istemci yolu acilista 5 baglanti kurar: 105 ms; soguk baslangic 12 ms -> 117 ms
baglama yolu acilista hicbir baglanti kurmaz: 0 ms; soguk baslangic 12 ms -> 12 ms (kol ilk kullanimda baglanir)

40 soguk baslangic, dokunulan kaynak ortalamasi 2.20/5
acilista yapilan is: istemci 4200 ms, baglama 1936 ms (53.9% daha az)

baglamanin kapsami: 5/9 kaynak turu; kalan 4 kaynak (iliskisel, dis_servis, dizin, akis) istemciyle kurulur
karisik gercek: 45 satir istemci kodu ve 124 ms acilis isi yerinde kalir
```

Kod satırı ilk ölçüdür. Beş kaynağa istemciyle erişmek 51, bağlamayla erişmek 7 satır tutar. Fark
bir biçim tercihi değil, işin nerede yapıldığıdır: istemci yolunda her alan bir satırdır, bağlamada
bütün alanlar tek satırın arkasına düşer.

İkinci ölçü açılışta yapılan iştir ve soğuk başlangıca doğrudan eklenir. İstemci yolu açılırken beş
bağlantıyı da kurar: 105 milisaniye, yani 12 milisaniyelik taban **117 milisaniyeye** çıkar. Bağlama
yolu hiçbir bağlantı kurmaz; taban 12 milisaniyede kalır, bağlanma yalnız kol kullanıldığında olur.
Kırk soğuk başlangıçlık kurgu trafikte bir çağrı ortalama 2,20 kaynağa dokunur, dolayısıyla bağlama
yolu 4200 yerine 1936 milisaniye bağlantı işi yapar: **yüzde 53,9 daha az.** Fark, istemci yolunun o
çağrıda hiç kullanılmayacak bağlantıları da kurmasıdır.

Üçüncü satır kapsamı verir. Bağlama dokuz kaynak türünden **beşini**
tanır; ilişkisel veritabanı, dış servis, dizin ve akış için istemci kurmaktan başka yol yoktur. Bu
dört kaynak 45 satır istemci kodunu ve 124 milisaniye açılış işini yerinde tutar.

#### Kimlik Nerede Durur ve Hata Ne Zaman Görülür

```js
// guven.mjs — kimlik nerede duruyor, hata ne zaman goruluyor, tasima ne tutuyor.
import { TURLER, KAYNAKLAR, BAGLANABILIR, GIZLI, istemciKur, baglamaKolu, tara,
  istemciKodu, baglamaSatiri, ORTAK, SARMAL } from "./kaynak.mjs";

const ortam = {};                                   // kimlik once surec ortamina yazilir
for (const k of BAGLANABILIR) for (const a of TURLER[k.tur].alan)
  ortam[`${k.ad.toUpperCase()}_${a.toUpperCase()}`] = a === "kimlik" ? `${GIZLI}-${k.ad}` : `deger-${a}`;
const istemciler = Object.fromEntries(BAGLANABILIR.map((k) => [k.ad, istemciKur(k.tur,
  Object.fromEntries(TURLER[k.tur].alan.map((a) => [a, ortam[`${k.ad.toUpperCase()}_${a.toUpperCase()}`]])))]));
const kollar = Object.fromEntries(BAGLANABILIR.map((k) => [k.ad, baglamaKolu(k)]));

const say = (m) => (JSON.stringify(m).match(new RegExp(GIZLI, "g")) || []).length;
const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 15 : 24)).join("").trimEnd());
sut("kimlik nerede", "istemci", "baglama");
sut("dagitim yapilandirmasi", BAGLANABILIR.length, BAGLANABILIR.length);
sut("surec ortami", Object.values(ortam).filter((v) => v.startsWith(GIZLI)).length, 0);
sut("kod icindeki nesne", tara(istemciler).length, tara(kollar).length);
sut("diziye cevirmede", say(istemciler), say(kollar));
console.log(`taranan alan yollari: ${tara(istemciler).slice(0, 2).join(", ")} ...\n`);

const HATALAR = [                                   // bes kurgu yanlis yapilandirma
  { kaynak: "olcum_deposu", ne: "alan adi yanlis yazildi", yapisal: true },
  { kaynak: "arsiv_deposu", ne: "zorunlu alan verilmedi", yapisal: true },
  { kaynak: "bildirim_konusu", ne: "katalogda olmayan tur", yapisal: true },
  { kaynak: "sayac_kuyrugu", ne: "kaynak adi yanlis", yapisal: true },
  { kaynak: "arsiv_deposu", ne: "baska var olan hedef", yapisal: false },
];
const ilk = (ad) => KAYNAKLAR.find((k) => k.ad === ad).ilk;
const s2 = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 17 : 40)).join("").trimEnd());
s2("yanlis yapilandirma", "istemci", "baglama");
for (const h of HATALAR)
  s2(`${h.kaynak}: ${h.ne}`, `${ilk(h.kaynak)} dk sonra`, h.yapisal ? "dagitimda, 0 dk" : `${ilk(h.kaynak)} dk sonra`);
const gec = HATALAR.filter((h) => !h.yapisal);
console.log(`istemci: 0/${HATALAR.length} dagitimda yakalandi, toplam gecikme ` +
  `${HATALAR.reduce((t, h) => t + ilk(h.kaynak), 0).toFixed(1)} dk, en kotusu ${Math.max(...HATALAR.map((h) => ilk(h.kaynak)))} dk`);
console.log(`baglama: ${HATALAR.length - gec.length}/${HATALAR.length} dagitimda yakalandi, ` +
  `kalan ${gec.length} hata ${gec.reduce((t, h) => t + ilk(h.kaynak), 0)} dk sonra\n`);

const STUB = 3;                                     // her kol icin yazilan sahte kol satiri
const degisenIstemci = BAGLANABILIR.reduce((t, k) => t + TURLER[k.tur].alan.length, 0);
const degisenBaglama = BAGLANABILIR.reduce((t, k) => t + baglamaSatiri(k).length, 0) + SARMAL
  + BAGLANABILIR.length * STUB;
console.log(`baska bir hizmete tasima: istemci yolunda 0 kod satiri degisir, ` +
  `${degisenIstemci} yapilandirma degeri degisir`);
console.log(`baglama yolunda ${degisenBaglama} satir degisir: ` +
  `${degisenBaglama - BAGLANABILIR.length * STUB} manifesto satiri hizmete ozgudur, ` +
  `${BAGLANABILIR.length * STUB} satir yerel sinama icin sahte kol`);
console.log(`istemci kodunun ${BAGLANABILIR.reduce((t, k) => t + istemciKodu(k).length, 0) + ORTAK} satiri ` +
  `oldugu gibi tasinir; baglama tanimi tasinmaz`);
```

```
kimlik nerede           istemci        baglama
dagitim yapilandirmasi  5              5
surec ortami            5              0
kod icindeki nesne      5              0
diziye cevirmede        5              0
taranan alan yollari: kok.olcum_deposu.ayar.kimlik, kok.sayac_kuyrugu.ayar.kimlik ...

yanlis yapilandirma                     istemci          baglama
olcum_deposu: alan adi yanlis yazildi   0.2 dk sonra     dagitimda, 0 dk
arsiv_deposu: zorunlu alan verilmedi    540 dk sonra     dagitimda, 0 dk
bildirim_konusu: katalogda olmayan tur  47 dk sonra      dagitimda, 0 dk
sayac_kuyrugu: kaynak adi yanlis        0.2 dk sonra     dagitimda, 0 dk
arsiv_deposu: baska var olan hedef      540 dk sonra     540 dk sonra
istemci: 0/5 dagitimda yakalandi, toplam gecikme 1127.4 dk, en kotusu 540 dk
baglama: 4/5 dagitimda yakalandi, kalan 1 hata 540 dk sonra

baska bir hizmete tasima: istemci yolunda 0 kod satiri degisir, 19 yapilandirma degeri degisir
baglama yolunda 22 satir degisir: 7 manifesto satiri hizmete ozgudur, 15 satir yerel sinama icin sahte kol
istemci kodunun 51 satiri oldugu gibi tasinir; baglama tanimi tasinmaz
```

Birinci tablo kimlik bilgisinin kaç yerde durduğunu sayar ve iki yol tek satırda birleşir: dağıtım
yapılandırmasındaki beş kimlik ikisinde de vardır, çünkü erişim yetkisi bir yerde tanımlanmak
zorundadır. Ayrılık ondan sonra başlar. İstemci yolunda kimlik süreç ortamına yazılır, oradan ayar
nesnesine, oradan istemciye geçer; tarayıcı işlev nesne grafında beş `kimlik` alanı bulur ve nesne
diziye çevrildiğinde değer beş kez görünür. Bağlama yolunda dördü de sıfırdır:
**kol nesnesinde kimlik diye bir alan yoktur**, çağrıyı çalışma zamanı imzalar. Bir kayıt satırı, bir
hata dökümü istemci yolunda beş değeri açığa çıkarabilir; bağlama yolunda açığa çıkacak değer
yoktur.

İkinci tablo hatanın ne zaman görüldüğünü sayar. Beş kurgu yanlış yapılandırmadan dördü yapısaldır:
alan adı yanlış, zorunlu alan eksik, katalogda olmayan tür, yanlış kaynak adı. Bağlama yolunda
dağıtım doğrulayıcısı dördünü de sıfırıncı dakikada yakalar. İstemci yolunda hiçbiri yakalanmaz,
çünkü doğrulanacak bir bildirim yoktur; her hata kaynağa ilk çağrıldığı anda görülür. **Arşiv deposu yalnız gecelik iş sırasında çağrıldığı için oradaki hata dağıtımdan 540
dakika sonra ortaya çıkar** — dokuz saat. Beş hatanın toplam gecikmesi istemci yolunda 1127,4 dakika,
bağlama yolunda 540 dakikadır.

Beşinci hata iki yolda da geç görülür ve doğrulamanın sınırını çizer: hedef adı geçerli, tür doğru,
katalogda karşılığı var — yalnızca yanlış kaynağa işaret ediyor. **Dağıtım doğrulayıcısı biçimi
denetler, niyeti denetlemez.**

#### Bağlamanın Kısıtı

Son üç satır taşınabilirliği sayar; bağlamanın ikinci kısıtı buradadır. İstemci kodu taşınırken
**sıfır satırı değişir**, yalnız 19 yapılandırma değeri değişir: kod kaynağı adresle ve ayarla tanır,
hizmetle değil. Bağlama tanımı ise hizmete özgüdür: 7 manifesto satırının tamamı yeni
hizmetin biçimine göre baştan yazılır. Üstüne, kol çalışma zamanınca verildiği için yerel sınamada
karşılığı yoktur: beş kol için 15 satırlık sahte kol gerekir. Taşımanın bedeli
bağlama yolunda **22 satır**, istemci yolunda sıfır satır ve 19 değerdir.

İki kısıt birlikte okunduğunda bağlamanın gerçek kapsamı çıkar. Dokuz kaynağın beşi bağlanır, dördü
bağlanmaz; o dördü için 45 satır istemci kodu, 124 milisaniye açılış işi ve süreç içinde duran kimlik
bilgileri yerinde kalır. **Bağlama kimliği koddan çıkarmaz, kaynakların beş dokuzunda çıkarır.**
Devredilen karar bağlantı kurmaktır: karşılığında soğuk başlangıçta 105 milisaniye, kodda 44 satır ve
hatanın görülmesinde 587 dakika kazanılır, ama kaynak türü seçimi kataloğa, dağıtım tanımı hizmete
bağlanır.

#### Özet

- Beş kaynağa istemciyle erişim 51 satır, bağlamayla erişim 7 satır tuttu; oran 7,3 kat.
- İstemci yolu açılışta 5 bağlantıyı kurup soğuk başlangıcı 12 milisaniyeden 117 milisaniyeye
  çıkardı; bağlama 12 milisaniyede kaldı. Kırk soğuk başlangıçta çağrı başına ortalama 2,20 kaynağa
  dokunuldu, bağlantı işi 4200 yerine 1936 milisaniye oldu.
- Kimlik bilgisi istemci yolunda 4 yerde durdu (dağıtım yapılandırması, süreç ortamı, ayar nesnesi,
  diziye çevrilmiş istemci); bağlamada yalnız dağıtım yapılandırmasında durdu, kodda 0 kez göründü.
- 5 yanlış yapılandırmanın 4'ü bağlamada dağıtım anında yakalandı; istemcide 0'ı yakalandı ve toplam
  1127,4 dakika sonra görüldü. En kötüsü gecelik işte çağrılan kaynakta 540 dakikaydı.
- Bağlama 9 kaynak türünden 5'ini tanıdı; kalan 4 kaynak 45 satır istemci kodunu ve 124 milisaniye
  açılış işini yerinde tuttu.
- Taşınabilirlik bedeli bağlamada 22 satır oldu (7 manifesto, 15 sahte kol); istemcide 0 kod satırı
  ve 19 yapılandırma değeri.

#### Sonraki Adım

Bu konu boyunca kenar sırayla kazandı: istek işleme, depolama, eşgüdümlü durum, eşzamansız iş ve
bildirimsel erişim. Her kazanç bir kısıtla geldi. Geriye kısıtların toplamına bakmak kalıyor: kenar
çalışma zamanının hiçbir dolambaçla aşamadığı sınırlar hangileri, bir işi kenara taşımanın anlamlı
olduğu eşik nerede bitiyor. Bir sonraki ders bu sınırları toplar ve kursu kapatır.

### Kenar Sınırları

Source: https://academia.sh/tr/kurslar/sunucusuz/kenar-sinirlari

Kenarın üç eşiği on iki işlik bir kümeye uygulanır; parçalamanın bedeli ek tur ve hata noktasıyla, kenarın kazandırmadığı üç durum sayıyla çıkarılır. Kurs kapanışı yirmi dersin devredilen kararını ve kısıtını toplar.

Bir önceki ders kaynaklara erişimi bildirimsel hâle getirdi. Sınanmayan bir şey kaldı: kenarda
**ne kadar iş yapılabileceği**. İstek işlendi, durum tutuldu, kuyruk kuruldu, kaynak bağlandı —
hepsinin kenara sığdığı varsayıldı. Bu ders üç eşiği bir iş kümesine uygular ve sığmayanı sığdırmanın
faturasını çıkarır.

Ölçüm **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; eşikler, iş kümesi ve kullanıcı grupları
`node` ile kurulmuş bir **modeldir** ve fiyatlar kurgu birimdir.

**KE37.** Üç eşik kurgudur: istek başına 50 ms işlem, 128 MB bellek ve ilk derste sayılan eksik
arayüz kalemleri.
**KE38.** İş kümesi on iki iştir; her iş için işlem süresi, tepe bellek ve istenen kalemler yazılı.
**KE39.** Parçalanan iş eşiğin %80'ini kullanır; parçalar arasında ara durum depoya yazılır (64 ms)
ve okunur (2 ms). Hata noktası adım artı geçiş sayısıdır.
**KE40.** Uyumluluğa takılan iş parçalanamaz; merkeze düşer, kenar yalnız yönlendirir.
**KE41.** Altı kullanıcı grubu için uçta sonlanan ve doğrudan merkeze giden istek turu yazılıdır;
uçtan geçip merkeze giden istek ikisinin toplamını öder.
**KE42.** Sürekli sunucu aynı işi 0,55 katsayıyla yapar; işlevde soğuk oran %2, soğuk ek 900 ms'dir.

#### Üç Eşik, On İki İş

```js
// sinir.mjs — kenar calisma zamaninin uc esigi ve kurgu is kumesi (model).
export const ESIK = { islem: 50, bellek: 128 };     // istek basina ms islem, MB bellek
export const YOK = ["dosya sistemi", "yerel disk", "uzun surec", "ham yuva", "ikili eklenti"];
export const ISLER = [                              // islem ms, bellek MB, istenen arayuz kalemleri
  { ad: "istek yonlendirme", islem: 3, bellek: 6 },
  { ad: "baslik duzenleme", islem: 2, bellek: 4 },
  { ad: "oturum dogrulama", islem: 9, bellek: 12 },
  { ad: "tarife arama", islem: 6, bellek: 22 },
  { ad: "okuma bicim cevirimi", islem: 18, bellek: 40 },
  { ad: "sayac imza dogrulama", islem: 34, bellek: 48 },
  { ad: "anomali esigi", islem: 62, bellek: 90 },
  { ad: "tuketim egrisi", islem: 140, bellek: 260 },
  { ad: "gunluk arsivleme", islem: 40, bellek: 96, ister: ["dosya sistemi", "yerel disk"] },
  { ad: "fatura belgesi", islem: 220, bellek: 180, ister: ["dosya sistemi", "ikili eklenti"] },
  { ad: "gecelik uzlastirma", islem: 40000, bellek: 700, ister: ["uzun surec", "dosya sistemi"] },
  { ad: "cihaz kalici baglantisi", islem: 5, bellek: 30, ister: ["ham yuva", "uzun surec"] },
];
export const PAY = 0.8;                             // parcanin kullanabildigi esik payi
export const ARA_SABIT = 20;                        // parca basina sabit bellek, MB
export const YAZMA = 64, OKUMA = 2, GERI_DUSUS = 60; // depoya yazma/okuma, kenar-bolge turu, ms

export function denetle(i) {                        // uc esik ayri ayri uygulanir
  const asan = [];
  if (i.islem > ESIK.islem) asan.push("sure");
  if (i.bellek > ESIK.bellek) asan.push("bellek");
  const eksik = (i.ister ?? []).filter((k) => YOK.includes(k));
  if (eksik.length) asan.push("uyumluluk");
  return { ...i, asan, eksik };
}
export function parcala(i) {                        // yalniz sure/bellek asan is parcalanabilir
  const kullanilabilir = ESIK.islem * PAY;
  const adim = Math.ceil(i.islem / kullanilabilir);
  const tepeBellek = Math.ceil(i.bellek / adim) + ARA_SABIT;
  return { adim, tepeBellek, ekTur: (adim - 1) * 2, ekSure: (adim - 1) * (YAZMA + OKUMA),
    hata: 2 * adim - 1 };
}
export const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 13 : 24)).join("").trimEnd());
```

```js
// esik.mjs — uc esik is kumesine uygulanir; kac is kenarda kosuyor ve parcalamanin bedeli nedir.
import { ESIK, YOK, ISLER, PAY, denetle, parcala, GERI_DUSUS, sut } from "./sinir.mjs";

console.log(`esikler: islem ${ESIK.islem} ms/istek, bellek ${ESIK.bellek} MB, ` +
  `kenarda olmayan arayuz kalemi ${YOK.length}\n`);
sut("is", "islem", "bellek", "eksik kalem", "sonuc");
const d = ISLER.map(denetle);
for (const i of d) sut(i.ad, `${i.islem} ms`, `${i.bellek} MB`, i.eksik.length,
  i.asan.length ? `${i.asan.join(" + ")} asiyor` : "kosar");
const say = (e) => d.filter((i) => i.asan.includes(e)).length;
const kosan = d.filter((i) => !i.asan.length);
console.log(`\n${ISLER.length} isten ${kosan.length} tanesi kenarda kosuyor; ` +
  `sure ${say("sure")}, bellek ${say("bellek")}, uyumluluk ${say("uyumluluk")} isi durduruyor ` +
  `(bir is birden cok esige takilabilir)\n`);

const bolunebilir = d.filter((i) => i.asan.length && !i.asan.includes("uyumluluk"));
const dusen = d.filter((i) => i.asan.includes("uyumluluk"));
sut("parcalanan is", "adim", "tepe bellek", "ek tur", "ek sure", "hata noktasi");
let ekTur = 0, ekSure = 0, hata = 0;
for (const i of bolunebilir) {
  const p = parcala(i);
  ekTur += p.ekTur; ekSure += p.ekSure; hata += p.hata;
  sut(i.ad, p.adim, `${p.tepeBellek} MB`, p.ekTur, `${p.ekSure} ms`, p.hata);
}
console.log(`\nparcalama ${bolunebilir.length} isi kenara sokuyor: esik payi %${PAY * 100}, ` +
  `toplam ${ekTur} ek tur, ${ekSure} ms ek sure, ${hata} hata noktasi (parcalanmadan is basina 1)`);
console.log(`parcalanamayan ${dusen.length} is merkeze duser (${dusen.map((i) => i.ad).join(", ")}); ` +
  `bedeli istek basina ${GERI_DUSUS} ms kenar-bolge turu, kenar yalniz yonlendirir`);
console.log(`son durum: ${kosan.length + bolunebilir.length}/${ISLER.length} kenarda, ` +
  `${dusen.length}/${ISLER.length} merkezde`);
```

```
esikler: islem 50 ms/istek, bellek 128 MB, kenarda olmayan arayuz kalemi 5

is                      islem        bellek       eksik kalem  sonuc
istek yonlendirme       3 ms         6 MB         0            kosar
baslik duzenleme        2 ms         4 MB         0            kosar
oturum dogrulama        9 ms         12 MB        0            kosar
tarife arama            6 ms         22 MB        0            kosar
okuma bicim cevirimi    18 ms        40 MB        0            kosar
sayac imza dogrulama    34 ms        48 MB        0            kosar
anomali esigi           62 ms        90 MB        0            sure asiyor
tuketim egrisi          140 ms       260 MB       0            sure + bellek asiyor
gunluk arsivleme        40 ms        96 MB        2            uyumluluk asiyor
fatura belgesi          220 ms       180 MB       2            sure + bellek + uyumluluk asiyor
gecelik uzlastirma      40000 ms     700 MB       2            sure + bellek + uyumluluk asiyor
cihaz kalici baglantisi 5 ms         30 MB        2            uyumluluk asiyor

12 isten 6 tanesi kenarda kosuyor; sure 4, bellek 3, uyumluluk 4 isi durduruyor (bir is birden cok esige takilabilir)

parcalanan is           adim         tepe bellek  ek tur       ek sure      hata noktasi
anomali esigi           2            65 MB        2            66 ms        3
tuketim egrisi          4            85 MB        6            198 ms       7

parcalama 2 isi kenara sokuyor: esik payi %80, toplam 8 ek tur, 264 ms ek sure, 10 hata noktasi (parcalanmadan is basina 1)
parcalanamayan 4 is merkeze duser (gunluk arsivleme, fatura belgesi, gecelik uzlastirma, cihaz kalici baglantisi); bedeli istek basina 60 ms kenar-bolge turu, kenar yalniz yonlendirir
son durum: 8/12 kenarda, 4/12 merkezde
```

Üç eşik on iki işin altısını geçirir; kalan altıda süre dördünü, bellek üçünü, uyumluluk dördünü
durdurur ve iki iş üçüne birden takılır.

İkinci tablo parçalamanın ne satın aldığını yazar. Süre ve belleğe takılan iki iş bölünebilir ve
bölünme belleği de böler: tüketim eğrisinin tepe belleği 260 MB'dan 85 MB'a iner. Bedel sekiz ek tur,
264 milisaniye ve **on hata noktasıdır** — parçalanmadan her iş tek noktaydı. Uyumluluğa takılan dört
iş parçalanamaz, çünkü eksik olan süre değil bir arayüz kalemidir.

#### Kenarın Kazandırmadığı Yer

```js
// katman.mjs — kenarin kazandirmadigi durumlar ve ayni isin uc katmanda karsilastirilmasi.
import { ISLER, parcala, sut } from "./sinir.mjs";

const GRUP = [                                      // tur sureleri ms, model girdisi
  { ad: "sube-a", istek: 2600, ucta: 8, dogrudan: 124 },
  { ad: "sube-b", istek: 2100, ucta: 12, dogrudan: 116 },
  { ad: "sube-c", istek: 1800, ucta: 18, dogrudan: 80 },
  { ad: "merkez-kampus", istek: 1500, ucta: 22, dogrudan: 14 },
  { ad: "veri-merkezi-ici", istek: 1200, ucta: 28, dogrudan: 6 },
  { ad: "sube-d", istek: 800, ucta: 14, dogrudan: 132 },
];   // merkeze giden istek ucdan gectigi icin dogrudan yola ucun turunu ekler
const N = GRUP.reduce((t, g) => t + g.istek, 0);
const ort = (f) => GRUP.reduce((t, g) => t + g.istek * f(g), 0) / N;

const kaybeden = GRUP.filter((g) => g.dogrudan <= g.ucta);
const kn = kaybeden.reduce((t, g) => t + g.istek, 0);
console.log(`${N} istek, ${GRUP.length} grup: ucta sonlanan iste agirlikli kazanc ` +
  `${ort((g) => g.dogrudan - g.ucta).toFixed(1)} ms, merkeze giden iste kayip ` +
  `${ort((g) => g.ucta).toFixed(1)} ms`);
console.log(`${kaybeden.length}/${GRUP.length} grup (${kn} istek, %${(100 * kn / N).toFixed(0)}) ` +
  `kaynaga zaten yakin: kenar onlara ${kaybeden.map((g) => g.dogrudan - g.ucta).join(" ve ")} ms yaziyor\n`);

const YAZMA = 64, BOLGE_YAZMA = 10, SUNUCU_KAT = 0.55;
const yaz = ort((g) => g.ucta) + YAZMA, yazB = ort((g) => g.dogrudan) + BOLGE_YAZMA;
console.log(`tutarli yazma: kenardan ${yaz.toFixed(1)} ms, bolgeden ${yazB.toFixed(1)} ms; kazanc ` +
  `${(yazB - yaz).toFixed(1)} ms, ucta sonlananin %` +
  `${(100 * (yazB - yaz) / ort((g) => g.dogrudan - g.ucta)).toFixed(0)}'i — ${YAZMA} ms hic eksilmiyor`);
const ag = ISLER.find((i) => i.ad === "tuketim egrisi"), ap = parcala(ag), sn = ag.islem * SUNUCU_KAT;
console.log(`agir hesap (${ag.islem} ms): kenarda ${ap.adim} parcada ${ag.islem + ap.ekSure} ms, ` +
  `sunucuda ${Math.round(sn)} ms — ${((ag.islem + ap.ekSure) / sn).toFixed(1)} kat\n`);

const IS = ISLER.find((i) => i.ad === "okuma bicim cevirimi");
const AYLIK = 12_000_000, SOGUK_ORAN = 0.02, SOGUK_EK = 900;
const BIRIM = { kenar: 0.0000003, islev: 0.0000012, sunucu_saat: 0.096 };   // kurgu birim
const eszaman = Math.ceil((AYLIK / 2_592_000) * (IS.islem / 1000));
const uc = ort((g) => g.ucta), bl = ort((g) => g.dogrudan);
const KATMAN = [
  ["kenar calisma zamani", uc + IS.islem, "50 ms / 128 MB / 5 eksik kalem", AYLIK * BIRIM.kenar],
  ["islev calistirma ortami", bl + IS.islem + SOGUK_ORAN * SOGUK_EK, "900 sn / 3008 MB / soguk",
    AYLIK * BIRIM.islev],
  ["surekli sunucu", bl + IS.islem * SUNUCU_KAT, "kapasite elde / olcekleme elle",
    Math.max(1, Math.ceil(eszaman / 40)) * 730 * BIRIM.sunucu_saat],
];
console.log(`ayni is "${IS.ad}", ayda ${AYLIK / 1e6} milyon istek; birimler kurgudur`);
sut("katman", "gecikme", "aylik birim", "kisit");
for (const [ad, ms, kisit, birim] of KATMAN)
  sut(ad, `${ms.toFixed(1)} ms`, birim.toFixed(2), kisit);
const [k, i, s] = KATMAN.map((x) => x[3]);
console.log(`kenar isleve gore ${(i / k).toFixed(1)} kat, sunucuya gore ${(s / k).toFixed(0)} kat ucuz; ` +
  `ama bu satir yalnizca uc esige sigan ${ISLER.length - 4}/${ISLER.length} is icin yazilabilir`);
```

```
10000 istek, 6 grup: ucta sonlanan iste agirlikli kazanc 68.8 ms, merkeze giden iste kayip 15.6 ms
2/6 grup (2700 istek, %27) kaynaga zaten yakin: kenar onlara -8 ve -22 ms yaziyor

tutarli yazma: kenardan 79.6 ms, bolgeden 94.4 ms; kazanc 14.8 ms, ucta sonlananin %21'i — 64 ms hic eksilmiyor
agir hesap (140 ms): kenarda 4 parcada 338 ms, sunucuda 77 ms — 4.4 kat

ayni is "okuma bicim cevirimi", ayda 12 milyon istek; birimler kurgudur
katman                  gecikme      aylik birim  kisit
kenar calisma zamani    33.6 ms      3.60         50 ms / 128 MB / 5 eksik kalem
islev calistirma ortami 120.4 ms     14.40        900 sn / 3008 MB / soguk
surekli sunucu          94.3 ms      70.08        kapasite elde / olcekleme elle
kenar isleve gore 4.0 kat, sunucuya gore 19 kat ucuz; ama bu satir yalnizca uc esige sigan 8/12 is icin yazilabilir
```

Üç durum kenarın kazandırmadığı yerleri sayar. Altı grubun ikisi — 2.700 istek, %27 — bölgeye uçtan
daha yakındır ve kenar onlara 8 ile 22 milisaniye **yazar**. Tutarlı yazmada sıralama merkezde olduğu
için 64 milisaniye hiç eksilmez: kazanç 68,8'den 14,8 milisaniyeye iner. Ağır hesapta 140
milisaniyelik iş kenarda 338, sunucuda 77 milisaniye tutar.

Son tablo üç katmanı aynı iş üzerinde yan yana koyar. Eşiklere sığan iş için kenar üç ölçütte de
kazanır: 33,6 milisaniye ve aylık 3,60 kurgu birim — işlevin dörtte biri, sunucunun on dokuzda biri.
Koşulu son cümlededir: **yalnızca on iki işin sekizi için yazılabilir.**

#### Özet

- Üç eşik on iki işin 6'sını geçirdi; süre 4, bellek 3, uyumluluk 4 işi durdurdu.
- Parçalama 2 işi daha kenara soktu ve tepe belleği 260 MB'dan 85 MB'a indirdi; bedel 8 ek tur, 264 ms
  ve iş başına 1 yerine toplam 10 hata noktasıdır. Uyumluluğa takılan 4 iş parçalanamaz ve merkeze
  düşer: 8/12 kenarda, 4/12 merkezde.
- Kenar üç yerde kazandırmaz: 2.700 istek (%27) bölgeye zaten yakın, tutarlı yazmada kazanç 68,8'den
  14,8 ms'ye iner, 140 ms'lik hesap kenarda 338, sunucuda 77 ms sürer.
- Sığan iş için kenar 33,6 ms ve 3,60 birimle işlevin 4, sunucunun 19 katı ucuzdur — ama kümenin
  yalnız 8/12'si için.

#### Kurs Kapanışı

| Ders | Devredilen karar | Karşılığında gelen kısıt | Dolaşmanın bedeli |
|---|---|---|---|
| İH-01 Sunucusuz kavramı | kapasite, 8 karar | eşzamanlılık 200 | 11.520 boşta örnek-dk |
| İH-02 Çağırma modelleri | yeniden deneme | 5.487 eş düşen kayıt | tekilleştirme %5,5 |
| İH-03 Soğuk başlangıç | havuz ömrü | soğuk çağrı 1.300 ms | ısıtma %50 fatura |
| İH-04 Kaynak sınırları | bellek kademesi | 12'den 6'sı sığmaz | 246 çağrı, 245 kayıt |
| İH-05 Takma adlar | trafik dağıtımı | %1 payda +100 ms | 15 yapay çağrı |
| İH-06 Paylaşılan katmanlar | bağımlılık yeri | alt uç 745 → 2.093 | 6 yeniden yayım |
| İH-07 Uymayan işler | sürekli kapasite | 5'ten 2'si uymaz | 13 hata noktası |
| OS-01 Olay veri yolu | yönlendirme | 433 sessiz düşme | 781 boşa uyandırma |
| OS-02 Kuyruk ve konu | tüketici ölçekleme | 5 ayar kalemi | 1 ileti 7 istek |
| OS-03 Orkestrasyon | akış durumu | 1.119 geçiş, 280 birim | üçe bölünürse 840 birim |
| OS-04 Zamanlanmış tetikleme | saat | 3.600 yinelenen fatura | koşum başına kapsam sorgusu |
| OS-05 Geçit servisi | geçit işletimi | 102 yapılandırma kalemi | 48.469 yeniden çağrı |
| OS-06 Bildirim servisleri | gönderim | 25 gün kısılma | 630 olay, 6,3 birim |
| KE-01 Çalışma zamanı | kurulum ve sürüm | 13'ten 7 kalem yok | istek başına +9 tur |
| KE-02 İstek işleme | yerleşim | 7'den 3'ü uçta olmaz | +64 ms, 640 sn |
| KE-03 Kenar depolama | çoğaltma | 12.857 bayat okuma | okuma 2 → 62 ms |
| KE-04 Durum nesneleri | eşzamanlılık | tavan 166,7 istek/sn | anahtar bölünür, 6 okuma |
| KE-05 Kenar kuyrukları | eşzamansız iş | 438 yanlış endeks | 2.400 ek yazma |
| KE-06 Bağlamalar | bağlantı kurma | 9 türden 5'i | 45 satır kod, 124 ms |
| KE-07 Kenar sınırları | işlem ve bellek | 12'den 6'sı sığar | 8 ek tur, 10 hata |

Kursun kuralı yirmi satırda da aynıdır: **kapasite yönetimini devretmek onu ortadan kaldırmaz;
kısıt olarak geri gelir ve tasarımı o kısıt belirler.** Üçüncü sütun dört aileye ayrılır: sekiz
satırda kısıt **sayılı bir üst sınırdır** (eşzamanlılık, süre, bellek, arayüz kalemi, istek/sn), üç
satırda **başlangıç bedelidir**, dört satırda **görünmeyen bir yapılandırma yüzeyidir** (kural, beş
kalem, akış tanımı, 102 kalem), beş satırda **sessiz kayıp ya da yinelenen iştir**. Dördüncü sütun
ise hiçbir satırda kısıtın birimiyle yazılmaz: süre sınırı çağrıya, saklama süresi ikinci bir
kopyaya, eksik arayüz ağ turuna çevrilir.

Dört kurstur her katman kiralandı: makine, ağ, veri ve hesabın kendisi. Her kiralama bir karar
devretti, karşılığında sayılabilir bir kısıt verdi. Ama bütün bu hesapların **kime ait olduğu**,
kimin neye erişebildiği ve faturanın kime çıktığı hiç sorulmadı. **M23/K05 Bulut Yönetişimi,
Güvenlik ve Maliyet** bu soruyla başlar.

