---
title: 'Konteyner Orkestrasyonu'
source: 'https://academia.sh/tr/kurslar/orkestrasyon'
language: tr
updated: '2026-08-17T04:40:40+00:00'
license: 'CC BY-SA 4.0'
lessons: 30
outcomes:
    - 'Uzlaşma döngüsünü ve küme bileşenlerinin görevlerini ölçüyle açıklar'
    - 'Uygulamayı bildirimsel nesnelerle dağıtır ve ölçekler'
    - 'Kaynak, güvenlik ve dağıtım politikalarını sayıya bağlar'
---

# Konteyner Orkestrasyonu

Kaç kopyanın nerede ve ne zaman koşacağı kararının bir sisteme devredilmesi: elle yönetimin sınırları, denetim düzlemi ve düğüm bileşenlerinin görevleri, istenen durum ile gerçek durumu sürekli karşılaştıran uzlaşma döngüsü, en küçük dağıtım biriminden kopya kümesine ve bildirimsel sürüm yönetimine uzanan temel nesneler, küme içi kararlı adresleme ve dış erişim, yapılandırma, sır ve kalıcı depolama nesneleri, kaynak istekleri ve sınırlarının zamanlayıcı kararına etkisi, yerleşim kısıtları, tahliye ve öncelikler, ölçüt tabanlı otomatik ölçekleme, dağıtım kalıpları, sağlık denetimleri, yetki ve ağ politikaları, şablonlama, kaynak türü genişletme, işletim bilgisinin denetleyiciye kodlanması ve çok kümeli işletim.

## Küme Mimarisi

Kararın insandan sisteme geçmesi: elle konteyner yönetiminin nerede tükendiği, denetim düzleminin arayüz, zamanlayıcı, denetleyici ve durum deposu olarak ayrılması, düğüm tarafındaki aracı süreç, çalışma zamanı ve ağ vekilinin görevleri, istenen durum ile gerçek durumu sürekli karşılaştıran uzlaşma döngüsünün gecikme ve iş cinsinden ölçülmesi ve kümeyi kendi işletme kararının bedeli.

### Orkestrasyon İhtiyacı

Source: https://academia.sh/tr/kurslar/orkestrasyon/orkestrasyon-ihtiyaci

Elle yönetim makine ve servis sayısıyla taranır: karar sayısı doğrusal büyürken karar başına bakılan bilgi çarpım olarak büyüyor, arıza fark etme gecikmesi tur süresine bağlanıyor. Devretmenin eşiği gün cinsinden hesaplanır ve kararın dayandığı altı bilgi kaleminden biri yazılmadığında sistemin kaç kopyayı yanlış yerleştirdiği sayılır.

Bir önceki kursun bütün ölçümleri tek makinede yapıldı: çıktı taşınabilir oldu, kimliği
içeriğinden türedi, yalıtımı ve yetkisi kalem kalem sayıldı. Geriye tek bir soru kaldı — o
çıktının **kaç kopya, hangi makinede ve ne zaman** çalışacağına karar veren hâlâ bir insandı. Bu
ders o kararın kendisini ölçer: elle verildiğinde ölçekle nasıl büyüyor, bir sisteme
devredildiğinde o sistemin **neyi bilmesi** gerekiyor ve devretmenin **kazandırmadığı** durum
nerede duruyor.

**Orkestrasyon**, birden çok makine üzerinde çalışan iş yüklerinin yerleştirme, kopya sayısı ve
arıza sonrası yeniden başlatma kararlarını bir sisteme devretme işidir. Bu kursun ölçü birimi
**devrin bedeli**dir: her devredilen karar, o kararın dayandığı bilgiyi sürekli ve zamanında
üretmeyi gerektirir.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan,
faturalayan ve saha iş emri açan **kurgu** yazılım; gecelik toplu iş de aynı ağın parçasıdır.
Burada koşan şey gerçek bir küme değil, `node` ile kurulmuş bir **modeldir**; sayılar modelin
sayılarıdır ve modelin varsayımları aşağıda yazılıdır.

**KM1.** Ağ dört servisten oluşur ve her servisin üç kopyası vardır; makine sayısı ve servis
sayısı ayrı ayrı taranır.
**KM2.** Elle adım maliyeti sabittir: bir kopyayı yerleştirmek 4 adım, bir makineyi hazırlamak 6
adım, bir kopyayı gözle denetlemek 20 saniye.
**KM3.** Arızalar kendi yazdığımız 32 bitlik üreteçten gelir; tohum `20260401` çıktıda görünür,
kopya başına günlük arıza olasılığı 0,15'tir.
**KM4.** İnsan kopyaları sırayla denetleyerek tur atar; iki senaryo koşulur — kesintisiz nöbet ve
sekiz saatlik tek vardiya.
**KM5.** Devredilmiş yönetimde makine başına hazırlık 6 yerine 9 adımdır (aracı süreç de kurulur),
bildirim periyodu 10 saniye, uzlaşma periyodu 15 saniyedir.
**KM6.** Yerleştirme kısıtı gerçektir: toplayıcı kopyaları yalnız sayaç ağına fiziksel bağlantısı
olan makinelerde koşabilir; on altı makinenin dördü böyledir.

#### Elle Yönetim İki Ayrı Hızda Büyür

```js
// olcek.mjs — elle yonetimin makine ve servis sayisiyla taranmasi. Bu bir modeldir; gercek
// kume kosturulmaz. Zaman saniye, "adim" bir insan islemidir.
export const uretec = (tohum) => { let s = tohum >>> 0;  // kendi uretecimiz: 32 bit, tohum gorunur
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };

const A_KOPYA = 4, A_MAKINE = 6, D_SURE = 20, GUN = 86400, VARDIYA = 8 * 3600;

export function elle({ M, S, r, arizaOrani, tohum, kesintisiz }) {
  const N = S * r, rnd = uretec(tohum), T = N * D_SURE;   // T: bir denetim turunun suresi
  const arizalar = [];
  for (let i = 0; i < N; i++) if (rnd() < arizaOrani) arizalar.push({ i, t: rnd() * GUN });
  let gecikme = 0;
  for (const a of arizalar) {
    let t = a.t;
    if (!kesintisiz && t % GUN >= VARDIYA) t = Math.floor(t / GUN) * GUN + GUN; // vardiya disi
    const yer = a.i * D_SURE;                              // kopyanin tur icindeki sirasi
    let d = Math.ceil((t - yer) / T) * T + yer;
    if (d < t) d += T;
    if (!kesintisiz && d % GUN >= VARDIYA) d = Math.floor(d / GUN) * GUN + GUN + yer;
    gecikme += d - a.t;
  }
  const karar = N + S + arizalar.length;                   // yerlestirme + kac kopya + yeniden yer
  return { N, karar, bakis: (N + arizalar.length) * M, turSuresi: T,
    adim: A_MAKINE * M + A_KOPYA * N + A_KOPYA * arizalar.length, ariza: arizalar.length,
    ortGecikme: arizalar.length ? gecikme / arizalar.length : 0 };
}

if (import.meta.url === `file://${process.argv[1]}`) {        // ikinci blok bu dosyayi ice aktarir
  console.log("M  S   kopya  karar  bakis  adim  tur(dk)  ariza  gecikme(dk)  gecikme-tek-vardiya");
  for (const [M, S] of [[1,4],[2,4],[4,6],[8,8],[16,12],[32,16]]) {
    const g = { M, S, r: 3, arizaOrani: 0.15, tohum: 20260401 };
    const k = elle({ ...g, kesintisiz: true }), v = elle({ ...g, kesintisiz: false });
    console.log(`${String(M).padStart(2)} ${String(S).padStart(2)} ${String(k.N).padStart(6)}` +
      `${String(k.karar).padStart(7)}${String(k.bakis).padStart(7)}${String(k.adim).padStart(6)}` +
      `${(k.turSuresi/60).toFixed(1).padStart(9)}${String(k.ariza).padStart(7)}` +
      `${(k.ortGecikme/60).toFixed(1).padStart(13)}${(v.ortGecikme/60).toFixed(1).padStart(21)}`);
  }
}
```

```
M  S   kopya  karar  bakis  adim  tur(dk)  ariza  gecikme(dk)  gecikme-tek-vardiya
 1  4     12     21     17    74      4.0      5          1.2                394.8
 2  4     12     21     34    80      4.0      5          1.2                394.8
 4  6     18     29     92   116      6.0      5          2.4                394.8
 8  8     24     38    240   168      8.0      6          3.6                330.2
16 12     36     56    704   272     12.0      8          6.5                363.5
32 16     48     74   1856   424     16.0     10          7.7                324.5
```

İki sütun iki ayrı hızda büyüyor. **Karar sayısı doğrusaldır**: 21'den 74'e, üç buçuk kat. Elle
adım da doğrusaldır: 74'ten 424'e. Bu iki sayıya bakan biri elle yönetimin ölçekle sorunsuz
büyüdüğü sonucuna varabilir, çünkü kopya sayısı da tam olarak dört kat arttı.

**Bakış sütunu** aynı ölçekte 17'den 1856'ya çıkıyor — yüz dokuz kat. Bakış, bir yerleştirme
kararını verirken kaç makinenin durumuna bakıldığıdır. Karar sayısı kopya sayısıyla, karar başına
bakılan bilgi makine sayısıyla büyür; ikisinin çarpımı **karar sayısının kendisiyle aynı hızda
büyümez**. Elle yönetimin pahalıya çıktığı yer karar sayısı değil, her kararın altındaki bilgi
toplama işidir.

Üçüncü ölçü fark etme gecikmesidir. Kesintisiz nöbette gecikme 1,2 dakikadan 7,7 dakikaya çıkıyor
ve doğrusal görünüyor: bir denetim turu kopya sayısıyla uzuyor, ortalama bekleme turun yarısı
kadar oluyor. Tek vardiya sütunu ise bambaşka bir şey söylüyor — 394,8'den 324,5 dakikaya, yani
**ölçekle büyümüyor, hatta düşüyor**. Bu bir hesap hatası değil, baskın terimin değişmesidir: tek
vardiyada gecikmenin kaynağı tur süresi değil, **gecenin kendisidir**. Ölçüm ağının gecelik toplu
işi 02:30'da başlar; o sırada düşen bir toplayıcı kopyası vardiya açılana kadar düşük kalır ve
kopya sayısını artırmak bu bekleyişi uzatmaz.

#### Devretmenin Eşiği

```js
// esik.mjs — elle yonetim ile devredilmis yonetimin ayni kalemlerde karsilastirilmasi.
import { elle, uretec } from "./olcek.mjs";
const KURULUM = 120, BILDIRIM = 9, A_DUGUM = 9, A_KOPYA = 4, GUN = 86400;
const P = 10, U = 15;                                    // bildirim ve uzlasma periyodu (saniye)

function devredilmis({ M, S, r, arizaOrani, tohum }) {
  const N = S * r, rnd = uretec(tohum), arizalar = [];
  for (let i = 0; i < N; i++) if (rnd() < arizaOrani) arizalar.push({ i, t: rnd() * GUN });
  let g = 0;
  for (const a of arizalar) g += Math.ceil(Math.ceil(a.t / P) * P / U) * U - a.t;
  return { kurulum: KURULUM + BILDIRIM * S + A_DUGUM * M, ariza: arizalar.length,
    ortGecikme: arizalar.length ? g / arizalar.length : 0 };
}

console.log("kopya  elle-kur  elle/gun  devir-kur  esik(gun)  elle-gecikme(dk)  devir-gec(sn)");
for (const [M, S] of [[1,2],[2,4],[4,6],[8,8],[16,12],[32,16]]) {
  const g = { M, S, r: 3, arizaOrani: 0.15, tohum: 20260401 };
  const e = elle({ ...g, kesintisiz: true }), d = devredilmis(g);
  const eKur = e.adim - A_KOPYA * e.ariza, eGun = A_KOPYA * e.ariza;
  console.log(`${String(e.N).padStart(5)}${String(eKur).padStart(10)}${String(eGun).padStart(10)}` +
    `${String(d.kurulum).padStart(11)}${Math.ceil((d.kurulum - eKur) / eGun).toString().padStart(11)}` +
    `${(e.ortGecikme/60).toFixed(1).padStart(18)}${d.ortGecikme.toFixed(1).padStart(15)}`);
}

console.log("\nariza orani  ariza/gun  elle/gun  devir-kur  esik(gun)   [M=8, S=8, 24 kopya]");
for (const o of [0, 0.02, 0.05, 0.10, 0.15, 0.30]) {
  const g = { M: 8, S: 8, r: 3, arizaOrani: o, tohum: 20260401 };
  const e = elle({ ...g, kesintisiz: true }), d = devredilmis(g);
  const eKur = e.adim - A_KOPYA * e.ariza, eGun = A_KOPYA * e.ariza;
  console.log(`${o.toFixed(2).padStart(11)}${String(e.ariza).padStart(11)}` +
    `${String(eGun).padStart(10)}${String(d.kurulum).padStart(11)}` +
    `${(eGun ? String(Math.ceil((d.kurulum - eKur) / eGun)) : "sonsuz").padStart(11)}`);
}

// Bilinmeyen kisit: toplayici kopyalari yalniz sayac agina bagli makinelerde kosabilir.
const makine = Array.from({ length: 16 }, (_, i) => ({ ad: i, sayacAgi: i % 5 === 0 }));
const kopyalar = [...Array(6).fill("toplayici"), ...Array(4).fill("dogrulayici"),
  ...Array(3).fill("faturalama"), ...Array(3).fill("is-emri")];
for (const yazili of [false, true]) {
  const yuk = makine.map(() => 0), yer = [];
  for (const k of kopyalar) {
    const uygun = makine.filter((m) => !(yazili && k === "toplayici") || m.sayacAgi);
    const s = uygun.reduce((a, b) => (yuk[a.ad] <= yuk[b.ad] ? a : b));
    yuk[s.ad]++; yer.push({ k, m: s });
  }
  const yanlis = yer.filter((y) => y.k === "toplayici" && !y.m.sayacAgi).length;
  console.log(`kisit bildirimde ${yazili ? "yazili " : "yazisiz"}: kopya ${yer.length}` +
    `   yanlis yerlestirme ${yanlis}   duzeltme adimi ${yanlis * A_KOPYA}` +
    `   bildirim kalemi ${yazili ? 5 : 4}`);
}
```

```
kopya  elle-kur  elle/gun  devir-kur  esik(gun)  elle-gecikme(dk)  devir-gec(sn)
    6        30         4        147         30               1.0            2.0
   12        60        20        174          6               1.2            8.1
   18        96        20        210          6               2.4            8.1
   24       144        24        264          5               3.6            8.7
   36       240        32        372          5               6.5            9.1
   48       384        40        552          5               7.7            8.0

ariza orani  ariza/gun  elle/gun  devir-kur  esik(gun)   [M=8, S=8, 24 kopya]
       0.00          0         0        264     sonsuz
       0.02          2         8        264         15
       0.05          3        12        264         10
       0.10          6        24        264          5
       0.15          6        24        264          5
       0.30         10        40        264          3
kisit bildirimde yazisiz: kopya 16   yanlis yerlestirme 4   duzeltme adimi 16   bildirim kalemi 4
kisit bildirimde yazili : kopya 16   yanlis yerlestirme 0   duzeltme adimi 0   bildirim kalemi 5
```

Devretmenin kurulum maliyeti her ölçekte elle kurulumdan yüksektir: 6 kopyada 147'ye karşı 30
adım, 48 kopyada 552'ye karşı 384. Devretme **ilk gün her zaman zarardır**. Fark günlük kalemde
ortaya çıkar: elle yönetimde arızalar her gün elle karşılanır, devredilmiş yönetimde günlük elle
adım sıfırdır. Eşik sütunu iki maliyetin kesiştiği günü verir.

Bu eşik ölçekle hızla düşüyor. Altı kopyalı bir kurulumda elle yönetim **otuz gün** boyunca daha
ucuzdur; on iki kopyada altı güne, yirmi dördün üstünde beş güne iner. Otuz gün, tek servisli bir
deneme ortamı ya da bir aylık bir pilot için gerçek bir cevaptır — o ölçekte devretmek gereksiz
iştir. Beş gün ise cevap değildir; ölçüm ağının dört servisi ve on iki kopyası, kararı devretmenin
bir hafta içinde kendini ödediği bölgededir.

Gecikme sütunları eşikten daha keskin bir ayrım gösteriyor: elle yönetimde 1,0–7,7 **dakika**,
devredilmiş yönetimde 2,0–9,1 **saniye**. Devredilmiş yönetimde bu sayı ölçekle büyümüyor, çünkü
gecikmenin kaynağı tarama değil, iki sabit periyottur — bildirim periyodu ve uzlaşma periyodu.
Ölçek büyüdükçe elle yönetimin kaybı adım sayısında değil, burada birikiyor.

#### Sistemin Bilmesi Gereken Altı Kalem

Devredilen karar tek cümleyle yazılabilir: **hangi kopya hangi makinede çalışacak ve düştüğünde
ne olacak.** Sistemin bu kararı verebilmesi için sürekli bilmesi gereken kalemler şunlardır.

| Bilgi kalemi | Kaynağı | Eskirse |
|---|---|---|
| makine listesi | düğüm kaydı | olmayan makineye yerleştirme |
| makine kapasitesi | düğüm bildirimi | kapasitesi dolu makineye yerleştirme |
| makine sağlığı | düzenli bildirim | ölü makinede kopya sanma |
| istenen kopya sayısı | insanın yazdığı bildirim | eksik ya da fazla kopya |
| kopyaların gerçek durumu | düğümden bildirim | düşen kopyayı geç fark etme |
| yerleştirme kısıtları | insanın yazdığı bildirim | çalışamayacak makineye yerleştirme |

Altı kalemin dördü sistemin kendi topladığı ölçümdür; ikisi **insanın yazması gerekendir**. Bu
ayrım maliyetin de ayrımıdır. Toplanan dört kalem sürekli bir bildirim yükü doğurur: her makine
her periyotta kapasitesini, sağlığını ve üzerindeki kopyaların durumunu bildirmek zorundadır ve
devredilmiş yönetimin dokuz saniyelik fark etme gecikmesi tam olarak bu periyodun bedelidir.
Periyodu büyütmek yükü azaltır, gecikmeyi büyütür. Yazılan iki kalem ise tek seferliktir ama
bakımsız kalırsa sessizce yanlışlanır — istenen kopya sayısı bir kez yazılıp unutulduğunda sistem
hâlâ o sayıya doğru çalışır ve kimse ondan şüphelenmez.

 Son
satırın bedeli çıktının son iki satırında duruyor. Kısıt bildirimde yazılı değilken yerleştirici
altı toplayıcı kopyasının dördünü sayaç ağı olmayan makinelere koydu; o dört kopya başlar ama
okuma çekemez. Kısıt bildirime eklendiğinde yanlış yerleştirme sıfıra indi ve bildirimin kalem
sayısı dörtten beşe çıktı. **Bir kalemlik yazı, dört yanlış yerleştirmeyi önledi** — devrin bedeli
tam olarak budur ve peşin ödenir.

#### Devretmenin Kazandırmadığı Üç Durum

Birincisi eşiğin altıdır: altı kopyalı bir kurulumda devretme otuz gün boyunca zarardır ve o
kurulum otuz gün yaşamayacaksa hiç kazanmaz.

İkincisi arıza oranının düşüklüğüdür ve ikinci tarama bunu sayıyla veriyor. Yirmi dört kopyalı
aynı kurulumda arıza oranı 0,30 iken eşik üç gündür; 0,05'te on güne, 0,02'de on beş güne çıkar ve
oran sıfırlandığında **sonsuz** olur — hiç arıza olmayan bir kurulumda devretmenin geri ödemesi
yoktur. Kararı devretmek arızayı ucuzlatır, **arızasızlığı** değil; kazancın tamamı arıza
kaleminden gelir ve o kalem küçüldükçe kazanç da küçülür.

Üçüncüsü ve en pahalısı, kararın dayandığı bilginin **yazılabilir olmamasıdır**. Kısıt deneyi bunun
kolay hâliydi: kısıt bir satırda yazılabiliyordu. Yazılamayan kısıtlar da vardır — bir makinenin
saha ekibince fiziksel olarak erişilebilir olması, bir servisin belirli bir müşteriyle yapılmış
sözleşme gereği belirli bir binada durması. Bu kalemler bildirime girmediği sürece sistem
onlardan habersizdir ve **habersiz olduğu her kalem bir yanlış karar sınıfı üretir**. Elle yönetimde
bu bilgi insanın kafasında durur ve hiçbir maliyeti yokmuş gibi görünür; devredildiğinde ilk kez
bir bedel olarak ortaya çıkar. Devretme kararı bu yüzden bir ölçek kararı olduğu kadar bir
**yazılabilirlik** kararıdır: kararı besleyen bilginin ne kadarı bir dosyaya girebiliyor.

#### Özet

- Elle yönetimde karar sayısı doğrusal büyüdü (21 → 74), karar başına bakılan bilgi çarpım olarak
  büyüdü (17 → 1856); pahalı olan karar değil, kararın altındaki bilgi toplama işiydi.
- Arıza fark etme gecikmesi kesintisiz nöbette tur süresiyle doğrusal büyüdü (1,2 → 7,7 dakika);
  tek vardiyada 325–395 dakikada kaldı ve ölçekten bağımsızdı, çünkü baskın terim gecenin
  kendisiydi.
- Devretme ilk gün her ölçekte zarardır; eşik 6 kopyada 30 gün, 12 kopyada 6 gün, 24 kopyanın
  üstünde 5 gündür.
- Devredilmiş yönetimde fark etme gecikmesi 2–9 saniyede kaldı ve ölçekle büyümedi; kaynağı
  tarama değil, iki sabit periyottu.
- Yerleştirme kararı altı bilgi kalemine dayanır; kısıt kalemi yazılmadığında altı toplayıcı
  kopyasının dördü çalışamayacağı makineye yerleştirildi, bir kalemlik yazı bunu sıfıra indirdi.

#### Sonraki Adım

Kararı devretmek için karşılığında bir sistem gerekiyor ve o sistemin altı bilgi kalemini toplayıp
saklaması, kararı üretmesi ve sonucu uygulaması lazım. Bu işlerin hepsi tek bir parçada durmaz.
Bir sonraki ders kararı üstlenen tarafı — **denetim düzlemini** — parçalarına ayırır: küme
arayüzü, zamanlayıcı, denetleyici yöneticisi ve durum deposu. Ölçülecek şey bir isteğin uçtan uca
kaç bileşenden geçtiği, her bileşenin hangi bilgiyi okuyup yazdığı ve bir bileşen düştüğünde
**hangi kararların durup hangilerinin sürdüğü**dür.

### Denetim Düzlemi Bileşenleri

Source: https://academia.sh/tr/kurslar/orkestrasyon/denetim-duzlemi-bilesenleri

Kararı üstlenen taraf dört parçaya ayrılır ve tek bir istek uçtan uca izlenir: kaç bileşenden geçtiği, her bileşenin hangi bilgiyi okuyup yazdığı, durum deposuna düşen okuma ve yazma sayılır. Sonra her bileşen tek tek düşürülür ve hangi kararların durup hangilerinin sürdüğü ölçülür.

Bir önceki ders yerleştirme kararının altı bilgi kalemine dayandığını ve bu kalemlerin dördünün
sürekli toplanması gerektiğini saydı. Toplayan, saklayan, karar üreten ve sonucu uygulayan taraf
tek bir parça değildir. Bu ders o tarafı — **denetim düzlemini** — dört bileşene ayırır ve iki şey
ölçer: bir isteğin uçtan uca izi ve bir bileşen düştüğünde hangi kararların durduğu.

Bileşenler görevleriyle anılır: **küme arayüzü** (tek yazma kapısı ve doğrulama), **durum deposu**
(bütün kalemlerin kalıcı yeri), **zamanlayıcı** (yerleştirme kararı), **denetleyici yöneticisi**
(istenen ile gerçek arasındaki farkı kapatan iş). Düğüm tarafı burada tek bir toplu parça olarak
durur; parçalarına bir sonraki ders ayırır.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan ve doğrulayan
**kurgu** yazılım. Koşan şey gerçek bir küme değil, `node` ile kurulmuş bir **modeldir**.

**KM7.** Şema kendi şemamızdır: üç anahtar öneki — `servis/<ad>`, `kopya/<ad>`, `dugum/<ad>`.
**KM8.** Denetim düzlemi dört bileşendir; düğüm tarafı tek bir toplu parça olarak modellenir.
**KM9.** Küme arayüzü tek yazma kapısıdır ve kendi durumu yoktur; her yazma durum deposuna iner.
**KM10.** Okuma bir öneki tarayan tek işlemdir; taranan kalem sayısı okuma yükü olarak sayılır.
**KM11.** Başlangıç durumu iki servis (toplayıcı 3 kopya, doğrulayıcı 2 kopya) ve üç düğümdür;
düğüm kapasitesi dörttür.
**KM12.** Bir bileşen düştüğünde yalnız o bileşen durur; ağ ve düğümler ayaktadır. Bir kopyanın
öldüğü bilgisi de küme arayüzünden geçerek deftere girer.

#### Dört Bileşen, Tek Yazma Kapısı

```js
// duzlem.mjs — denetim duzleminin dort bileseni ve durum deposu. Model; gercek kume degil.
// Sema kendi semamizdir: servis/<ad>, kopya/<ad>, dugum/<ad>.
export function kur(baslangic) {
  const veri = new Map(Object.entries(baslangic)); const iz = [];
  let rev = 0, aktif = "-";
  const d = {
    veri, iz, get rev() { return rev; },
    oku(on) { const c = [...veri].filter(([a]) => a.startsWith(on));
      iz.push({ b: aktif, i: "oku", a: on + "*", n: c.length }); return c; },
    yaz(a, v) { veri.set(a, v); rev++; iz.push({ b: aktif, i: "yaz", a, n: 1 }); },
    sil(a) { veri.delete(a); rev++; iz.push({ b: aktif, i: "sil", a, n: 1 }); },
    bilesen(ad) { aktif = ad; },
  };
  return d;
}

// 1) Kume arayuzu: tek yazma kapisi. Semayi dogrular, depoya yazar. Kendi durumu yoktur.
export const arayuz = (d, istek) => {
  d.bilesen("kume arayuzu");
  if (!istek.anahtar.match(/^(servis|kopya|dugum)\//)) return "sema disi";
  istek.deger === null ? d.sil(istek.anahtar) : d.yaz(istek.anahtar, istek.deger);
  return "yazildi";
};

// 2) Denetleyici yoneticisi: istenen kopya sayisi ile gercek kopya sayisini karsilastirir.
export const denetleyici = (d) => {
  d.bilesen("denetleyici yoneticisi"); let is = 0;
  const servisler = d.oku("servis/"), hepsi = d.oku("kopya/");
  for (const [a, v] of hepsi) if (v.durum === "olu") { d.sil(a); is++; }   // olu kaydi temizle
  for (const [a, s] of servisler) {
    const ad = a.slice(7), on = `kopya/${ad}-`;
    const k = hepsi.filter(([, v]) => v.servis === ad && v.durum !== "olu");
    let n = Math.max(0, ...hepsi.filter(([b]) => b.startsWith(on)).map(([b]) => +b.slice(on.length)));
    for (let i = k.length; i < s.istenen; i++, is++)
      d.yaz(on + ++n, { servis: ad, dugum: null, durum: "bekliyor" });
    for (let i = k.length; i > s.istenen; i--, is++) d.sil(k[i - 1][0]);
  }
  return is;
};

// 3) Zamanlayici: dugumu olmayan kopyalara kapasitesi yeten en bos dugumu secer.
export const zamanlayici = (d) => {
  d.bilesen("zamanlayici"); let is = 0;
  const dugumler = d.oku("dugum/").filter(([, v]) => v.saglik === "canli");
  const kopyalar = d.oku("kopya/");
  const yuk = new Map(dugumler.map(([a]) => [a, kopyalar.filter(([, v]) => v.dugum === a).length]));
  for (const [a, k] of kopyalar.filter(([, v]) => v.dugum === null && v.durum === "bekliyor")) {
    const uygun = dugumler.filter(([n, v]) => yuk.get(n) < v.kapasite);
    if (!uygun.length) continue;                                  // cozumsuz: yer yok
    const s = uygun.reduce((x, y) => (yuk.get(x[0]) <= yuk.get(y[0]) ? x : y))[0];
    yuk.set(s, yuk.get(s) + 1); d.yaz(a, { ...k, dugum: s }); is++;
  }
  return is;
};

// 4) Araci sureclerin toplu karsiligi: atanmis kopyayi baslatir ve durumunu bildirir.
export const dugumler = (d) => {
  d.bilesen("dugum araci surecleri"); let is = 0;
  for (const [a, k] of d.oku("kopya/"))
    if (k.dugum && k.durum === "bekliyor") { d.yaz(a, { ...k, durum: "calisiyor" }); is++; }
  return is;
};
```

Dikkat edilecek yer bileşenlerin **birbirini hiç çağırmamasıdır**. Denetleyici yöneticisi
zamanlayıcıya haber vermez; kopya nesnesini düğümsüz olarak deftere yazar ve orada bırakır.
Zamanlayıcı da kimseye haber vermez; düğümsüz kopyaları okur, düğüm seçer, deftere yazar. Dört
bileşenin ortak dili tek bir yerdir — durum deposu — ve bu seçim düşme davranışını da belirler.
Deponun her yazmada artırdığı **revizyon** sayacı bu dilin zaman damgasıdır: bir bileşenin
gördüğü defterin hangi anın defteri olduğunu ancak o sayı söyler.

#### Bir İsteğin Uçtan Uca İzi

```js
// iz.mjs — tek bir istegin uctan uca izi: hangi bilesen neyi okuyor, neyi yaziyor.
import { kur, arayuz, denetleyici, zamanlayici, dugumler } from "./duzlem.mjs";

export const baslangic = () => {
  const b = { "servis/toplayici": { istenen: 3 }, "servis/dogrulayici": { istenen: 2 } };
  for (let i = 1; i <= 3; i++)
    b[`kopya/toplayici-${i}`] = { servis: "toplayici", dugum: `m${i}`, durum: "calisiyor" };
  for (let i = 1; i <= 2; i++)
    b[`kopya/dogrulayici-${i}`] = { servis: "dogrulayici", dugum: `m${i}`, durum: "calisiyor" };
  for (let i = 1; i <= 3; i++) b[`dugum/m${i}`] = { kapasite: 4, saglik: "canli" };
  return b;
};

if (import.meta.url === `file://${process.argv[1]}`) {   // ucuncu blok bu dosyayi ice aktarir
  const d = kur(baslangic());
  arayuz(d, { anahtar: "servis/toplayici", deger: { istenen: 5 } });
  let tur = 0, is;
  do { is = denetleyici(d) + zamanlayici(d) + dugumler(d); tur++; } while (is > 0 && tur < 8);

  let oku = 0, yaz = 0;
  console.log("istek: toplayici servisinin istenen kopya sayisi 3 -> 5");
  console.log("#  bilesen                 islem  anahtar                    kalem  oku  yaz");
  d.iz.forEach((e, i) => {
    e.i === "oku" ? (oku += e.n) : yaz++;
    console.log(`${String(i + 1).padStart(2)} ${e.b.padEnd(23)} ${e.i.padEnd(6)} ` +
      `${e.a.padEnd(26)} ${String(e.n).padStart(5)} ${String(oku).padStart(4)} ${String(yaz).padStart(4)}`);
  });
  const bilesenler = new Set(d.iz.map((e) => e.b));
  console.log(`\ngecilen bilesen ${bilesenler.size}   iz adimi ${d.iz.length}   depo okuma ${oku}` +
    `   depo yazma ${yaz}   revizyon 0 -> ${d.rev}   tur ${tur}`);
}
```

```
istek: toplayici servisinin istenen kopya sayisi 3 -> 5
#  bilesen                 islem  anahtar                    kalem  oku  yaz
 1 kume arayuzu            yaz    servis/toplayici               1    0    1
 2 denetleyici yoneticisi  oku    servis/*                       2    2    1
 3 denetleyici yoneticisi  oku    kopya/*                        5    7    1
 4 denetleyici yoneticisi  yaz    kopya/toplayici-4              1    7    2
 5 denetleyici yoneticisi  yaz    kopya/toplayici-5              1    7    3
 6 zamanlayici             oku    dugum/*                        3   10    3
 7 zamanlayici             oku    kopya/*                        7   17    3
 8 zamanlayici             yaz    kopya/toplayici-4              1   17    4
 9 zamanlayici             yaz    kopya/toplayici-5              1   17    5
10 dugum araci surecleri   oku    kopya/*                        7   24    5
11 dugum araci surecleri   yaz    kopya/toplayici-4              1   24    6
12 dugum araci surecleri   yaz    kopya/toplayici-5              1   24    7
13 denetleyici yoneticisi  oku    servis/*                       2   26    7
14 denetleyici yoneticisi  oku    kopya/*                        7   33    7
15 zamanlayici             oku    dugum/*                        3   36    7
16 zamanlayici             oku    kopya/*                        7   43    7
17 dugum araci surecleri   oku    kopya/*                        7   50    7

gecilen bilesen 4   iz adimi 17   depo okuma 50   depo yazma 7   revizyon 0 -> 7   tur 2
```

Bir insan tek bir kalem yazdı: toplayıcı servisinin istenen kopya sayısı 3 yerine 5. Bunun
karşılığı **dört bileşen, on yedi iz adımı, 50 kalem okuma ve 7 yazma** oldu. Yazma sayısı en
öğretici olanıdır: insanın yazdığı 1 yazmaya karşılık düzlem 6 yazma daha üretti — iki kopya
nesnesinin yaratılması, ikisinin düğüme atanması, ikisinin çalışır olarak bildirilmesi. **Bir
kalem üç kez yazılıyor**, çünkü her bileşen aynı nesnenin ayrı bir alanını dolduruyor.

Kopya nesnesinin yolculuğu satırlarda görülüyor: 4. adımda düğümsüz ve `bekliyor` olarak doğuyor,
9. adımda bir düğüm alıyor, 12. adımda `calisiyor` oluyor. Üç bileşen aynı anahtara sırayla
dokunuyor ve hiçbiri ötekini beklemiyor; her biri yalnız deftere bakıp kendi işini yapıyor.

İkinci tur — 13'ten 17'ye kadar olan adımlar — bu dersin en pahalı sayısını taşır: **0 yazma, 26
kalem okuma**. Fark kapandıktan sonra da her bileşen defteri baştan okudu ve yapacak iş bulamadı.
Kümenin "hiçbir şey yapmamak" için ödediği bedel budur ve durmaz; ölçüm ağının sakin bir gecesinde
bile denetleyici yöneticisi ile zamanlayıcı defteri taramayı sürdürür. Okuma yükü kalem sayısıyla
büyür, yapılan işle değil.

#### Bir Bileşen Düştüğünde

```js
// matris.mjs — bir bilesen dustugunde hangi kararlar duruyor, hangileri suruyor.
import { kur, arayuz, denetleyici, zamanlayici, dugumler } from "./duzlem.mjs";
import { baslangic } from "./iz.mjs";

const OLAY = [["servis/toplayici", { istenen: 5 }],                       // olcek istegi
  ["kopya/toplayici-2", { servis: "toplayici", dugum: "m2", durum: "olu" }],  // dugum bildirimi
  ["dugum/m4", { kapasite: 4, saglik: "canli" }]];                        // yeni dugum

function kos(dusen) {
  const d = kur(baslangic());
  if (dusen === "durum deposu") { d.oku = () => []; d.yaz = () => {}; d.sil = () => {}; }
  for (const [a, v] of OLAY)
    if (dusen !== "kume arayuzu") arayuz(d, { anahtar: a, deger: v });
  const bildirildi = d.veri.get("kopya/toplayici-2")?.durum === "olu";   // olum kaydedilebildi mi
  let tur = 0, is;
  do { is = (dusen === "denetleyici yoneticisi" ? 0 : denetleyici(d)) +
    (dusen === "zamanlayici" ? 0 : zamanlayici(d)) + dugumler(d); tur++; } while (is > 0 && tur < 8);

  const k = [...d.veri].filter(([a]) => a.startsWith("kopya/toplayici"));
  const say = (t) => k.filter(([, v]) => v.durum === t).length;
  const durum = (bitti, kismi) => (bitti ? "tamam" : kismi ? "yarim" : "durdu");
  const sanilan = say("calisiyor"), gercek = sanilan - (bildirildi ? 0 : 1);  // toplayici-2 olmustu
  return [dusen, durum(sanilan === 5, say("bekliyor") > 0),
    bildirildi ? durum(say("olu") === 0 && sanilan === 5, say("olu") === 0) : "bilmiyor",
    d.veri.has("dugum/m4") ? "tamam" : "durdu",
    dusen === "kume arayuzu" || dusen === "durum deposu" ? "durdu" : "tamam",
    "surer", `${sanilan}/${gercek}`, d.iz.filter((e) => e.i === "oku").reduce((t, e) => t + e.n, 0),
    d.iz.filter((e) => e.i !== "oku").length];
}

console.log("dusen bilesen           olcek  ariza     dugum  okuma  trafik  sanilan/gercek oku yaz");
for (const b of ["-", "kume arayuzu", "durum deposu", "zamanlayici", "denetleyici yoneticisi"]) {
  const r = kos(b);
  console.log(`${r[0].padEnd(23)} ${r[1].padEnd(6)} ${r[2].padEnd(9)} ${r[3].padEnd(6)}` +
    ` ${r[4].padEnd(6)} ${r[5].padEnd(7)} ${r[6].padStart(11)} ${String(r[7]).padStart(5)}` +
    ` ${String(r[8]).padStart(3)}`);
}
```

```
dusen bilesen           olcek  ariza     dugum  okuma  trafik  sanilan/gercek oku yaz
-                       tamam  tamam     tamam  tamam  surer           5/5    52  13
kume arayuzu            durdu  bilmiyor  durdu  durdu  surer           3/2    20   0
durum deposu            durdu  bilmiyor  durdu  durdu  surer           3/2     0   0
zamanlayici             yarim  yarim     tamam  tamam  surer           2/2    30   7
denetleyici yoneticisi  durdu  durdu     tamam  tamam  surer           2/2    14   3
```

**Trafik sütunu her satırda `surer`.** Denetim düzleminin tamamı düşse bile çalışan kopyalar
çalışmaya devam eder; sayaç okumaları toplanır, doğrulama sürer, gecelik toplu iş başlar. Küme
"çalışmaz" hâle gelmiyor — **karar veremez** hâle geliyor. Bu ayrım kursun tamamında geçerlidir:
denetim düzlemi iş yapmaz, iş yapanlara ne yapacaklarını söyler.

Dört düşme senaryosu üç ayrı arıza türü üretiyor.

**Küme arayüzü ya da durum deposu düştüğünde** hiçbir yazma deftere inmez. Ölçek isteği kaybolur,
yeni düğüm kaydı kaybolur, okuma isteği yanıtsız kalır. En ağır satır sonuncusudur: `bilmiyor`.
Bir kopyanın öldüğü bilgisi de arayüzden geçtiği için bildirim hiç kaydedilmez ve defter o kopyayı
hâlâ çalışıyor sayar — sanılan 3, gerçek 2. Onarımdan sonra bile bu fark kendiliğinden kapanmaz;
kaybolan şey bir karar değil, bir **olaydır** ve olayın kendisi geri gelmez. Yeniden öğrenmenin
tek yolu düğümün aynı bilgiyi yeniden bildirmesidir.

**Zamanlayıcı düştüğünde** karar üretilir ama yer bulunmaz. Denetleyici yöneticisi eksik kopyaları
görüp nesnelerini yaratır; nesneler düğümsüz olarak birikir. Ölçek isteği `yarim` kalır: defterde
beş kopya vardır, ikisi hiçbir yerde çalışmaz. Bu durumun onarımı ucuzdur — zamanlayıcı geri
geldiğinde biriken kopyaları okur ve dağıtır, çünkü **iş defterde durmaktadır**.

**Denetleyici yöneticisi düştüğünde** bilgi doğrudur, karşılığı üretilmez. Ölen kopyanın bildirimi
deftere iner, defter onu ölü bilir, ama yerine yeni kopya yaratan kimse yoktur. Küme neyin yanlış
olduğunu bilir ve düzeltmez. Bu da onarımla kapanır.

Ayrım tek cümleye iner: **bilmemek ile bilip yapmamak ayrı arızalardır.** İkincisi bileşen geri
gelince kendiliğinden kapanır, çünkü fark hâlâ defterdedir. Birincisi kapanmaz, çünkü kapanması
için gereken bilgi hiç yazılmamıştır.

Son iki sütun bunun maliyet tarafını veriyor. Hepsi ayaktayken defter 52 kalem okundu ve 13 yazma
aldı; zamanlayıcı düşünce okuma 30'a, denetleyici yöneticisi düşünce 14'e indi. **Depo yükünün
büyük kısmı karar veren bileşenlerden gelir**, isteklerden değil. Bir insanın tek isteği 1 yazma
üretti; aynı süre içinde karar bileşenleri 52 kalem okudu.

#### Özet

- Tek bir insan yazması (istenen kopya 3 → 5) dört bileşenden geçti, 17 iz adımı, 50 kalem okuma
  ve 7 depo yazması üretti; kopya nesnesi üç ayrı bileşen tarafından üç kez yazıldı.
- Bileşenler birbirini çağırmıyor, yalnız durum deposuna bakıyor; fark kapandıktan sonraki
  doğrulama turu 0 yazma ve 26 kalem okuma tuttu — okuma yükü yapılan işle değil kalem sayısıyla
  büyüyor.
- Denetim düzleminin tamamı düşse de çalışan kopyalar hizmet vermeyi sürdürdü; kümenin
  kaybettiği yetenek çalışmak değil karar vermekti.
- Küme arayüzü ya da durum deposu düştüğünde ölüm bildirimi hiç kaydedilmedi ve defter kopyayı
  hâlâ çalışıyor saydı: sanılan 3, gerçek 2.
- Zamanlayıcı düşünce ölçek isteği yarım kaldı (defterde 5 kopya, 2'si düğümsüz); denetleyici
  yöneticisi düşünce bilgi doğru kalıp karşılığı üretilmedi — ikisi de onarımla kendiliğinden
  kapanır, bilinmeyen bildirim kapanmaz.
- Depo okuması hepsi ayaktayken 52, zamanlayıcı düşünce 30, denetleyici yöneticisi düşünce 14
  oldu; yükün kaynağı istekler değil karar veren bileşenlerdi.

#### Sonraki Adım

Bu dersin bütün ölçümleri defterin bir tarafındaydı: kararın nasıl üretildiği ve nereye yazıldığı.
Defterin öteki tarafında ise bir varsayım duruyordu — düğümlerin ne çalıştırdıklarını doğru
bildirdiği. Son senaryoda o varsayımın kırıldığı bir an göründü: bildirim kaydedilemeyince küme
eski bir gerçeği doğru sandı. Bir sonraki ders düğüm tarafını parçalarına ayırır — **aracı süreç,
çalışma zamanı, ağ vekili** — ve bildirimin kendisini ölçer: ne bildiriliyor, ne sıklıkta, ne
kadar gecikmeyle ve bir bildirim kaybolduğunda küme ne kadar süre eski gerçeği doğru sanıyor.

### Düğüm Bileşenleri

Source: https://academia.sh/tr/kurslar/orkestrasyon/dugum-bilesenleri

Düğüm tarafındaki bilgi akışı ölçülür: aracı süreç ne bildiriyor, ne sıklıkta, bildirimin ne kadarı gerçekten değişmiş. Canlılık eşiği taranarak kümenin eski gerçeği doğru sandığı süre, yanlış ölü ilanı ve kayıp istek sayılır; ağ vekilinin kural sayısının servis sayısıyla, kural değişiminin ise düğüm sayısıyla büyüdüğü gösterilir.

Bir önceki dersin son senaryosu tek bir varsayımın kırıldığı yerdi: bildirim kaydedilemeyince
defter ölmüş bir kopyayı hâlâ çalışıyor saydı. O varsayım — düğümlerin ne çalıştırdıklarını doğru
ve zamanında bildirmesi — denetim düzleminin bütün kararlarının altındadır. Bu ders düğüm tarafını
parçalarına ayırır ve bildirimin kendisini ölçer.

Üç parça vardır. **Aracı süreç** düğümün deftere bakan yüzüdür: kendine atanmış kopyaları okur,
çalıştırılmasını ister ve sonucu geri bildirir. **Çalışma zamanı** çıktıyı gerçekten çalıştıran
parçadır; yalıtımı ve kaynak sınırları bir önceki kursta ölçülmüştü, burada yalnız aracı sürece
durum döndüren taraf olarak durur. **Ağ vekili** bir servis adını o an çalışan kopyalara çeviren
kural kümesini düğümde tutar.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; koşan şey gerçek bir küme değil,
`node` ile kurulmuş bir **modeldir**.

**KM13.** Düğüm tarafı üç parçadır: aracı süreç, çalışma zamanı, ağ vekili.
**KM14.** Aracı süreç her 10 saniyede bir bildirir; bildirim düğüm başına 3 sabit kalem (sağlık,
toplam ve kullanılan kapasite) ve kopya başına 2 kalem (durum, kaynak kullanımı) taşır.
**KM15.** Bir periyotta gerçekten değişen kalem oranı 0,02'dir.
**KM16.** Canlılık eşiği E'dir: son bildirimden E saniye geçen düğüm bilinmiyor sayılır ve
üzerindeki kopyalar ölü ilan edilip yeniden yaratılır.
**KM17.** Bir günde 4 kalıcı düğüm arızası ve 30 geçici bildirim kesintisi (5–90 saniye) olur;
üreteci kendimiz yazdık, tohum `20260403` çıktıda görünür.
**KM18.** Ağ vekili defteri her 5 saniyede okur; düğüm başına kural sayısı servis girişi ile kopya
yönlendirme kurallarının toplamıdır, kopya başına istek hızı saniyede 80'dir.

#### Aracı Sürecin Bildirdiği

```js
// dugum.mjs — dugum tarafinin bildirdigi bilgi ve bildirimin kume olcegindeki yuku. Model.
export const P = 10;                     // bildirim periyodu (saniye)
const SABIT = 3;                         // saglik, toplam kapasite, kullanilan kapasite
export const kalem = (kopya) => SABIT + 2 * kopya;   // kopya basina: durum + kaynak kullanimi
export const DEGISIM = 0.02;             // bir periyotta gercekten degisen kalem orani

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log("dugum  kopya  bildirim/dugum  kalem/sn  gunluk kalem  yazma/sn  yalniz-degisen/sn");
  for (const M of [1, 3, 10, 30, 100, 300]) {
    const kopya = 8, k = kalem(kopya), kalemSn = (M * k) / P;
    console.log(`${String(M).padStart(5)}${String(kopya).padStart(7)}${String(k).padStart(16)}` +
      `${kalemSn.toFixed(1).padStart(10)}${(kalemSn * 86400).toFixed(0).padStart(14)}` +
      `${(M / P).toFixed(1).padStart(10)}${(kalemSn * DEGISIM).toFixed(2).padStart(19)}`);
  }
}
```

```
dugum  kopya  bildirim/dugum  kalem/sn  gunluk kalem  yazma/sn  yalniz-degisen/sn
    1      8              19       1.9        164160       0.1               0.04
    3      8              19       5.7        492480       0.3               0.11
   10      8              19      19.0       1641600       1.0               0.38
   30      8              19      57.0       4924800       3.0               1.14
  100      8              19     190.0      16416000      10.0               3.80
  300      8              19     570.0      49248000      30.0              11.40
```

Bildirimin içeriği azdır: sekiz kopyalı bir düğüm her periyotta 19 kalem gönderir. Yükü yapan şey
içerik değil **sıklıktır**. Üç yüz düğümlü bir kümede saniyede 570 kalem, günde 49 milyon kalem
bildirilir; bunun için düğümler saniyede 30 yazma üretir.

Son sütun asıl sayıyı veriyor. Bildirilen 570 kalemin gerçekten değişmiş olanı **11,4'tür** —
yüzde iki. Kalan yüzde doksan sekiz, hiçbir şeyin değişmediğini söylemenin bedelidir. Bu ölçü
bir önceki dersin doğrulama turunun düğüm tarafındaki karşılığıdır: orada denetim düzlemi 0 yazma
için 26 kalem okuyordu, burada düğümler hiçbir değişiklik olmadığı için 558 kalem gönderiyor.

Bu yükü kesmenin kolay göründüğü yer bir tuzaktır. Yalnız değişeni bildirmek kalem sayısını
elliye bölerdi, ama kümenin canlılık kararı bildirimin **içeriğine** değil **varlığına** dayanır.
Susan bir düğüm ile "hiçbir şey değişmedi" diyen bir düğüm defterde aynı görünür; ikisini ayırt
eden tek şey bildirimin gelip gelmediğidir. Bu yüzden bildirim boşken bile gönderilir ve bildirim
yükünün büyük kısmı **bilginin kendisi için değil, kanıtı için** ödenir.

Bildirimin **kapsamı** ayrı bir sınırdır. Aracı süreç çalışma zamanına kopyanın ayakta olup
olmadığını sorar ve aldığı yanıtı iletir; kopyanın **işini yapıp yapmadığını** sormaz. Ölçüm ağında
bir toplayıcı kopyası ayakta durup sayaç okumalarını hiç işlemiyor olabilir — süreç yaşıyordur,
kaynak kullanımı düşüktür, bildirim `calisiyor` der. Defterde bu kopya sağlıklıdır, ağ vekili ona
trafik yollar ve denetleyici yöneticisi eksik kopya görmediği için hiçbir iş yapmaz. Üç bileşenin
üçü de doğru çalışır ve sonuç yanlıştır, çünkü **kararın dayandığı kalem bildirimde yoktur**.
Kapsamı genişletmek — kopyanın kendi durumunu ayrıca bildirmesini istemek — bu kalemi ekler,
ama beraberinde ayrı bir soru getirir: o bildirimi kim, ne sıklıkta ve neye bakarak üretecek.

#### Kümenin Eski Gerçeği Doğru Sandığı Süre

```js
// eski-gercek.mjs — bildirim kaybolunca kume ne kadar sure eski gercegi dogru saniyor.
import { P } from "./dugum.mjs";
const uretec = (tohum) => { let s = tohum >>> 0;          // kendi uretecimiz; tohum gorunur
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const GUN = 86400, KOPYA = 3, ISTEK = 80, V = 5;   // dugum basina kopya, kopya basina istek/sn,
const rnd = uretec(20260403);                      // V: ag vekilinin depoyu okuma periyodu
const ariza = Array.from({ length: 4 }, () => rnd() * GUN);            // kalici dugum arizasi
const kesinti = Array.from({ length: 30 }, () => ({ t: rnd() * GUN, d: 5 + rnd() * 85 }));

console.log(`kesintilerin en uzunu ${Math.max(...kesinti.map((k) => k.d)).toFixed(1)} sn` +
  `   bildirim periyodu ${P} sn   vekil okuma periyodu ${V} sn`);
console.log("esik  ort-fark-etme  en-kotu  yanlis-olu-ilani  bosuna-kopya  kayip-istek");
for (const E of [20, 30, 40, 60, 90, 100, 120, 300]) {
  const g = ariza.map((t) => Math.floor(t / P) * P + E - t);           // eski gercegin suresi
  const yanlis = kesinti.filter((k) => Math.floor(k.t / P) * P + E < k.t + k.d).length;
  const kayip = g.reduce((s, x) => s + (x + V) * KOPYA * ISTEK, 0);
  console.log(`${String(E).padStart(4)}${(g.reduce((a, b) => a + b) / g.length).toFixed(1).padStart(15)}` +
    `${Math.max(...g).toFixed(1).padStart(9)}${String(yanlis).padStart(18)}` +
    `${String(yanlis * KOPYA).padStart(14)}${kayip.toFixed(0).padStart(13)}`);
}
```

```
kesintilerin en uzunu 84.6 sn   bildirim periyodu 10 sn   vekil okuma periyodu 5 sn
esik  ort-fark-etme  en-kotu  yanlis-olu-ilani  bosuna-kopya  kayip-istek
  20           17.3     19.9                26            78        21408
  30           27.3     29.9                21            63        31008
  40           37.3     39.9                19            57        40608
  60           57.3     59.9                13            39        59808
  90           87.3     89.9                 2             6        88608
 100           97.3     99.9                 0             0        98208
 120          117.3    119.9                 0             0       117408
 300          297.3    299.9                 0             0       290208
```

Birinci sütun kümenin yanıldığı süredir. Eşik ne olursa olsun küme bir arızayı **en az** E eksi
bir periyot, **en çok** E saniye sonra öğrenir: 40 saniyelik eşikte ortalama 37,3 saniye boyunca
ölü bir düğümü canlı sayar. Bu süre sıfırlanamaz, çünkü bir arızanın kendini bildirmesi diye bir
şey yoktur — kümenin elindeki tek kanıt gelmeyen bildirimdir ve gelmeyen bir şeyin ne zaman
gelmediğine karar vermek için beklemek gerekir.

İkinci ve üçüncü sütunlar bekleme süresinin kısaltılmasının bedelidir. Eşik 20 saniyeye
indirildiğinde otuz geçici kesintinin **yirmi altısı** kalıcı arıza sanıldı; küme 78 kopyayı
boşuna ölü ilan edip yerine yenisini açtı — üstelik eski kopyalar ölmemişti, düğüm birkaç saniye
sonra geri döndü. Eşik büyüdükçe bu sayı düşüyor: 60 saniyede 13, 90 saniyede 2, 100 saniyede
sıfır.

Sıfırın nerede olduğu tesadüf değil. Kesintilerin en uzunu 84,6 saniyedir ve bildirim periyodu 10
saniyedir; eşiğin bu ikisinin toplamını geçtiği ilk basamakta yanlış ilan biter. **Doğru eşik
kümenin kendi ölçülerinden değil, ağın davranışından türer** — kümenin bilmediği ve ölçmediği bir
dağılımın en uzun kuyruğundan. Kesintiler bir gün 84,6 yerine 130 saniye sürerse 100 saniyelik
eşik sessizce yanlış ilan üretmeye başlar ve bunun kümede bir alarmı yoktur.

Son sütun ödemenin öteki yarısıdır. Ağ vekilinin kuralı ancak kopya ölü ilan edildikten sonra
güncellendiği için, o ana kadar gelen istekler çalışmayan kopyalara gönderilir. Yanlış ilanı
sıfırlayan 100 saniyelik eşikte gün boyunca **98.208 istek** ölü kopyalara gitti; 20 saniyelik
eşikte bu sayı 21.408'di. İki uç arasındaki seçim bir ayar değil, iki yanlışın paylaştırılmasıdır:
hızlı davranan küme sağlam kopyaları öldürür, sabırlı küme ölü kopyalara trafik yollar. Hiçbir eşik ikisini birden sıfırlamaz ve ikisini birden sıfırlayacak bilgi düğümde yoktur. Ölçüm
ağında bunun karşılığı somuttur — 98 bin sayaç okuma isteği yanıtsız kalır ve gecelik toplu iş
eksik veriyle başlar.

#### Bildirim Gecikmesi Nerede Birikiyor

Bir kopyanın düşmesi ile bunun deftere geçip karara dönüşmesi arasında dört ayrı bekleme vardır ve
her biri kendi periyodunu bekletir.

```js
// gecikme.mjs — bir olayin dorda bolunmus bildirim gecikmesi. Her asama kendi periyodunu bekletir.
import { P } from "./dugum.mjs";
const uretec = (tohum) => { let s = tohum >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; };
const rnd = uretec(20260404), N = 20000;
const C = 2, YAZ = 0.05, U = 15;        // calisma zamani yoklama, depo yazma, uzlasma periyodu
const asama = [["calisma zamani yoklama", C], ["araci surec bildirimi", P],
  ["arayuz + depo yazma", 0], ["denetleyici yoneticisi turu", U]];

let toplam = new Array(N).fill(0);
console.log("asama                         periyot  ort(sn)  en kotu(sn)  yigilmis ort(sn)");
for (const [ad, periyot] of asama) {
  const pay = toplam.map(() => (periyot ? rnd() * periyot : YAZ));
  toplam = toplam.map((x, i) => x + pay[i]);
  console.log(`${ad.padEnd(29)}${(periyot || YAZ).toFixed(2).padStart(8)}` +
    `${(pay.reduce((a, b) => a + b) / N).toFixed(2).padStart(9)}` +
    `${Math.max(...pay).toFixed(2).padStart(13)}` +
    `${(toplam.reduce((a, b) => a + b) / N).toFixed(2).padStart(18)}`);
}
console.log(`olay ${N}   en kotu uctan uca ${Math.max(...toplam).toFixed(2)} sn` +
  `   asama sayisi ${asama.length}`);
```

```
asama                         periyot  ort(sn)  en kotu(sn)  yigilmis ort(sn)
calisma zamani yoklama           2.00     1.00         2.00              1.00
araci surec bildirimi           10.00     4.99        10.00              5.99
arayuz + depo yazma              0.05     0.05         0.05              6.04
denetleyici yoneticisi turu     15.00     7.49        15.00             13.53
olay 20000   en kotu uctan uca 26.36 sn   asama sayisi 4
```

Ortalama uçtan uca gecikme 13,53 saniye, en kötüsü 26,36 saniyedir. Dağılım öğreticidir:
gecikmenin 1,00 saniyesi çalışma zamanının yoklamasından, 4,99 saniyesi aracı sürecin bildirim
periyodundan, 0,05 saniyesi yazma işleminden, **7,49 saniyesi denetleyici yöneticisinin turundan**
gelir. Yani gecikmenin yarısından fazlası düğüm tarafında değil, denetim düzleminin kendi
periyodundadır.

Bu ayrım hangi ayarın işe yaradığını belirler. Aracı sürecin bildirim periyodunu ikiye bölmek
ortalamayı 2,5 saniye düşürür ve bildirim yükünü ikiye katlar; denetleyici yöneticisinin tur
periyodunu ikiye bölmek 3,75 saniye düşürür ve düğümlere hiçbir yük bindirmez, ama defter okuma
yükünü ikiye katlar. **Aynı gecikme iki ayrı yerde ve iki ayrı fiyata satılır**; hangi ayarın
ucuz olduğu kümenin nerede darlaştığına bağlıdır.

#### Ağ Vekilinin Kural Sayısı

```js
// vekil.mjs — ag vekilinin kural sayisi servis sayisiyla nasil buyuyor; degisim nereye yayiliyor.
const M = 30, r = 5, V = 5, DEGISIKLIK = 200;   // dugum, kopya/servis, okuma periyodu, kopya/gun
const kural = (S) => S * (1 + r);               // dugum basina: servis girisi + kopya yonlendirme

console.log(`dugum ${M}   kopya/servis ${r}   vekil okuma periyodu ${V} sn`);
console.log("servis  kopya  kural/dugum  kume kurali  tek degisiklik  okunan kalem/sn  gunluk yazma");
for (const S of [2, 4, 8, 16, 32, 64]) {
  console.log(`${String(S).padStart(6)}${String(S * r).padStart(7)}${String(kural(S)).padStart(13)}` +
    `${String(M * kural(S)).padStart(13)}${String(M).padStart(16)}` +
    `${((M * S * r) / V).toFixed(0).padStart(17)}${String(DEGISIKLIK * M).padStart(14)}`);
}
```

```
dugum 30   kopya/servis 5   vekil okuma periyodu 5 sn
servis  kopya  kural/dugum  kume kurali  tek degisiklik  okunan kalem/sn  gunluk yazma
     2     10           12          360              30               60          6000
     4     20           24          720              30              120          6000
     8     40           48         1440              30              240          6000
    16     80           96         2880              30              480          6000
    32    160          192         5760              30              960          6000
    64    320          384        11520              30             1920          6000
```

İki sütun iki ayrı eksende büyüyor. **Kural sayısı servis sayısıyla** büyür: iki serviste düğüm
başına 12 kural, altmış dört serviste 384. Küme geneli bunun düğüm sayısıyla çarpımıdır ve 11.520
kurala ulaşır, çünkü aynı kural kümesi otuz düğümün her birinde ayrı ayrı durur. Vekilin defteri
okuma yükü de aynı eksende büyür: saniyede 60 kalemden 1.920 kaleme.

**Değişimin yayılımı ise servis sayısından bağımsızdır.** Tek bir kopyanın doğması ya da ölmesi,
kaç servis olursa olsun, otuz düğümde otuz kural yazması doğurur — çünkü her düğümün o servise
erişebilmesi gerekir. Günde iki yüz kopya değişikliği 6.000 kural yazmasına çıkar ve bu sayı
servis sayısı otuz iki katına çıksa da değişmez.

Ayrım işletim açısından önemlidir: yeni servis eklemek **durağan** maliyeti büyütür (kural sayısı,
bellek, okuma yükü), düğüm eklemek ya da kopyaları sık değiştirmek **akan** maliyeti büyütür
(kural yazma, yayılma penceresi). Bir önceki bölümdeki kayıp istek sayısı da bu pencerede birikir:
kopya ölü ilan edildikten sonra kuralın güncellenmesi vekilin okuma periyodu kadar daha gecikir.
Bu beş saniye otuz düğümün her birinde ayrı ayrı ve farklı anlarda kapanır; kural değişimi kümeye
tek bir anda değil, bir pencere boyunca yayılır.

#### Özet

- Sekiz kopyalı bir düğüm her periyotta 19 kalem bildirir; 300 düğümde bu günde 49 milyon kalem
  eder ve bunun yalnız 11,4 kalem/saniyesi gerçekten değişmiştir — kalan yüzde doksan sekiz,
  bilginin değil düğümün hâlâ ayakta olduğunun kanıtı için ödenir.
- Bir olayın karara dönüşmesi dört beklemeden geçer ve ortalama 13,53, en kötü 26,36 saniye sürer;
  bunun 7,49 saniyesi düğümden değil denetleyici yöneticisinin tur periyodundan gelir.
- Küme bir arızayı en az eşik eksi bir periyot, en çok eşik kadar sonra öğrenir; 40 saniyelik
  eşikte ortalama 37,3 saniye boyunca ölü bir düğümü canlı sayar ve bu süre sıfırlanamaz.
- Eşik 20 saniyeye indirilince 30 geçici kesintinin 26'sı kalıcı arıza sanıldı ve 78 kopya boşuna
  açıldı; yanlış ilan ancak eşik en uzun kesinti (84,6 sn) ile bir bildirim periyodunun toplamını
  geçince, 100 saniyede sıfırlandı.
- Yanlış ilanı sıfırlayan eşikte ölü kopyalara giden istek 98.208'e çıktı; 20 saniyelik eşikte
  21.408'di — iki uç arasındaki seçim iki yanlışın paylaştırılmasıdır.
- Ağ vekilinin kural sayısı servis sayısıyla büyür (12 → 384 düğüm başına, küme geneli 11.520),
  değişimin yayılımı ise servis sayısından bağımsızdır: tek kopya değişikliği 30 düğümde 30 kural
  yazması, günde 6.000.

#### Sonraki Adım

İki ders iki tarafı ayrı ayrı ölçtü: denetim düzlemi kararı üretiyor, düğümler durumu bildiriyor.
İkisini birbirine bağlayan şey henüz adlandırılmadı — istenen durum ile gerçek durumun sürekli
karşılaştırılıp farkın kapatılması. Bir sonraki ders bu konunun merkezidir ve **uzlaşma
döngüsünü** küme ölçeğinde gerçekten yazar: yakınsama turu, tur başına iş ve bu dersin bıraktığı
soru — rapor gecikmesi büyüdükçe döngü kaç kopyayı gereksiz açıyor, kaçını boşuna siliyor ve
döngü periyodu ile rapor gecikmesi arasında nasıl bir ilişki var.

### Uzlaşma Döngüsü

Source: https://academia.sh/tr/kurslar/orkestrasyon/uzlasma-dongusu

İstenen durum ile gerçek durumun sürekli karşılaştırılması küme ölçeğinde çalışan bir döngüyle yazılır ve rapor gecikmesi taranır: sistem kaç gereksiz kopya açıyor, kaç kopyayı boşuna siliyor, salınımın genliği ne. Döngü periyodu ile rapor gecikmesi arasındaki bağıntı elli altı hücrede sınanır ve eksik bilgi kaleminin sistemin kendi geçmişi olduğu gösterilir.

Bu konunun ilk üç dersi iki tarafı ayrı ayrı ölçtü. Şimdi ikisini birbirine bağlayan şey yazılır:
istenen durum ile gerçek durumun sürekli karşılaştırılıp farkın kapatılması, yani **uzlaşma
döngüsü**. Döngünün kendisi yeni değildir — daha önce tek makinede çalışan bir uzlaştırıcı
görülmüştü: istenen durumu dosyadan, gerçek durumu diskten okuyor, yalnız farklı kaleme dokunuyor
ve ikinci koşumda sıfır iş yapıyordu. O ölçüm burada girdi olarak alınır ve tekrarlanmaz.

Küme ölçeğinde tek bir şey değişir. Gerçek durum artık diskten okunmaz; düğümlerden gelen ve bir
önceki dersin ölçtüğü gecikmeyi taşıyan **raporlardan** gelir. Bu dersin tamamı o tek farkın
bedelini sayar: gecikmeli bir görüntüye bakarak verilen doğru kararlar, kaç yanlış düzeltme
üretiyor.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; koşan şey `node` ile kurulmuş bir
**modeldir**, gerçek bir küme değil.

**KM19.** İstenen durum tek kalemdir: toplayıcı servisinin kopya sayısı altıdır ve insanın yazdığı
bildirimden gelir.
**KM20.** Gerçek durum düğüm raporlarından gelir; defter gerçek dünyanın G saniye gerisindedir.
**KM21.** Yaratılan bir kopya B saniye sonra çalışır hâle gelir, çalıştığı bilgisi G saniye sonra
deftere düşer; silinen bir kopya da defterden G saniye sonra kaybolur.
**KM22.** Döngü periyodu U'dur; her turda defter okunur, fark hesaplanır, düzeltme yazılır.
**KM23.** Olaylar yazılıdır, rastgelelik yoktur: 300. saniyede iki kopya ölür; koşum 900 saniyedir.
**KM24.** İki denetleyici karşılaştırılır — yalnız deftere bakan ve kendi bekleyen eylemlerini de
sayan.
**KM25.** Silme komutu defterde görünene verilir; zaten ölmüş bir kopyaya verilen komut iş olarak
sayılır ama canlı kopya sayısını değiştirmez.

#### Küme Ölçeğinde Uzlaşma Döngüsü

```js
// uzlas.mjs — kume olceginde uzlasma dongusu. Istenen durum bildirimden, gercek durum
// gecikmeli raporlardan gelir. Model; gercek kume kosturulmaz. Rastgelelik yok, olaylar yazili.
export const OLUM = [[300, 2]];              // yazili olay: 300. saniyede 2 kopya olur

export function kos({ istenen = 6, U = 15, G = 0, B = 5, sure = 900, niyet = false }) {
  const gercek = [];                          // {dogum, hazir, olum}
  let yaratildi = 0, komut = 0, silindi = 0, is = 0, tur = 0, asim = 0, sonSapma = 0;
  const canli = (t) => gercek.filter((r) => r.hazir <= t && (r.olum === null || r.olum > t));
  const gorunen = (t) => gercek.filter((r) =>            // defter G saniye geride
    r.hazir + G <= t && (r.olum === null || r.olum + G > t));

  for (let t = 0; t <= sure; t++) {
    for (const [an, kac] of OLUM)                        // yazili olum: en eski kopyalar duser
      if (t === an) canli(t).slice(0, kac).forEach((r) => { r.olum = t; });
    if (t % U === 0) {
      tur++;
      const g = gorunen(t);
      const bekleyen = niyet ? gercek.filter((r) => r.olum === null && r.hazir + G > t).length : 0;
      const fark = istenen - g.length - bekleyen;        // niyet: kendi bekleyen eylemlerini say
      if (fark > 0) {
        for (let i = 0; i < fark; i++) gercek.push({ dogum: t, hazir: t + B, olum: null });
        yaratildi += fark; is += fark;
      } else if (fark < 0) {
        komut += -fark; is += -fark;                     // silme komutu: defterde gorunene verilir
        g.slice(0, -fark).forEach((r) => { if (r.olum === null) { r.olum = t; silindi++; } });
      }
    }
    const c = canli(t).length;
    asim = Math.max(asim, c - istenen);
    if (c !== istenen) sonSapma = t;
  }
  const gerekli = istenen + OLUM.reduce((s, k) => s + k[1], 0);
  return { tur, isTur: is / tur, yaratildi, gereksiz: yaratildi - gerekli, komut, silindi, asim,
    kararli: sonSapma === sure ? null : sonSapma + 1 };
}

const satir = (ilk, r) => `${ilk}${r.isTur.toFixed(2).padStart(8)}${String(r.yaratildi).padStart(11)}` +
  `${String(r.gereksiz).padStart(10)}${String(r.komut).padStart(14)}${String(r.silindi).padStart(9)}` +
  `${String(r.asim).padStart(6)}${(r.kararli === null ? "yok" : r.kararli).toString().padStart(13)}`;

if (import.meta.url === `file://${process.argv[1]}`) {
  console.log("U=15 sn dongu, B=5 sn baslama, istenen 6 kopya, 300. sn'de 2 olum, 900 sn kosum");
  for (const niyet of [false, true]) {
    console.log(`\ndenetleyici: ${niyet ? "defter + kendi bekleyen eylemleri" : "yalniz defter"}`);
    console.log("G(sn)  is/tur  yaratilan  gereksiz  silme komutu  silinen  asim  kararli(sn)");
    for (const G of [0, 5, 10, 20, 30, 60])
      console.log(satir(String(G).padStart(5), kos({ G, niyet })));
  }
}
```

```
U=15 sn dongu, B=5 sn baslama, istenen 6 kopya, 300. sn'de 2 olum, 900 sn kosum

denetleyici: yalniz defter
G(sn)  is/tur  yaratilan  gereksiz  silme komutu  silinen  asim  kararli(sn)
    0    0.13          8         0             0        0     0          305
    5    0.13          8         0             0        0     0          320
   10    0.13          8         0             0        0     0          320
   20    0.52         16         8            16        8     6          375
   30    0.92         24        16            32       16    12          405
   60    2.75         40        32           128       32    24          495

denetleyici: defter + kendi bekleyen eylemleri
G(sn)  is/tur  yaratilan  gereksiz  silme komutu  silinen  asim  kararli(sn)
    0    0.13          8         0             0        0     0          305
    5    0.13          8         0             0        0     0          320
   10    0.13          8         0             0        0     0          320
   20    0.13          8         0             0        0     0          335
   30    0.13          8         0             0        0     0          335
   60    0.13          8         0             0        0     0          365
```

Üst tablonun ilk üç satırı tanıdıktır. Gecikme sıfır, beş ya da on saniyeyken döngü sekiz kopya
yarattı — altısı ilk kurulum, ikisi ölenlerin yerine — hiçbirini boşuna silmedi, hiç aşım yapmadı.
Tur başına iş 0,13'tür: altmış bir turun neredeyse tamamı sıfır iş yaptı. Tek makinede ölçülen
etkisizlik küme ölçeğinde de duruyor.

Dördüncü satırda döngü davranış değiştirir. Yirmi saniyelik rapor gecikmesinde döngü on altı kopya
yarattı; sekizi gereksizdi. Sekiz kopya boşuna silindi ve canlı kopya sayısı altı yerine on ikiye
çıktı. Altmış saniyelik gecikmede tablo iyice bozulur: kırk kopya yaratıldı, otuz ikisi gereksiz;
yüz yirmi sekiz silme komutu verildi; aşım yirmi dört, yani bir ara **otuz kopya** çalıştı.

Bu satırlarda dikkat edilecek yer denetleyicinin hiçbir hata yapmamış olmasıdır. Her turda defteri
okudu, farkı doğru hesapladı ve tam da o farkı kapatacak düzeltmeyi yazdı. Kural doğru, aritmetik
doğru, girdi eski. Kopyalar yaratıldı ama henüz raporlanmadıkları için denetleyici bir sonraki
turda onları göremedi ve **aynı eksiği yeniden gördü**. Yanlış düzeltmenin kaynağı karar kuralı
değil, kararın dayandığı görüntünün yaşıdır.

Silme komutu ile gerçekten silinen kopya arasındaki fark aynı körlüğün ikinci yüzüdür. Altmış
saniyelik gecikmede 128 silme komutu verildi, bunların yalnız 32'si canlı bir kopyaya denk geldi;
kalan 96 komut zaten ölmüş kopyalara gitti. Sistem yalnız kendi yarattığını değil, **kendi
sildiğini de** gecikmeyle görür.

Ölçüm ağında bunun karşılığı somuttur: altı kopyalık toplayıcı servisi bir ara otuz kopyayla
çalıştı, arkasındaki veritabanına beş kat bağlantı açıldı ve aynı sayaç okuma partileri birden çok
kopya tarafından çekildi. Salınım bir gösterge sorunu değil, gerçek bir yük. Üstelik bu yükün hiçbir kaydı, denetleyicinin "altı kopya istendi, altı kopya var" diyen son satırında görünmez; salınım kapandıktan sonra geriye yalnız doğru bir son durum kalır.

#### Döngü Periyodu ile Rapor Gecikmesinin İlişkisi

```js
// oran.mjs — dongu periyodu U ile rapor gecikmesi G arasindaki iliski sayiyla.
import { kos } from "./uzlas.mjs";
const B = 5, ISTENEN = 6;
const ongoru = (G, U) => ISTENEN * (Math.ceil((G + B) / U) - 1);   // sinanacak baginti

console.log("G=30 sn sabit, B=5 sn; dongu periyodu taraniyor");
console.log("U(sn)  ceil((G+B)/U)  ongorulen asim  olculen asim  gereksiz  silinen  is/tur");
for (const U of [5, 10, 15, 20, 30, 35, 60]) {
  const r = kos({ U, G: 30, B });
  console.log(`${String(U).padStart(5)}${String(Math.ceil(35 / U)).padStart(15)}` +
    `${String(ongoru(30, U)).padStart(16)}${String(r.asim).padStart(14)}` +
    `${String(r.gereksiz).padStart(10)}${String(r.silindi).padStart(9)}` +
    `${r.isTur.toFixed(2).padStart(8)}`);
}

console.log("\nasim tablosu (satir: rapor gecikmesi G, sutun: dongu periyodu U)");
const U_LER = [5, 10, 15, 20, 30, 45, 60, 90];
console.log("G\\U  " + U_LER.map((u) => String(u).padStart(5)).join(""));
let sapma = 0, hucre = 0;
for (const G of [0, 10, 20, 30, 45, 60, 90]) {
  const s = U_LER.map((U) => { const a = kos({ U, G, B }).asim; hucre++;
    if (a !== ongoru(G, U)) sapma++; return String(a).padStart(5); });
  console.log(String(G).padStart(3) + "  " + s.join(""));
}
console.log(`\nbaginti asim = istenen x (ceil((G+B)/U) - 1);  ${hucre} hucrenin ${sapma} tanesi sapiyor`);
```

```
G=30 sn sabit, B=5 sn; dongu periyodu taraniyor
U(sn)  ceil((G+B)/U)  ongorulen asim  olculen asim  gereksiz  silinen  is/tur
    5              7              36            36        48       48    1.90
   10              4              18            18        24       24    1.14
   15              3              12            12        16       16    0.92
   20              2               6             6         8        8    0.70
   30              2               6             6         8        8    0.77
   35              1               0             0         0        0    0.31
   60              1               0             0         0        0    0.50

asim tablosu (satir: rapor gecikmesi G, sutun: dongu periyodu U)
G\U      5   10   15   20   30   45   60   90
  0      0    0    0    0    0    0    0    0
 10     12    6    0    0    0    0    0    0
 20     24   12    6    6    0    0    0    0
 30     36   18   12    6    6    0    0    0
 45     54   24   18   12    6    6    0    0
 60     72   36   24   18   12    6    6    0
 90    108   54   36   24   18   12    6    6

baginti asim = istenen x (ceil((G+B)/U) - 1);  56 hucrenin 0 tanesi sapiyor
```

Üst tablo tek bir gecikmeyi (30 saniye) sabit tutup döngü periyodunu tarıyor ve beklenmedik yönü
gösteriyor: **döngüyü hızlandırmak zararı büyütür.** Beş saniyelik periyotta aşım otuz altı,
gereksiz kopya kırk sekizdir; otuz beş saniyelik periyotta ikisi de sıfırdır. Sık uzlaşan bir
döngü, gecikme sabitken aynı eski görüntüyü daha çok kez okur ve her okumada aynı eksiği yeniden
kapatmaya çalışır.

Alt tablo bağıntıyı verir. Aşım, ölçülen bütün hücrelerde şu değerdedir:

**aşım = istenen kopya × (⌈(G + B) / U⌉ − 1)**

Elli altı hücrenin hiçbirinde sapma yok. Bağıntının okunuşu basittir: `(G + B) / U`, bir kopyanın
yaratılmasından defterde görünmesine kadar geçen sürede **kaç tur** koştuğudur. O turların ilki
gerçek eksiği kapatır; kalanların her biri aynı eksiği bir kez daha kapatır. Kör tur sayısı bir
olduğunda — yani `U ≥ G + B` — aşım sıfırlanır ve tablonun sıfır bölgesi tam olarak bu köşegenin
üstünde kalır.

Bu, bir önceki dersin canlılık eşiği kuralının kardeşidir. Orada eşiğin en uzun geçici kesintiyi
artı bir bildirim periyodunu geçmesi gerekiyordu; burada döngü periyodunun rapor gecikmesini artı
başlama süresini geçmesi gerekiyor. İkisinde de kümenin ayarı, kümenin kendi ölçmediği bir süreye
bağlıdır ve ikisinde de yanlış ayarın alarmı yoktur — salınım sessizce çalışır. Bağıntının
kendisi de bu yüzden işletim değeri taşır: aşımı görmeden, yalnız üç süreyi bilerek hesaplamak
mümkündür.

G burada serbest bir ayar değildir; bir önceki ders onu ölçmüştü. Dört aşamalı bildirim
zincirinin ortalaması 13,53, en kötüsü 26,36 saniyeydi. Beş saniyelik başlama süresiyle birlikte
`G + B` ortalamada 18,5, en kötü durumda 31,4 saniye eder. On beş saniyelik bir döngü periyodu bu
sayıların ikisinin de altındadır — yani ölçülen gecikmelerle çalışan bir küme, hiçbir şey
bozulmadan, **varsayılan ayarında salınım bölgesindedir**. Tablodaki `U=15, G=20` satırı bir uç
durum değil, sıradan bir gündür.

Döngünün taban maliyeti de burada görünür. Tur başına iş 0,13'tür ve turların çoğu sıfır iş yapar,
ama sıfır iş yapan tur bedava değildir: her tur defteri baştan okur. Bir önceki dersin doğrulama
turu bu okumayı 26 kalem olarak saymıştı. Döngünün maliyeti yaptığı düzeltmelerle değil, **kalem
sayısı ile periyodun oranıyla** büyür; periyodu küçültmek hem okuma yükünü hem — gecikme sabitse —
aşımı büyütür.

#### Eksik Olan Kalem Sistemin Kendi Geçmişidir

Alt tablo ikinci denetleyiciyi gösteriyor ve sonuç keskindir: kendi bekleyen eylemlerini sayan
denetleyici bütün gecikme değerlerinde sekiz kopya yarattı, sıfır gereksiz, sıfır silme, tur başına
0,13 iş. Aşım her satırda sıfırdır.

Eklenen bilgi kalemi tek bir satırdır ve dünyayla ilgili değildir: **son turlarda ne yarattığımın
kaydı.** Denetleyici artık "defterde altı yerine dört kopya görüyorum" demiyor; "defterde dört
kopya görüyorum ve iki tanesini iki tur önce ben yarattım, henüz görünmemiş olabilirler" diyor.
Kursun ölçüsü buraya oturur: devredilen karar doğru verilebilsin diye eklenen kalem, çoğu zaman
bir ölçüm değil, sistemin **kendi eylemlerinin hafızasıdır** — ve bu kalem bedavaya yakındır,
çünkü kimseden bildirim istemez.

Bedavaya yakındır ama her şeyi çözmez. İki tablonun son sütunu karşılaştırıldığında görülür:
niyet kaydı olan denetleyicide de kararlı hâle gelme anı gecikmeyle birlikte büyüyor — 305
saniyeden 365 saniyeye. Ölen iki kopyanın yerine yenisi, ölüm defterde görünene kadar açılamaz.
Ayrım tek cümleye iner: **gecikme fark etmeyi geciktirir, kayıtsız niyet ise işi çoğaltır.** Bunlar
ayrı iki sorundur; ikincisi bir satırla kapanır, birincisi kapanmaz — yalnız bildirim periyodu ve
ağ gecikmesi küçültülerek pahalıya azaltılır — ve bir önceki dersin gösterdiği gibi, o periyotları küçültmenin faturası düğüm başına bildirim yükü olarak geri gelir.

#### Özet

- Rapor gecikmesi sıfır, 5 ve 10 saniyeyken döngü 8 kopya yarattı, hiç boşuna silme yapmadı ve 61
  turun neredeyse tamamı sıfır iş yaptı; tek makinede ölçülen etkisizlik küme ölçeğinde de duruyor.
- 20 saniyelik gecikmede 8 gereksiz kopya açıldı, 8 kopya boşuna silindi, canlı sayı 6 yerine 12'ye
  çıktı; 60 saniyede 32 gereksiz kopya, 128 silme komutu ve 30 canlı kopyalık bir salınım oluştu.
- 128 silme komutunun yalnız 32'si canlı bir kopyaya denk geldi; sistem kendi yarattığını da, kendi
  sildiğini de gecikmeyle görüyor.
- Aşım bütün taramalarda `istenen × (⌈(G+B)/U⌉ − 1)` çıktı; 56 hücrede sıfır sapma. Aşımın
  sıfırlandığı sınır `U ≥ G + B`, yani döngü periyodunun rapor gecikmesi artı başlama süresini
  geçmesidir.
- Döngüyü hızlandırmak zararı büyüttü: 30 saniyelik gecikmede periyot 5 saniyeyken aşım 36, periyot
  35 saniyeyken 0.
- Kendi bekleyen eylemlerini sayan denetleyici bütün gecikmelerde 0 gereksiz kopya ve 0 boşuna
  silme yaptı; kararlı olma anı yine de 305'ten 365 saniyeye çıktı — gecikme fark etmeyi geciktirir,
  kayıtsız niyet işi çoğaltır.

#### Sonraki Adım

Bu ders döngünün kendisini ölçtü: neyi okuduğunu, ne sıklıkta koştuğunu, gecikmeli bir görüntüyle
ne kadar yanlış iş yaptığını. Konunun son dersi bir işletim kararına döner — bu düzlemi kendin mi
işleteceksin, yoksa işletimini başkasına mı devredeceksin. Ölçülecek şey iki seçeneğin aynı
kalemlerde karşılaştırılmasıdır: devredilen işletim kalemi sayısı, elde kalan kalem, sürüm
yükseltme penceresi, denetim düzlemine erişimin kaybı ve kararın geri alınabilirliği.

### Yerel ve Yönetilen Küme

Source: https://academia.sh/tr/kurslar/orkestrasyon/yerel-ve-yonetilen-kume

Kümeyi kendin işletmek ile işletimini devretmek aynı kalemlerde karşılaştırılır: devredilen ve elde kalan işletim kalemi, aylık saat, sürüm yükseltme penceresi, denetim düzlemine erişimin kaybı ve çıkış maliyeti. Erişim kaybının bir önceki dersin salınım bağıntısındaki kaldıracı elden aldığı sayıyla gösterilir.

Bu konu kümenin ne olduğunu, hangi bileşenlerden kurulduğunu ve nasıl uzlaştığını ölçtü. Geriye
tek bir işletim kararı kalıyor: bu düzlemi kendin mi işleteceksin, yoksa işletimini devralan bir
tarafa mı bırakacaksın. İki seçenek burada **tür olarak** anılır — **kendi işlettiğin küme** ve
**işletimi devredilmiş küme** — ve aynı kalemlerde karşılaştırılır.

Karar bu kursun ölçüsünün bir üst katmanıdır. Önceki dersler yerleştirme ve kopya sayısı kararını
bir sisteme devretmenin bedelini saydı; bu ders **o sistemin kendisinin işletimini** devretmenin
bedelini sayar. Sorular aynıdır: hangi kalemler devrediliyor, karşılığında hangi bilgi ve hangi
denetim kaybediliyor ve karar geri alınabilir mi.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; koşan şey `node` ile kurulmuş
**modellerdir**.

**KM26.** İşletim yirmi bir kalemle temsil edilir; her kalemin aylık saati, sorumlusu ve çıkışta
yeniden kurulup kurulmayacağı yazılıdır.
**KM27.** Paylaşılan kalemlerde saatin yarısı devralan tarafa geçer.
**KM28.** Çıkışta yeniden kurulacak kalemlerin ilk kurulum yükü aylık saatin dört katıdır.
**KM29.** Sürüm her dört ayda bir çıkar, desteği on iki ay sürer; koşum otuz altı aydır.
**KM30.** Kendi işletimde yükseltme ekibin kapasitesine göre yapılır; devredilmiş işletimde destek
bittiği ay yapılır ve takvim devralandadır.
**KM31.** Yükseltme başına yük kendi işletimde 8 saat denetim düzlemi artı 7 saat düğüm,
devredilmiş işletimde yalnız 7 saat düğümdür.
**KM32.** Rapor gecikmesi ve başlama süresi önceki derslerden alınır: ortalama 13,53 ve en kötü
26,36 saniye, başlama süresi 5 saniye.

#### Aynı Kalemler, İki Sahip

```js
// kalemler.mjs — kume isletiminin kalemleri. [ad, aylik saat, kim, cikista yeniden kurulur mu]
// "kim" iki secenekte de ayni ada bakar: isletimi devralan taraf, paylasilan, ya da sen.
export const KALEM = [
  ["denetim duzlemi kurulumu", 6, "devralan", true],
  ["denetim duzlemi surum yukseltme", 8, "devralan", true],
  ["durum deposu yedekleme", 5, "devralan", true],
  ["durum deposu onarimi", 4, "devralan", true],
  ["arayuz sertifikalari", 2, "devralan", true],
  ["denetim duzlemi yedekliligi", 5, "devralan", true],
  ["denetim duzlemi olcut toplama", 3, "devralan", true],
  ["dugum hazirlama", 6, "paylasilan", false],
  ["dugum surum yukseltme", 7, "paylasilan", false],
  ["dugum isletim sistemi yamasi", 5, "paylasilan", false],
  ["kume olcekleme kurallari", 3, "paylasilan", false],
  ["ag yapilandirmasi", 4, "paylasilan", false],
  ["depolama baglama", 3, "paylasilan", false],
  ["olay mudahalesi", 6, "paylasilan", false],
  ["is yuku bildirimleri", 9, "sen", false],
  ["kaynak istekleri ve sinirlari", 5, "sen", false],
  ["yetki kurallari", 4, "sen", false],
  ["ag politikalari", 3, "sen", false],
  ["gozlem ve uyari", 8, "sen", false],
  ["surum yayma", 7, "sen", false],
  ["maliyet takibi", 3, "sen", false],
];
const PAY = 0.5;                       // paylasilan kalemde saatin yarisi devralan tarafa gecer

if (import.meta.url === `file://${process.argv[1]}`) {
  const say = (k) => KALEM.filter(([, , x]) => x === k);
  const saat = (l) => l.reduce((t, [, s]) => t + s, 0);
  const toplam = saat(KALEM);
  const devir = saat(say("devralan")) + saat(say("paylasilan")) * PAY;
  console.log("kalem  toplam  devralan  paylasilan  sen");
  console.log(`sayi ${String(KALEM.length).padStart(6)}${String(say("devralan").length).padStart(10)}` +
    `${String(say("paylasilan").length).padStart(12)}${String(say("sen").length).padStart(5)}`);
  console.log(`saat ${String(toplam).padStart(6)}${String(saat(say("devralan"))).padStart(10)}` +
    `${String(saat(say("paylasilan"))).padStart(12)}${String(saat(say("sen"))).padStart(5)}`);
  console.log(`\nkendi islettigin kume : kalem ${KALEM.length}   aylik saat ${toplam}`);
  console.log(`isletimi devredilmis  : kalem ${say("paylasilan").length + say("sen").length}` +
    `   aylik saat ${toplam - devir}   devredilen ${devir}   oran %${(100 * devir / toplam).toFixed(1)}`);
  const cikis = KALEM.filter(([, , , c]) => c);
  console.log(`cikis maliyeti        : yeniden kurulacak kalem ${cikis.length}` +
    `   aylik saat ${saat(cikis)}   ilk kurulum ${saat(cikis) * 4} saat (dort aylik es deger)`);
}
```

```
kalem  toplam  devralan  paylasilan  sen
sayi     21         7           7    7
saat    106        33          34   39

kendi islettigin kume : kalem 21   aylik saat 106
isletimi devredilmis  : kalem 14   aylik saat 56   devredilen 50   oran %47.2
cikis maliyeti        : yeniden kurulacak kalem 7   aylik saat 33   ilk kurulum 132 saat (dort aylik es deger)
```

Yirmi bir kalemin yedisi devredilir, yedisi paylaşılır, yedisi her durumda sende kalır. Saat
tarafında devredilen pay aylık 106 saatin 50 saatidir — **yüzde 47,2**. Kalem sayısı 21'den 14'e,
aylık yük 106 saatten 56 saate iner.

Bu tablonun en çok yanlış okunan yeri elde kalan sütunudur. Devir yarıya yakın bir azalma sağlıyor
ama **yarıdan fazlası duruyor**: iş yükü bildirimleri, kaynak istekleri, yetki kuralları, ağ
politikaları, gözlem, sürüm yayma ve maliyet takibi hiçbir devirde azalmaz, çünkü bunların hepsi
kümenin değil **senin uygulamanın** kalemleridir. Devir kararı bu kalemlerin hiçbirine dokunmaz ve dokunduğunu sanmak devir sonrası ekip yükünün en sık yanlış tahmin edilen yeridir. Ölçüm ağının dört servisi ve gecelik toplu işi
için yazılacak bildirim, kümeyi kimin işlettiğinden bağımsızdır.

Ortadaki yedi kalem — paylaşılan sütun — iki seçenekte de tam olarak kimseye ait değildir ve
sürprizlerin çıktığı yer burasıdır. Düğüm hazırlama, düğüm sürüm yükseltme, ağ yapılandırması ve
olay müdahalesi devirden sonra da yarı yarıya sende kalır; devir sözleşmesinde bu kalemlerin
sınırı yazılı değilse, aylık 34 saatin hangi yarısının kime düştüğü ancak ilk olayda belli olur.
Ölçüm ağında bunun karşılığı şudur: sayaç toplayıcının düğümü kapasitesi dolduğu için kopya
alamıyorsa, sorunun kümede mi yoksa iş yükü bildiriminde mi olduğunu iki taraf ayrı ayrı arar.

Son satır kararın geri alınabilirliğini veriyor. Devredilen yedi kalem çıkışta yeniden kurulmak
zorundadır; aylık 33 saatlik bakım yüküne karşılık ilk kurulumları 132 saattir. Çıkış maliyeti
**kalem sayısıyla** ölçülür: yedi kalem ve bu yedi kalemin hiçbiri gündelik işte görünmez, çünkü
devredildikleri sürece kimse onlara bakmaz. Karar geri alınabilir, ama geri alma bedeli devir
kararının verildiği gün ödenmeyen bedeldir.

#### Sürüm Yükseltme Penceresi

```js
// pencere.mjs — 36 aylik surum yukseltme penceresi. Surum her 4 ayda cikar, destegi 12 ay surer.
const AY = 36, ARALIK = 4, DESTEK = 12, SAAT_DUZLEM = 8, SAAT_DUGUM = 7;
const sonSurum = (ay) => Math.floor(ay / ARALIK) * ARALIK;

function kos({ ad, ekip, zorunlu }) {          // ekip: kendi kapasiten (ay); zorunlu: devralanin
  let s = 0, yukseltme = 0, desteksiz = 0, enYasli = 0, saat = 0;
  for (let ay = 1; ay <= AY; ay++) {
    if (zorunlu ? ay === s + DESTEK : ay % ekip === 0 && sonSurum(ay) > s) {
      s = sonSurum(ay); yukseltme++; saat += zorunlu ? SAAT_DUGUM : SAAT_DUZLEM + SAAT_DUGUM;
    }
    const yas = ay - s;
    enYasli = Math.max(enYasli, yas);
    if (yas > DESTEK) desteksiz++;
  }
  return [ad, yukseltme, desteksiz, enYasli, saat, zorunlu ? "devralanda" : "sende"];
}

const satir = (r) => console.log(`${String(r[0]).padEnd(27)}${String(r[1]).padStart(9)}` +
  `${String(r[2]).padStart(14)}${String(r[3]).padStart(14)}${String(r[4]).padStart(6)}  ${r[5]}`);
satir(["secenek", "yukseltme", "desteksiz ay", "en yasli (ay)", "saat", "takvim"]);
for (const ekip of [4, 6, 12, 18, 24]) satir(kos({ ad: `kendi isletim (ekip ${ekip} ay)`, ekip }));
satir(kos({ ad: "isletimi devredilmis", zorunlu: true }));
```

```
secenek                    yukseltme  desteksiz ay en yasli (ay)  saat  takvim
kendi isletim (ekip 4 ay)          9             0             3   135  sende
kendi isletim (ekip 6 ay)          6             0             7    90  sende
kendi isletim (ekip 12 ay)         3             0            11    45  sende
kendi isletim (ekip 18 ay)         2            12            19    30  sende
kendi isletim (ekip 24 ay)         1            11            23    15  sende
isletimi devredilmis               3             0            11    21  devralanda
```

Altı satır aynı otuz altı ayı anlatıyor. Kendi işletimde yükseltme sıklığı ekibin kapasitesine
bağlıdır ve sonuçları doğrusaldır: dört ayda bir yükselten ekip 9 yükseltme ve 135 saat harcar,
sürüm hiç 3 aydan eski olmaz. On iki ayda bir yükselten ekip 3 yükseltme, 45 saat harcar ve sürüm
en fazla 11 ay eskir. Bu iki satır arasında yanlış cevap yoktur; ikisi de bir tercihtir ve tercihi yapan taraf sensin.

Alt sınır beşinci ve altıncı satırlarda görünür. On sekiz ayda bir yükseltebilen bir ekip otuz altı
ayın **on ikisini desteksiz** geçirir ve sürümü on dokuz aya kadar eskir. Kendi işletim takvimi
sana verir, ama takvimi tutmak da senin işindir; tutulmayan takvim desteksiz aya dönüşür ve bunun
kimseye bildirilen bir alarmı yoktur.

Devredilmiş satır ilginç bir yerde durur: 3 yükseltme, 0 desteksiz ay, en yaşlı sürüm 11 ay — yani
on iki ayda bir yükselten ekiple **aynı tazelik**, ama 45 saat yerine 21 saat. Fark saatte değil
son sütundadır. Yükseltmenin **ne zaman** olacağına karar veren taraf değişir. Ölçüm ağının
faturalama dönemi ayın ilk haftasındadır ve gecelik toplu iş her gece 02:30'da başlar; zorunlu bir
yükseltme penceresi bu iki takvimden birine denk gelirse, denk gelmemesi için yapılabilecek şey
devralanla konuşmaktan ibarettir. Kendi işletimde aynı çakışma bir çizelgeleme sorunudur; devredilmiş işletimde bir görüşme konusudur ve iki farklı süreyle çözülür.

#### Denetim Düzlemine Erişimin Kaybı

```js
// erisim.mjs — ayar ve gozlem kalemlerine erisim, ve bunun onceki derslerin bagintisina etkisi.
const AYAR = [                       // [kalem, kendi islettiginde, isletimi devredildiginde]
  ["bildirim periyodu (G'yi belirler)", "tam", "yok"], ["canlilik esigi", "tam", "yok"],
  ["dongu periyodu (U)", "tam", "yok"], ["vekil okuma periyodu", "tam", "kismen"],
  ["zamanlayici oncelikleri", "tam", "kismen"], ["arayuz denetim kaydi", "tam", "kismen"],
  ["durum deposunu dogrudan okuma", "tam", "yok"], ["denetim duzlemi kutugu", "tam", "kismen"],
  ["denetleyici yoneticisi olcutleri", "tam", "yok"], ["baslama suresi (B)", "tam", "tam"],
  ["istenen kopya sayisi", "tam", "tam"], ["dugum turu ve sayisi", "tam", "tam"],
];
const say = (i, d) => AYAR.filter((a) => a[i] === d).length;
console.log("erisim         tam  kismen  yok   kalem");
for (const [i, ad] of [[1, "kendi islettigin"], [2, "isletimi devredilmis"]])
  console.log(`${ad.padEnd(21)}${String(say(i, "tam")).padStart(3)}${String(say(i, "kismen")).padStart(8)}` +
    `${String(say(i, "yok")).padStart(5)}${String(AYAR.length).padStart(8)}`);

// Onceki derste sinanan baginti: asim = istenen x (ceil((G+B)/U) - 1)
const ISTENEN = 6, B = 5;
const asim = (G, U) => ISTENEN * (Math.ceil((G + B) / U) - 1);
console.log("\nolculen rapor gecikmesiyle asim (istenen 6 kopya, B=5 sn)");
console.log("G(sn)   U secilebilir (35)   U sabit (15)   asimi sifirlayan B   uygulanabilir mi");
for (const G of [13.53, 26.36]) {
  const gerekenB = 15 - G;
  console.log(`${G.toFixed(2).padStart(5)}${String(asim(G, 35)).padStart(20)}` +
    `${String(asim(G, 15)).padStart(15)}${gerekenB.toFixed(2).padStart(21)} sn` +
    `${(gerekenB > 0 ? "cok zor" : "olanaksiz").padStart(17)}`);
}
```

```
erisim         tam  kismen  yok   kalem
kendi islettigin      12       0    0      12
isletimi devredilmis   3       4    5      12

olculen rapor gecikmesiyle asim (istenen 6 kopya, B=5 sn)
G(sn)   U secilebilir (35)   U sabit (15)   asimi sifirlayan B   uygulanabilir mi
13.53                   0              6                 1.47 sn          cok zor
26.36                   0             12               -11.36 sn        olanaksiz
```

Üst tablo kaybın büyüklüğünü veriyor: on iki ayar ve gözlem kaleminin kendi işlettiğin kümede
hepsi tam erişilebilirken, işletimi devredilmiş kümede yalnız üçü tam erişilebilir; dördü kısmen,
**beşi hiç**. Erişilemeyen beş kalem tesadüfen seçilmiş değildir — bu konunun üç dersinde
ölçtüğümüz kalemlerdir: bildirim periyodu, canlılık eşiği, döngü periyodu, durum deposunun
doğrudan okunması ve denetleyici yöneticisinin ölçütleri.

Alt tablo bunun sonucunu sayıya çeviriyor. Bir önceki ders aşımın `istenen × (⌈(G+B)/U⌉ − 1)`
olduğunu elli altı hücrede sınamıştı. Ölçülen rapor gecikmesiyle — ortalama 13,53, en kötü 26,36
saniye — döngü periyodu seçilebilir olduğunda 35 saniyeye çekilir ve aşım **her iki durumda da
sıfırdır**. Döngü periyodu devralanın varsayılanında sabitlendiğinde aşım ortalama gecikmede 6,
en kötü gecikmede 12 olur.

Elde kalan tek kaldıraç başlama süresidir ve son iki sütun onun da yetmediğini gösteriyor: aşımı
sıfırlamak için başlama süresinin 1,47 saniyeye inmesi gerekir, en kötü gecikmede ise gereken
değer eksi 11,36 saniyedir — **olanaksız**. Devir burada bir saat kalemi devretmedi; bir önceki
dersin bulduğu ayarı elden aldı.

Kaybın gözlem tarafı ayarlardan daha sessizdir. Bu konunun ikinci dersi tek bir isteğin izini
çıkarmış, dört bileşenden geçtiğini ve 50 kalem okuma ile 7 yazma ürettiğini saymıştı. O ölçüm
durum deposunun doğrudan okunmasını gerektirir. Erişim kalkınca ölçüm de kalkar: bir isteğin niye
uygulanmadığı sorusu artık düzlemin içinden değil, dışarıdan — sonuçlara bakarak — yanıtlanır.
Sonuçlara bakmak yanlış cevap vermez, geç cevap verir; bir önceki dersin salınımı da tam olarak
böyle bir şeydir, yani sonuçta doğru sayıya yakınsayan ve yolda görünmeyen bir hata.

Ayrım şudur: devredilen kalemlerin çoğu **iş**tir ve devredilince yük azalır. Ama bazıları
**bilgi ve denetim**dir; devredilince yük azalmaz, yalnız kimin elinde olduğu değişir. İkinci
sınıfın maliyeti aylık saatte değil, bir sorun çıktığında elinde kalan seçenek sayısında görünür.

Karar bu yüzden tek yönlü değildir. Kazanılan 50 saat, sekiz kişilik bir ekipte ayda kişi başına
6,25 saattir ve kaybedilen beş ayar kaleminin hiçbirine ihtiyaç duyulmayan bir kurulumda bu takas
açık ara kazançlıdır. Aynı takas, gecikmeye duyarlı bir iş yükünde — döngü periyodunu ayarlaması
gereken bir kümede — 50 saat karşılığında kapatılamayan bir salınım satın alır. Ölçülmesi gereken
şey saat değil, **hangi kalemlerin sende kalması gerektiğidir**; bu liste kurulumdan kuruluma
değişir ve devir sözleşmesi imzalanmadan önce yazılmadıysa sonradan yazılamaz.

#### Özet

- Yirmi bir işletim kaleminin 7'si devredilir, 7'si paylaşılır, 7'si her durumda sende kalır;
  aylık 106 saatin 50'si (yüzde 47,2) devredilir ve kalem sayısı 21'den 14'e iner.
- Elde kalan kalemler kümenin değil uygulamanın kalemleridir — bildirimler, kaynak istekleri,
  yetki, ağ politikası, gözlem, sürüm yayma — ve hiçbir devirle azalmaz.
- Çıkış maliyeti 7 kalemdir: aylık 33 saatlik bakım yükü, 132 saatlik yeniden kurulum; devir
  sürdükçe bu kalemler kimsenin bakmadığı kalemlerdir.
- Otuz altı ayda devredilmiş işletim 3 yükseltme, 0 desteksiz ay ve 11 aylık en yaşlı sürüm verdi;
  aynı tazeliği kendi işletimle tutmak 45 saat sürerken devredilmişte 21 saat sürdü, fakat takvim
  devralana geçti.
- Kendi işletimde takvim sende kalır ama tutulmayan takvim bedel yazar: 18 aylık kapasiteyle otuz
  altı ayın 12'si desteksiz geçti ve sürüm 19 aya kadar eskidi.
- On iki ayar ve gözlem kaleminin devredilmiş kümede yalnız 3'ü tam erişilebilir; erişilemeyen 5
  kalem bu konunun ölçtüğü kalemlerdir ve döngü periyodu sabitlenince aşım 0 yerine 6 (en kötü
  gecikmede 12) olur, elde kalan tek kaldıraç ise olanaksız bir başlama süresi ister.

#### Sonraki Adım

Bu konu boyunca kümenin ne olduğu, hangi parçalardan kurulduğu, o parçaların ne bildirdiği,
döngünün nasıl uzlaştığı ve kimin işlettiği ölçüldü. Bir şey hiç tanımlanmadı: **uzlaştırılan şeyin
kendisi**. Dört derste "istenen kopya sayısı", "yerleştirme kısıtı", "servis" gibi kalemler geçti
ve hepsi modelin kendi küçük şemasında birer alan olarak durdu. Kümeye gerçekte ne bildirildiği —
bir iş yükünün en küçük dağıtım biriminin ne olduğu, kopyaların hangi nesneyle sayıldığı, bir adın
hangi kopyalara çözüldüğü, yapılandırmanın ve sırların nereye yazıldığı — hiç tanımlanmadı. Bir
sonraki konu bu nesneleri kurar ve her birini aynı ölçüyle sınar: bu nesne hangi kararı taşıyor,
taşıması için hangi bilgiyi istiyor.

## Temel Nesneler

Bildirimsel nesnelerle dağıtım: en küçük dağıtım biriminin neyi bir arada tuttuğu, kopya kümesi ve sürüm nesnesiyle bildirimsel sürüm yönetimi, küme içi kararlı adresleme, dış erişimin yönlendirme ve dengeleme katmanı, yapılandırma ve sır nesnelerinin uygulamaya geçirilmesi, kalıcı birim talebi ve sürücü arayüzü, sıralı kimlik isteyen durum bilgili uygulamalar, bir kerelik ve yinelenen görevler, ad alanları ve kotalarla çok kiracılı kaynak ayrımı.

### Kapsül

Source: https://academia.sh/tr/kurslar/orkestrasyon/kapsul

Kümeye bildirilen en küçük dağıtım biriminin ölçüsü: bir arada tutulan üç şeyin ne kazandırdığı, iki süreci tek kapsülde ya da iki kapsülde paketlemenin ölçek birimi, arıza yayılımı, kaynak muhasebesi ve ağ turu cinsinden farkı.

Küme kuruldu, uzlaşma döngüsü döner hâle geldi: bir yerde istenen durum durur, bir yerde gerçek
durum ölçülür, aradaki fark bir düzeltmeye çevrilir. Bu döngünün ölçüsü çıkarıldı — kaç turda
yakınsadığı, tur başına ne kadar iş yaptığı, gecikmiş bilgiyle kaç yanlış düzeltme ürettiği. Ama
döngünün üzerinde çalıştığı şeyin kendisi hiç tanımlanmadı. **Kümeye ne bildiriliyor?** İstenen
durum bir sayı değildir; bir nesnedir ve o nesnenin sınırları, uzlaştırıcının neyi tek parça sayıp
neyi ayrı ayrı düzelteceğini belirler.

Bu konunun ilk kararı da orada başlar: kümeye bildirilebilecek **en küçük parça** nedir. Yanıt tek
bir konteyner değildir. En küçük dağıtım birimi, birlikte taşınmayı bildiren bir konteyner
kümesidir; bu birime bu kursta **kapsül** denir (İngilizce karşılığı *pod*). Bu ders kapsülün ne
tuttuğunu sayar ve iki paketleme kararını dört ölçüyle karşılaştırır. Ölçülen şey `node` ile
kurulan bir modeldir; gerçek bir küme koşturulmaz.

**TN1 — bölgesel ölçüm ağı bu kursta bir küme üzerinde koşar:** sayaç okumalarını toplayan,
doğrulayan ve faturaya çeviren bu yazılım kurgudur. **TN2 — bir kapsülün içindeki süreçler üç şeyi
paylaşır:** aynı ağ adı, aynı yerel dosya alanı, aynı yaşam süresi. **TN3 — ayrı kapsüllerdeki iki
süreç arasındaki her alışveriş bir ad çözümleme ve bir ağ turu ekler**; aynı kapsülde bu sayı
sıfırdır. **TN4 — okuma toplayıcı altı, günlük dönüştürücü iki kopya gerektirir**; doğrulayıcı ile
yerel önbellek dörder, faturalama ile iş emri üçer. **TN5 — kapsül içindeki bir süreç çökerse
kapsülün tamamı yeniden başlar** ve iki tur hizmet vermez. **TN6 — kaynak isteği ve sınır kapsül
düzeyinde bildirilir**; içerideki süreçlerin ayrı hesabı tutulmaz.

#### Sınır Nerede Çizilir

Okuma toplayıcının yanında bir günlük dönüştürücü koşar: toplayıcının ürettiği ham satırları okur,
biçimlendirir, dışarı verir. Bu iki süreç aynı kapsülde mi paketlenecek, ayrı kapsüllerde mi? Soru
bir tercih gibi görünür; aşağıdaki model soruyu dört sayıya indirir.

```js
// kapsul.mjs — iki paketleme kararinin olculmesi (MODEL; gercek kume kosturulmaz).
// TN1-TN6 varsayimlari koda gomulu; butun sayilar bu dosyadan cikar.

export const SURECLER = {
  'okuma-toplayici':    { kopya: 6, ortakDosya: true,  alisveris: 120 },
  'gunluk-donusturucu': { kopya: 2, ortakDosya: true,  alisveris: 120 },
  'dogrulayici':        { kopya: 4, ortakDosya: false, alisveris: 400 },
  'yerel-onbellek':     { kopya: 4, ortakDosya: false, alisveris: 400 },
  'faturalama':         { kopya: 3, ortakDosya: false, alisveris: 12 },
  'is-emri':            { kopya: 3, ortakDosya: false, alisveris: 12 },
};

export const TUR = 2;                                    // TN3: ad cozumleme + ag turu
export const PAYLASILAN = ['ag adi', 'yerel dosya alani', 'yasam suresi'];

// Iki paketleme karari, ayni sureci ayni yuk altinda tutar; degisen yalniz sinirdir.
export function paketle(a, b) {
  const A = SURECLER[a], B = SURECLER[b];
  const en = Math.max(A.kopya, B.kopya), top = A.kopya + B.kopya;
  const alisveris = Math.min(A.alisveris, B.alisveris);
  return {
    alisveris,
    birlikte: { kapsul: en, surec: 2 * en, fazla: 2 * en - top, olcekBirimi: 1,
      ariza: 2, muhasebe: en, surecHesabi: 0, tur: 0, ekBildirim: 0 },
    ayri: { kapsul: top, surec: top, fazla: 0, olcekBirimi: 2,
      ariza: 1, muhasebe: top, surecHesabi: top, tur: TUR * alisveris,
      ekBildirim: PAYLASILAN.length },
  };
}

// Devredilen karar: bu iki surec ayni kapsulde mi tasinacak?
export const BILGI = ['ortak dosya', 'alisveris sikligi', 'kopya orani'];
const ESIK = 100;

export function karar(k) {
  const eksik = BILGI.filter((x) => k[x] === undefined);
  if (eksik.length) return { sonuc: 'karar verilemez', not: `eksik: ${eksik.join(', ')}` };
  const sik = k['ortak dosya'] || k['alisveris sikligi'] >= ESIK;
  if (k['kopya orani'] !== 1 && sik) return { sonuc: 'catisma', not: 'iki olcut ters yonde' };
  if (k['kopya orani'] !== 1) return { sonuc: 'ayri kapsul', not: 'kopya orani 1 degil' };
  if (sik) return { sonuc: 'ayni kapsul', not: 'siki bagli, oran 1' };
  return { sonuc: 'ayri kapsul', not: 'seyrek alisveris' };
}

export function kayit(a, b) {
  const A = SURECLER[a], B = SURECLER[b];
  return { 'ortak dosya': A.ortakDosya && B.ortakDosya,
    'alisveris sikligi': Math.min(A.alisveris, B.alisveris),
    'kopya orani': Math.max(A.kopya, B.kopya) / Math.min(A.kopya, B.kopya) };
}

export const CIFTLER = [
  ['okuma-toplayici', 'gunluk-donusturucu', 'toplayici+donusturucu'],
  ['dogrulayici', 'yerel-onbellek', 'dogrulayici+onbellek'],
  ['faturalama', 'is-emri', 'faturalama+is-emri'],
];

if (import.meta.url === `file://${process.argv[1]}`) {
  const s = (x, n) => String(x).padStart(n);
  console.log(`${'cift'.padEnd(23)}${'sinir'.padEnd(12)}${s('kapsul', 7)}${s('surec', 6)}`
    + `${s('fazla', 6)}${s('olcek', 6)}${s('ariza', 6)}${s('hesap', 6)}${s('tur', 6)}`
    + `${s('bildirim', 9)}`);
  for (const [a, b, ad] of CIFTLER) {
    const p = paketle(a, b);
    for (const [sinir, r] of [['tek kapsul', p.birlikte], ['iki kapsul', p.ayri]]) {
      console.log(`${ad.padEnd(23)}${sinir.padEnd(12)}`
        + `${s(r.kapsul, 7)}${s(r.surec, 6)}${s(r.fazla, 6)}${s(r.olcekBirimi, 6)}`
        + `${s(r.ariza, 6)}${s(r.surecHesabi, 6)}${s(r.tur, 6)}${s(r.ekBildirim, 9)}`);
    }
  }

  console.log(`\npaylasilan kalem (tek kapsul): ${PAYLASILAN.join(', ')} = ${PAYLASILAN.length}`);
  console.log(`ayri kapsulde her biri ayri bir bildirim kalemine doner: ${PAYLASILAN.length}`);

  console.log(`\n${'cift'.padEnd(25)}${'karar'.padEnd(16)}gerekce`);
  for (const [a, b, ad] of CIFTLER) {
    const r = karar(kayit(a, b));
    console.log(`${ad.padEnd(25)}${r.sonuc.padEnd(16)}${r.not}`);
  }
  const eksikK = { ...kayit('faturalama', 'is-emri') };
  delete eksikK['kopya orani'];
  const r = karar(eksikK);
  console.log(`${'faturalama+is-emri (kor)'.padEnd(25)}${r.sonuc.padEnd(16)}${r.not}`);

  // Bilginin maliyeti: 'kopya orani' bilinmezse sistem yine de paketlemek zorundadir.
  let yanlis = 0, fazlaSurec = 0;
  for (const [a, b] of CIFTLER) {
    const k = kayit(a, b);
    const tam = karar(k);
    const korK = { ...k }; delete korK['kopya orani'];
    const kor = korK['ortak dosya'] || korK['alisveris sikligi'] >= ESIK
      ? 'ayni kapsul' : 'ayri kapsul';
    const dogruYer = tam.sonuc === 'ayni kapsul' ? 'ayni kapsul' : 'ayri kapsul';
    if (kor !== dogruYer) { yanlis++; fazlaSurec += paketle(a, b).birlikte.fazla; }
  }
  console.log(`\nkopya orani bilinmezse: ${CIFTLER.length} ciftin ${yanlis}'inde yanlis paketleme,`
    + ` ${fazlaSurec} gereksiz surec ornegi`);
}
```

```
cift                   sinir        kapsul surec fazla olcek ariza hesap   tur bildirim
toplayici+donusturucu  tek kapsul        6    12     4     1     2     0     0        0
toplayici+donusturucu  iki kapsul        8     8     0     2     1     8   240        3
dogrulayici+onbellek   tek kapsul        4     8     0     1     2     0     0        0
dogrulayici+onbellek   iki kapsul        8     8     0     2     1     8   800        3
faturalama+is-emri     tek kapsul        3     6     0     1     2     0     0        0
faturalama+is-emri     iki kapsul        6     6     0     2     1     6    24        3

paylasilan kalem (tek kapsul): ag adi, yerel dosya alani, yasam suresi = 3
ayri kapsulde her biri ayri bir bildirim kalemine doner: 3

cift                     karar           gerekce
toplayici+donusturucu    catisma         iki olcut ters yonde
dogrulayici+onbellek     ayni kapsul     siki bagli, oran 1
faturalama+is-emri       ayri kapsul     seyrek alisveris
faturalama+is-emri (kor) karar verilemez eksik: kopya orani

kopya orani bilinmezse: 3 ciftin 1'inde yanlis paketleme, 4 gereksiz surec ornegi
```

Birinci çift, kapsül sınırının neden bir tercih olmadığını gösteriyor. Toplayıcı altı, dönüştürücü
iki kopya ister. Tek kapsülde ölçek birimi **birdir**: altı kapsül açılır, on iki süreç örneği
koşar, dördü hiçbir yükü karşılamaz. Dört fazla süreç örneği, ölçek biriminin bir olmasının
doğrudan bedelidir — dönüştürücü, ihtiyacı olmadığı hâlde toplayıcının ölçeğine binmiştir. İki
kapsülde bu dört örnek yok olur, karşılığında iki yüz kırk ağ turu doğar: yüz yirmi alışverişin
her biri bir ad çözümleme ve bir ağ turu öder.

İkinci çift aynı hesabın tersini veriyor. Doğrulayıcı ile yerel önbelleğin kopya sayıları eşit, bu
yüzden tek kapsülde fazla süreç örneği **sıfırdır**; ayırmanın kazandırdığı hiçbir şey yoktur ve
sekiz yüz ağ turu ödenir. Sıkı bağlı, aynı oranda ölçeklenen yardımcı süreçler kapsül sınırının
içine girer; bu, sınırın var olma nedenidir. Üçüncü çift üçüncü durumu gösteriyor: eşit ölçek, ama
seyrek alışveriş. Yirmi dört tur ucuzdur; ayırmak, arıza yayılımını ikiden bire indirmek ve süreç
başına kaynak muhasebesi kazanmak için yeterli gerekçedir.

Kaynak muhasebesi sütunu **TN6**'nın doğrudan sonucudur. Tek kapsülde altı muhasebe kalemi vardır
ama süreç başına hesap sıfırdır: kapsülün isteği ve sınırı iki sürecin toplamıdır, hangisinin ne
kadar tükettiği bildirimde görünmez. İki kapsülde sekiz kalem ve sekiz süreç hesabı olur. Bu fark
ölçekleme kararına girer — neyin büyüdüğünü bilmeyen bir sistem, ikisini birden büyütür.

Son satır bildirim bedelini sayıyor. Tek kapsülde paylaşılan üç kalem bedavadır çünkü sınırın
kendisi onları verir. Ayırmak üçünü de bir bildirim kalemine çevirir: ağ adı bir servis nesnesine,
yerel dosya alanı bir aktarım biçimine, ortak yaşam süresi de artık var olmayan bir güvenceye. Tek
makinedeki bileşim dosyası da birden çok süreci tek dosyada toplar; farkı, orada birlikteliğin
*aynı makinede olmak* demesi, kapsülde ise *birlikte taşınmak, birlikte ölmek ve tek bir adı
paylaşmak* demesidir. Bileşim dosyasının başlatma dalgaları ve hazır olma denetimi ölçümü orada
yapıldı; burada tekrarlanmaz, karşılaştırma girdisi olur.

#### Aynı Yaşam Süresinin Bedeli

Ölçek, tur ve muhasebe sayıları sabit bir tablodan okunur. Üçüncü paylaşılan kalem — aynı yaşam
süresi — ancak zaman içinde görünür. İkinci koşum aynı arıza dizisini iki paketlemeye uygular.

```js
// yasam.mjs — ayni yasam suresinin bedeli: ayni ariza dizisi iki paketlemeye uygulanir (MODEL).
import { SURECLER } from './kapsul.mjs';

const TOHUM = 20260801, TUR_SAYISI = 24, ONARIM = 2, SIKLIK = 0.35;
// Uretec kendi yazildi; 32 bitlik tam sayi islemleri, tohum gorunur.
const uret = (t) => () => { t ^= t << 13; t ^= t >>> 17; t ^= t << 5; return (t >>> 0) / 2 ** 32; };

// Gereken surec ornekleri: 6 toplayici + 2 donusturucu. Ariza dizisi bir kez uretilir.
const GEREKLI = [
  ...Array.from({ length: SURECLER['okuma-toplayici'].kopya }, (_, i) => ['toplayici', i]),
  ...Array.from({ length: SURECLER['gunluk-donusturucu'].kopya }, (_, i) => ['donusturucu', i]),
];
const rnd = uret(TOHUM);
const ARIZALAR = Array.from({ length: TUR_SAYISI },
  () => (rnd() < SIKLIK ? GEREKLI[Math.floor(rnd() * GEREKLI.length)] : null));

// Tek kapsul: kapsul i hem toplayici i hem donusturucu i tasir; biri duserse ikisi de duser.
// Iki kapsul: her surec ornegi kendi kapsulunde; ariza yalniz onu dusurur.
function kosum(birlikte) {
  const bosta = {};                                      // surec ornegi -> ne zamana kadar dusuk
  let dusen = 0, komsu = 0;
  const eksikTur = { toplayici: 0, donusturucu: 0 };
  for (let t = 0; t < TUR_SAYISI; t++) {
    if (ARIZALAR[t]) {
      const [rol, i] = ARIZALAR[t];
      // Kapsul i, tek kapsul sinirinda hem toplayici i hem donusturucu i tasir. TN5.
      for (const [r, k] of birlikte ? [['toplayici', i], ['donusturucu', i]] : [[rol, i]]) {
        const anahtar = `${r}#${k}`;
        if (!GEREKLI.some(([x, y]) => x === r && y === k)) continue;
        if ((bosta[anahtar] ?? -1) < t) { dusen++; if (r !== rol) komsu++; }
        bosta[anahtar] = t + ONARIM;
      }
    }
    for (const rol2 of ['toplayici', 'donusturucu']) {
      const ad = rol2 === 'toplayici' ? 'okuma-toplayici' : 'gunluk-donusturucu';
      const ayakta = Array.from({ length: SURECLER[ad].kopya }, (_, k) => `${rol2}#${k}`)
        .filter((a) => (bosta[a] ?? -1) < t).length;
      if (ayakta < SURECLER[ad].kopya) eksikTur[rol2]++;
    }
  }
  return { dusen, komsu, ...eksikTur };
}

const s = (x, n) => String(x).padStart(n);
console.log(`tohum ${TOHUM}, ${TUR_SAYISI} tur, ${ARIZALAR.filter(Boolean).length} ariza,`
  + ` onarim ${ONARIM} tur`);
console.log(`${'sinir'.padEnd(12)}${s('dusen', 7)}${s('komsu yuzunden', 16)}`
  + `${s('toplayici eksik', 17)}${s('donusturucu eksik', 19)}`);
for (const [ad, b] of [['tek kapsul', true], ['iki kapsul', false]]) {
  const r = kosum(b);
  console.log(`${ad.padEnd(12)}${s(r.dusen, 7)}${s(r.komsu, 16)}${s(`${r.toplayici} tur`, 17)}`
    + `${s(`${r.donusturucu} tur`, 19)}`);
}
```

```
tohum 20260801, 24 tur, 11 ariza, onarim 2 tur
sinir         dusen  komsu yuzunden  toplayici eksik  donusturucu eksik
tek kapsul       13               3           22 tur              7 tur
iki kapsul       10               0           20 tur              4 tur
```

On bir arıza iki paketlemede on üç ve on düşüş üretiyor. Aradaki üç fark ile üçüncü sütundaki üç
sayı aynı şeyi söylüyor: **tek kapsülde üç süreç örneği, kendisiyle ilgisi olmayan bir arıza
yüzünden düştü.** Bu üç düşüşün hiçbirinde dönüştürücünün ya da toplayıcının kendi kodunda bir
sorun yoktu; komşusu çöktü, kapsül yeniden başladı, o da onunla gitti. İki kapsül sınırında bu
sütun sıfırdır — arıza, bildirimde çizilen sınırın dışına çıkmaz.

Son sütun bunun hizmete yansımasıdır. Dönüştürücü, tek kapsülde yirmi dört turun yedisinde eksik
kopyayla çalıştı, ayrı kapsülde dördünde. Üç turluk fark küçük görünür; asıl büyüyen oran değil
**nedendir**: dönüştürücünün eksik turlarının neredeyse yarısı kendi arızasından değil, komşusunun
arızasından gelir ve bu pay, kapsüle konan süreç sayısıyla artar. Aynı yaşam süresi bir kolaylık
olarak bildirilir, bir kesinti kaynağı olarak ödenir.

#### Devredilen Karar ve Bilmediği Şey

Bu derste insandan sisteme geçen karar şudur: **hangi süreçler tek parça olarak taşınacak.** Karar
verildikten sonra yerleştirme, yeniden başlatma ve ölçekleme bu parçanın üzerinden yürür; sistem
kapsülün içine bakmaz. Kararın dayandığı bilgi kalemleri modelde adlandırılmıştır ve üç tanedir:
ortak dosya kullanımı, alışveriş sıklığı, kopya oranı. Üçünün de bir kaynağı vardır — ilk ikisi
ölçümden, üçüncüsü yük bildiriminden gelir.

Bilginin maliyeti üçüncü kalemde en açıktır. Kopya oranı bir ölçüm değil, bir **tahmindir**: iki
sürecin gelecekteki yükü aynı yönde mi büyüyecek? Bu tahmin yazılmazsa sistem yine de paketlemek
zorundadır ve modelin son satırı ne olduğunu söyler: üç çiftin birinde yanlış paketleme, dört
gereksiz süreç örneği. Yanlışın kaynağı bir hata değil, bir **boşluktur**; kopya oranını bilmeyen
bir kural, ucuz görünen seçeneği alır ve toplayıcı ile dönüştürücüyü aynı kapsüle koyar.

Birinci çiftin kararı ise bilgiyle bile çözülmüyor: iki ölçüt ters yönü gösterdiği için sonuç
`catisma` çıkıyor. Ortak dosya ve sık alışveriş birlikteliği söylerken, üç kat kopya oranı ayrılığı
söylüyor. Bu, devretmenin **kazandırmadığı** bir durumdur: sistem kuralı uygular, kural bir yanıt
üretmez ve karar insana geri döner. Yanıt ancak girdilerden biri değiştirilirse çıkar — ya dört
fazla süreç örneği kabul edilir, ya ortak dosya bir aktarıma çevrilip iki yüz kırk tur ödenir.
Kararı devretmek, kararın dayandığı büyüklüklerden birini değiştirmeyi zorunlu kılar.

#### Özet

- Kapsül, kümeye bildirilebilen en küçük dağıtım birimidir ve üç şeyi bir arada tutar: aynı ağ adı,
  aynı yerel dosya alanı, aynı yaşam süresi. Ayırmak bu üçünü üç ayrı bildirim kalemine çevirir.
- Altı ve iki kopya isteyen iki süreç tek kapsülde paketlenirse ölçek birimi bire iner ve dört
  gereksiz süreç örneği doğar; ayrılırsa bu dört örnek yok olur, iki yüz kırk ağ turu eklenir.
- Kopya oranı eşit olan çiftte ayırmanın kazancı sıfır, bedeli sekiz yüz turdur; eşit ölçekli ve
  seyrek konuşan çiftte ise yirmi dört tur karşılığında arıza yayılımı ikiden bire iner.
- Kaynak muhasebesi kapsül düzeyindedir: tek kapsülde altı kalem tutulur, süreç başına hesap
  sıfırdır ve neyin büyüdüğü bildirimde görünmez.
- Aynı arıza dizisinde tek kapsül on üç, iki kapsül on düşüş üretti; farkın tamamı komşu arızasıdır
  ve dönüştürücü eksik kopyayla dört tur yerine yedi tur çalıştı.
- Devredilen karar üç bilgi kalemine dayanır; kopya oranı eksildiğinde üç çiftin birinde yanlış
  paketleme ve dört gereksiz süreç örneği doğar, ölçütler çakıştığında ise kural yanıt üretmez.

#### Sonraki Adım

Bu ders tek bir kapsülün sınırını çizdi ve kaç kopya gerektiğini bir varsayım olarak aldı: altı,
dört, üç. Oysa o sayı da kümeye bildirilen bir şeydir ve bildirildiği anda yeni bir soru doğar —
gerçek kopya sayısı istenenden saptığında kim, ne kadar sürede, hangi sırayla düzeltir. Dahası
istenen kopya sayısı sabit kalırken **kopyanın içeriği** değişebilir; yeni bir sürüme geçmek, aynı
anda kaç fazla ve kaç eksik kopyaya izin verildiğini bildirmeyi gerektirir. Sonraki ders bu iki
nesneyi `node` ile yazar ve geçişi tur tur sayar: kaç turda tamamlandığı, kaç turunda kapasitenin
altına düşüldüğü ve geri almanın kaç tur sürdüğü.

### Kopya Kümeleri ve Sürüm Nesneleri

Source: https://academia.sh/tr/kurslar/orkestrasyon/kopya-kumeleri-ve-dagitimlar

Bildirimsel sürüm yönetiminin iki ölçüsü: istenen kopya sayısı ile gerçek kopya sayısını uzlaştıran denetleyicinin tur başına işi ve geçiş ayarlarının — kaç fazla, kaç eksik kopya — geçiş turu, kapasite altı tur ve geri alma penceresi üzerindeki etkisi.

Önceki ders kapsülün sınırını çizdi ve altı kopya gerektiğini bir varsayım olarak aldı. O varsayım
tek başına hiçbir şey yapmaz: bir kapsül düşerse yerine yenisi gelmez, bir düğüm kaybolursa
üzerindeki kapsüller de kaybolur. Altı sayısının bir etkisi olması için bir yere **bildirilmesi** ve
bir denetleyicinin o bildirimi sürekli gerçekle karşılaştırması gerekir. Bu bildirimi taşıyan nesne
**kopya kümesi**dir: tek bir kapsül şablonu ve tek bir sayı.

Sayı yeterli değildir. Şablonun kendisi de değişir — yeni bir sürüm çıkar ve altı kapsülün içeriği
değişmesi gerekir. Bunu yöneten nesne **sürüm nesnesi**dir; iki kopya kümesi tutar ve istenen sayıyı
ikisi arasında adım adım kaydırır. Bu ders iki nesneyi de `node` ile yazar ve geçişi tur tur sayar.
Ölçülen şey bir modeldir; gerçek bir küme koşturulmaz.

**TN7 — okuma toplayıcı için istenen kopya sayısı altıdır.** **TN8 — denetleyicinin bildiği tek şey
istenen sayı ile gerçek sayıdır**; kapsüllerin içi ona görünmez. **TN9 — yeni oluşturulan kapsül iki
tur sonunda hazır olur**, silme aynı turda biter. **TN10 — sürüm nesnesi iki kopya kümesi tutar** ve
istenen sayıyı ikisi arasında paylaştırır. **TN11 — geçiş ayarı iki sayıdır:** en çok kaç fazla
kapsül, en çok kaç eksik hazır kopya. **TN12 — yeni sürümün bozukluğu dördüncü turun sonunda
anlaşılır**; geri alma aynı ayarlarla ters yönde yürür.

#### İstenen Sayı ile Gerçek Sayı

Denetleyicinin yaptığı iş tek satırdır: farkı al, işareti neyse o yöne bir eylem üret. Aşağıdaki
koşum bu tek satırı dört olayın üzerinden geçiriyor — soğuk başlangıç, iki kapsülün çökmesi,
istenen sayının değişmesi ve dışarıdan elle iki kapsül eklenmesi.

```js
// kopya.mjs — kopya kumesi denetleyicisi: istenen ile gercek kopya sayisini uzlastirir (MODEL).
export const HAZIR_TUR = 2;                              // TN9: yeni kapsul 2 turda hazir olur

export const kume = (ad, istenen) => ({ ad, istenen, hazir: 0, bekleyen: [] });
export const toplam = (k) => k.hazir + k.bekleyen.length;

export function ilerle(k) {                              // bekleyen kapsuller hazir olur
  k.bekleyen = k.bekleyen.map((x) => x - 1);
  const olan = k.bekleyen.filter((x) => x <= 0).length;
  k.hazir += olan;
  k.bekleyen = k.bekleyen.filter((x) => x > 0);
  return olan;
}
export const olustur = (k, n) => { for (let i = 0; i < n; i++) k.bekleyen.push(HAZIR_TUR); };
export function sil(k, n) {                              // once bekleyen, sonra hazir silinir
  let kalan = n;
  while (kalan > 0 && k.bekleyen.length) { k.bekleyen.pop(); kalan--; }
  const d = Math.min(kalan, k.hazir); k.hazir -= d;
  return n - (kalan - d);
}

// Denetleyici: farki bir eyleme cevirir. Bildigi tek sey istenen ve gercek sayidir. TN8.
export function uzlas(k) {
  const fark = k.istenen - toplam(k);
  if (fark > 0) { olustur(k, fark); return `+${fark} olustur`; }
  if (fark < 0) { sil(k, -fark); return `${fark} sil`; }
  return 'fark yok';
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const K = kume('okuma-toplayici', 6);                  // TN7
  const OLAY = { 4: ['iki kapsul cokti', (k) => (k.hazir -= 2)],
    8: ['istenen 8 oldu', (k) => (k.istenen = 8)],
    11: ['elle iki kapsul eklendi', (k) => olustur(k, 2)] };
  const s = (x, n) => String(x).padStart(n);
  let olusan = 0, silinen = 0, eksikTur = 0;
  console.log(`${'tur'.padEnd(4)}${'olay'.padEnd(25)}${s('istenen', 8)}${s('hazir', 6)}`
    + `${s('bekleyen', 9)}   eylem`);
  for (let t = 1; t <= 14; t++) {
    const o = OLAY[t]; if (o) o[1](K);
    ilerle(K);
    const once = toplam(K);
    const eylem = uzlas(K);
    const d = toplam(K) - once;
    if (d > 0) olusan += d; else silinen += -d;
    if (K.hazir < K.istenen) eksikTur++;
    console.log(`${String(t).padEnd(4)}${(o ? o[0] : '').padEnd(25)}${s(K.istenen, 8)}`
      + `${s(K.hazir, 6)}${s(K.bekleyen.length, 9)}   ${eylem}`);
  }
  console.log(`\n14 turda ${olusan} olusturma, ${silinen} silme, ${eksikTur} turda hazir sayisi`
    + ` istenenin altinda`);
}
```

```
tur olay                      istenen hazir bekleyen   eylem
1                                   6     0        6   +6 olustur
2                                   6     0        6   fark yok
3                                   6     6        0   fark yok
4   iki kapsul cokti                6     4        2   +2 olustur
5                                   6     4        2   fark yok
6                                   6     6        0   fark yok
7                                   6     6        0   fark yok
8   istenen 8 oldu                  8     6        2   +2 olustur
9                                   8     6        2   fark yok
10                                  8     8        0   fark yok
11  elle iki kapsul eklendi         8     8        0   -2 sil
12                                  8     8        0   fark yok
13                                  8     8        0   fark yok
14                                  8     8        0   fark yok

14 turda 10 olusturma, 2 silme, 6 turda hazir sayisi istenenin altinda
```

Dört olay dört ayrı gerekçeden geliyor; denetleyicinin verdiği yanıt ise tek biçimdir. Soğuk
başlangıçta altı, çöküşte iki, istenen sayı arttığında iki kapsül oluşturulur; hepsinde uygulanan
kural aynıdır ve hiçbirinde **neden** düşüldüğü sorulmaz. Denetleyici çöküşle elle silmeyi ayırt
etmez, çünkü **TN8** gereği ikisi de aynı sayıya iner. Bu, devretmenin en somut kazancıdır: dört
farklı senaryo için dört ayrı yordam yazılmaz.

On birinci tur bunun ters yüzüdür. Dışarıdan eklenen iki kapsül aynı turda silinir; bildirimin
dışında yapılan bir değişiklik, bir sonraki uzlaşma turundan uzun yaşamaz. Kümede elle yapılan iş
kalıcı değildir ve bunu gösteren tek kanıt tablodaki `-2 sil` satırıdır.

Sayıların bedeli ise ikinci ve beşinci turlarda görünüyor: `fark yok` yazan iki turda gerçekten hiç
iş yapılmaz, ama hazır kopya sayısı hâlâ istenenin altındadır. Toplam ölçü altı turdur — on dört
turun altısında küme eksik kapasiteyle çalıştı. Bunun tamamı **TN9**'dan, yani hazır olmanın iki
tur sürmesinden gelir; denetleyici farkı gördüğü turda kapatamaz, yalnız kapatma emrini verir.
Kapasite açığı, kararın verilmesiyle etkisinin görünmesi arasındaki gecikmedir.

Tablonun on turunda yazan `fark yok` da bir sonuçtur. Aynı kural her turda yeniden koşar ve fark
kapalıysa hiçbir şey yapmaz; bu, uzlaşma döngüsünün küme ölçeğinde de değişmeyen özelliğidir.
Denetleyici bir kez tetiklenip biten bir yordam değil, sürekli koşan ve çoğu turda hiçbir iş
üretmeyen bir karşılaştırmadır. Tur başına iş, on dört turun dördünde sıfırdan farklıdır.

#### Geçişin Ayarları

Kopya sayısı sabit kalırken şablon değişirse iş uzlaşma olmaktan çıkar, bir **geçişe** dönüşür.
Sürüm nesnesi iki kopya kümesini aynı anda yönetir ve iki sayıya uyar: aynı anda en çok kaç fazla
kapsül olabilir, aynı anda en çok kaç kopya eksik olabilir.

```js
// gecis.mjs — surum nesnesi: iki kopya kumesi arasinda asamali gecis ve geri alma (MODEL).
import { kume, toplam, ilerle, olustur, sil } from './kopya.mjs';

const N = 6;                                             // TN7: istenen kopya sayisi

// fazla: en cok kac fazla kapsul; eksik: en cok kac eksik hazir kopya. TN11.
function gecis(fazla, eksik, bozukTur = null) {
  const eski = kume('surum-1', N), yeni = kume('surum-2', 0);
  eski.hazir = N;
  const olusan = { 'surum-1': 0, 'surum-2': 0 };
  let t = 0, altTur = 0, tepe = N, silinen = 0, geriTur = null, durgun = 0, yon = 'ileri';
  while (t < 80) {
    t++;
    ilerle(eski); ilerle(yeni);
    if (bozukTur && t === bozukTur && yon === 'ileri') { yon = 'geri'; geriTur = t - 1; }
    const hedef = yon === 'ileri' ? yeni : eski, kaynak = yon === 'ileri' ? eski : yeni;
    const yer = Math.min(N + fazla - (toplam(eski) + toplam(yeni)), N - toplam(hedef));
    if (yer > 0) { olustur(hedef, yer); olusan[hedef.ad] += yer; }
    const dus = Math.min(eski.hazir + yeni.hazir - (N - eksik), toplam(kaynak));
    if (dus > 0) { sil(kaynak, dus); silinen += dus; }
    tepe = Math.max(tepe, toplam(eski) + toplam(yeni));
    if (eski.hazir + yeni.hazir < N) altTur++;
    durgun = yer <= 0 && dus <= 0 && !eski.bekleyen.length && !yeni.bekleyen.length
      ? durgun + 1 : 0;
    if (durgun >= 2) return { tur: null, altTur, tepe, olusan, silinen, geriTur };
    if (toplam(kaynak) === 0 && hedef.hazir >= N) break;
  }
  return { tur: t, altTur, tepe, olusan, silinen, geriTur };
}

const AYAR = [[0, 0], [0, 1], [1, 0], [1, 1], [2, 2], [6, 0]];
const s = (x, n) => String(x).padStart(n);
console.log(`istenen kopya ${N}, hazir olma 2 tur`);
console.log(`${s('fazla', 6)}${s('eksik', 6)}${s('tur', 11)}${s('kapasite alti', 15)}`
  + `${s('tepe kapsul', 13)}${s('olusan', 8)}${s('silinen', 9)}`);
for (const [f, e] of AYAR) {
  const r = gecis(f, e), o = r.olusan['surum-1'] + r.olusan['surum-2'];
  console.log(`${s(f, 6)}${s(e, 6)}${s(r.tur ?? 'ilerlemez', 11)}${s(`${r.altTur} tur`, 15)}`
    + `${s(r.tepe, 13)}${s(o, 8)}${s(r.silinen, 9)}`);
}

console.log(`\nyeni surum 4. turun sonunda bozuk cikarsa (TN12):`);
console.log(`${s('fazla', 6)}${s('eksik', 6)}${s('ileri tur', 11)}${s('geri tur', 10)}`
  + `${s('toplam', 8)}${s('kapasite alti', 15)}${s('bosa olusan', 13)}`);
for (const [f, e] of AYAR.slice(1)) {
  const r = gecis(f, e, 5);
  if (r.geriTur === null) {
    console.log(`${s(f, 6)}${s(e, 6)}   gecis 4. turdan once bitti: geri alinacak eski kopya yok`);
    continue;
  }
  console.log(`${s(f, 6)}${s(e, 6)}${s(r.geriTur, 11)}${s(r.tur - r.geriTur, 10)}`
    + `${s(r.tur, 8)}${s(`${r.altTur} tur`, 15)}${s(r.olusan['surum-2'], 13)}`);
}
```

```
istenen kopya 6, hazir olma 2 tur
 fazla eksik        tur  kapasite alti  tepe kapsul  olusan  silinen
     0     0  ilerlemez          0 tur            6       0        0
     0     1         19         18 tur            6       6        6
     1     0         18          0 tur            7       6        6
     1     1         10          9 tur            7       6        6
     2     2          6          5 tur            8       6        6
     6     0          3          0 tur           12       6        6

yeni surum 4. turun sonunda bozuk cikarsa (TN12):
 fazla eksik  ileri tur  geri tur  toplam  kapasite alti  bosa olusan
     0     1          4         6      10          9 tur            1
     1     0          4         5       9          0 tur            2
     1     1          4         6      10          9 tur            3
     2     2          4         6      10          9 tur            6
     6     0   gecis 4. turdan once bitti: geri alinacak eski kopya yok
```

İlk satır iki sayının anlamını en keskin biçimde veriyor: ikisi de sıfırsa geçiş **başlamaz**. Ne
fazladan bir kapsüle yer vardır ne de bir kopyayı eksiltmeye izin; sürüm nesnesi kuralları ihlal
etmeden hiçbir adım atamaz ve model durgunluğu görüp çıkar. Bildirimsel bir nesnenin ilerlemek için
en az bir yönde esneklik istemesi, bu tablonun ilk sonucudur.

Sonraki iki satır aynı sayıda kapsül oluşturup silmelerine rağmen taban tabana zıt maliyet
üretiyor. Bir eksiğe izin verip fazlaya izin vermemek geçişi on dokuz tura yayar ve bunların on
sekizinde küme eksik kapasiteyle çalışır; tepe kapsül sayısı altıda kalır, yani hiç ek kaynak
harcanmaz. Bir fazlaya izin verip eksiğe izin vermemek on sekiz tur sürer, kapasitenin altına
**hiç** düşmez ve karşılığında yalnız bir kapsüllük ek kaynak ister. İki ayar arasındaki tur farkı
birdir; kapasite farkı on sekiz turdur. Ek kaynak vermeye razı olmak, aynı süreyi kesintisiz
geçirmenin bedelidir.

Alttaki iki satır hızın nereden geldiğini gösteriyor. Bir fazla ve bir eksik birlikte tanındığında
tur sayısı on sekizden ona iner; iki ve iki tanındığında altıya. Hız her iki ayardan da beslenir,
ama kapasite altı turlar da onunla birlikte gelir. Son satır bu eğrinin ucudur: altı fazla kapsüle
izin verildiğinde geçiş üç turda biter; kapasite hiç düşmez — tepe kapsül sayısı on ikidir, yani
kaynak bir süreliğine iki katına çıkar. Bu ayar, iki ortamlı geçişin sayısal karşılığıdır.

İkinci tablo o üç turluk hızın gizli bedelini ödetiyor. Dördüncü turun sonunda yeni sürümün bozuk
olduğu anlaşıldığında, bir fazla ve sıfır eksik ayarında geri alma beş tur sürer, kapasite hiç
düşmez ve boşa giden kapsül sayısı ikidir. İki-iki ayarında geri alma altı tur alır ve altı kapsül
boşa gitmiştir — dört tur içinde yeni sürümün tamamı kurulmuştur. Altı fazlalı ayarda ise geri alma
diye bir şey yoktur: geçiş dördüncü turdan önce bitmiş, eski kopya kümesi sıfırlanmıştır. **Geri
alma penceresi, geçişin süresiyle aynı şeydir.** Geçişi hızlandıran her ayar bu pencereyi kısaltır
ve bir noktadan sonra kapatır.

#### Devredilen Karar ve Bilmediği Şey

Bu derste devredilen karar iki tanedir: **kaç kopya koşacağı** ve **yeni şablona hangi hızla
geçileceği.** Birincisi için sistemin bilmesi gereken tek bilgi kalemi istenen sayıdır — bu yüzden
ucuzdur ve dört farklı olaya tek kuralla yanıt verir. İkincisi için iki kalem gerekir: fazla ve
eksik. Bu iki sayı bir tercih değil, iki kaynağın karşılıklı fiyatıdır; biri geçici kapasite, öteki
geçici kesinti.

İki kalemin maliyeti de eşit değildir. İstenen sayı bir kez yazılır ve nadiren değişir; ölçüm
gerektirmez, eskimez, yanlış olduğunda sonucu doğrudan görünür. Geçiş ayarları ise her yayında
yeniden değerlendirilmesi gereken bir tahmine dayanır: yeni sürümün ne kadar sürede ayağa kalkacağı
ve arızalıysa ne kadar sürede belli olacağı. İkinci tahmin ölçülemez olduğu için ayarlar çoğu
zaman bir kez yazılır ve her yayında aynı kalır — oysa tablonun gösterdiği gibi aynı ayar, hızlı
ayağa kalkan bir sürümde geri alma penceresini tümüyle kapatabilir.

Sistemin **bilmediği** şey de aynı tabloda duruyor. Sürüm nesnesi yeni kopyaların hazır olduğunu
görür, doğru çalıştığını görmez; **TN8** gereği kapsülün içi ona kapalıdır. Bozukluk dördüncü turun
sonunda bir yerden gelir ve modelde bu bir varsayımdır. Sistemin ölçemediği bu bilgi kalemi
yüzünden iki-iki ayarında altı kapsül boşa kurulur, altı fazlalı ayarda ise eski sürüm hiç
kalmadığı için geri dönülecek yer kalmaz. Yanlış karar burada bir hesap hatası değildir: hız,
sistemin göremediği bir bilginin gelmesini beklemeden ilerlemektir.

#### Özet

- Kopya kümesi denetleyicisi tek kural uygular: fark artıysa oluştur, eksiyse sil. Soğuk başlangıç,
  çöküş, istenen sayının değişmesi ve elle ekleme aynı yordamla karşılanır.
- Bildirimin dışında elle eklenen iki kapsül aynı turda silindi; kümede elle yapılan iş bir sonraki
  uzlaşma turundan uzun yaşamaz.
- On dört turun altısında hazır kopya sayısı istenenin altında kaldı; bunun kaynağı hazır olmanın
  iki tur sürmesi, yani kararla etkisi arasındaki gecikmedir.
- Geçiş ayarının iki sayısı da sıfırsa geçiş hiç başlamaz; bir eksiğe izin vermek on dokuz turun on
  sekizini kapasite altında geçirtir, bir fazlaya izin vermek aynı işi on sekiz turda ve hiç kapasite
  düşürmeden yapar.
- İki fazla ve iki eksik geçişi altı tura, altı fazla üç tura indirir; ikincisinde tepe kapsül sayısı
  on ikiye, yani iki katına çıkar.
- Geri alma penceresi geçişin süresiyle aynıdır: dördüncü turda fark edilen bozukluk bir-sıfır
  ayarında iki kapsülü, iki-iki ayarında altı kapsülü boşa çıkarır; üç turda biten geçişte geri
  dönülecek eski kopya kalmaz.

#### Sonraki Adım

Bu ders altı kapsülü ayakta tutmayı ve içeriğini değiştirmeyi ölçtü. İki koşumda da kapsüller
sürekli oluşturulup silindi: on dört turda on oluşturma iki silme, geçişte altı oluşturma altı
silme. Her yeni kapsül yeni bir kapsüldür ve öncekinin adresi onunla gitmiştir. Bu durumda ona
istek gönderen bir başka bileşen kime bağlanacaktır? Kopya kümesi altı kapsülü garanti eder ama
**hangi altı** olduğunu garanti etmez. Sonraki ders bu boşluğu dolduran nesneyi ölçer: kopya
kümesi altında değişirken üstte sabit kalan bir ad, o adın çözümlenmesinin isteğe eklediği tur ve
hazır olmayan bir kopyaya giden istek sayısı.

### Servis Nesneleri

Source: https://academia.sh/tr/kurslar/orkestrasyon/servisler

Küme içi kararlı adreslemenin iki ölçüsü: on bir kapsül gelip giderken adın kaç kez değiştiği ve listenin kaç kez değiştiği, hazır olma denetimi olan ve olmayan koşumda hazır olmayan uca giden istek sayısı ve ad çözümleme ömrünün eklediği tur ile bayat uca giden istek arasındaki takas.

Önceki ders altı kopyayı ayakta tutmayı ölçtü ve ölçerken bir şeyi görünür kıldı: kopya kümesi
**altı kapsül** olacağını garanti eder, **hangi altı** olacağını garanti etmez. On dört turluk
koşumda on kapsül oluşturuldu, geçişte altısı silinip altısı kuruldu. Her yeni kapsül yeni bir
kapsüldür; öncekinin adresi onunla birlikte gitmiştir. Doğrulayıcı, okuma toplayıcıya istek
göndermek istediğinde kime bağlanacaktır?

Bu boşluğu dolduran nesne **servis nesnesi**dir. Tuttuğu şey bir yazılım değildir; bir ad ve o adın
arkasındaki uç nokta listesidir. Liste kopya kümesinden türer ve kapsüller geldikçe gittikçe
kendiliğinden güncellenir. M16/K06'da **servis**, ayrı dağıtılan ve ayrı sahiplenilen bir yazılım
parçasıydı; buradaki servis nesnesi o yazılımın kopyalarının önünde duran bir addır — aynı sözcük,
başka bir nesne. Bu ders adı ve listeyi `node` ile modelleyip ikisini de sayar; gerçek bir küme
koşturulmaz.

**TN13 — servis nesnesi bir ada bağlı uç nokta listesi tutar** ve liste kopya kümesindeki
kapsüllerden türer. **TN14 — adın listeye çözümlenmesi isteğe bir tur ekler**, sonuç bir ömür
boyunca önbellekte tutulabilir. **TN15 — istekler uç nokta listesi üzerinde dönüşümlü dağıtılır.**
**TN16 — yeni kapsül iki tur sonra hazır olur**; hazır olma denetimi yoksa oluşturulduğu turda
listeye girer. **TN17 — hazır olmayan ya da bildirimden düşmüş bir uca giden istek başarısız
olur.** **TN18 — koşum yirmi dört tur sürer**, her turda on iki istek gelir, kapsül devri tohumlu
bir üreteçle üretilir.

#### Değişen Liste, Değişmeyen Ad

Aşağıdaki koşum aynı devir çizelgesini iki kez uygular. Değişen tek şey uç nokta listesinin nereden
türediğidir: bütün kapsüllerden mi, yoksa yalnız hazır olanlardan mı.

```js
// servis.mjs — servis nesnesi: ad sabit kalirken uc nokta listesi degisir (MODEL).
export const TOHUM = 20260803, TUR = 24, ISTEK = 12, N = 6, HAZIR = 2, DEVIR = 0.45;
// Uretec kendi yazildi; 32 bitlik tam sayi islemleri, tohum gorunur.
export const uret = (t) => () =>
  { t ^= t << 13; t ^= t >>> 17; t ^= t << 5; return (t >>> 0) / 2 ** 32; };

// Devir cizelgesi bir kez uretilir; iki kosum da ayni kapsulleri ayni turlarda kaybeder.
const rnd = uret(TOHUM);
export const CIZELGE = Array.from({ length: TUR },
  () => (rnd() < DEVIR ? Math.floor(rnd() * N) : null));

export const SERVIS_ADI = 'okuma-toplayici.olcum';        // degismeyen tek sey

// Kopya kumesi her turda N kapsul tutar; devir olan yuvaya yeni kapsul konur (TN13).
export function kosum(denetim) {
  let sayac = N, ad = SERVIS_ADI;
  const yuva = Array.from({ length: N }, (_, i) => ({ ad: `kapsul-${i}`, hazirAn: 0 }));
  let istek = 0, basarisiz = 0, devir = 0, adDegisimi = 0, listeDegisimi = 0, sira = 0;
  let onceki = '';
  const ucSayisi = [], yuk = [];
  for (let t = 0; t < TUR; t++) {
    const j = CIZELGE[t];
    if (j !== null) { yuva[j] = { ad: `kapsul-${sayac++}`, hazirAn: t + HAZIR }; devir++; }
    // Hazir olma denetimi varsa liste yalniz hazir kapsullerden turer; yoksa hepsinden.
    const uclar = denetim ? yuva.filter((k) => k.hazirAn <= t) : [...yuva];
    const imza = uclar.map((k) => k.ad).sort().join(',');
    if (t && imza !== onceki) listeDegisimi++;
    if (ad !== SERVIS_ADI) adDegisimi++;                       // ada dokunan hicbir yol yok
    onceki = imza;
    ucSayisi.push(uclar.length);
    yuk.push(uclar.length ? Math.ceil(ISTEK / uclar.length) : ISTEK);
    for (let i = 0; i < ISTEK; i++) {
      istek++;
      if (!uclar.length) { basarisiz++; continue; }
      const hedef = uclar[sira++ % uclar.length];               // TN15: donusumlu dagitim
      if (hedef.hazirAn > t) basarisiz++;                       // TN17
    }
  }
  return { istek, basarisiz, devir, adDegisimi, listeDegisimi,
    ucEnAz: Math.min(...ucSayisi), ucEnCok: Math.max(...ucSayisi), yukEnCok: Math.max(...yuk) };
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const s = (x, n) => String(x).padStart(n);
  console.log(`tohum ${TOHUM}, ${TUR} tur, tur basina ${ISTEK} istek, ${N} kopya,`
    + ` hazir olma ${HAZIR} tur, servis adi '${SERVIS_ADI}'`);
  console.log(`${'denetim'.padEnd(12)}${s('istek', 7)}${s('basarisiz', 11)}${s('oran', 8)}`
    + `${s('uc sayisi', 11)}${s('uc basina en cok', 18)}${s('liste degisimi', 16)}`
    + `${s('ad degisimi', 13)}`);
  for (const [etiket, d] of [['yok', false], ['hazir olma', true]]) {
    const r = kosum(d);
    console.log(`${etiket.padEnd(12)}${s(r.istek, 7)}${s(r.basarisiz, 11)}`
      + `${s(`%${(100 * r.basarisiz / r.istek).toFixed(1)}`, 8)}`
      + `${s(`${r.ucEnAz}-${r.ucEnCok}`, 11)}${s(r.yukEnCok, 18)}${s(r.listeDegisimi, 16)}`
      + `${s(r.adDegisimi, 13)}`);
  }
  console.log(`\n${TUR} turda ${kosum(true).devir} kapsul gelip gitti;`
    + ` cagiran taraf hep ayni adi kullandi`);
}
```

```
tohum 20260803, 24 tur, tur basina 12 istek, 6 kopya, hazir olma 2 tur, servis adi 'okuma-toplayici.olcum'
denetim       istek  basarisiz    oran  uc sayisi  uc basina en cok  liste degisimi  ad degisimi
yok             288         44   %15.3        6-6                 2              10            0
hazir olma      288          0    %0.0        4-6                 3              13            0

24 turda 11 kapsul gelip gitti; cagiran taraf hep ayni adi kullandi
```

Son satır bu dersin bütün gerekçesidir. Yirmi dört turda on bir kapsül gelip gitti; uç nokta
listesi on üç kez değişti; **ad sıfır kez değişti.** Değişim sayısı ile sabitlik sayısı yan yana
durduğunda servis nesnesinin ne yaptığı görünür hâle gelir: bir değişkenlik kaynağını, çağıran
tarafın hiç görmediği bir yere taşır. Doğrulayıcının kodunda yazılı olan tek şey `okuma-toplayici.olcum`
adıdır ve o ad, kopya kümesindeki hiçbir olaydan etkilenmez.

Listenin kendisi de bildirilmez, **türetilir**. Servis nesnesine yazılan tek şey hangi kapsüllerin
bu ada ait sayılacağıdır; hangi kapsüllerin o an var olduğu bir ölçümden gelir. Bu ayrım, önceki
iki dersin bilgi kalemleri arasındaki farkın aynısıdır: istenen kopya sayısı bildirimdir ve
eskimez, uç nokta listesi ölçümdür ve her turda yeniden üretilmesi gerekir. Bir nesnenin bildirim
mi ölçüm mü taşıdığı, onun ne sıklıkta yanlış olabileceğini belirler.

Başarısız istek sütunu ise adın **yeterli olmadığını** söylüyor. Hazır olma denetimi yokken uç
nokta listesi her zaman altı kapsüllüktür — sayı doğru, içerik yanlıştır. Yeni oluşturulan kapsül
iki tur boyunca hizmet veremediği hâlde listede durur ve dönüşümlü dağıtım ona sırayla istek
gönderir. Sonuç iki yüz seksen sekiz isteğin kırk dördü, yani her yedi istekten biridir. Hazır olma
denetimi açıldığında bu sayı **sıfıra** iner; liste yalnız hizmet verebilen kapsülleri gösterir.

Bedel, hemen yanındaki iki sütunda. Denetimli koşumda uç sayısı zaman zaman dörde iner ve bir uca
düşen istek en çok ikiden üçe çıkar. Denetim istekleri kurtarmaz, **yeniden dağıtır**: hazır
olmayan kapsüle gidecek olan istek, hazır olan kapsüllere eklenir. Liste değişim sayısının onda üç
artması da aynı nedendendir — kapsül artık listeye iki kez girer çıkar: oluşturulduğunda değil,
hazır olduğunda girer, düştüğünde çıkar. Kararlı ad, altındaki listenin daha sık değişmesi
pahasına elde edilir.

Sıfır sayısının kaynağı bir şans değil, bir ayrımdır. Ad, kopya kümesinden ayrı bir nesnede durur;
kapsül oluşturan, silen ve hazır sayan hiçbir yol o nesneye dokunmaz. Servis nesnesi olmasaydı bu
sıfırın yerine on üç gelirdi: uç nokta listesinin her değişimi, çağıran tarafın elindeki adres
listesinin de değişmesi gerektiği anlamına gelirdi ve o listeyi güncel tutma işi doğrulayıcının
kendi kodunda bir bileşen olurdu. Ad, tam olarak bu bileşeni ortadan kaldırmak için vardır.

#### Adı Çözmenin Bedeli

Ad sabit, liste değişken. Çağıran taraf isteği göndermeden önce adı bir listeye çevirmek zorundadır
ve **TN14** bunun bir tur ettiğini söyler. Bu turu her istekte ödemek de, bir kez ödeyip sonucu
saklamak da mümkündür; ikisinin arasındaki alan aşağıda ölçülüyor.

```js
// cozumleme.mjs — adin coze coze mi yoksa onbellekten mi okunacagi (MODEL).
import { CIZELGE, N, HAZIR, TUR, ISTEK } from './servis.mjs';

// Ayni devir cizelgesi; her turun canli kumesi ve hazir uc listesi bir kez cikarilir.
function zamanCizgisi() {
  let sayac = N;
  const yuva = Array.from({ length: N }, (_, i) => ({ ad: `kapsul-${i}`, hazirAn: 0 }));
  const canli = [], hazirListe = [];
  for (let t = 0; t < TUR; t++) {
    const j = CIZELGE[t];
    if (j !== null) yuva[j] = { ad: `kapsul-${sayac++}`, hazirAn: t + HAZIR };
    canli.push(new Set(yuva.map((k) => k.ad)));
    hazirListe.push(yuva.filter((k) => k.hazirAn <= t).map((k) => k.ad));
  }
  return { canli, hazirListe };
}

// TN14: her cozumleme isteme bir tur ekler; sonuc omur boyunca onbellekte tutulur.
function onbellek(omur) {
  const { canli, hazirListe } = zamanCizgisi();
  let cozumleme = 0, istek = 0, bayat = 0, sira = 0, liste = [], son = -Infinity;
  for (let t = 0; t < TUR; t++) {
    for (let i = 0; i < ISTEK; i++) {
      if (omur === 0 || t - son >= omur) { liste = hazirListe[t]; son = t; cozumleme++; }
      istek++;
      const hedef = liste[sira++ % liste.length];
      if (!canli[t].has(hedef)) bayat++;                 // bildirimden dusmus uca giden istek
    }
  }
  return { cozumleme, istek, bayat };
}

const s = (x, n) => String(x).padStart(n);
console.log(`${TUR} tur x ${ISTEK} istek = ${TUR * ISTEK} istek`);
console.log(`${s('onbellek omru', 14)}${s('cozumleme', 11)}${s('ek tur', 8)}`
  + `${s('istek basina ek tur', 21)}${s('bayat uca istek', 17)}${s('oran', 8)}`);
for (const omur of [0, 2, 4, 8, TUR]) {
  const r = onbellek(omur);
  console.log(`${s(omur === 0 ? 'yok' : `${omur} tur`, 14)}${s(r.cozumleme, 11)}`
    + `${s(r.cozumleme, 8)}${s((r.cozumleme / r.istek).toFixed(2), 21)}${s(r.bayat, 17)}`
    + `${s(`%${(100 * r.bayat / r.istek).toFixed(1)}`, 8)}`);
}
```

```
24 tur x 12 istek = 288 istek
 onbellek omru  cozumleme  ek tur  istek basina ek tur  bayat uca istek    oran
           yok        288     288                 1.00                0    %0.0
         2 tur         12      12                 0.04               12    %4.2
         4 tur          6       6                 0.02               35   %12.2
         8 tur          3       3                 0.01               72   %25.0
        24 tur          1       1                 0.00              216   %75.0
```

Tablo iki uçtan okunmalıdır. Üstte hiç önbellekleme yoktur: her istek adını yeniden çözer, iki yüz
seksen sekiz istek iki yüz seksen sekiz ek tur öder ve bayat uca giden istek sıfırdır. Altta ad bir
kez çözülür: ek tur bire iner, karşılığında iki yüz on altı istek — dörtte üçü — artık var olmayan
kapsüllere gider. Aradaki üç satır bu iki ucun arasındaki eğridir ve eğri diktir: ömür ikiden dörde
çıktığında ek tur altıya iner, bayat istek on ikiden otuz beşe çıkar.

Bu tablonun söylediği şey, bu kursun ölçü ekseninin kendisidir. Uç nokta listesi bir **bilgi
kalemidir** ve her bilgi kaleminin iki fiyatı vardır: onu almanın maliyeti ile eskimesinin
maliyeti. Sıfır ömürde birinci fiyat ödenir, sonuncu satırda ikinci fiyat. Bayat uca giden yüzde
yetmiş beşlik pay, hiçbir bileşenin arızalanmadığı bir kümede doğar — yalnızca çağıran tarafın
elindeki liste, kümenin gerçek durumundan yirmi dört tur geridedir.

Eğrinin ortası da bir şey söylüyor. İki turluk ömür, çözümleme yükünü iki yüz seksen sekizden on
ikiye, yani yirmi dörtte birine indirirken bayat isteği yüzde dört buçukta tutar. Dört turluk ömür
çözümlemeyi yalnızca ikiye böler, bayat isteği ise üç katına çıkarır. İki uçta da kazanç ve kayıp
aynı hızda büyümez: birinci adımda çok kazanılır az ödenir, sonraki adımlarda az kazanılır çok
ödenir. Bu asimetri ömrün seçilecek bir sayı olduğunu, iki uçtan birinin doğru olmadığını
gösteriyor.

#### Devredilen Karar ve Bilmediği Şey

Devredilen karar burada açıktır: **isteğin hangi kapsüle gideceği.** Bu karar daha önce çağıranın
yapılandırmasında yazılıydı; şimdi servis nesnesinin listesinden okunur. Kararın dayandığı bilgi üç
kalemdir: hangi kapsüllerin var olduğu, hangilerinin hazır olduğu, listenin ne zaman okunduğu.
Birincisi kopya kümesinden bedava gelir. İkincisi bir denetim gerektirir ve bedeli birinci tabloda
yazılıdır: uç başına düşen en yüksek istek ikiden üçe çıkar. Üçüncüsü de bir tur eder ve ikinci
tablonun ilk sütununda durur.

Sistemin bilmediği şey, listenin **ne zaman eskidiğidir**. Model bunu bir ömür sayısıyla yaklaşık
olarak çözüyor; ömür, kapsül devrinin ne sıklıkta olduğuna dair bir tahmindir. Devir tahminden
sıksa bayat uca giden istekler artar, seyrekse gereksiz çözümleme turları ödenir. Yirmi dört turda
on bir devir olan bu koşumda iki turluk ömür bile on iki bayat istek üretir; devrin sıklığı yarıya
inseydi aynı ömür daha ucuz olurdu. Yanlış kararın kaynağı burada bir hesap değil, **bir sayının
ne kadar süre doğru kaldığına dair bilgisizliktir.**

Üç sonuç bir arada sayıldığında tablo şöyle çıkıyor. Denetimli ve önbelleksiz koşumda iki yüz
seksen sekiz yönlendirme kararının tamamı doğrudur. Denetimsiz koşumda kırk dördü yanlıştır ve
yanlışın kaynağı tek bir eksik bilgi kalemidir: kapsülün hazır olup olmadığı. **Karar verememe**
durumu bu koşumda hiç görülmedi, çünkü hazır uç sayısı en az dörde indi, sıfıra hiç inmedi. Devir
sıklığı artıp bütün kapsüller aynı anda hazır olmayı beklerse liste boşalır ve servis nesnesi
elinde ad olduğu hâlde yönlendirecek yer bulamaz; o durumda karar ne doğru ne yanlıştır,
verilememiştir.

#### Özet

- Servis nesnesi bir yazılım değil, bir ad ile onun arkasındaki uç nokta listesidir; liste kopya
  kümesinden türer. M16/K06'nın **servis**'i ayrı dağıtılan bir yazılım parçasıydı, buradaki nesne
  o parçanın kopyalarının önündeki addır.
- Yirmi dört turda on bir kapsül gelip gitti ve uç nokta listesi on üç kez değişti; ad sıfır kez
  değişti. Çağıran tarafın kodunda yazılı olan tek şey addır.
- Hazır olma denetimi olmadan iki yüz seksen sekiz isteğin kırk dördü hazır olmayan bir kapsüle
  gitti; denetim açıldığında bu sayı sıfıra indi.
- Denetimin bedeli istek kaybı değil yük kaymasıdır: uç sayısı dörde iner, bir uca düşen en yüksek
  istek ikiden üçe çıkar ve liste on yerine on üç kez değişir.
- Ad çözümlemesi isteğe bir tur ekler; hiç önbelleklenmezse iki yüz seksen sekiz ek tur ödenir,
  bir kez çözülüp saklanırsa ek tur bire iner ama isteklerin yüzde yetmiş beşi artık var olmayan
  uçlara gider.
- Bu iki tablo bir bilgi kaleminin iki fiyatını gösterir: onu almanın maliyeti ile eskimesinin
  maliyeti; ömür seçimi, kapsül devri sıklığına dair bir tahmindir.

#### Sonraki Adım

Bu dersin bütün istekleri kümenin içinden geldi: doğrulayıcı, aynı kümedeki okuma toplayıcıyı
çağırdı. Ad çözümlemesi de dönüşümlü dağıtım da o sınırın içinde çalışır. Oysa bölgesel ölçüm ağının
faturalama arayüzüne dışarıdan, kümeyi hiç bilmeyen bir istemciden istek gelir. O isteğin bir servis
nesnesine ulaşması için kaç katmandan geçmesi ve her katmanda kaç kural yazılması gerekir? Sonraki
ders dışarıdan gelen tek bir isteğin katmanlarını sayar: her katmanın eklediği tur, yol tabanlı ve
ad tabanlı yönlendirmenin kural sayısı ile servis sayısı ilişkisi ve dışarı açılan yüzeyin kaç uç
ile kaç yoldan oluştuğu.

### Dış Erişim

Source: https://academia.sh/tr/kurslar/orkestrasyon/dis-erisim

Kümenin dışına açılan yolun iki ölçüsü: dış dengeleyici, giriş kuralı, servis nesnesi ve kapsülden oluşan dört katmanın eklediği tur ile taranan kural sayısı ve yol tabanlı ile ad tabanlı yönlendirmenin dış uç, kimlik kalemi ve toplam yüzey cinsinden farkı.

Önceki dersin bütün istekleri kümenin içinden geldi. Doğrulayıcı, aynı kümedeki okuma toplayıcıyı
adıyla çağırdı; ad çözümlemesi de dönüşümlü dağıtım da o sınırın içinde çalıştı. Bölgesel ölçüm
ağının faturalama arayüzüne gelen istek ise dışarıdandır — kümeyi bilmeyen, servis adını
çözemeyen, uç nokta listesini görmeyen bir istemciden. Bu isteğin bir kapsüle ulaşması için
aradaki mesafenin nesnelerle döşenmesi gerekir.

Döşenen nesne **giriş kuralı**dır: dışarıdaki bir adı ve yolu, içerideki bir servis nesnesine
bağlayan bir eşleşme listesi. Tek başına yetmez; kuralın dinlediği bir dış uç ve o ucun arkasında
duran bir yük dengeleyici de gerekir. Bu ders o zinciri katman katman sayar ve iki yönlendirme
biçimini karşılaştırır. Yapılandırma örnekleri kendi küçük şemamızla yazılmıştır; ölçülen şey bir
modeldir, gerçek bir küme koşturulmaz.

**TN19 — bölgesel ölçüm ağının dışa açık arayüzleri on ikiye kadar sayılır**, hepsi kurgudur.
**TN20 — dışarıdan gelen istek dört katmandan geçer:** dış yük dengeleyici, giriş kuralı, servis
nesnesi, kapsül. **TN21 — her katman bir tur ekler**; dengeleyici ile giriş kuralı ayrıca kendi
listelerini sırayla tarar. **TN22 — yol tabanlı yönlendirmede bütün servisler tek bir dış ucun
arkasındadır**, ad tabanlı yönlendirmede her servisin kendi dış ucu vardır. **TN23 — her dış uç
bir kimlik kalemi ve bir dengeleyici kaydı ister.** **TN24 — kural listesi sırayla taranır ve ilk
eşleşme kazanır**; en uzun önek kuralı kendiliğinden uygulanmaz.

#### Dört Katman ve Dışa Açılan Yüzey

Aşağıdaki model önce tek bir isteğin katmanlarını, sonra üç farklı servis sayısında iki
yönlendirme biçiminin dışarıya ne kadar yüzey açtığını sayıyor.

```js
// dis-erisim.mjs — disaridan gelen istegin katmanlari ve disa acilan yuzey (MODEL).
// Giris kuralinin semasi burada tanimlidir: her kural bir (ana, yol) ciftini bir servise baglar.
export const SEMA = { ana: 'metin', yol: 'metin', servis: 'metin', kapi: 'sayi' };

export const SERVISLER = ['faturalama', 'is-emri', 'olcum-raporu', 'sayac-kayit',
  'abone-arayuzu', 'kesinti-bildirimi', 'tarife-sorgu', 'borc-sorgu', 'tahsilat',
  'ariza-kaydi', 'sozlesme', 'tuketim-gecmisi'];           // TN19: disa acik kurgu arayuzler

export function kurallar(n, bicim) {
  return SERVISLER.slice(0, n).map((s) => (bicim === 'ad'
    ? { ana: `${s}-disa`, yol: '/', servis: s, kapi: 8080 }
    : { ana: 'olcum-disa', yol: `/${s}`, servis: s, kapi: 8080 }));
}

// Disa acilan yuzey: kac dis uc, kac yol, uc basina bir kimlik kalemi (TN22, TN23).
export function yuzey(n, bicim) {
  const k = kurallar(n, bicim);
  const uc = new Set(k.map((x) => x.ana)).size;
  const yol = new Set(k.map((x) => `${x.ana}${x.yol}`)).size;
  return { uc, kural: k.length, yol, kimlik: uc, toplam: uc + yol + uc };
}

// TN20-TN21: dort katman, her biri bir tur; taranan kural sayisi katmana gore degisir.
export function katmanlar(n, bicim) {
  const y = yuzey(n, bicim);
  return [
    ['dis dengeleyici', 1, (y.uc + 1) / 2],
    ['giris kurali', 1, bicim === 'ad' ? 1 : (y.kural + 1) / 2],
    ['servis nesnesi', 1, 1],
    ['kapsul', 1, 0],
  ];
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const s = (x, n) => String(x).padStart(n);
  const N = 6;
  console.log(`${N} disa acik servis, kural semasi: ${Object.keys(SEMA).join(', ')}`);
  console.log(`${'katman'.padEnd(18)}${s('tur', 5)}${s('yol tabanli taranan', 21)}`
    + `${s('ad tabanli taranan', 20)}`);
  const yolK = katmanlar(N, 'yol'), adK = katmanlar(N, 'ad');
  const top = (k, i) => k.reduce((a, x) => a + x[i], 0);
  for (let i = 0; i < yolK.length; i++) {
    console.log(`${yolK[i][0].padEnd(18)}${s(yolK[i][1], 5)}${s(yolK[i][2], 21)}`
      + `${s(adK[i][2], 20)}`);
  }
  console.log(`${'toplam'.padEnd(18)}${s(top(yolK, 1), 5)}${s(top(yolK, 2), 21)}`
    + `${s(top(adK, 2), 20)}`);

  console.log(`\n${'servis'.padEnd(8)}${'bicim'.padEnd(12)}${s('dis uc', 8)}${s('kural', 7)}`
    + `${s('disa acik yol', 15)}${s('kimlik kalemi', 15)}${s('yuzey kalemi', 14)}`);
  for (const n of [3, 6, 12]) {
    for (const b of ['yol', 'ad']) {
      const y = yuzey(n, b);
      console.log(`${String(n).padEnd(8)}${(b === 'yol' ? 'yol tabanli' : 'ad tabanli').padEnd(12)}`
        + `${s(y.uc, 8)}${s(y.kural, 7)}${s(y.yol, 15)}${s(y.kimlik, 15)}${s(y.toplam, 14)}`);
    }
  }
}
```

```
6 disa acik servis, kural semasi: ana, yol, servis, kapi
katman              tur  yol tabanli taranan  ad tabanli taranan
dis dengeleyici       1                    1                 3.5
giris kurali          1                  3.5                   1
servis nesnesi        1                    1                   1
kapsul                1                    0                   0
toplam                4                  5.5                 5.5

servis  bicim         dis uc  kural  disa acik yol  kimlik kalemi  yuzey kalemi
3       yol tabanli        1      3              3              1             5
3       ad tabanli         3      3              3              3             9
6       yol tabanli        1      6              6              1             8
6       ad tabanli         6      6              6              6            18
12      yol tabanli        1     12             12              1            14
12      ad tabanli        12     12             12             12            36
```

Birinci tablo iki şey söylüyor. Birincisi katman sayısıdır: dışarıdan gelen bir istek kapsüle
varmadan önce dört durak geçer ve dördü de bir tur eder. Bu dört tur, istemcinin ödediği sabit
bedeldir; küme içindeki bir çağrının ödediği tur sayısıyla kıyaslandığında fark, kümenin dışında
olmanın fiyatıdır.

Bu dört turun ne kadar olduğu ancak bir karşılaştırmayla anlaşılır. Önceki dersteki küme içi çağrı
iki tur ediyordu: bir ad çözümleme turu ve isteğin kendisi. Dışarıdan gelen istek dört tur öder,
yani iki katı; aradaki iki tur dengeleyici ile giriş kuralının payıdır. Bu iki katman kaldırılıp
kapsüller doğrudan dışarı açılsaydı fark kapanırdı — ama o zaman dışa açılan yüzey kapsül sayısı
kadar olurdu ve kapsüller devir hâlindeyken adresleri de değişirdi. İki katman, önceki iki dersin
kurduğu kararlılığın dışarıya taşınmasının bedelidir.

İkincisi daha ilginçtir: **toplam taranan kural iki biçimde de aynıdır** — beş buçuk. Yol
tabanlıda dengeleyici tek kayıt tutar, giriş kuralı altı kuralı tarar; ad tabanlıda dengeleyici
altı kaydı tarar, giriş kuralı bir kuralla eşleşir. Ayrım bir tasarruf değil, **bir yer
değiştirmedir**: aynı iş bir katmandan ötekine taşınır. Bu, ölçmeden verilen "ad tabanlı daha
hızlıdır" türü kararların neden dayanaksız olduğunu gösteriyor.

Gerçek fark ikinci tablodadır ve tur değil **yüzeydir**. Üç serviste iki biçim arasındaki fark
beşe dokuzdur; altı serviste sekize on sekiz, on iki serviste on dörde otuz altı. Yol tabanlı
biçimde dış uç sayısı servis sayısından bağımsızdır, hep birdir; ad tabanlı biçimde servis sayısı
kadardır. Kimlik kalemi de uca bağlı olduğu için aynı oranda büyür. On iki servis dışarı
açıldığında yol tabanlı biçim on dört, ad tabanlı biçim otuz altı kalem yönetmeyi gerektirir —
yaklaşık 2,6 katı.

Kural sayısının iki biçimde de eşit olması bu tablonun ikinci sonucudur. **Kural sayısı servis
sayısına eşittir ve yönlendirme biçiminden bağımsızdır.** Değişen, kuralların kaç ayrı dış uca
dağıldığıdır. Bu yüzden "kaç kural yazılacak" sorusu biçim seçiminde bir ölçüt değildir; "kaç uç
korunacak" sorusu ölçüttür.

#### Kuralın Sırası

Kural sayısını bilmek yönlendirmenin doğru olacağını göstermez. **TN24** kural listesinin sırayla
tarandığını ve ilk eşleşmenin kazandığını söyler; iç içe yollar bu kuralla birleştiğinde sıra bir
ayrıntı olmaktan çıkar.

```js
// yonlendirme.mjs — kural sirasinin yonlendirme kararina etkisi (MODEL).
import { SEMA } from './dis-erisim.mjs';

// Ayni sema, ic ice yollarla: alt yol kendi servisine gitmelidir.
const KURALLAR = [
  { ana: 'olcum-disa', yol: '/fatura', servis: 'faturalama', kapi: 8080 },
  { ana: 'olcum-disa', yol: '/fatura/dokum', servis: 'fatura-dokum', kapi: 8080 },
  { ana: 'olcum-disa', yol: '/is-emri', servis: 'is-emri', kapi: 8080 },
  { ana: 'olcum-disa', yol: '/is-emri/acil', servis: 'acil-is-emri', kapi: 8080 },
  { ana: 'olcum-disa', yol: '/rapor', servis: 'olcum-raporu', kapi: 8080 },
  { ana: 'olcum-disa', yol: '/rapor/aylik', servis: 'aylik-rapor', kapi: 8080 },
];

// Beklenen sonuc: en uzun onek kazanir. Bu beklenti kuralda yazili degildir.
const ISTEKLER = [
  ['/fatura', 'faturalama'], ['/fatura/dokum', 'fatura-dokum'],
  ['/fatura/dokum/2026', 'fatura-dokum'], ['/is-emri', 'is-emri'],
  ['/is-emri/acil', 'acil-is-emri'], ['/is-emri/acil/12', 'acil-is-emri'],
  ['/rapor', 'olcum-raporu'], ['/rapor/aylik', 'aylik-rapor'],
  ['/rapor/aylik/03', 'aylik-rapor'], ['/rapor/gunluk', 'olcum-raporu'],
  ['/abone', null], ['/', null],
];

// TN24: kural listesi sirayla taranir, ilk eslesme kazanir.
function eslestir(kurallar, yol) {
  for (let i = 0; i < kurallar.length; i++) {
    const k = kurallar[i];
    if (yol === k.yol || yol.startsWith(`${k.yol}/`)) return { servis: k.servis, taranan: i + 1 };
  }
  return { servis: null, taranan: kurallar.length };
}

const SIRALAR = {
  'bildirim sirasi': KURALLAR,
  'ozgulluk sirasi': [...KURALLAR].sort((a, b) => b.yol.length - a.yol.length),
};

const s = (x, n) => String(x).padStart(n);
console.log(`${KURALLAR.length} kural, ${ISTEKLER.length} istek, sema: ${Object.keys(SEMA).join(', ')}`);
console.log(`${'kural sirasi'.padEnd(18)}${s('dogru', 7)}${s('yanlis servis', 15)}`
  + `${s('kural bulunamadi', 18)}${s('ortalama taranan', 18)}`);
for (const [ad, kurallar] of Object.entries(SIRALAR)) {
  let dogru = 0, yanlis = 0, yok = 0, taranan = 0;
  for (const [yol, beklenen] of ISTEKLER) {
    const r = eslestir(kurallar, yol);
    taranan += r.taranan;
    if (r.servis === null) yok++;
    if (r.servis === beklenen) dogru++; else if (r.servis !== null) yanlis++;
  }
  console.log(`${ad.padEnd(18)}${s(dogru, 7)}${s(yanlis, 15)}${s(yok, 18)}`
    + `${s((taranan / ISTEKLER.length).toFixed(2), 18)}`);
}

console.log(`\nbildirim sirasinda yanlis giden istekler:`);
for (const [yol, beklenen] of ISTEKLER) {
  const r = eslestir(SIRALAR['bildirim sirasi'], yol);
  if (r.servis !== beklenen && r.servis !== null) {
    console.log(`  ${yol.padEnd(20)} -> ${String(r.servis).padEnd(14)} (beklenen ${beklenen},`
      + ` ${r.taranan}. kuralda esletti)`);
  }
}
```

```
6 kural, 12 istek, sema: ana, yol, servis, kapi
kural sirasi        dogru  yanlis servis  kural bulunamadi  ortalama taranan
bildirim sirasi         6              6                 2              3.67
ozgulluk sirasi        12              0                 2              3.75

bildirim sirasinda yanlis giden istekler:
  /fatura/dokum        -> faturalama     (beklenen fatura-dokum, 1. kuralda esletti)
  /fatura/dokum/2026   -> faturalama     (beklenen fatura-dokum, 1. kuralda esletti)
  /is-emri/acil        -> is-emri        (beklenen acil-is-emri, 3. kuralda esletti)
  /is-emri/acil/12     -> is-emri        (beklenen acil-is-emri, 3. kuralda esletti)
  /rapor/aylik         -> olcum-raporu   (beklenen aylik-rapor, 5. kuralda esletti)
  /rapor/aylik/03      -> olcum-raporu   (beklenen aylik-rapor, 5. kuralda esletti)
```

Aynı altı kural, aynı on iki istek, iki farklı sıra: on doğru ya da dört doğru. Bildirim sırasında
yazılan liste okunduğunda hiçbir şey yanlış görünmez — her servisin kendi satırı vardır ve her
satır doğrudur. Yanlış olan **satırların arasındaki ilişkidir** ve bu ilişki dosyada hiçbir yerde
yazılı değildir. Alt yolun kendi servisine gitmesi gerektiği bir beklentidir; kural listesi bu
beklentiyi değil, yalnız sırayı bilir.

Alttaki dökümün son sütunu yanlışın nasıl oluştuğunu gösteriyor: altı isteğin hepsi de **daha genel
kuralla** eşleşiyor ve eşleşme birinci, üçüncü ve beşinci kuralda gerçekleşiyor. Daha özgül kural
listede hemen bir alttadır ve hiç okunmaz. Bu yüzden ortalama taranan kural sayısı yanlış sırada
daha **düşüktür** — üç virgül altmış yediye karşı üç virgül yetmiş beş. Yanlış yönlendirme daha az
iş yaparak elde edilir; hızlı olan yanıt doğru olan yanıt değildir.

Bu koşum, ad tabanlı biçimin ne kazandırdığını da geriye dönük olarak söylüyor. Her servisin kendi
dış ucu olduğunda o ucun kural listesinde tek bir satır bulunur; iki kuralın birbirini kapsaması
diye bir durum doğmaz ve buradaki altı yanlış yönlendirme **oluşamaz**. Otuz altı yüzey kaleminin
karşılığı budur: yönlendirme kararının, kuralların sırasına bağlı olmaktan çıkması. İki biçim
arasındaki seçim, yönetilecek nesne sayısı ile bir yanlış karar sınıfının varlığı arasında
yapılıyor.

İki satırda da eşleşmeyen istek sayısı ikidir ve bu iki istek bir hata değildir. `/abone` ile `/`
için dışa açılan yüzeyde bir kural yoktur, dolayısıyla giriş kuralı bir karar veremez ve isteği
reddeder. Dışa açık yüzeyin sayılabilir olmasının anlamı budur: yüzeyde olmayan bir yol, kümenin
içine hiçbir yoldan giremez.

#### Devredilen Karar ve Bilmediği Şey

Bu derste devredilen karar **dışarıdan gelen isteğin hangi iç servise gideceğidir.** Bu karar
istemcide de verilebilirdi — her arayüz için ayrı bir adres, istemcinin yapılandırmasında. Giriş
kuralı o kararı kümeye taşır ve karşılığında dört bilgi kalemi ister: dış ad, yol, hedef servis
adı, hedef kapı. Dört kalemin dördü de bildirimdir; ölçüm gerektirmez, eskimez.

Maliyet bildirimin kendisinde değil, **sayısında** ve **sırasındadır**. İkinci tablo sayının nasıl
büyüdüğünü gösterdi: on iki servis, ad tabanlı biçimde otuz altı yüzey kalemi eder ve bunların on
ikisi kimlik kalemidir; her biri süresi dolan, yenilenmesi gereken bir nesnedir. Yol tabanlı
biçimde aynı iş on dört kalemle görülür ve kimlik kalemi tektir. Devretmenin bedeli burada bir
gecikme değil, **yönetilecek nesne sayısıdır.**

Bilinen bir istek kümesinde üç sonuç şöyle sayılıyor. On iki isteğin onu bir kurala uyar, ikisi
uymaz. Özgüllük sırasında on doğru karar, sıfır yanlış karar ve iki **karar verememe** vardır;
bildirim sırasında dört doğru, altı yanlış ve yine iki karar verememe. Karar verememe sayısının iki
sırada da aynı kalması anlamlıdır: o iki istek yüzeyde karşılığı olmadığı için reddedilir ve bu,
sıradan bağımsız bir sonuçtur. Değişen tek şey, uyan on isteğin kaçının doğru yere gittiğidir.

Sistemin bilmediği şey ise ikinci koşumda görüldü: **kuralların hangisinin ötekini kapsadığı.**
Giriş kuralı yollar arasındaki içerme ilişkisini çıkarmaz, listeyi sırayla okur. Bu eksik bilgi
altı isteği yanlış servise götürdü ve hiçbirinde bir hata kaydı doğmadı — istekler yanıtlandı,
yalnız yanlış yerden. Doğru sıra bir kez yazılınca çalışır, ama bir kural sonradan eklendiğinde
aynı bilgi yeniden gerekir. Bir kararı devretmek, o kararın dayandığı ilişkinin **her değişiklikte
yeniden bildirilmesini** zorunlu kılar. Bildirim bir kez yazılıp unutulan bir metin değil, kural
kümesi her büyüdüğünde yeniden gözden geçirilmesi gereken bir sıralamadır; altı kuralda gözle
görülen bu ilişki, on iki kuralda görünmez olur.

#### Özet

- Dışarıdan gelen istek dört katmandan geçer — dış dengeleyici, giriş kuralı, servis nesnesi,
  kapsül — ve her katman bir tur ekler; toplam dört turdur.
- Yol tabanlı ve ad tabanlı yönlendirmede toplam taranan kural sayısı aynıdır (beş buçuk); ayrım
  bir tasarruf değil, işin bir katmandan ötekine taşınmasıdır.
- Kural sayısı servis sayısına eşittir ve biçimden bağımsızdır; değişen, kuralların kaç ayrı dış
  uca dağıldığıdır.
- Dışa açılan yüzey üç serviste beşe dokuz, altı serviste sekize on sekiz, on iki serviste on dörde
  otuz altıdır; ad tabanlı biçimde dış uç ve kimlik kalemi servis sayısıyla birlikte büyür.
- Aynı altı kural, bildirim sırasında on iki isteğin altısını yanlış servise gönderdi; özgüllük
  sırasında hepsi doğru gitti. Yanlış eşleşmeler daha az kural tarayarak, yani daha hızlı oluştu.
- Giriş kuralı dört bildirim kalemi ister ve hiçbiri eskimez; bilmediği tek şey kurallar arasındaki
  kapsama ilişkisidir ve bu ilişki her yeni kuralda yeniden bildirilmelidir.

#### Sonraki Adım

Bu ders isteği kapsülün kapısına kadar getirdi. İçeride çalışan sürecin ise kapıya gelen istekten
başka ihtiyaçları vardır: hangi veri deposuna bağlanacağı, hangi eşiklerle çalışacağı, hangi
anahtarla kimlik doğrulayacağı. Bu değerler imajın içine yazılırsa üç ortam üç ayrı imaj demektir;
dışarıda tutulursa kümeye bildirilen yeni bir nesne demektir. Sonraki ders bu nesneleri ölçer: aynı
ayar kümesi iki farklı biçimde geçirildiğinde değişikliğin koşan kapsüle ne zaman yansıdığı, kaç
anahtarın hangi biçimde taşındığı ve gizli tutulması gereken değerlerin küme içinde kaç özneye
görünür olduğu.

### Yapılandırma ve Sır Nesneleri

Source: https://academia.sh/tr/kurslar/orkestrasyon/yapilandirma-ve-sir-nesneleri

Uygulama ayarlarının kümeden geçirilmesinin iki ölçüsü: aynı on dört anahtar ortam değişkeni ya da bağlanan dosya olarak geçirildiğinde değişikliğin kaç anahtar-tur gecikmeyle yansıdığı ve kaç tur kesinti ürettiği ve bir sır nesnesini küme içinde kaç öznenin okuyabildiği.

Önceki ders isteği kapsülün kapısına kadar getirdi. İçeride çalışan sürecin ise kapıya gelen
istekten başka ihtiyaçları vardır: hangi kayıt deposuna bağlanacağı, hangi eşikle doğrulama
yapacağı, hangi anahtarla fatura imzalayacağı. Bu değerler imajın içine yazılırsa üç ortam üç ayrı
imaj demektir — ve o zaman imajın taşınabilirliği, yani M22/K02'de ölçülen özellik, ortadan kalkar.
Dışarıda tutulursa kümeye bildirilen yeni bir nesne demektir.

Bu nesneler ikidir: açık değerleri taşıyan **yapılandırma nesnesi** ve gizli tutulması gereken
değerleri taşıyan **sır nesnesi**. İkisi de aynı işi yapar; ayrımları taşıdıkları değerin
görünürlüğüne dair bir beklentidir ve bu dersin ikinci yarısı o beklentinin ne kadar tuttuğunu
sayar. M22/K01'in **sızıntı yolu taraması** burada tekrarlanmaz; oradaki soru bir değerin nerelere
sızdığıydı, buradaki soru kümede kaç öznenin onu okumaya yetkili olduğudur. Ölçülen şey bir
modeldir; değerler kurgudur.

**TN25 — doğrulayıcı on dört ayar anahtarı okur**, dördü gizli tutulmalıdır. **TN26 — ortam
değişkeni olarak geçirilen ayar süreç başlarken bir kez okunur**; nesne değişse bile koşan süreç
eski değeri görmeye devam eder. **TN27 — dosya olarak bağlanan ayar üç tur sonra koşan kapsüle
yansır** ve süreç dosyayı yeniden okuduğu için yeniden başlatma gerekmez. **TN28 — yeniden
başlatma üç tur sürer** ve o üç turda kapsül hizmet vermez. **TN29 — bir nesneyi bağlayan kapsül,
o kapsülün koştuğu düğümdeki aracı süreç ve denetim düzleminin iki bileşeni nesneyi okuyabilir**;
son ikisi yetki kuralıyla kapatılamaz. **TN30 — yirmi dört turluk koşumda üç değişiklik olur:**
beşinci turda açık bir ayar, on ikinci turda gizli bir ayar, on dokuzuncu turda yine açık bir
ayar.

#### Aynı Ayar, İki Biçim

Aşağıdaki koşum aynı on dört anahtarı ve aynı üç değişikliği dört düzende geçiriyor. Ölçülen
büyüklük **bayat anahtar-tur**dur: koşan kapsülün gördüğü değerin nesnedeki değerden farklı olduğu
her anahtar, her tur için bir sayılır.

```js
// ayar.mjs — ayni ayar kumesinin iki bicimde gecirilmesi (MODEL). Degerler kurgudur.
export const TUR = 24, YAYILIM = 3, YENIDEN = 2;          // TN27, TN28

export const ANAHTAR = [
  ['toplayici-adresi', false], ['dogrulama-esigi', false], ['gunluk-duzeyi', false],
  ['yeniden-deneme', false], ['zaman-asimi-tur', false], ['toplu-is-boyutu', false],
  ['bolge-kodu', false], ['olcum-birimi', false], ['rapor-araligi', false],
  ['onbellek-omru', false], ['kayit-deposu-parolasi', true], ['fatura-imza-anahtari', true],
  ['is-emri-belirteci', true], ['ariza-bildirim-anahtari', true],
];                                                        // TN25: 14 anahtar, 4'u gizli

// Degisiklik cizelgesi: hangi turda hangi anahtarin degeri degisiyor.
const DEGISIM = { 5: 'dogrulama-esigi', 12: 'fatura-imza-anahtari', 19: 'zaman-asimi-tur' };

// TN26: ortam degiskeni surec baslarken bir kez okunur; dosya bicimi YAYILIM tur sonra yansir.
export function kosum(bicim, yenidenBaslat) {
  const nesne = {}, gorunen = {};
  for (const [a] of ANAHTAR) { nesne[a] = 'kurgu-deger-0'; gorunen[a] = 'kurgu-deger-0'; }
  const bekleyen = [];
  let bayat = 0, yeniden = 0, kesinti = 0, kesintiSonu = -1;
  for (let t = 0; t < TUR; t++) {
    const ad = DEGISIM[t];
    if (ad) {
      nesne[ad] = `kurgu-deger-${t}`;
      const b = bicim(ad);
      if (b === 'dosya') bekleyen.push({ ad, an: t + YAYILIM });
      else if (yenidenBaslat) {                           // ortam bicimi: yalniz yeniden baslatmayla
        yeniden++; kesintiSonu = t + YENIDEN;
        for (const [x] of ANAHTAR) bekleyen.push({ ad: x, an: t + YENIDEN });
      }
    }
    for (let i = bekleyen.length - 1; i >= 0; i--) {      // yansiyan bildirim kuyruktan cikar
      if (bekleyen[i].an <= t) { gorunen[bekleyen[i].ad] = nesne[bekleyen[i].ad]; bekleyen.splice(i, 1); }
    }
    bayat += ANAHTAR.filter(([a]) => gorunen[a] !== nesne[a]).length;
    if (t <= kesintiSonu) kesinti++;
  }
  const kalan = ANAHTAR.filter(([a]) => gorunen[a] !== nesne[a]).length;
  return { bayat, yeniden, kesinti, kalan };
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const s = (x, n) => String(x).padStart(n);
  const gizli = ANAHTAR.filter(([, g]) => g).length;
  console.log(`${ANAHTAR.length} anahtar (${gizli} gizli), ${TUR} tur, ${Object.keys(DEGISIM).length}`
    + ` degisiklik; yayilim ${YAYILIM} tur, yeniden baslatma ${YENIDEN} tur`);
  const BICIM = [
    ['hepsi ortam, yb yok', () => 'ortam', false, `${ANAHTAR.length}/0`],
    ['hepsi ortam, yb var', () => 'ortam', true, `${ANAHTAR.length}/0`],
    ['hepsi dosya', () => 'dosya', false, `0/${ANAHTAR.length}`],
    ['karma', (a) => (ANAHTAR.find(([x]) => x === a)[1] ? 'dosya' : 'ortam'), true,
      `${ANAHTAR.length - gizli}/${gizli}`],
  ];
  console.log(`${'bicim'.padEnd(22)}${s('ortam/dosya', 13)}${s('bayat anahtar-tur', 19)}`
    + `${s('yeniden baslatma', 18)}${s('kesinti turu', 14)}${s('sonda bayat', 13)}`);
  for (const [ad, f, yb, dagilim] of BICIM) {
    const r = kosum(f, yb);
    console.log(`${ad.padEnd(22)}${s(dagilim, 13)}${s(r.bayat, 19)}${s(r.yeniden, 18)}`
      + `${s(r.kesinti, 14)}${s(r.kalan, 13)}`);
  }
}
```

```
14 anahtar (4 gizli), 24 tur, 3 degisiklik; yayilim 3 tur, yeniden baslatma 2 tur
bicim                   ortam/dosya  bayat anahtar-tur  yeniden baslatma  kesinti turu  sonda bayat
hepsi ortam, yb yok            14/0                 36                 0             0            3
hepsi ortam, yb var            14/0                  6                 3             9            0
hepsi dosya                    0/14                  9                 0             0            0
karma                          10/4                  7                 2             6            0
```

Birinci satır ortam değişkeni biçiminin sessiz sonucudur. Hiçbir şey başarısız olmaz, hiçbir kesinti
yaşanmaz — ve koşumun sonunda üç anahtar hâlâ yanlış değerdedir. Otuz altı bayat anahtar-tur,
kimsenin fark etmediği bir sapmadır: nesne değişmiş, bildirim güncellenmiş, kapsül eski değerle
çalışmaya devam etmiştir. Bildirimsel bir sistemde en tehlikeli durum budur, çünkü istenen durum
ile gerçek durum arasındaki fark **uzlaştırıcının baktığı yerde değildir**; kopya sayısı doğrudur,
kapsüller ayaktadır, yalnız içlerindeki değer eskimiştir.

İkinci satır bu sapmayı kapatıyor ve faturayı kesiyor. Değişiklikte yeniden başlatma yapılırsa
bayat anahtar-tur otuz altıdan altıya iner, sonda bayat kalan sıfırdır — ama üç yeniden başlatma
ve **dokuz tur kesinti** doğar. Yirmi dört turun dokuzu, yani neredeyse yüzde kırkı, tek satırlık
bir ayar değişikliği yüzünden hizmet dışıdır. Bu bedelin kaynağı **TN26**'dır: ortam değişkeni
sürece bir kez, başlangıçta verilir ve onu güncellemenin süreç ömrü içinde bir yolu yoktur.

Üçüncü satır iki ölçüyü de aynı anda düşürüyor: dokuz bayat anahtar-tur, sıfır yeniden başlatma,
sıfır kesinti. Dosya olarak bağlanan ayar üç turluk bir yayılım gecikmesiyle koşan kapsüle ulaşır
ve süreç dosyayı yeniden okuduğu için ayakta kalır. Üç değişiklik üç kez üçer tur bayatlık üretti;
toplam dokuz. Bu, ikinci satırdaki altıdan üç fazladır — ama karşılığında dokuz turluk kesinti
ortadan kalkmıştır.

Dördüncü satır yaygın bir bölüşümü ölçüyor: gizli dört anahtar dosya, açık on anahtar ortam
değişkeni. Sonuç ikisinin ortasıdır — yedi bayat anahtar-tur, iki yeniden başlatma, altı tur
kesinti — ve tam olarak **üçüncü satırdan kötüdür.** Karma düzen her iki biçimin de bedelini öder:
açık ayarlar için kesinti, gizli ayarlar için yayılım gecikmesi. Bu bölüşümün gerekçesi yansıma
hızı değil, bir sonraki bölümde ölçülen görünürlüktür; ama tabloya bakan biri karma düzenin
kendiliğinden daha iyi olduğunu **söyleyemez**.

Dört satırın ortak dersi, sapmanın **nerede ölçüldüğüyle** ilgilidir. Kopya kümesi denetleyicisi
istenen sayı ile gerçek sayıyı karşılaştırır ve farkı kapatır; ayar değerleri o karşılaştırmanın
dışındadır. Nesnedeki değer ile koşan süreçteki değer arasındaki fark hiçbir denetleyicinin
baktığı yerde değildir, bu yüzden birinci satırda yirmi dört tur boyunca kimse bir şey fark etmez.
Bildirimsel bir sistemde uzlaştırılmayan her alan, sessizce sapabilen bir alandır.

#### Sır Nesnesinin Görünürlüğü

Gizli anahtarları ayrı bir nesne türünde tutmanın gerekçesi görünürlüktür. Bu bölüm o gerekçeyi
sayıya çeviriyor: aynı yetki şemasıyla, aynı kümede, bir sır nesnesini kaç özne okuyabiliyor.

```js
// gorunurluk.mjs — bir sir nesnesini kume icinde kac ozne okuyabiliyor (MODEL).
import { ANAHTAR } from './ayar.mjs';

// Kendi kucuk yetki semamiz: bir kural bir ozneye, bir nesne turu ve ad kalibi uzerinde fiil verir.
export const YETKI_SEMA = { ozne: 'metin', tur: 'metin|*', ad: 'metin|*', fiil: 'liste' };

const KAPSULLER = {                                       // hangi kapsul hangi dugumde kosuyor
  'dogrulayici-kapsulu': 'dugum-1', 'faturalama-kapsulu': 'dugum-2',
  'toplayici-kapsulu': 'dugum-3',
};
const BAGLAYAN = {                                        // hangi nesneyi hangi kapsuller bagliyor
  'fatura-imza-anahtari': ['dogrulayici-kapsulu', 'faturalama-kapsulu'],
  'dogrulama-esigi': ['dogrulayici-kapsulu', 'faturalama-kapsulu', 'toplayici-kapsulu'],
};
const DENETIM_DUZLEMI = ['durum-deposu', 'kume-arayuzu'];  // her iki nesneyi de tasir

const ROLLER = {
  genis: [
    { ozne: 'islet-rolu', tur: '*', ad: '*', fiil: ['oku', 'yaz'] },
    { ozne: 'gozlem-rolu', tur: '*', ad: '*', fiil: ['oku'] },
    { ozne: 'yayin-oznesi', tur: '*', ad: '*', fiil: ['oku', 'yaz'] },
    { ozne: 'yedekleme-oznesi', tur: '*', ad: '*', fiil: ['oku'] },
    { ozne: 'denetim-oznesi', tur: '*', ad: '*', fiil: ['oku'] },
  ],
  'en az': [
    { ozne: 'islet-rolu', tur: 'yapilandirma', ad: '*', fiil: ['oku', 'yaz'] },
    { ozne: 'gozlem-rolu', tur: 'yapilandirma', ad: '*', fiil: ['oku'] },
    { ozne: 'yayin-oznesi', tur: 'sir', ad: 'fatura-imza-anahtari', fiil: ['yaz'] },
    { ozne: 'yedekleme-oznesi', tur: 'yapilandirma', ad: '*', fiil: ['oku'] },
    { ozne: 'denetim-oznesi', tur: 'yapilandirma', ad: '*', fiil: ['oku'] },
  ],
};

export function okuyabilen(nesne, tur, politika) {
  const kapsul = BAGLAYAN[nesne] ?? [];
  const araci = [...new Set(kapsul.map((k) => `araci-${KAPSULLER[k]}`))];
  const rol = ROLLER[politika]
    .filter((r) => (r.tur === '*' || r.tur === tur) && (r.ad === '*' || r.ad === nesne)
      && r.fiil.includes('oku'))
    .map((r) => r.ozne);
  return { kapsul, rol, araci, duzlem: DENETIM_DUZLEMI };
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const s = (x, n) => String(x).padStart(n);
  const gizli = ANAHTAR.filter(([, g]) => g).length;
  console.log(`${ANAHTAR.length} anahtarin ${gizli} tanesi sir nesnesinde, ${ANAHTAR.length - gizli}`
    + ` tanesi yapilandirma nesnesinde; yetki semasi: ${Object.keys(YETKI_SEMA).join(', ')}`);
  console.log(`${'nesne'.padEnd(24)}${'tur'.padEnd(14)}${'politika'.padEnd(9)}${s('kapsul', 8)}`
    + `${s('rol', 5)}${s('araci surec', 13)}${s('denetim duzlemi', 17)}${s('toplam', 8)}`);
  for (const [nesne, tur] of [['fatura-imza-anahtari', 'sir'], ['dogrulama-esigi', 'yapilandirma']]) {
    for (const p of ['genis', 'en az']) {
      const r = okuyabilen(nesne, tur, p);
      const toplam = r.kapsul.length + r.rol.length + r.araci.length + r.duzlem.length;
      console.log(`${nesne.padEnd(24)}${tur.padEnd(14)}${p.padEnd(9)}${s(r.kapsul.length, 8)}`
        + `${s(r.rol.length, 5)}${s(r.araci.length, 13)}${s(r.duzlem.length, 17)}${s(toplam, 8)}`);
    }
  }
  const az = okuyabilen('fatura-imza-anahtari', 'sir', 'en az');
  console.log(`\nen az yetkide sir nesnesini okuyabilenler: ${[...az.kapsul, ...az.rol,
    ...az.araci, ...az.duzlem].join(', ')}`);
  console.log(`bunlarin ${az.araci.length + az.duzlem.length} tanesi yetki kuraliyla kaldirilamaz`);
}
```

```
14 anahtarin 4 tanesi sir nesnesinde, 10 tanesi yapilandirma nesnesinde; yetki semasi: ozne, tur, ad, fiil
nesne                   tur           politika   kapsul  rol  araci surec  denetim duzlemi  toplam
fatura-imza-anahtari    sir           genis           2    5            2                2      11
fatura-imza-anahtari    sir           en az           2    0            2                2       6
dogrulama-esigi         yapilandirma  genis           3    5            3                2      13
dogrulama-esigi         yapilandirma  en az           3    4            3                2      12

en az yetkide sir nesnesini okuyabilenler: dogrulayici-kapsulu, faturalama-kapsulu, araci-dugum-1, araci-dugum-2, durum-deposu, kume-arayuzu
bunlarin 4 tanesi yetki kuraliyla kaldirilamaz
```

İlk ve üçüncü satırlar birlikte okunmalıdır. Geniş yetki politikasında sır nesnesini on bir, açık
yapılandırma nesnesini on üç özne okuyabiliyor. Aradaki iki fark, sırrı bağlayan kapsülün bir eksik
olmasından geliyor — rol sayısı ikisinde de beştir. **Nesnenin türü sır olduğu için hiçbir rol
daralmadı.** Bu, bu bölümün ilk sonucudur: bir değeri sır nesnesine koymak, onu kimin okuyabildiğini
tek başına değiştirmez; değiştiren şey yetki kuralıdır ve o kural ayrıca yazılmalıdır.

İkinci satır kuralı yazınca ne olduğunu gösteriyor. En az yetkili politikada sır nesnesini okuyan
rol sayısı beşten sıfıra iner; toplam on birden altıya düşer. Aynı politikada yapılandırma nesnesi
on ikide kalır, çünkü açık ayarları okumak dört rolün işidir. İki nesne türü arasındaki asıl fark
burada doğar — türde değil, o türe yazılan kuralda.

Son iki satır ise daralmanın nerede durduğunu söylüyor. En az yetkide bile altı okuyucu vardır ve
dördü **yetki kuralıyla kaldırılamaz**: sırrı bağlayan kapsüllerin koştuğu iki düğümdeki aracı
süreçler ile denetim düzleminin iki bileşeni. Aracı süreç, kapsülün dosya alanını kurduğu için
değeri görmek zorundadır; durum deposu ile küme arayüzü nesneyi sakladıkları ve dağıttıkları için
görürler. Bir sır nesnesi kümeye yazıldığı anda bu dört okuyucu doğar ve hiçbir rol tanımı onları
azaltmaz. Sayı sıfıra inmez, **dörde iner.**

#### Devredilen Karar ve Bilmediği Şey

Devredilen karar burada **ayarın kapsüle nasıl ulaşacağıdır.** Daha önce bu karar imajı üreten
kişideydi: değer imajın içine yazılırdı ve her ortam için ayrı imaj üretilirdi. Karar kümeye
geçtiğinde sistemin bilmesi gereken üç bilgi kalemi doğar: hangi anahtarın hangi biçimde geçeceği,
değişikliğin ne kadar sürede yansıması gerektiği ve hangi anahtarın gizli sayılacağı. Üçü de
bildirimdir, ölçüm gerektirmez; maliyetleri yazılmalarında değil, **yanlış yazıldıklarında hiçbir
şeyin uyarmamasındadır.**

Sistemin bilmediği şey, sürecin ayarı ne zaman **okuduğudur**. Model bunu **TN26** ve **TN27** ile
varsayım hâline getirdi; gerçekte bunu bilen tek yer sürecin kendi kodudur ve küme oraya bakamaz.
Bu bilgisizliğin bedeli birinci tablonun ilk satırında duruyor: otuz altı bayat anahtar-tur ve
sonda üç yanlış değer, hiçbir hata kaydı üretmeden. Yeniden başlatma kararı da aynı bilgisizlikten
doğar — süreç dosyayı yeniden okusa gerekmeyecek olan dokuz turluk kesinti, okuyup okumadığı
bilinmediği için ödenir.

İkinci tabloda ise devretmenin **kazandırmadığı** bir alan görünüyor. Gizli değeri ayrı bir nesne
türüne taşımak, görünürlüğü on üçten on bire indirdi; asıl indirimi yapan yetki kuralı oldu ve o
kural insan tarafından yazıldı. Sistem hangi rolün hangi sırra gerçekten ihtiyacı olduğunu bilmez;
bunu bilebilmesi için her öznenin her nesneye erişimini gözlemesi ve kullanılmayanı düşürmesi
gerekirdi. Bilinmediği için varsayılan geniş kalır ve beş rol, ihtiyacı olmadığı hâlde okuma
yetkisini taşır.

#### Özet

- Aynı on dört anahtar dört düzende geçirildi. Ortam değişkeni biçiminde yeniden başlatma
  yapılmazsa otuz altı bayat anahtar-tur doğar ve koşumun sonunda üç anahtar hâlâ yanlış değerdedir;
  hiçbir hata kaydı üretilmez.
- Değişiklikte yeniden başlatmak bayat anahtar-turu altıya indirir ama üç yeniden başlatma ve yirmi
  dört turun dokuzunda kesinti üretir.
- Dosya olarak bağlama dokuz bayat anahtar-tur, sıfır yeniden başlatma ve sıfır kesinti verir;
  yayılım gecikmesi değişiklik başına üç turdur.
- Gizliyi dosya, açığı ortam değişkeni yapan karma düzen yedi bayat anahtar-tur ile altı tur kesinti
  üretir — her iki biçimin de bedelini öder ve yalnız dosya biçiminden kötüdür.
- Bir değeri sır nesnesine koymak görünürlüğü tek başına daraltmaz: geniş politikada beş rol her iki
  nesne türünü de okuyabiliyor; daraltan şey ayrıca yazılan yetki kuralıdır.
- En az yetkili politikada sır nesnesinin okuyucusu on birden altıya iner, ama sıfıra inmez: iki
  düğümdeki aracı süreç ile denetim düzleminin iki bileşeni yetki kuralıyla kaldırılamaz.

#### Sonraki Adım

Yapılandırma ve sır nesneleri kapsüle bir dosya alanı üzerinden ulaştı ve o alan kapsülle birlikte
doğup kapsülle birlikte öldü. Bu, ayarlar için doğru davranıştır: değer nesnede durur, kapsül
gittiğinde bir şey kaybolmaz. Uygulamanın **ürettiği** veri için ise aynı davranış bir veri kaybı
demektir. Kayıt deposu kapsülü yeniden başladığında sayaç okumaları da onunla gitmemelidir; oysa
bu konuda ölçülen her şey — kopya kümesinin sildiği kapsüller, geçişte kurulan yeni sürüm, devirle
gelip giden uç noktalar — kapsülün ömrünün kısa olduğunu varsaydı. Sonraki ders bu varsayımın
kırıldığı yeri ele alır: kapsülden uzun yaşayan bir veri alanının kümeye nasıl bildirildiği ve o
bildirimin taşıdığı yeni bilgi kalemleri.

### Depolama ve Birimler

Source: https://academia.sh/tr/kurslar/orkestrasyon/depolama-ve-birimler

Kalıcı birim talebi ile küme arzının eşlenmesi: uygulamanın bildirdiği boyut, erişim kipi ve başarım sınıfı karşısında kümenin sunduğu birim havuzu, karşılanamayan taleplerin nedene göre sayımı, bağlama kipinin yerleştirmeden elediği düğüm sayısı ve envanter bildirimi eskidiğinde ortaya çıkan yanlış bağlama.

Ayarlar kapsülün dışına çıktı: yapılandırma ve sır ayrı nesneler olarak duruyor, kapsül onları koşum
anında okuyor. Veri için aynı şey söylenemez. Kapsülün yazdığı her bayt hâlâ kapsülün ömrüne bağlı;
kapsül yeniden yaratıldığında yeni bir yazılabilir katmanla başlıyor ve dünkü iş durumu orada değil.

Tek makinede bu sorunun çözümü ölçülmüştü — veriyi yazılabilir katmanın dışına, adla anılan bir
birime ya da mutlak yolla anılan bir dizine çıkarmak — ve orada sayılan şey konteyner silindikten
sonra kalan bayttı. Kümede o sayı çözülmüş kabul edilir; sorulan soru başkadır. Kapsül hangi düğümde
açılırsa açılsın aynı baytları bulacaksa, o baytları tutan depolamanın **o düğümden erişilebilir**
olması gerekir. Bu, uygulamanın tek başına veremeyeceği bir karardır: uygulama ne istediğini bilir,
kümenin ne sunduğunu bilmez.

Devir burada ikiye bölünmüş bir bildirimle yapılır. Uygulama bir **kalıcı birim talebi** yazar; küme
bir **birim havuzu** bildirir; ikisini eşleyen şey bir **depolama sürücü arayüzü**dür. Bu ders üç
şeyi sayıyor: kaç talep karşılanamıyor ve neden, bağlama kipi yerleştirmeden kaç seçenek eliyor,
envanter bildirimi eskidiğinde kaç bağlama yanlış çıkıyor.

#### Talep, Arz ve Eşleme

Talep ve arz aynı sözlüğü kullanmak zorundadır. Uygulama üç kalem bildirir: ne kadar yer, hangi
erişim kipi, hangi başarım sınıfı. Küme her birim için dört kalem bildirir: boyut, sınıf,
desteklediği kipler ve topoloji. Eşleme kuralı üç karşılaştırmadan ibarettir; zor olan
karşılaştırma değil, iki tarafın da güncel bildirim yapmasıdır.

- **TN31** — Küme, birim havuzu, düğüm topolojisi ve envanter bildirimi `node` içinde kurulan bir
  modeldir; gerçek bir küme koşturulmuyor. Aşağıdaki sayılar modelin sayılarıdır.
- **TN32** — Ölçüm ağı kurgudur. On kalıcı birim talebi ağın servislerinden ve gecelik toplu
  işinden geliyor; adlar o kurgudan alınmıştır.
- **TN33** — Başarım sınıfları `hizli`, `standart`, `arsiv` ve `cok-hizli`; erişim kipleri tek
  düğüm yazar, çok düğüm okur, çok düğüm yazar.
- **TN34** — Küme altı düğüm ve iki bölgedir. Bir birim ya tek bir düğüme bağlıdır ya da bir
  bölgenin tamamına açıktır; üçüncü topoloji yok.
- **TN35** — Eskime taramasında havuz 24 birim, koşum 10 tur, tur başına dört talep gelir. Her tur
  iki birim küme dışındaki başka bir istekçiye bağlanır, bir birim serbest kalır.
- **TN36** — Rastgelelik doğrusal eşlenik üreteçle üretiliyor, tohum `20260801`. Üç envanter yaşı
  aynı havuz ve aynı talep dizisiyle koşuyor.

```js
// olcum/talep-arz.mjs — kalici birim talebi ile kume arzinin eslenmesi ve yerlestirme kisiti.
// MODEL: kume, birim havuzu, dugum topolojisi ve envanter bildirimi node icinde kurulan modeldir;
// gercek bir kume kosturulmuyor. Sayilar modelin sayilaridir.
const DUGUM = [["d1", "bolge-a"], ["d2", "bolge-a"], ["d3", "bolge-a"],
  ["d4", "bolge-b"], ["d5", "bolge-b"], ["d6", "bolge-b"]];

// talep: ad, boyut(Gi), erisim kipi, basarim sinifi  -> uygulamanin bildirdigi 3 kalem
const TALEP = [
  ["toplayici-durum", 20, "tek-yazar", "hizli"], ["dogrulayici-onbellek", 5, "tek-yazar", "standart"],
  ["faturalama-veri", 200, "tek-yazar", "hizli"], ["is-emri-veri", 50, "tek-yazar", "standart"],
  ["tarife-tablosu", 2, "cok-okur", "standart"], ["gecelik-cikti", 100, "cok-yazar", "standart"],
  ["arsiv-2025", 500, "cok-okur", "arsiv"], ["olcum-ham", 300, "tek-yazar", "hizli"],
  ["rapor-paylasim", 40, "cok-yazar", "hizli"], ["kapanis-defteri", 30, "tek-yazar", "cok-hizli"]];

// arz: ad, boyut(Gi), sinif, desteklenen kipler, bolge, bagli dugum (yoksa bolge geneli)
const ARZ = [
  ["b01", 30, "hizli", ["tek-yazar"], "bolge-a", "d1"], ["b02", 8, "standart", ["tek-yazar"], "bolge-a", "d2"],
  ["b03", 250, "hizli", ["tek-yazar"], "bolge-b", "d4"], ["b04", 60, "standart", ["tek-yazar"], "bolge-b", "d5"],
  ["b05", 4, "standart", ["tek-yazar", "cok-okur"], "bolge-a", null],
  ["b06", 120, "standart", ["tek-yazar"], "bolge-a", null], ["b07", 400, "arsiv", ["tek-yazar", "cok-okur"], "bolge-b", null],
  ["b08", 20, "hizli", ["tek-yazar"], "bolge-a", "d3"], ["b09", 512, "standart", ["tek-yazar", "cok-okur"], "bolge-b", null],
  ["b10", 50, "hizli", ["tek-yazar", "cok-okur", "cok-yazar"], "bolge-a", null]];

const uyar = (t, b) => b[1] >= t[1] && b[2] === t[3] && b[3].includes(t[2]);
function esle(kural) {                                        // kural: ilk-uyan | en-kucuk-uyan
  const bos = new Set(ARZ.map((b) => b[0])), sonuc = [];
  for (const t of TALEP) {
    const aday = ARZ.filter((b) => bos.has(b[0]) && uyar(t, b));
    if (aday.length) {
      const s = kural === "ilk-uyan" ? aday[0] : aday.reduce((a, b) => (b[1] < a[1] ? b : a));
      bos.delete(s[0]); sonuc.push([t, s, null]); continue;
    }
    const sinif = ARZ.some((b) => bos.has(b[0]) && b[2] === t[3]);
    const kip = ARZ.some((b) => bos.has(b[0]) && b[2] === t[3] && b[3].includes(t[2]));
    sonuc.push([t, null, !sinif ? "sinif yok" : !kip ? "kip yok" : "boyut yetmiyor"]);
  }
  return sonuc;
}

const A = esle("en-kucuk-uyan"), neden = {};
console.log(`${"talep".padEnd(22)}${"Gi".padStart(5)}${"kip".padStart(11)}${"sinif".padStart(10)}${"birim".padStart(7)}${"sonuc".padStart(16)}`);
for (const [t, b, n] of A) {
  if (n) neden[n] = (neden[n] || 0) + 1;
  console.log(`${t[0].padEnd(22)}${String(t[1]).padStart(5)}${t[2].padStart(11)}${t[3].padStart(10)}` +
    `${(b ? b[0] : "-").padStart(7)}${(b ? "baglandi" : n).padStart(16)}`);
}
const bagli = A.filter(([, b]) => b);
console.log(`${TALEP.length} talebin ${bagli.length} tanesi karsilandi, ${TALEP.length - bagli.length} tanesi karsilanmadi: ` +
  Object.entries(neden).map(([k, v]) => `${k} ${v}`).join(", "));
for (const k of ["ilk-uyan", "en-kucuk-uyan"]) {
  const r = esle(k).filter(([, b]) => b);
  console.log(`kural ${k.padEnd(15)} karsilanan ${r.length}  fazla ayrilan ${r.reduce((a, [t, b]) => a + b[1] - t[1], 0)} Gi`);
}

const uygunlar = (b) => DUGUM.filter(([d, bo]) => (b[5] ? d === b[5] : bo === b[4])).map(([d]) => d);
console.log(`\n${"talep".padEnd(22)}${"kip".padStart(11)}${"birim topolojisi".padStart(20)}${"uygun dugum".padStart(13)}${"elenen".padStart(8)}`);
let uygunTop = 0;
for (const [t, b] of bagli) {
  const u = uygunlar(b); uygunTop += u.length;
  console.log(`${t[0].padEnd(22)}${t[2].padStart(11)}${(b[5] ? `dugum ${b[5]}` : `bolge ${b[4]}`).padStart(20)}` +
    `${u.join(",").padStart(13)}${String(DUGUM.length - u.length).padStart(8)}`);
}
console.log(`kisitsiz ${bagli.length * DUGUM.length} yerlestirme secenegi vardi, ${uygunTop} tanesi kaldi; elenen ${bagli.length * DUGUM.length - uygunTop}`);
for (const k of ["tek-yazar", "cok-okur", "cok-yazar"]) {
  const g = bagli.filter(([t]) => t[2] === k); if (!g.length) continue;
  console.log(`kip ${k.padEnd(10)} talep ${g.length}  talep basina ortalama uygun dugum ` +
    `${(g.reduce((a, [, b]) => a + uygunlar(b).length, 0) / g.length).toFixed(2)}`);
}

// --- envanter eskimesi: karar eski bildirimle veriliyor ---
const TOHUM = 20260801;
let s = TOHUM % 2147483647;
const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;
const HAVUZ = 24, TUR = 10, TUR_TALEP = 4, DIS = 2;
const havuz = Array.from({ length: HAVUZ }, (_, i) => [`h${String(i + 1).padStart(2, "0")}`,
  [10, 40, 120, 400][Math.floor(rast() * 4)], ["hizli", "standart", "arsiv"][Math.floor(rast() * 3)]]);
const gelen = [];
for (let t = 0; t < TUR; t += 1)
  for (let i = 0; i < TUR_TALEP; i += 1)
    gelen.push([t, [10, 40, 120][Math.floor(rast() * 3)], ["hizli", "standart", "arsiv"][Math.floor(rast() * 3)]]);

function kosum(yas) {
  s = TOHUM % 2147483647; for (let i = 0; i < 3 * HAVUZ + 2 * gelen.length; i += 1) rast();
  const dolu = new Set(), gecmis = [], kuyruk = [];
  let dogru = 0, yanlis = 0, kararsiz = 0, bekleme = 0;
  for (let t = 0; t < TUR; t += 1) {
    gecmis.push(new Set(dolu));
    const envanter = yas === 0 ? dolu : gecmis[Math.max(0, t - yas)];
    kuyruk.push(...gelen.filter((g) => g[0] === t));
    for (const talep of kuyruk.splice(0, kuyruk.length)) {
      const aday = havuz.find((b) => !envanter.has(b[0]) && b[1] >= talep[1] && b[2] === talep[2]);
      if (!aday) { kararsiz += 1; kuyruk.push(talep); continue; }
      if (dolu.has(aday[0])) { yanlis += 1; kuyruk.push(talep); continue; }
      dolu.add(aday[0]); dogru += 1; bekleme += t - talep[0];
    }
    for (let i = 0; i < DIS; i += 1) {                        // baska bir istekci havuzdan birim baglar
      const bos = havuz.filter((b) => !dolu.has(b[0]));
      if (bos.length) dolu.add(bos[Math.floor(rast() * bos.length)][0]);
    }
    const d = [...dolu]; if (d.length) dolu.delete(d[Math.floor(rast() * d.length)]);
  }
  return { dogru, yanlis, kararsiz, bekleme, bekleyen: kuyruk.length };
}

console.log(`\n${"envanter yasi"}${"dogru".padStart(8)}${"yanlis baglama".padStart(16)}${"karar verememe".padStart(16)}` +
  `${"bekleyen".padStart(10)}${"ort. bekleme turu".padStart(19)}${"tur basina bildirim".padStart(21)}`);
for (const yas of [0, 1, 3]) {
  const r = kosum(yas);
  console.log(`${String(yas).padEnd(13)}${String(r.dogru).padStart(8)}${String(r.yanlis).padStart(16)}` +
    `${String(r.kararsiz).padStart(16)}${String(r.bekleyen).padStart(10)}${(r.bekleme / Math.max(1, r.dogru)).toFixed(2).padStart(19)}` +
    `${String(Math.round(HAVUZ * 3 / (yas + 1))).padStart(21)}`);
}
console.log(`bilgi kalemi: ${TALEP.length} talep x 3 + ${ARZ.length} birim x 4 + ${DUGUM.length} dugum x 1 = ` +
  `${TALEP.length * 3 + ARZ.length * 4 + DUGUM.length} kalem (tohum ${TOHUM})`);
```

```
talep                    Gi        kip     sinif  birim           sonuc
toplayici-durum          20  tek-yazar     hizli    b08        baglandi
dogrulayici-onbellek      5  tek-yazar  standart    b02        baglandi
faturalama-veri         200  tek-yazar     hizli    b03        baglandi
is-emri-veri             50  tek-yazar  standart    b04        baglandi
tarife-tablosu            2   cok-okur  standart    b05        baglandi
gecelik-cikti           100  cok-yazar  standart      -         kip yok
arsiv-2025              500   cok-okur     arsiv      -  boyut yetmiyor
olcum-ham               300  tek-yazar     hizli      -  boyut yetmiyor
rapor-paylasim           40  cok-yazar     hizli    b10        baglandi
kapanis-defteri          30  tek-yazar cok-hizli      -       sinif yok
10 talebin 6 tanesi karsilandi, 4 tanesi karsilanmadi: kip yok 1, boyut yetmiyor 2, sinif yok 1
kural ilk-uyan        karsilanan 6  fazla ayrilan 85 Gi
kural en-kucuk-uyan   karsilanan 6  fazla ayrilan 75 Gi

talep                         kip    birim topolojisi  uygun dugum  elenen
toplayici-durum         tek-yazar            dugum d3           d3       5
dogrulayici-onbellek    tek-yazar            dugum d2           d2       5
faturalama-veri         tek-yazar            dugum d4           d4       5
is-emri-veri            tek-yazar            dugum d5           d5       5
tarife-tablosu           cok-okur       bolge bolge-a     d1,d2,d3       3
rapor-paylasim          cok-yazar       bolge bolge-a     d1,d2,d3       3
kisitsiz 36 yerlestirme secenegi vardi, 10 tanesi kaldi; elenen 26
kip tek-yazar  talep 4  talep basina ortalama uygun dugum 1.00
kip cok-okur   talep 1  talep basina ortalama uygun dugum 3.00
kip cok-yazar  talep 1  talep basina ortalama uygun dugum 3.00

envanter yasi   dogru  yanlis baglama  karar verememe  bekleyen  ort. bekleme turu  tur basina bildirim
0                  21               0              80        19               0.33                   72
1                  15              86              44        25               1.93                   36
3                  10             134              33        30               3.20                   18
bilgi kalemi: 10 talep x 3 + 10 birim x 4 + 6 dugum x 1 = 76 kalem (tohum 20260801)
```

#### Karşılanamayan Talep: Dört Ret, Üç Neden

On talebin **altısı bağlandı, dördü karşılanmadı** ve ret nedenleri aynı sınıfta değil. Bir talep
**kip yok** dedi: gecelik toplu işin çıktısı için çok düğüm yazar kipinde bir birim isteniyor,
havuzda o boyutta ve o sınıfta birim var ama hiçbiri o kipi desteklemiyor. İki talep **boyut
yetmiyor** dedi: arşiv sınıfında yalnız 400 Gi'lik bir birim var, istenen 500 Gi; hızlı sınıfında
kalan en büyük birim 50 Gi, istenen 300 Gi. Bir talep **sınıf yok** dedi: `cok-hizli` diye bir sınıf
bildiren tek bir birim bile yok.

Bu üç neden aynı işi gerektirmiyor ve ayırmak devrin ilk kazancıdır. Boyut reddi bir kapasite
kararıdır: havuza daha büyük birim eklenir. Kip reddi bir **arayüz** kararıdır; hiçbir büyütme onu
çözmez, çünkü çok düğüm yazar kipini sunmak depolamanın kendi özelliğidir. Sınıf reddi ise bir
**sözlük** hatası olabilir: uygulama kümenin tanımadığı bir sınıf adı bildirmiştir. Karar
devredildiğinde ret gerekçesinin makine tarafından üretilmesi gerekiyor, yoksa talep yalnız
"bağlanmadı" der.

İkinci satır çifti seçim kuralının bedelini veriyor. İlk uyan birimi seçmekle yeterli olan en
küçüğü seçmek **karşılanan sayıyı değiştirmiyor**, ikisinde de altı; değişen şey israftır: 85 Gi'ye
karşı 75 Gi fazla ayırma. Büyük birimleri erken tüketen kural sonradan gelen büyük talepleri
karşılayamaz hâle gelir. Seçim kuralı bugünkü kararı değil **yarınki karşılanma oranını**
değiştiriyor ve sistem yarın hangi taleplerin geleceğini bilmiyor.

#### Bağlama Kipi: Yerleştirmeden Elenen Düğümler

İkinci tablo, depolama kararının aslında bir **yerleştirme** kararı olduğunu gösteriyor. Bağlanan
altı talep için altı düğümlük kümede 36 yerleştirme seçeneği vardı; kip ve topoloji birlikte
bunların **26 tanesini eledi**, geriye 10 seçenek kaldı.

Eleme kipe göre keskin biçimde ayrışıyor. Tek düğüm yazar kipindeki dört talebin birimi belirli bir
düğüme bağlı; her biri için **tek bir uygun düğüm** kalıyor, beşi eleniyor. Çok düğüm okur ve çok
düğüm yazar kipindeki iki talebin birimi bölge geneline açık; onlar için üç düğüm uygun, üçü
eleniyor. Ortalama uygun düğüm sayısı tek yazar kipinde 1,00, ötekilerde 3,00.

Bunun sonucu, yerleştirmenin ilk sorusunun artık "hangi düğümde yer var" olmamasıdır. Kapsül tek
düğüm yazar kipinde bir birim istediği anda düğüm zaten seçilmiştir; kalan tek soru o düğümde
yeterli işlemci ve bellek bulunup bulunmadığıdır, bulunmazsa yerleştirme **çözümsüz** kalır ve başka
düğüme kaçış yoktur. Devredilen karar iki sistemi birden bağlıyor: depolama eşlemesi zamanlayıcının
seçim uzayını daraltıyor, zamanlayıcı da bu daralmayı bilmek zorunda. Bilmezse kapsülü uygun olmayan
bir düğüme koyar, birim bağlanmaz, kapsül açılmaz.

Ölçüm ağında ayrım okunabilir bir kurala dönüşüyor: tarife tablosu bütün doğrulayıcı kopyalarınca
okunduğu için çok düğüm okur kipiyle bildiriliyor ve üç düğüm uygun kalıyor; iş emri verisini tek
bir yazar tuttuğu için tek yazar kipi onu bir düğüme çiviliyor.

#### Envanterin Yaşı ve Yanlış Bağlama

Üçüncü tablo devrin asıl bedelini veriyor. Eşleme kararı **bildirilmiş bir envantere** dayanıyor ve
o envanter bir andan sonra gerçeği anlatmıyor.

Envanter yaşı sıfırken — yani karar anında havuzun gerçek doluluğu okunuyorken — **yanlış bağlama
yok**: 21 talep doğru bağlandı, ortalama bekleme 0,33 tur. Yaş bir tura çıktığında doğru bağlama 15'e
düşüyor ve **86 yanlış bağlama** ortaya çıkıyor: sistem envanterde boş görünen bir birimi seçiyor,
bağlama anında birimin dolu olduğu anlaşılıyor, talep kuyruğa dönüyor ve bir sonraki turda yeniden
deneniyor. Yaş üç tura çıktığında doğru bağlama 10'a, yanlış bağlama 134'e gidiyor; ortalama bekleme
0,33 turdan 3,20 tura çıkıyor ve koşum sonunda hâlâ bekleyen talep sayısı 19'dan 30'a yükseliyor.

Karar verememe sütunu ters yönde hareket ediyor ve bu ilk bakışta yanıltıcıdır: 80'den 33'e iniyor.
Sayı iyileşmiyor — eski envanterde havuz **olduğundan boş** göründüğü için sistem "uygun birim yok"
demeyi bırakıp yanlış birim seçmeye başlıyor. Yani gecikmiş bilgi bir karar sınıfını başka bir karar
sınıfına çeviriyor: dürüst bir "bilmiyorum" yerine yanlış bir "buldum" üretiyor. İkincisi daha
pahalıdır, çünkü bağlama denemesi yapılıyor, başarısız oluyor ve tur harcanıyor.

Son sütun bedelin öbür ucudur. Yaş sıfırı sürdürmek tur başına 72 bildirim kalemi ister — havuzdaki
24 birimin üç kaleminin her turda yeniden okunması. Yaş üçte bu sayı 18'e iniyor, bildirim yükü
dörtte bire düşüyor ve karşılığında yanlış bağlama sıfırdan 134'e çıkıyor. Bu ders için devrin
bedeli tek satırda söylenebilir: eşleme kararının dayandığı **76 bilgi kalemi** (10 talep × 3, 10
birim × 4, 6 düğüm × 1) sürekli ve zamanında üretilmezse, karar mekanizması değişmediği hâlde sonuç
bozulur. Sistemin bilmediği şey birimin kim tarafından ne zaman bağlandığıdır; bilmediği için
yaptığı şey, dolu bir birime bağlanmayı denemektir.

#### Özet

- Talep ve arz ayrı bildirimlerdir: uygulama üç kalem, küme birim başına dört kalem bildirir;
  eşlemeyi depolama sürücü arayüzü yapar.
- On talebin altısı karşılandı, dördü karşılanmadı ve nedenler ayrı sınıflardadır: boyut 2, kip 1,
  sınıf 1. Boyut bir kapasite kararı, kip bir arayüz kararı, sınıf bir sözlük hatasıdır.
- Seçim kuralı karşılanan talep sayısını değiştirmiyor (ikisinde de 6), fazla ayrılan yeri
  değiştiriyor: ilk uyan 85 Gi, en küçük uyan 75 Gi.
- Bağlama kipi bir yerleştirme kısıtıdır: 36 seçeneğin 26'sı elendi. Tek düğüm yazar kipinde talep
  başına ortalama 1,00 uygun düğüm kalıyor, çok düğüm kiplerinde 3,00.
- Envanter yaşı 0 → 1 → 3 tur arttıkça doğru bağlama 21 → 15 → 10, yanlış bağlama 0 → 86 → 134,
  ortalama bekleme 0,33 → 1,93 → 3,20 tur. Bildirim yükü tur başına 72 → 36 → 18 kaleme iniyor.
- Gecikmiş bilgi "karar verememe"yi (80 → 33) "yanlış karar"a çeviriyor: ucuz bilinmezlik yerine
  pahalı yanlış bağlama üretiliyor.

#### Sonraki Adım

Kalıcı veri kümede yerini buldu: talep bildiriliyor, arz eşleniyor, kapsül birimin erişilebildiği
düğümde açılıyor. Ölçülen her şey **tek bir talep ile tek bir birim** arasındaydı. Oysa gecelik
toplu işi besleyen doğrulayıcı tek kopya değil; üç kopya koşuyor ve her kopyanın kendi verisi var.
Kopya kümesi kopyaları birbirinin yerine geçebilir sayar, adlarını da kalıcı tutmaz — o zaman bir
kopya yeniden başladığında hangi birime bağlanacağını ne söyleyecek, ölçek küçültülünce hangi
kopyanın verisi öksüz kalacak? Sonraki ders sıralı kimlik veren bir nesneyi sırasız kopya kümesiyle
aynı olayda karşılaştırıyor ve şunları sayıyor: yeniden başlatmada kaç kopya aynı birime döndü,
ölçek küçültmede hangi kopya gitti, sıralı başlatmanın tur maliyeti ne ve sıraya uyulmadığında küme
üyeliğiyle veri sahipliği nasıl bozuluyor.

### Durum Bilgili Uygulamalar

Source: https://academia.sh/tr/kurslar/orkestrasyon/durum-bilgili-uygulamalar

Sıralı kimlik ve kalıcı depolamanın birlikte ölçülmesi: sıralı küme ile sırasız kopya kümesi aynı altı olaylık dizide karşılaştırılır, kopya adının ve birim bağının kalıcılığı sayılır, sıralı başlatma ile durdurmanın tur maliyeti taranır ve sıraya uyulmadığında küme üyeliğiyle veri sahipliğinin nasıl bozulduğu modellenir.

Kalıcı birim talebi kapsülün verisini kapsülden uzun yaşatıyor. Bu, tek bir talep ile tek bir birim
arasındaki bağ için yeterli. Ölçüm ağının doğrulayıcısı ise tek kopya değil: beş kopya koşuyor, her
kopyanın kendi 40 Gi'lik verisi var ve kopyalar bu veriyi birbirinin yerine geçerek sunamıyor.
Kopya bir sayaç aralığının sahibi; o aralığın verisi onun biriminde.

Kopya kümesi bu varsayımın tam tersini kurar. Onun için kopyalar **birbirinin yerine geçebilir**;
adları koşum boyunca kalıcı değildir, çünkü ada bağlı hiçbir şey olmaması gerekir. Ada bağlı bir
birim ortaya çıktığı anda bu varsayım bozulur: yeniden yaratılan kopyanın adı değişmişse hangi
birime bağlanacağını söyleyecek bir bilgi kalmaz.

Bu ders devredilen kararı şöyle adlandırıyor: **hangi kopya hangi veriye sahiptir ve yeniden
yaratıldığında nereye bağlanır**. Kararı verecek sistemin kopya başına üç kalem bilmesi gerekiyor —
sıra numarası, birim bağı, hazır olma durumu. Sayılan üç şey: aynı olay dizisinde iki nesne kaç
öksüz birim bırakıyor, sıralı başlatmanın tur maliyeti ne, sıraya uyulmadığında ne bozuluyor.

#### Aynı Olay Dizisi, İki Nesne

İki nesne aynı altı olaydan geçiyor: kurulum, düğüm arızası, yeniden yaratma, ölçek küçültme, tam
yeniden başlatma, ölçek büyütme. Karşılaştırma yalnız bu dizinin sonunda anlam kazanıyor; tek bir
olayda ikisi de aynı görünür.

- **TN37** — Kopyalar, birimler, küme üyeliği ve parça sahipliği `node` içinde kurulan bir
  modeldir; gerçek bir küme koşturulmuyor.
- **TN38** — Ölçüm ağı kurgudur. Doğrulayıcı beş kopya koşuyor, her kopyanın 40 Gi'lik kendi birimi
  var ve üç düğüme sırayla yerleşiyorlar.
- **TN39** — Sıralı kümede kopya adı sıra numarasından türüyor ve birim talebi ada bağlı; kopya
  kümesinde ad her yaratımda yeniden üretiliyor ve her yeni ad yeni bir birim talebi doğuruyor.
- **TN40** — Ölçek küçültmede sıralı küme en yüksek sıra numarasını kaldırıyor; kopya kümesinde
  giden kopya üreteçle seçiliyor. Kaldırılan kopyanın birimi silinmiyor, sahipsiz kalıyor.
- **TN41** — Hazır olma süreleri 1–3 tur arasında üreteçle veriliyor. Sıralı başlatmada her kopya
  öncekinin hazır olmasını bekliyor, durdurma ters sırada ve kopya başına bir tur.
- **TN42** — Üyelik modeli: sıra sıfır tohumdur, tohum açık değilken açılan kopya kendi üyeliğini
  kurar ve sonradan birleşme yoktur. Parça sahipliği her üyelik içinde `parça mod üye sayısı` ile
  dağıtılıyor; parça `p`'nin verisi fiziksel olarak sıra `p mod 5`'in birimindedir. Tohum
  `20260807`.

```js
// olcum/kimlik.mjs — sirali kume ile sirasiz kopya kumesi ayni olay dizisinde.
// MODEL: kopyalar, birimler, uyelik ve parca sahipligi node icinde kurulan modeldir; gercek bir
// kume kosturulmuyor. Sayilar modelin sayilaridir.
const N = 5, DUGUM = ["d1", "d2", "d3"], PARCA = 12, TOHUM = 20260807;
let s = TOHUM % 2147483647;
const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;
const ek = () => Array.from({ length: 4 }, () => "abcdefghijklmnopqrstuvwxyz"[Math.floor(rast() * 26)]).join("");

function kosum(tur) {
  const birim = new Map();                     // birim adi -> sahip kopya adi (bos ise null)
  let kopya = [], kayit = [];
  const yarat = (sira) => {
    const ad = tur === "sirali" ? `dgr-${sira}` : `dgr-${ek()}`;
    const b = `veri-${ad}`, vardi = birim.has(b);
    birim.set(b, ad);
    return { sira, ad, birim: b, vardi, dugum: DUGUM[sira % DUGUM.length] };
  };
  const sil = (k) => { birim.set(k.birim, null); kopya = kopya.filter((x) => x !== k); };
  const olay = (etiket, yeni) => {
    const oksuz = [...birim.values()].filter((v) => v === null).length;
    kayit.push([etiket, yeni.length, yeni.filter((k) => k.vardi).length, kopya.length, oksuz]);
  };
  let y = Array.from({ length: N }, (_, i) => yarat(i)); kopya = [...y]; olay("ilk kurulum", y);
  for (const k of kopya.filter((k) => k.dugum === "d2")) sil(k); olay("dugum d2 arizasi", []);
  const eksik = [0, 1, 2, 3, 4].filter((i) => !kopya.some((k) => k.sira === i));
  y = eksik.map((i) => yarat(i)); kopya.push(...y); olay("yeniden yaratma", y);
  for (let i = 0; i < 2; i += 1) {             // olcek 5 -> 3
    const aday = tur === "sirali" ? kopya.reduce((a, b) => (b.sira > a.sira ? b : a))
      : kopya[Math.floor(rast() * kopya.length)];
    sil(aday);
  }
  const kalanSira = kopya.map((k) => k.sira).sort();
  olay(`olcek 5->3 (giden ${[0, 1, 2, 3, 4].filter((i) => !kalanSira.includes(i)).join(",")})`, []);
  const eski = [...kopya]; for (const k of eski) sil(k);
  y = eski.map((k) => yarat(k.sira)); kopya = [...y]; olay("tam yeniden baslatma", y);
  const bos = [0, 1, 2, 3, 4].filter((i) => !kopya.some((k) => k.sira === i)).slice(0, 2);
  y = bos.map((i) => yarat(i)); kopya.push(...y); olay("olcek 3->5", y);
  return { kayit, oksuz: [...birim.values()].filter((v) => v === null).length, birim: birim.size };
}

console.log(`${"olay".padEnd(26)}${"nesne".padStart(13)}${"yaratilan".padStart(11)}${"eski birime donen".padStart(19)}${"acik kopya".padStart(12)}${"oksuz birim".padStart(13)}`);
for (const tur of ["sirali", "sirasiz"]) {
  const r = kosum(tur);
  for (const [e, yaratilan, donen, acik, oksuz] of r.kayit)
    console.log(`${e.padEnd(26)}${(tur === "sirali" ? "sirali kume" : "kopya kumesi").padStart(13)}` +
      `${String(yaratilan).padStart(11)}${String(donen).padStart(19)}${String(acik).padStart(12)}${String(oksuz).padStart(13)}`);
  console.log(`  -> ${tur}: toplam ${r.birim} birim yaratildi, ${r.oksuz} tanesi oksuz (${r.oksuz * 40} Gi sahipsiz)`);
}

// --- sirali baslatma ve durdurmanin tur maliyeti ---
console.log(`\n${"kopya".padEnd(7)}${"hazir olma turlari".padStart(20)}${"sirali baslatma".padStart(17)}${"paralel".padStart(9)}${"sirali durdurma".padStart(17)}${"paralel".padStart(9)}${"fark".padStart(7)}`);
s = TOHUM % 2147483647;
for (const n of [3, 5, 9]) {
  const hazir = Array.from({ length: n }, () => 1 + Math.floor(rast() * 3));
  const sb = hazir.reduce((a, b) => a + b, 0), pb = Math.max(...hazir);
  console.log(`${String(n).padEnd(7)}${hazir.join(",").padStart(20)}${String(sb).padStart(17)}${String(pb).padStart(9)}` +
    `${String(n).padStart(17)}${String(1).padStart(9)}${String(sb + n - pb - 1).padStart(7)}`);
}

// --- siraya uyulmadiginda: kume uyeligi ve veri sahipligi ---
function uyelik(sira) {
  const gruplar = [];
  for (const i of sira) {
    const tohumlu = gruplar.find((g) => g.includes(0));
    if (i === 0 || !tohumlu) gruplar.push([i]); else tohumlu.push(i);
  }
  const iddia = Array.from({ length: PARCA }, () => []);
  for (const g of gruplar) for (let p = 0; p < PARCA; p += 1) iddia[p].push(g[p % g.length]);
  return {
    uyelik: gruplar.length,
    cift: iddia.filter((a) => a.length > 1).length,
    yanlis: iddia.reduce((a, l, p) => a + l.filter((k) => k !== p % N).length, 0),
    verisiz: iddia.filter((a, p) => !a.includes(p % N)).length,
  };
}
console.log(`\n${"baslatma sirasi".padEnd(18)}${"uyelik".padStart(8)}${"cift iddia edilen".padStart(19)}${"yanlis iddia".padStart(14)}${"verisiz sunulan".padStart(17)}`);
const siralar = [[0, 1, 2, 3, 4]];
for (let i = 0; i < 3; i += 1) {
  const p = [0, 1, 2, 3, 4];
  for (let j = p.length - 1; j > 0; j -= 1) { const k = Math.floor(rast() * (j + 1)); [p[j], p[k]] = [p[k], p[j]]; }
  siralar.push(p);
}
for (const sira of siralar) {
  const r = uyelik(sira);
  console.log(`${sira.join(",").padEnd(18)}${String(r.uyelik).padStart(8)}${String(r.cift).padStart(19)}` +
    `${String(r.yanlis).padStart(14)}${String(r.verisiz).padStart(17)}`);
}
console.log(`${PARCA} parca, ${N} kopya, tohum ${TOHUM}; bilgi kalemi: kopya basina 3 (sira, birim bagi, hazir olma) = ${N * 3}`);
```

```
olay                              nesne  yaratilan  eski birime donen  acik kopya  oksuz birim
ilk kurulum                 sirali kume          5                  0           5            0
dugum d2 arizasi            sirali kume          0                  0           3            2
yeniden yaratma             sirali kume          2                  2           5            0
olcek 5->3 (giden 3,4)      sirali kume          0                  0           3            2
tam yeniden baslatma        sirali kume          3                  3           3            2
olcek 3->5                  sirali kume          2                  2           5            0
  -> sirali: toplam 5 birim yaratildi, 0 tanesi oksuz (0 Gi sahipsiz)
ilk kurulum                kopya kumesi          5                  0           5            0
dugum d2 arizasi           kopya kumesi          0                  0           3            2
yeniden yaratma            kopya kumesi          2                  0           5            2
olcek 5->3 (giden 0,1)     kopya kumesi          0                  0           3            4
tam yeniden baslatma       kopya kumesi          3                  0           3            7
olcek 3->5                 kopya kumesi          2                  0           5            7
  -> sirasiz: toplam 12 birim yaratildi, 7 tanesi oksuz (280 Gi sahipsiz)

kopya    hazir olma turlari  sirali baslatma  paralel  sirali durdurma  paralel   fark
3                     2,1,1                4        2                3        1      4
5                 1,2,3,3,1               10        3                5        1     11
9         1,1,1,1,2,3,1,1,1               12        3                9        1     17

baslatma sirasi     uyelik  cift iddia edilen  yanlis iddia  verisiz sunulan
0,1,2,3,4                1                  0             0                0
2,1,0,3,4                3                 12            30                6
1,4,3,0,2                4                 12            38                2
0,1,2,4,3                1                  0             4                4
12 parca, 5 kopya, tohum 20260807; bilgi kalemi: kopya basina 3 (sira, birim bagi, hazir olma) = 15
```

#### Ad Kalıcı mı, Birim Geri Geliyor mu

İlk tablonun ilk iki satırı iki nesnede aynı: beş kopya kuruldu, `d2` düştü, iki kopya gitti, iki
birim öksüz kaldı. Ayrışma **yeniden yaratma** satırında başlıyor. Sıralı küme eksik iki sıra
numarasını gördüğü için aynı iki adı yeniden üretiyor; ad aynı olduğu için birim talebi de aynı ve
**iki kopya da eski birimine dönüyor**, öksüz sayısı sıfıra iniyor. Kopya kümesi iki yeni ad
üretiyor; yeni ad yeni talep doğuruyor, eski birime dönen kopya sayısı **sıfır** ve iki öksüz birim
yerinde duruyor.

Ölçek küçültmede giden kopyaların kimliği de ayrı. Sıralı kümede giden kopyalar `3` ve `4` — en
yüksek iki sıra ve bu kural koşumdan koşuma değişmez. Kopya kümesinde giden kopyalar `0` ve `1`
oldu; seçim üretecin verdiği sıradandır ve başka bir koşumda başka bir çift gider. Fark yalnız hangi
kopyanın gittiği değil: sıralı kümede küçültmenin hangi veriyi kenara koyduğu **önceden bilinir**,
büyütme geldiğinde aynı iki kopya aynı iki birime döner. Tabloda bu, son satırdaki `2` sayısıdır.

Dizinin sonundaki iki satır özeti veriyor. Sıralı küme boyunca **5 birim** yaratıldı ve sonunda
öksüz kalan **0**. Kopya kümesi aynı olaylarda **12 birim** yarattı ve **7'si öksüz** kaldı — 280
Gi'lik veri, hiçbir kopyanın bağlanmadığı birimlerde duruyor. Bu veri kaybolmuş değil; kaybolan şey
ona ulaşacak **ad**. Kimlik kalıcı olmayınca kalıcı depolamanın kendisi de erişilemez hâle geliyor:
kalıcılık ve kimlik ayrı ayrı çözülebilen sorunlar değil.

Yedi öksüz birimin ikinci bir bedeli daha var. Onları silecek bir yaşam döngüsü yok — kopya
gittiğinde birim durur, çünkü içindeki veri değerli olabilir. Karar bir insana kalır ve o insanın
`veri-dgr-qxlm` gibi bir adın hangi geceye, hangi sayaç aralığına ait olduğunu bilmesi gerekir. Ad
kalıcı olmadığı için bu bilgi hiçbir yerde durmuyor; kalan tek seçenek birimi açıp içine bakmaktır.
Sıralı kümede aynı soru sorulmaz, çünkü `veri-dgr-3` adı zaten yanıtı taşır.

#### Sıralı Başlatmanın Tur Maliyeti

İkinci tablo, sıralı kimliğin karşılığında ödenen bedeli veriyor. Sıralı küme kopyaları teker teker
açar; her kopya bir öncekinin hazır olma denetiminden geçmesini bekler. Durdurma ters sırada, yine
teker teker.

Beş kopyada hazır olma süreleri 1, 2, 3, 3, 1 tur. Sıralı başlatma bunların toplamı olan **10 tur**
sürüyor; hepsi aynı anda açılsaydı en yavaş kopyanın süresi olan **3 tur** yeterdi. Durdurma sıralı
5 tur, paralel 1 tur. İki uçtaki toplam fark **11 tur**. Dokuz kopyada başlatma 12 tura, durdurma 9
tura çıkıyor, fark **17 tur**. Ölçek büyüdükçe fark toplama göre büyüyor: paralel maliyet en yavaş
kopyaya bağlı kalırken sıralı maliyet kopya sayısıyla doğrusal artıyor.

Bu bedel bir bilgi bedelidir. Sistemin sırayı uygulayabilmesi için her adımda "önceki kopya gerçekten
hazır mı" sorusunu yanıtlaması gerekiyor ve bu yanıt bir denetimden geliyor. Denetim gevşetilirse tur
kazanılır, ama sıra güvencesi de kaybedilir — sonraki tablo bunun ne demek olduğunu sayıyor.

Bedelin karşılıksız kaldığı bir durum da var ve onu adlandırmak gerekiyor. Sıra, kopyalar arasında
bir **kuruluş bağımlılığı** olduğu için ödenir: biri tohum, ötekiler ona katılır. Kopyaların
birbirinden haberi olmayan bir uygulamada böyle bir bağımlılık yoktur; o durumda beş kopya için
ödenen 11 tur hiçbir şey satın almaz, yalnız yayın penceresini uzatır. Ölçüm ağında ayrım nettir:
doğrulayıcı kopyaları ortak bir üyelik kurar, okuma toplayıcının kopyaları kurmaz — biri sıralı
küme ister, öteki istemez.

#### Sıra Bozulunca: Üyelik ve Sahiplik

Üçüncü tablo iki ayrı bozulmayı ayırıyor. Doğru sırada — `0,1,2,3,4` — tek üyelik kuruluyor, çift
iddia edilen parça yok, yanlış iddia yok, verisiz sunulan parça yok.

`2,1,0,3,4` sırasında tohum üçüncü sırada açılıyor. Ondan önce açılan iki kopya tohumu bulamayınca
kendi üyeliklerini kuruyor: **üç ayrı üyelik**. Her üyelik 12 parçayı kendi üye sayısına göre
dağıttığı için **12 parçanın hepsi çift iddia ediliyor** ve 30 iddia yanlış kopyaya düşüyor. Altı
parça, verisi kendisinde olmayan kopyalar tarafından sunuluyor. `1,4,3,0,2` sırasında bölünme dörde
çıkıyor ve yanlış iddia 38'e yükseliyor.

Son satır en sinsi durumdur ve tek başına okunmalıdır. `0,1,2,4,3` sırasında tohum en başta açılıyor,
**üyelik bölünmüyor** — tek üyelik, çift iddia sıfır. Buna rağmen dört parça verisi olmayan bir
kopyaya düşüyor, çünkü sahiplik dağıtımı **katılma sırasına** göre yapılıyor ve `4` ile `3` yer
değiştirmiş. Yani sıra ihlali iki farklı arıza üretiyor: gözle görülür olanı üyeliğin bölünmesi,
görülmeyeni sahipliğin kaymasıdır. İkincisinde küme sağlıklı görünür, sorgular yanıtlanır, yalnız
dört parçanın yanıtı yanlış kopyadan gelir.

Devrin bedeli burada tek satırda toplanıyor: karar kopya başına üç kaleme dayanıyor — sıra numarası,
birim bağı, hazır olma durumu; beş kopya için **15 kalem**. Bu kalemlerin hepsi doğru ve zamanında
üretilirse öksüz birim 0, üyelik 1, yanlış iddia 0. Sıra numarası kalemi düşerse 7 öksüz birim, hazır
olma kalemi düşerse bölünmüş üyelik ve kayan sahiplik ortaya çıkıyor.

#### Özet

- Aynı altı olayda sıralı küme 5 birim yaratıp 0'ını öksüz bırakıyor; kopya kümesi 12 birim yaratıp
  7'sini öksüz bırakıyor (280 Gi sahipsiz veri).
- Ad kalıcılığı birim bağının önkoşuludur: yeniden yaratmada sıralı kümede 2 kopyanın 2'si eski
  birimine döndü, kopya kümesinde 0'ı döndü.
- Ölçek küçültmede sıralı küme en yüksek sırayı kaldırıyor (3 ve 4) ve büyütmede aynı iki kopya
  aynı birimlere geri dönüyor; kopya kümesinde giden çift (0 ve 1) koşuma bağlı ve geri dönüş yok.
- Sıralı başlatmanın bedeli tur cinsindendir: beş kopyada 10 tura karşı 3 tur, dokuz kopyada 12 tura
  karşı 3 tur; durdurmayla birlikte toplam fark 11 ve 17 tur.
- Sıra ihlali iki ayrı arıza üretiyor: tohum geç açılınca üyelik 3–4'e bölünüyor ve 12 parçanın
  hepsi çift iddia ediliyor; tohum erken açılıp katılma sırası bozulunca üyelik tek kalıyor ama 4
  parça verisi olmayan kopyaya düşüyor.
- Karar kopya başına üç kaleme dayanıyor (sıra, birim bağı, hazır olma); beş kopya için 15 kalem.

#### Sonraki Adım

Sıralı küme ile kopya kümesi arasındaki fark ölçüldü ve ikisinin de ortak bir varsayımı var:
kapsüller **bitmez**. Kopya sayısı istenen değere getirilir ve orada tutulur; bir kapsül sonlanırsa
bu bir arızadır ve yeniden başlatılır. Ölçüm ağının gecelik toplu işi bu varsayıma uymuyor. O iş
başlar, günün okumalarını doğrular, faturalama girdisini üretir ve **biter** — bitmesi beklenen
davranıştır, arıza değil. Bittiğini kim, neye bakarak söyleyecek; bitmezse kaç kez denenecek; her
gece aynı saatte başlaması gerekiyorsa o saati kim koruyacak? Sonraki ders bir kerelik ve yinelenen
görevleri iki ayrı nesneyle kurup şunları sayıyor: tamamlanma güvencesi kaç denemeye mal oluyor,
paralellik ile tamamlanma sayısı ayarları hangi sonucu veriyor, kaçırılan koşumda ne oluyor ve
önceki koşum bitmeden yenisi geldiğinde üç politika birbirinden nasıl ayrılıyor.

### İşler ve Zamanlanmış İşler

Source: https://academia.sh/tr/kurslar/orkestrasyon/isler-ve-zamanlanmis-isler

Bitmesi beklenen görevlerin küme nesnesiyle modellenmesi: iş nesnesinin tamamlanma güvencesi deneme sınırına göre sayılır, paralellik ile tamamlanma sayısı ayarlarının tur ve boş yuva sonuçları taranır, zamanlanmış işte kaçırılan koşum ölçülür ve üst üste binme için atla, sıraya al ve paralel koş politikaları ayrı ayrı karşılaştırılır.

Kopya kümesi ve sıralı küme aynı varsayımı paylaşıyor: kapsüller bitmez. İstenen kopya sayısı bir
hedeftir, bir kapsül sonlanırsa bu bir sapmadır ve uzlaştırıcı onu yeniden yaratır. Ölçüm ağının
gecelik toplu işi bu varsayıma uymuyor. O iş her gece başlar, günün okumalarını on iki sayaç
kümesinde doğrular, faturalama girdisini üretir ve **biter**. Bitmesi beklenen davranıştır; kopya
kümesine verilseydi uzlaştırıcı onu her gece sonsuz kez yeniden başlatırdı.

Bu yüzden ikinci bir nesne türü gerekiyor: **iş nesnesi**. İş nesnesinin hedefi çalışan kapsül
sayısı değil, **tamamlanmış koşum sayısıdır**. Sonlanma sapma değil, hedefin kendisidir. Üstüne bir
takvim eklenince **zamanlanmış iş** çıkar: belirli anlarda iş nesnesi üreten bir nesne.

Devredilen karar burada üç parçalıdır: iş bitti mi, bitmediyse yeniden denenecek mi, bir sonraki
koşum ne zaman ve önceki hâlâ sürüyorsa ne yapılacak. Sayılan dört şey: deneme sınırı tamamlanmayı
ne kadar satın alıyor, paralellik hangi turu ve hangi israfı veriyor, üç çakışma politikası neyi
feda ediyor, kaçırılan koşum telafi edilebiliyor mu.

#### Bitmesi Beklenen İş

Uzlaştırıcı iki nesnede de aynı döngüyü koşar — istenen durum, gerçek durum, fark, düzeltme — ama
"istenen durum" başka bir şeydir. Kopya kümesinde istenen durum bir **an** hakkındadır: şu anda üç
kapsül çalışıyor olmalı. İş nesnesinde istenen durum bir **geçmiş** hakkındadır: on iki dilim
tamamlanmış olmalı. Birinci durum sürekli denetlenir, ikincisi bir kez sağlanır ve bir daha bozulmaz.

- **TN43** — İş nesnesi, deneme sayacı, paralellik yuvaları ve gece takvimi `node` içinde kurulan
  bir modeldir; gerçek bir küme koşturulmuyor.
- **TN44** — Ölçüm ağı kurgudur. Gecelik toplu iş 30 gece koşuyor ve her koşum on iki sayaç
  kümesine (dilime) bölünüyor.
- **TN45** — Bir denemenin başarısız olma olasılığı 0,5; başarısızlık kaynağı modelde tek sınıftır
  (girdi dosyası hazır değil). Deneme sınırı 1, 3 ve 6 değerleriyle taranıyor.
- **TN46** — Her dilim bir tur sürüyor; paralellik eş zamanlı yuva sayısıdır. Bir dilim ikinci
  denemeye kalırsa toplam süreye bir tur ekleniyor.
- **TN47** — Zamanlanmış işin aralığı 24 saat. Koşum süreleri üreteçten geliyor: yaklaşık dörtte
  bir olasılıkla 30–54 saat, ötekiler 3–7 saat.
- **TN48** — Denetleyici üç gece kapalı kalıyor. Başlangıç penceresi 0, 1 ve 3 gece değerleriyle
  taranıyor. Tohum `20260813`.

```js
// olcum/isler.mjs — is nesnesinin tamamlanma guvencesi ve zamanlanmis isin cakisma politikalari.
// MODEL: is nesnesi, deneme sayaci, paralellik yuvalari ve gece takvimi node icinde kurulan
// modeldir; gercek bir kume kosturulmuyor. Sayilar modelin sayilaridir.
const GECE = 30, DILIM = 12, ARALIK = 24, TOHUM = 20260813, P_HATA = 0.5;
let s = TOHUM % 2147483647;
const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;

// --- 1. tamamlanma guvencesi: deneme siniri ---
console.log(`${"deneme siniri".padEnd(14)}${"tamamlanan gece".padStart(16)}${"basarisiz gece".padStart(16)}` +
  `${"toplam deneme".padStart(15)}${"bosa giden deneme".padStart(19)}${"kalan artik kapsul".padStart(20)}`);
for (const sinir of [1, 3, 6]) {
  s = TOHUM % 2147483647;
  let tamam = 0, deneme = 0, bosa = 0;
  for (let g = 0; g < GECE; g += 1) {
    let d = 0, ok = false;
    while (d < sinir && !ok) { d += 1; deneme += 1; if (rast() >= P_HATA) ok = true; else bosa += 1; }
    if (ok) tamam += 1;
  }
  console.log(`${String(sinir).padEnd(14)}${String(tamam).padStart(16)}${String(GECE - tamam).padStart(16)}` +
    `${String(deneme).padStart(15)}${String(bosa).padStart(19)}${String(bosa).padStart(20)}`);
}

// --- 2. paralellik ve tamamlanma sayisi ---
console.log(`\n${"paralellik".padEnd(11)}${"tamamlanma sayisi".padStart(18)}${"tur".padStart(5)}${"kapsul-tur".padStart(12)}` +
  `${"bos yuva".padStart(10)}${"bir dilim 2 deneme".padStart(20)}${"artis".padStart(8)}`);
for (const p of [1, 3, 5, 6, 12]) {
  const tur = Math.ceil(DILIM / p), gecikmeli = tur + 1;
  console.log(`${String(p).padEnd(11)}${String(DILIM).padStart(18)}${String(tur).padStart(5)}${String(DILIM).padStart(12)}` +
    `${String(p * tur - DILIM).padStart(10)}${String(gecikmeli).padStart(20)}${`%${Math.round((gecikmeli / tur - 1) * 100)}`.padStart(8)}`);
}

// --- 3. ust uste binme: uc politika ---
s = TOHUM % 2147483647;
const SURE = Array.from({ length: GECE }, () => (rast() < 0.25 ? 30 + Math.floor(rast() * 25) : 3 + Math.floor(rast() * 5)));
console.log(`\n${GECE} gecenin kosum sureleri (saat): ${SURE.join(",")}`);

function politika(ad) {
  const bas = new Array(GECE).fill(null), bit = new Array(GECE).fill(null);
  let bitis = 0, baslayan = 0, atlanan = 0, gecikme = 0;
  for (let g = 0; g < GECE; g += 1) {
    const t = g * ARALIK;
    if (ad === "atla" && bitis > t) { atlanan += 1; continue; }
    const b = ad === "siraya al" ? Math.max(t, bitis) : t;
    bas[g] = b; bit[g] = b + SURE[g]; bitis = bit[g]; gecikme += b - t; baslayan += 1;
  }
  let enFazla = 0, enKuyruk = 0;
  for (let g = 0; g < GECE; g += 1) {
    const t = g * ARALIK;
    enFazla = Math.max(enFazla, bas.filter((b, i) => b !== null && b <= t && bit[i] > t).length);
    enKuyruk = Math.max(enKuyruk, bas.filter((b, i) => b !== null && b > t && i * ARALIK <= t).length);
  }
  const son = GECE * ARALIK;
  return { baslayan, atlanan, gecikme, enFazla, enKuyruk,
    kalan: bas.filter((b) => b !== null && b >= son).length,
    saat: bas.reduce((a, b, i) => a + (b === null ? 0 : bit[i] - b), 0) };
}
const P = {};
console.log(`${"politika".padEnd(13)}${"baslayan".padStart(10)}${"atlanan".padStart(9)}${"en fazla es zamanli".padStart(21)}` +
  `${"en fazla kuyruk".padStart(17)}${"ort. gecikme (saat)".padStart(21)}${"kapsul-saat".padStart(13)}`);
for (const ad of ["atla", "siraya al", "paralel kos"]) {
  const r = politika(ad); P[ad] = r;
  console.log(`${ad.padEnd(13)}${String(r.baslayan).padStart(10)}${String(r.atlanan).padStart(9)}${String(r.enFazla).padStart(21)}` +
    `${String(r.enKuyruk).padStart(17)}${(r.gecikme / r.baslayan).toFixed(2).padStart(21)}${String(r.saat).padStart(13)}`);
}
console.log(`islenmeyen gece: atla ${GECE - P["atla"].baslayan}, siraya al ${GECE - P["siraya al"].baslayan}, ` +
  `paralel kos ${GECE - P["paralel kos"].baslayan}; sondan sonraya sarkan kosum ${P["siraya al"].kalan}`);

// --- 4. kacirilan kosum: denetleyici gece 10-12 arasi kapali ---
const KACAN = 3;
console.log(`\n${"baslangic penceresi".padEnd(20)}${"telafi edilen".padStart(15)}${"dusurulen".padStart(11)}` +
  `${"atla ile kosan".padStart(16)}${"siraya al ile kosan".padStart(21)}${"paralel ile kosan".padStart(19)}`);
for (const pencere of [0, 1, 3]) {
  const telafi = Math.min(pencere, KACAN);
  console.log(`${String(pencere).padEnd(20)}${String(telafi).padStart(15)}${String(KACAN - telafi).padStart(11)}` +
    `${String(Math.min(telafi, 1)).padStart(16)}${String(telafi).padStart(21)}${String(telafi).padStart(19)}`);
}
console.log(`bilgi kalemi: gece basina 4 (planli an, kosum suresi, deneme sayaci, acik kosum sayisi) = ${GECE * 4} (tohum ${TOHUM})`);
```

```
deneme siniri  tamamlanan gece  basarisiz gece  toplam deneme  bosa giden deneme  kalan artik kapsul
1                           19              11             30                 11                  11
3                           27               3             49                 22                  22
6                           29               1             54                 25                  25

paralellik  tamamlanma sayisi  tur  kapsul-tur  bos yuva  bir dilim 2 deneme   artis
1                          12   12          12         0                  13      %8
3                          12    4          12         0                   5     %25
5                          12    3          12         3                   4     %33
6                          12    2          12         0                   3     %50
12                         12    1          12         0                   2    %100

30 gecenin kosum sureleri (saat): 5,4,7,5,6,5,5,4,7,31,3,3,5,3,50,4,51,6,5,3,5,7,47,5,3,37,6,5,3,5
politika       baslayan  atlanan  en fazla es zamanli  en fazla kuyruk  ort. gecikme (saat)  kapsul-saat
atla                 25        5                    1                0                 0.00          266
siraya al            30        0                    1                2                 4.23          335
paralel kos          30        0                    2                0                 0.00          335
islenmeyen gece: atla 5, siraya al 0, paralel kos 0; sondan sonraya sarkan kosum 0

baslangic penceresi   telafi edilen  dusurulen  atla ile kosan  siraya al ile kosan  paralel ile kosan
0                                 0          3               0                    0                  0
1                                 1          2               1                    1                  1
3                                 3          0               1                    3                  3
bilgi kalemi: gece basina 4 (planli an, kosum suresi, deneme sayaci, acik kosum sayisi) = 120 (tohum 20260813)
```

#### Tamamlanma Güvencesi: Deneme Sınırı

Tek denemede iş nesnesi 30 gecenin **19'unu** tamamlıyor, 11 gece başarısız. Deneme sınırı üçe
çıkınca tamamlanan gece 27'ye, altıya çıkınca 29'a yükseliyor. Güvence satın alınabiliyor, ama
doğrusal değil: birinci artış 8 gece kazandırıyor, ikinci artış yalnız 2 gece.

Bedel öbür sütunlarda. Toplam deneme 30'dan 49'a, oradan 54'e çıkıyor; boşa giden deneme 11'den
22'ye, oradan 25'e. Yani sınırı 3'ten 6'ya çıkarmak 2 gece kazandırırken 3 boşa giden deneme
ekliyor — kazanılan her gece için bir buçuk boşa koşum. Bu koşumlar kaynak tüketiyor ve
zamanlanmış işin penceresini de yiyor.

Son sütun sessiz bir maliyettir. Başarısız denemenin kapsülü silinmez; günlüğü okunabilsin diye
tutulur. Sınır 6'da geriye **25 artık kapsül** kalıyor ve bunları kimse toplamıyor. İş nesnesinin
bir saklama süresi bildirmesi gerekiyor, yoksa otuz gecenin sonunda küme, çoktan anlamını yitirmiş
başarısız kapsüllerle dolu olur.

"Başarısız gece" ne demek olduğu da ayrıca söylenmelidir. Sınır 1'de 11 gecenin verisi hiç
doğrulanmadı; iş nesnesi bunu bir durum alanında bildirir, ama **bildirmek işlemek değildir**.
Devredilen karar yalnız "yeniden dene" kararıdır; "denemeler tükendi, veri eksik kaldı" kararının
sahibi hâlâ dışarıdadır.

#### Paralellik ve Tamamlanma Sayısı

İkinci tablo iki ayarın birlikte ne verdiğini gösteriyor. Tamamlanma sayısı 12 sabit — on iki
dilimin hepsi işlenmeli. Paralellik 1'den 12'ye çıktıkça tur sayısı 12'den 1'e iniyor ve
**kapsül-tur toplamı hiç değişmiyor**: her durumda 12. Paralellik toplam işi azaltmıyor, yalnız onu
zamana yayıyor.

Değişen iki şey var. Birincisi boş yuva: paralellik 5 iken üç turun sonuncusunda 15 yuvanın 12'si
dolu, **3 yuva boş** kalıyor. Tamamlanma sayısını bölmeyen paralellik değerleri israf üretiyor.
İkincisi ve daha önemlisi son iki sütun: bir dilim ikinci denemeye kalırsa toplam süre bir tur
uzuyor ve bu bir turun **oranı** paralellikle birlikte büyüyor. Paralellik 1'de artış %8, 12'de
**%100**. Tam paralellikte iş, en yavaş dilimin süresine eşittir; tek bir yavaş dilim toplam süreyi
ikiye katlar.

Tamamlanma sayısı bildirilmediğinde nesne başka bir kipe geçer: kapsüller bir iş kuyruğunu tüketir
ve kuyruk boşalınca kendileri sonlanır. Tur sayısı aynı kalır, ama **bitiş kararı kapsülün
içindedir**. Küme yalnız kapsülün sonlanmasını görür; kaç dilimin işlendiğini bilmez. Devredilen
kararın burada geri alındığı nokta budur: tamamlanma sayısı bildirilirse güvenceyi küme verir,
bildirilmezse uygulama verir.

#### Üst Üste Binme: Üç Politika

Üçüncü tablo gecelik işin gerçek sorusudur. Otuz gecenin koşum sürelerinde beş gece 31, 37, 47, 50
ve 51 saat — yani 24 saatlik aralıktan uzun. Önceki koşum bitmeden yenisi geliyor.

**Atla** politikası çakışan koşumu başlatmıyor: 25 koşum başladı, **5 gece atlandı**. Eş zamanlılık
1'de kalıyor, kuyruk yok, gecikme yok ve kaynak tüketimi 266 kapsül-saatle en düşük. Bedel doğrudan
veri kapsamasıdır: beş gecenin okumaları hiç doğrulanmadı ve bu politika onları geri getirmiyor.

**Sıraya al** politikası hiçbir geceyi atlamıyor: 30 koşum, işlenmeyen gece 0. Karşılığında koşumlar
planlı anlarından ortalama **4,23 saat** geç başlıyor ve kuyrukta bir noktada iki koşum birden
bekliyor. Eş zamanlılık yine 1 — tek koşucu güvencesi korunuyor. Kritik nokta gecikmenin
**birikmemesidir**: uzun geceler dağınık olduğu için kuyruk boşalıyor ve otuzuncu gecenin sonrasına
sarkan koşum kalmıyor. Uzun koşumlar art arda gelseydi bu sütun kontrolsüz büyürdü.

**Paralel koş** politikası da 30 koşumun hepsini başlatıyor, gecikme sıfır, ama eş zamanlılık **2'ye
çıkıyor**. İki koşum aynı anda aynı sayaç kümelerini okuyup aynı faturalama girdisini yazıyor. Küme
açısından bir sorun yok — iki kapsül de sağlıklı; sorun uygulamanın veri katmanındadır ve küme onu
göremez. Kaynak tarafında da sıraya al ile aynı 335 kapsül-saat harcanıyor.

Üç politikanın ortak yanı şudur: hiçbiri koşum süresini **bilmiyor**. Politika koşum başlamadan önce
seçiliyor, süre koşumdan sonra öğreniliyor. Sistem bilmediği için biri veri kapsamasını, biri
zamanlamayı, biri de tekillik güvencesini feda ediyor.

Ölçüm ağı için doğru seçim tabloda okunur. Faturalama girdisi eksik geceye tahammül etmiyor, bu
yüzden atlanın 5 gecesi kabul edilemez. Aynı geceyi iki koşumun birden yazması da kabul edilemez,
çünkü faturalama girdisi eklemeli yazılıyor ve iki koşum aynı okumaları iki kez ekler. Geriye sıraya
al kalıyor ve onun bedeli tabloda görünüyor: ortalama 4,23 saatlik gecikme, tepe noktada iki koşumluk
kuyruk. Bu bedel yalnız kuyruk boşaldığı sürece ödenebilir; uzun geceler art arda gelirse gecikme
birikir ve gecelik iş bir noktada gündüze taşar. Yani politika seçimi bir kez yapılıp bırakılan bir
ayar değil, koşum süresi dağılımı değiştikçe yeniden bakılması gereken bir karardır.

#### Kaçırılan Koşum

Son tablo denetleyicinin üç gece kapalı kaldığı durumu ölçüyor. Başlangıç penceresi 0 gece iken
kaçan üç koşumun **hiçbiri** telafi edilmiyor; pencere 1 gece iken biri koşuyor, ikisi düşürülüyor;
pencere 3 gece iken üçü de sıraya giriyor.

Telafi edilmek koşmak demek değil. Pencere 3'te üç koşum aynı anda uygun hâle geliyor ve o an
çakışma politikası devreye giriyor: **atla** politikasıyla yalnız biri koşuyor, ikisi yine
düşüyor; sıraya al ile üçü ardışık koşuyor; paralel koş ile üçü aynı anda başlıyor. Yani iki ayar
birbirini iptal edebiliyor — geniş pencere ile sıkı çakışma politikası bir arada seçilirse telafi
kâğıt üzerinde açık, sonuçta kapalıdır.

Bu dersin devir bilançosu şudur: karar gece başına dört kaleme dayanıyor — planlı an, koşum süresi,
deneme sayacı, açık koşum sayısı; otuz gece için **120 kalem**. Bunlardan üçü ölçümle gelir, biri
(koşum süresi) ancak koşum bittikten sonra bilinir. Sistemin bilmediği tek kalem bu ve üç politika
arasındaki bütün fark oradan çıkıyor.

#### Özet

- İş nesnesinin hedefi çalışan kapsül sayısı değil tamamlanmış koşum sayısıdır; sonlanma sapma
  değil hedefin kendisidir.
- Deneme sınırı 1 → 3 → 6 arttıkça tamamlanan gece 19 → 27 → 29, boşa giden deneme 11 → 22 → 25.
  Son artış 2 gece kazandırıp 3 boşa koşum ekliyor; geriye 25 artık kapsül kalıyor.
- Paralellik toplam işi değiştirmiyor (her durumda 12 kapsül-tur), turu 12'den 1'e indiriyor;
  paralellik 5'te 3 boş yuva doğuyor ve tek bir yavaş dilimin maliyeti %8'den %100'e çıkıyor.
- Tamamlanma sayısı bildirilmezse güvence kümeden uygulamaya geçiyor: küme yalnız sonlanmayı görür,
  kaç dilimin işlendiğini bilmez.
- Üç çakışma politikası üç ayrı şeyi feda ediyor: atla 5 geceyi işlemiyor (266 kapsül-saat), sıraya
  al ortalama 4,23 saat geciktiriyor, paralel koş eş zamanlılığı 2'ye çıkarıp aynı veriye iki yazar
  salıyor (335 kapsül-saat).
- Başlangıç penceresi 0 → 1 → 3 gece ile telafi 0 → 1 → 3; ama telafi edilen koşumların kaçının
  gerçekten koştuğunu çakışma politikası belirliyor (atla ile 1).

#### Sonraki Adım

Gecelik iş küme nesnesi hâline geldi: bitişi tanımlı, denemesi sınırlı, takvimi bildirilmiş.
Ölçülen bütün sayılar tek bir uygulamanın kendi hesabındaydı — 335 kapsül-saat, eş zamanlı iki
koşum, on iki paralel dilim. Oysa küme yalnız ölçüm ağının değil. Aynı düğümlerde iki uygulama daha
koşuyor ve gecelik iş on iki dilimi birden açtığında onların isteklerine ne oluyor sorusu hiç
sorulmadı. Kapsül, kopya kümesi, sürüm nesnesi, servis nesnesi, birim, iş nesnesi — hepsi tek bir
adlandırma uzayında duruyor ve hepsi aynı kaynak havuzundan yiyor. Sonraki ders üç kiracıyı tek bir
kümede toplayıp şunları sayıyor: kota olmadan bir kiracı ötekini kaç istek boyunca aç bırakıyor,
kota konunca kaç istek reddediliyor, kotaların toplamı kümenin kaç birimini boşta bırakıyor ve
varsayılan istek değerleri bu üç sayıyı nasıl kaydırıyor.

### Ad Alanları ve Kotalar

Source: https://academia.sh/tr/kurslar/orkestrasyon/ad-alanlari-ve-kotalar

Çok kiracılı kaynak ayrımının sayılarla kurulması: üç kiracı bir kümeyi paylaşırken kota olmadan bir kiracının ötekileri aç bıraktığı ölçülür, kota konunca reddedilen istek sayısı ile kotanın boşta bıraktığı kapasite karşılaştırılır ve bildirimsiz kapsüllere uygulanan varsayılan istek değerinin kabul, fazla ayırma ve düğüm baskısı üzerindeki etkisi taranır.

Gecelik iş küme nesnesi hâline geldi ve on iki dilimi bir anda açabiliyor. Buraya kadar ölçülen her
sayı tek bir uygulamanın kendi hesabındaydı; kümenin başkalarına da ait olduğu hiç hesaba
katılmadı. Aynı altı düğümde iki uygulama daha koşuyor ve üçünün nesneleri aynı adlandırma uzayında,
aynı kaynak havuzunda duruyor.

**Ad alanı** bu uzayı bölen nesnedir. Sözcük tanıdıktır: çalışma zamanı ölçümlerinde `ad alanı`,
çekirdeğin bir sürece hangi süreçleri, hangi ağı ve hangi dosya sistemini gösterdiğini belirleyen
**görünürlük eşlemesiydi**; burada aynı sözcük, kümedeki nesne adlarını ve kaynak muhasebesini
bölen bir **bölmeyi** anlatıyor — biri bir sürecin gördüğünü kısar, öteki bir kiracının adlandırma
ve kaynak uzayını ayırır. İkisi farklı katmanlarda, farklı nesnelerdir.

Ad alanı tek başına yalnız adları ayırır; kaynağı ayırmaz. Kaynağı ayıran nesne **kota**dır. Bu ders
devredilen kararı şöyle adlandırıyor: **bir isteğin kabul edilip edilmeyeceği**. Karar bir insandan
kümeye geçtiğinde kümenin istek başına üç kalem bilmesi gerekiyor — hangi kiracı, ne kadar istiyor,
gerçekte ne kadar kullanıyor. Üçüncü kalem hiçbir bildirimde yoktur; ancak ölçümle gelir ve bu
dersin bütün sapması oradan çıkıyor.

#### Üç Kiracı, Bir Küme

Ölçülen üç durum aynı istek dizisini kullanıyor: kota yok, kota var, kota var ve bildirimsiz
kapsüllere varsayılan uygulanıyor. Dizinin sırası değişmiyor, çünkü sıranın kendisi ölçülen
şeylerden biri.

- **TN49** — Küme kapasitesi, kiracılar, istek dizisi ve kota muhasebesi `node` içinde kurulan bir
  modeldir; gerçek bir küme koşturulmuyor.
- **TN50** — Küme 96 işlemci birimidir (6 düğüm × 16). Tek boyut ölçülüyor; bellek aynı aritmetikle
  işlediği için ayrıca sayılmıyor.
- **TN51** — Üç kiracı kurgudur: ölçüm ağı, saha servisi, raporlama. Altmış istek geliyor;
  11.–30. istekler ölçüm ağının gecelik patlamasıdır, ötekiler dönüşümlü.
- **TN52** — İstek büyüklükleri kiracıya göre üreteçten geliyor: ölçüm ağı 1–6, saha servisi 1–4,
  raporlama 1–2 birim.
- **TN53** — İsteklerin yaklaşık üçte biri kaynak isteği bildirmiyor. Gerçek kullanım, bildirilen
  değerin 0,4–1,1 katıdır.
- **TN54** — Kota muhasebesi **bildirilen** isteğe bakar, gerçek kullanıma değil. Tohum `20260819`.

```js
// olcum/kota.mjs — uc kiracinin bir kumeyi paylasmasi: kotasiz, kotali ve varsayilan istekli.
// MODEL: kume kapasitesi, kiracilar, istek dizisi ve kota muhasebesi node icinde kurulan modeldir;
// gercek bir kume kosturulmuyor. Sayilar modelin sayilaridir.
const KAPASITE = 96, TOHUM = 20260819;                 // 6 dugum x 16 islemci birimi
const KIRACI = ["olcum-agi", "saha-servisi", "raporlama"];
let s = TOHUM % 2147483647;
const rast = () => (s = (s * 48271) % 2147483647) / 2147483647;

const ISTEK = [];                                       // sira: donusumlu -> patlama -> donusumlu
for (let i = 0; i < 60; i += 1) {
  const k = i >= 10 && i < 30 ? KIRACI[0] : KIRACI[i % 3];
  const iste = 1 + Math.floor(rast() * (k === "raporlama" ? 2 : k === "saha-servisi" ? 4 : 6));
  ISTEK.push({ k, iste, bildirdi: rast() >= 0.3, gercek: Math.max(1, Math.round(iste * (0.4 + rast() * 0.7))) });
}
const say = (f) => KIRACI.map((k) => ISTEK.filter((i) => i.k === k && f(i)).length);

// --- 1. kota yok: ilk gelen alir ---
let kalan = KAPASITE;
const kabul = new Set();
for (const [n, i] of ISTEK.entries()) if (i.iste <= kalan) { kalan -= i.iste; kabul.add(n); }
console.log(`${"kiraci".padEnd(14)}${"gelen istek".padStart(12)}${"kabul".padStart(7)}${"red".padStart(6)}` +
  `${"kabul orani".padStart(13)}${"tuketilen".padStart(11)}${"kume payi".padStart(11)}`);
for (const k of KIRACI) {
  const g = ISTEK.filter((i) => i.k === k), a = g.filter((i) => kabul.has(ISTEK.indexOf(i)));
  const t = a.reduce((x, i) => x + i.iste, 0);
  console.log(`${k.padEnd(14)}${String(g.length).padStart(12)}${String(a.length).padStart(7)}${String(g.length - a.length).padStart(6)}` +
    `${`%${Math.round(a.length / g.length * 100)}`.padStart(13)}${String(t).padStart(11)}${`%${Math.round(t / KAPASITE * 100)}`.padStart(11)}`);
}
console.log(`kotasiz: ${kabul.size} istek kabul, ${ISTEK.length - kabul.size} red, bosta kalan kapasite ${kalan}`);

// --- 2. kota: iki dagitim ---
function kotali(kota, varsayilan = null) {
  const kullanim = Object.fromEntries(KIRACI.map((k) => [k, 0]));
  const kabulK = Object.fromEntries(KIRACI.map((k) => [k, 0]));
  const kotaRed = Object.fromEntries(KIRACI.map((k) => [k, 0]));
  let bos = KAPASITE, gercek = 0, yazilan = 0, baski = 0;
  for (const i of ISTEK) {
    const yaz = i.bildirdi ? i.iste : (varsayilan === null ? i.iste : varsayilan);
    if (kullanim[i.k] + yaz > kota[i.k] || yaz > bos) { kotaRed[i.k] += 1; continue; }
    kullanim[i.k] += yaz; bos -= yaz; kabulK[i.k] += 1;
    yazilan += yaz; gercek += i.gercek; if (i.gercek > yaz) baski += 1;
  }
  return { kullanim, kabulK, kotaRed, bos, gercek, yazilan, baski };
}
const DAGITIM = { esit: { "olcum-agi": 32, "saha-servisi": 32, raporlama: 32 },
  agirlikli: { "olcum-agi": 48, "saha-servisi": 32, raporlama: 16 } };
console.log(`\n${"dagitim".padEnd(11)}${"kiraci".padEnd(14)}${"kota".padStart(6)}${"kabul".padStart(7)}${"kota reddi".padStart(12)}` +
  `${"kullanilan".padStart(12)}${"kotanin bos kalani".padStart(20)}`);
for (const [ad, kota] of Object.entries(DAGITIM)) {
  const r = kotali(kota);
  for (const k of KIRACI)
    console.log(`${ad.padEnd(11)}${k.padEnd(14)}${String(kota[k]).padStart(6)}${String(r.kabulK[k]).padStart(7)}` +
      `${String(r.kotaRed[k]).padStart(12)}${String(r.kullanim[k]).padStart(12)}${String(kota[k] - r.kullanim[k]).padStart(20)}`);
  const toplamRed = KIRACI.reduce((a, k) => a + r.kotaRed[k], 0);
  console.log(`  -> ${ad}: kabul ${ISTEK.length - toplamRed}, red ${toplamRed}, kumede bosta kalan kapasite ${r.bos} ` +
    `(kotalarin toplami ${Object.values(kota).reduce((a, b) => a + b, 0)})`);
}

// --- 3. varsayilan istek degeri ---
console.log(`\n${"varsayilan istek".padEnd(17)}${"kabul".padStart(7)}${"kotaya yazilan".padStart(16)}${"gercek kullanim".padStart(17)}` +
  `${"fazla ayirma".padStart(14)}${"dugum baskisi".padStart(15)}${"bosta kapasite".padStart(16)}`);
for (const v of [0, 1, 2, 4, null]) {
  const r = kotali(DAGITIM.agirlikli, v);
  const kabulT = KIRACI.reduce((a, k) => a + r.kabulK[k], 0);
  console.log(`${(v === null ? "bildirimi zorunlu" : String(v)).padEnd(17)}${String(kabulT).padStart(7)}${String(r.yazilan).padStart(16)}` +
    `${String(r.gercek).padStart(17)}${String(r.yazilan - r.gercek).padStart(14)}${String(r.baski).padStart(15)}${String(r.bos).padStart(16)}`);
}
console.log(`${ISTEK.length} istek, ${say((i) => !i.bildirdi).reduce((a, b) => a + b, 0)} tanesi istek bildirmiyor`);
console.log(`bilgi kalemi: istek basina 3 (kiraci, istek, gercek kullanim) = ${ISTEK.length * 3}, tohum ${TOHUM}`);
```

```
kiraci         gelen istek  kabul   red  kabul orani  tuketilen  kume payi
olcum-agi               34     26     8          %76         77        %80
saha-servisi            13      5     8          %38         13        %14
raporlama               13      4     9          %31          6         %6
kotasiz: 35 istek kabul, 25 red, bosta kalan kapasite 0

dagitim    kiraci          kota  kabul  kota reddi  kullanilan  kotanin bos kalani
esit       olcum-agi         32     13          21          32                   0
esit       saha-servisi      32     12           1          30                   2
esit       raporlama         32     13           0          21                  11
  -> esit: kabul 38, red 22, kumede bosta kalan kapasite 13 (kotalarin toplami 96)
agirlikli  olcum-agi         48     17          17          48                   0
agirlikli  saha-servisi      32     12           1          30                   2
agirlikli  raporlama         16     10           3          16                   0
  -> agirlikli: kabul 39, red 21, kumede bosta kalan kapasite 2 (kotalarin toplami 96)

varsayilan istek   kabul  kotaya yazilan  gercek kullanim  fazla ayirma  dugum baskisi  bosta kapasite
0                     53              79               92           -13             22              17
1                     47              88               77            11             11               8
2                     41              94               67            27              2               2
4                     32              96               52            44              0               0
bildirimi zorunlu     39              94               64            30              0               2
60 istek, 22 tanesi istek bildirmiyor
bilgi kalemi: istek basina 3 (kiraci, istek, gercek kullanim) = 180, tohum 20260819
```

#### Kota Yokken: Aç Kalan Kiracı

Kotasız kümede kural tek satırdır: yer varsa kabul et. Sonuç ilk tabloda.

Ölçüm ağı 34 istek gönderdi, **26'sı kabul edildi** — kabul oranı %76 — ve kümenin **%80'ini**
tuttu. Saha servisi 13 istekten 5'ini geçirebildi (%38), raporlama 13 istekten 4'ünü (%31).
Raporlamanın küme payı **%6**. Küme boş kalmadı; kapasite tamamen tükendi ve 25 istek reddedildi.

Aç kalmanın nedeni istek büyüklüğü değil, **sıra**. Ölçüm ağının gecelik patlaması 11. istekten
30. isteğe kadar kesintisiz akıyor ve o aralıkta kapasitenin çoğunu tüketiyor; sonra gelen küçük
raporlama istekleri artığa talip oluyor. Raporlamanın istekleri en küçük olanlar (1–2 birim) ve
yine de en düşük kabul oranını alıyor. Yani kotasız paylaşımda pay, ihtiyaca ya da kibarlığa değil,
**zamanlamaya** göre dağılıyor. Bir kiracının kendi kapsül sayısını artırması ötekinin istekleri
üzerinde doğrudan bir etkidir ve bu etki hiçbir yerde bildirilmez.

Reddedilen 25 isteğin ne olduğu da ayrıca söylenmelidir. İstek reddedilmiyor, **bekliyor**: kapsül
nesnesi bildirilmiş durumda, yalnız hiçbir düğümde yeri yok. Raporlamanın kullanıcısı bunu bir
hata olarak görmez, yavaşlık olarak görür ve nedenini kendi ad alanında arar. Kotasız paylaşımın en
pahalı yanı budur — bir kiracının sorunu başka bir kiracının davranışından doğuyor ve iki tarafın da
göremediği bir yerde duruyor.

Ad alanı bu tabloyu değiştirmez. Üç kiracının nesneleri ayrı ad alanlarında dursa da aynı 96 birimi
paylaşırlar; ad alanı yalnız `gecelik-is` adının üç kez kullanılabilmesini ve yetkinin bölme
başına verilebilmesini sağlar. Kaynak ayrımı için ikinci bir nesne gerekiyor.

#### Kota Konunca: İki Bedel

İkinci tablo kotanın ne satın aldığını ve karşılığında ne ödettiğini birlikte gösteriyor.

**Eşit dağıtımda** (32/32/32) ölçüm ağı kotasına çarpıyor: **21 kota reddi** alıyor ve 32 birimde
duruyor. Karşılığında raporlama 13 isteğinin hepsini geçiriyor, tek bir ret bile almıyor. Aç kalma
bitti. Bedel son sütunda: raporlama kotasının **11 birimini hiç kullanmıyor** ve küme genelinde
**13 birim boşta** kalıyor. Ölçüm ağının 21 isteği reddedilirken kümede 13 birim boş duruyor —
kotanın israfı tam olarak budur. Toplam kabul kotasız durumdaki 35'ten 38'e çıkıyor, yani kota
verimi düşürmedi; ama boşta kalan kapasite sıfırdan 13'e çıktı.

**Ağırlıklı dağıtımda** (48/32/16) israf düşüyor: boşta kalan kapasite 2 birim, toplam kabul 39.
Ölçüm ağının reddi 21'den 17'ye iniyor. Bedel yer değiştirdi — raporlama artık 3 ret alıyor.
Ağırlık, talebin bilinmesini gerektiriyor; bu dağıtım ancak kim ne kadar isteyeceği önceden
ölçüldüğü için doğru. Talep değişirse — örneğin raporlama aylık kapanışta büyürse — aynı dağıtım
ters yönde israf üretir.

Kotanın saydığı kalem yalnız işlemci değildir. Aynı muhasebe bellek için, kalıcı birim talebinin
toplam boyutu için ve nesne sayıları için ayrı ayrı tutulabilir — bir ad alanında en fazla kaç
servis nesnesi, kaç sır nesnesi, kaç kalıcı birim talebi bulunabileceği gibi. Sayı kalemleri işlemci
kaleminden farklı bir şeyi korur: kapasiteyi değil, denetim düzleminin kendi yükünü. Bir kiracının
binlerce sır nesnesi bildirmesi hiçbir düğümü doldurmaz ama durum deposunu ve uzlaşma döngüsünü
doldurur. Ölçülen tablo tek kalemi izliyor; ötekiler aynı aritmetikle işler.

İki satır birlikte okunduğunda kotanın gerçek doğası görünüyor: kota bir **kapasite ayırma** değil,
bir **üst sınır**dır. Kullanılmayan kota kimseye geçmez; boşta kalan 13 birim ölçüm ağına
açılmıyor, öylece duruyor. Devredilen karar burada kısmen geri alınmıştır: küme "bu isteği kabul et"
kararını verir, ama "kim ne kadar alacak" kararını hâlâ kotayı yazan insan verir ve o insan gelecek
haftanın talebini bilmez.

#### Varsayılan İstek Değeri

Üçüncü tablo, kota muhasebesinin dayandığı sayının nereden geldiğini soruyor. Altmış isteğin
**22'si** kaynak isteği bildirmiyor. Kota bir sayı görmek zorunda, o yüzden bildirimsiz kapsüllere
bir varsayılan uygulanıyor.

Burada iki ayrı sayı vardır ve karıştırılmamalıdır. **Kaynak isteği** muhasebe ve yerleştirme
sayısıdır: kota onu toplar, zamanlayıcı düğümde o kadar yer arar. **Sınır** koşum anında dayatılan
tavandır; kapsül onu aşamaz. Kota her ikisini ayrı ayrı sayabilir ve ikisi için ayrı varsayılan
tanımlanabilir. Aşağıdaki tarama istek varsayılanını değiştiriyor, çünkü kabul kararını belirleyen
sayı odur; sınır varsayılanının etkisi başka bir yerde görünür — sınır düşük konursa kapsül
kotadan geçer, düğümde yer bulur, sonra kendi tavanına çarpar ve iş yavaşlar ya da sonlanır. İkisi
birlikte düşünülmediğinde kota tablosu temiz görünürken uygulama tarafında açıklanamayan
sonlanmalar birikir.

Varsayılan **0** iken bu kapsüller kotadan hiçbir şey yemiyor: kabul 53'e fırlıyor, kotaya yazılan
toplam 79'da kalıyor ve küme kendini 17 birim boşta sanıyor. Gerçek kullanım ise **92** — yani
bildirilenden 13 birim fazla ve 22 kapsül bildirdiğinden çoğunu kullanıyor. Küme muhasebe
defterinde rahat, düğümlerde ise baskı altındadır. Bu, kotanın en tehlikeli ayarıdır: kural
uygulanıyor görünür, uygulanmaz.

Varsayılan büyüdükçe tablo ters yöne dönüyor. **2** birimde düğüm baskısı 2'ye, **4** birimde
**0**'a iniyor; kabul 53'ten 32'ye düşüyor ve fazla ayırma 44 birime çıkıyor — kotaya yazılan 96
birimin 44'ü hiç kullanılmıyor. Güvenlik satın alındı, karşılığında kümenin neredeyse yarısı kâğıt
üzerinde harcandı.

Son satır üçüncü yolu veriyor: bildirimi zorunlu kılmak. Kabul 39, fazla ayırma 30, düğüm baskısı
**0**, boşta kapasite 2. Sabit bir varsayılanın hiçbir değeri bunu birden yakalayamıyor, çünkü
varsayılan tek sayıdır ve 22 kapsülün gerçek ihtiyacı tek sayı değildir. Bildirimi zorunlu kılmanın
bedeli ise küme tarafında değil, bildirimi yazan tarafta ödenir.

Konunun devir bilançosu şudur: kabul kararı istek başına üç kaleme dayanıyor — hangi kiracı, ne
kadar istiyor, gerçekte ne kadar kullanıyor; altmış istek için **180 kalem**. İlk iki kalem
bildirimden gelir ve ucuzdur; üçüncüsü yalnız ölçümle gelir ve kota onu hiç görmez. Sistem gerçek
kullanımı bilmediği için ya fazla ayırıp kapasiteyi boşa harcıyor ya da az ayırıp düğümü baskı
altına sokuyor.

#### Özet

- Ad alanı ile kota ayrı işler yapar: ad alanı adları ve yetkiyi böler, kaynağı bölmez; kaynağı
  bölen nesne kotadır.
- Kotasız kümede pay ihtiyaca değil sıraya göre dağılıyor: ölçüm ağı %76 kabul oranıyla kümenin
  %80'ini alırken raporlama %31 kabul oranıyla %6'sında kalıyor ve 25 istek reddediliyor.
- Kota aç kalmayı bitiriyor ama iki bedel ödetiyor: eşit dağıtımda ölçüm ağı 21 kota reddi alırken
  raporlama kotasının 11 birimi ve kümenin 13 birimi boşta duruyor.
- Ağırlıklı dağıtım israfı 13'ten 2 birime indiriyor, karşılığında reddi raporlamaya kaydırıyor;
  doğruluğu talebin önceden bilinmesine bağlıdır.
- Kullanılmayan kota kimseye geçmez: kota bir kapasite ayırma değil üst sınırdır.
- Varsayılan istek 0 iken küme kendini 17 birim boşta sanırken gerçek kullanım 92 ve 22 kapsül düğüm
  baskısı yaratıyor; varsayılan 4 iken baskı sıfırlanıyor ama 44 birim fazla ayrılıyor. Bildirimi
  zorunlu kılmak baskıyı 0'a indirip israfı 30'da tutuyor.

#### Sonraki Adım

Konu boyunca nesneler tek tek bildirildi: en küçük dağıtım birimi, kopya kümesi ve sürüm nesnesi,
servis nesnesi ve giriş kuralı, yapılandırma ve sır nesnesi, kalıcı birim talebi, sıralı küme, iş
nesnesi ve zamanlanmış iş, ad alanı ve kota. Hepsinin ortak bir eksiği var ve bu ders onu son
tabloyla açığa çıkardı: bildirimlerde **istek** var, kotalarda **üst sınır** var, ama hiçbir yerde
"bu kapsül hangi düğümde açılacak" yazmıyor. Kota bir isteği kabul ettiğinde iş bitmiyor; kabul
edilen kapsülün altı düğümden birine yerleşmesi gerekiyor ve o düğümde gerçekten yer bulunması
gerekiyor. Depolama ölçümü bu sorunun yarısını çoktan gösterdi: tek düğüm yazar kipindeki bir birim
otuz altı seçenekten yirmi altısını eledi. Peki kalan seçenekler arasından seçimi yapan nedir, karar
verirken hangi bilgiye bakar, bakması gereken bilgi eskimişse ne olur ve hiçbir seçenek uymadığında
kapsül nerede bekler? Sonraki konu bu kararı bir kısıt çözücü olarak yazıp yerleştirme kararını,
çözümsüz kalma sayısını ve ölçekleme kararının kendi gecikmesini ölçüyor.

## Zamanlama ve Ölçekleme

Yerleştirme ve büyütme kararının sayıya bağlanması: kaynak isteği ile sınırın zamanlayıcı kararına etkisi, etiket seçimi, yakınlık ve topoloji dağılımıyla yerleşim kısıtları, düğüm ayrımı için işaret ve tolerans, kaynak baskısında tahliye sırası ve öncelikler, ölçüt tabanlı yatay ölçeklemenin gecikme ve salınım dengesi, dikey boyutlandırma ve düğüm ekleme.

### Kaynak İstekleri ve Sınırları

Source: https://academia.sh/tr/kurslar/orkestrasyon/kaynak-istekleri-ve-sinirlari

Yerleştirme kararının iki sayıya bağlanması: kaynak isteğinin zamanlayıcı defterini, sınırın koşum davranışını belirlemesi, aynı iş kümesinin üç istek ayarında yerleşen kapsül sayısı ve boş kapasiteyle karşılaştırılması, isteğin gerçek kullanımdan sapmasının taranması ve aşırı bildirimin israfı ile eksik bildirimin çakışmasının sayılması.

Küme üzerinde koşan nesneler bildirildi: bir kapsül tanımlandı, kopyaları bir küme hâline
getirildi, bir ad alanı içine alındı ve o ad alanının toplam kaynağı bir kotayla paylaştırıldı.
Bütün bunlar boyunca tek bir soru hiç sorulmadı: **hangi kapsül hangi düğüme düşecek.** Kota bir
tavan koyar, yerleştirmez. Kopya sayısı kaç tane olacağını söyler, nerede olacağını söylemez.

Yerleştirme, insandan sisteme geçen ilk mekanik karardır ve iki sayıya dayanır. Kapsül bildiriminde
yan yana duran bu iki sayı ayrı yerlerde iş görür: **kaynak isteği** zamanlayıcının defterinde,
**sınır** düğümdeki çalışma zamanında. Kaç düğüm gerektiği burada sorulmaz — o hesap, yük kısıtı ile
arıza kısıtının büyüğü olarak, kapasite planlamasında yapıldı ve bu derste girdidir. Buradaki soru,
elde belirli sayıda düğüm varken yerleşimin ne olacağıdır.

Ölçülen şey gerçek bir küme değil, `node` ile kurulan bir **modeldir**. İş yükü bölgesel ölçüm ağının
(kurgu) servisleridir: okuma toplayıcı, doğrulayıcı, faturalama, iş emri ve gecelik toplu iş.

#### İstek Defteri Tutar, Sınır Kesme Yapar

Model üç düğüm ve on sekiz kapsülden oluşur. Zamanlayıcı ilk uyan düğüme yerleştirir ve yalnız
bildirilen isteği görür; gerçek kullanımı hiç görmez. Gerçek kullanım kendi yazdığımız üretecin
tohumundan türer ve tabanın yüzde 35 bandında dağılır.

```js
// zamanlama/istek.mjs — istek ve sinirin yerlestirmeye etkisi. Kurulan sey bir MODELDIR;
// gercek kume kosturulmaz. Is yuku bolgesel olcum aginin (kurgu) servisleridir.
export const DUGUM = { islemci: 3000, bellek: 4096 };  // ZO1: dugum basina ayrilabilir kapasite
export const DUGUM_SAYISI = 3;

// ZO2: servis, kapsul sayisi, taban islemci birimi, taban bellek (MiB)
const SERVIS = [
  ["okuma-toplayici", 6, 420, 384], ["dogrulayici", 4, 650, 704],
  ["faturalama", 3, 300, 512], ["is-emri", 3, 180, 256], ["gecelik-toplu", 2, 900, 1408],
];
const TOHUM = 20260801;                       // uretec kendi yazildi, tohum gorunur

export function uretec(tohum = TOHUM) {
  let s = tohum % 2147483647;
  return () => (s = (s * 48271) % 2147483647) / 2147483647;
}

// ZO3: gercek kullanim tabanin ±%35 bandinda; olculur, bildirilmez
export function isYuku() {
  const r = uretec(), k = [];
  for (const [ad, adet, ci, mi] of SERVIS)
    for (let i = 0; i < adet; i++) {
      const sapma = 0.65 + 0.7 * r();
      k.push({ ad: `${ad}-${i + 1}`, tabanC: ci, tabanM: mi,
               gercekC: Math.round(ci * sapma), gercekM: Math.round(mi * sapma) });
    }
  return k;
}

// Zamanlayici yalniz BILDIRILEN istegi gorur; gercek kullanimi hic gormez.
export function yerlestir(kapsuller, n = DUGUM_SAYISI) {
  const dugumler = Array.from({ length: n }, () => ({ isC: 0, isM: 0, kapsul: [] }));
  const yerlesmeyen = [];
  for (const k of kapsuller) {
    const d = dugumler.find((d) => d.isC + k.istekC <= DUGUM.islemci &&
                                   d.isM + k.istekM <= DUGUM.bellek);
    if (d === undefined) { yerlesmeyen.push(k); continue; }
    d.isC += k.istekC; d.isM += k.istekM; d.kapsul.push(k);
  }
  return { dugumler, yerlesmeyen };
}

// ZO4: sinir = istek x 1,25. Islemci sinirini asan kisitlanir, bellek sinirini asan sonlandirilir.
export const SINIR_CARPANI = 1.25;

export function olc(kapsuller, n = DUGUM_SAYISI) {
  const { dugumler, yerlesmeyen } = yerlestir(kapsuller, n);
  let israf = 0, cakisma = 0, kisitlanan = 0, sonlanan = 0, yerlesen = 0;
  for (const d of dugumler) {
    const gC = d.kapsul.reduce((t, k) => t + k.gercekC, 0);
    d.gercekC = gC;
    cakisma += Math.max(0, gC - DUGUM.islemci);
    yerlesen += d.kapsul.length;
    for (const k of d.kapsul) {
      israf += Math.max(0, k.istekC - k.gercekC);
      if (k.sinirC > 0 && k.gercekC > k.sinirC) kisitlanan++;
      if (k.sinirM > 0 && k.gercekM > k.sinirM) sonlanan++;
    }
  }
  return { dugumler, yerlesen, yerlesmeyen: yerlesmeyen.length, israf, cakisma,
           kisitlanan, sonlanan,
           bosIstek: dugumler.reduce((t, d) => t + (DUGUM.islemci - d.isC), 0) };
}

export function ayarla(kapsuller, kip) {
  return kapsuller.map((k) => {
    const c = kip === "yok" ? 0 : kip === "gercekci" ? k.tabanC : k.tabanC * 2;
    const m = kip === "yok" ? 0 : kip === "gercekci" ? k.tabanM : k.tabanM * 2;
    return { ...k, istekC: c, istekM: m,
             sinirC: kip === "yok" ? 0 : Math.round(c * SINIR_CARPANI),
             sinirM: kip === "yok" ? 0 : Math.round(m * SINIR_CARPANI) };
  });
}

if (process.argv[1].endsWith("istek.mjs")) {
  const k = isYuku();
  const topC = k.reduce((t, x) => t + x.gercekC, 0), topM = k.reduce((t, x) => t + x.gercekM, 0);
  console.log(`model: ${k.length} kapsul, ${DUGUM_SAYISI} dugum x ${DUGUM.islemci} islemci ` +
    `birimi / ${DUGUM.bellek} MiB = ${DUGUM_SAYISI * DUGUM.islemci} / ` +
    `${DUGUM_SAYISI * DUGUM.bellek}`);
  console.log(`gercek toplam kullanim ${topC} islemci birimi, ${topM} MiB (tohum ${TOHUM})\n`);
  const bas = (s) => s.padStart(13);
  console.log(`${"ayar".padEnd(18)}${bas("yerlesen")}${bas("yerlesmeyen")}${bas("bos istek")}` +
    `${bas("israf")}${bas("cakisma")}${bas("kisitlanan")}${bas("sonlanan")}`);
  for (const kip of ["yok", "gercekci", "sisirilmis"]) {
    const o = olc(ayarla(k, kip));
    console.log(`${kip.padEnd(18)}${bas(String(o.yerlesen))}${bas(String(o.yerlesmeyen))}` +
      `${bas(String(o.bosIstek))}${bas(String(o.israf))}${bas(String(o.cakisma))}` +
      `${bas(String(o.kisitlanan))}${bas(String(o.sonlanan))}`);
  }
  console.log(`\ndugum basina gercek doluluk (islemci birimi / ${DUGUM.islemci}):`);
  for (const kip of ["yok", "gercekci", "sisirilmis"]) {
    const o = olc(ayarla(k, kip));
    console.log(`  ${kip.padEnd(12)}` + o.dugumler.map((d, i) =>
      `d${i}: ${d.kapsul.length} kapsul %${((d.gercekC / DUGUM.islemci) * 100).toFixed(0)}`)
      .join("   "));
  }
  console.log(`\nkarar icin gereken bilgi: ${k.length} kapsul x 2 bildirim = ${k.length * 2}, ` +
    `${DUGUM_SAYISI} dugum x 2 olcum = ${DUGUM_SAYISI * 2}, toplam ${k.length * 2 + DUGUM_SAYISI * 2}`);
  console.log(`zamanlayicinin gormedigi kalem: gercek kullanim (${k.length} kapsul x 2 = ${k.length * 2})`);
}
```

```
model: 18 kapsul, 3 dugum x 3000 islemci birimi / 4096 MiB = 9000 / 12288
gercek toplam kullanim 8503 islemci birimi, 10193 MiB (tohum 20260801)

ayar                   yerlesen  yerlesmeyen    bos istek        israf      cakisma   kisitlanan     sonlanan
yok                          18            0         9000            0         5503            0            0
gercekci                     18            0          640          675          557            1            1
sisirilmis                   11            7          280         3934            0            0            0

dugum basina gercek doluluk (islemci birimi / 3000):
  yok         d0: 18 kapsul %283   d1: 0 kapsul %0   d2: 0 kapsul %0
  gercekci    d0: 8 kapsul %108   d1: 5 kapsul %110   d2: 5 kapsul %65
  sisirilmis  d0: 4 kapsul %49   d1: 4 kapsul %56   d2: 3 kapsul %55

karar icin gereken bilgi: 18 kapsul x 2 bildirim = 36, 3 dugum x 2 olcum = 6, toplam 42
zamanlayicinin gormedigi kalem: gercek kullanim (18 kapsul x 2 = 36)
```

#### Üç Ayar, Üç Ayrı Başarısızlık

Üç satır üç ayrı dünya kuruyor. **İstek yok** ayarında defterdeki her düğüm boştur, bu yüzden on
sekiz kapsülün tamamı ilk düğüme yığılır: zamanlayıcı hiç hata yapmadığını düşünürken düğümün
gerçek doluluğu yüzde 283 olur ve 5.503 birimlik çakışma doğar. Kaynak paylaşımı burada işletim
sistemine kalır ve kimin yavaşladığı bildirimden okunamaz.

**Gerçekçi istek** ayarında on sekiz kapsül üç düğüme dağılır, boş istek 640 birime iner. Ayarın
kusursuz olmadığı iki sütunda görünür: gerçek kullanım bildirimin altında kaldığı için 675 birim
rezerve edilip kullanılmıyor, üstüne çıktığı yerlerde 557 birimlik çakışma kalıyor. Bir kapsül
işlemci sınırını aştığı için kısıtlanıyor, bir kapsül bellek sınırını aştığı için sonlandırılıyor.
**Sınırın yaptırımı yerleştirmeden bağımsızdır**: iki kapsül de yerleşmiş, ikisi de defterde
uygundur.

**Şişirilmiş istek** ayarında hiçbir çakışma ve hiçbir kesme yoktur; bedeli yedi kapsülün hiç
yerleşmemesidir. Düğümler gerçekte yarı boş çalışır (yüzde 49, 56, 55) ve 3.934 birim rezerve edilip
kullanılmadan durur. Bu ayar bir güvenlik ayarı gibi görünür, bir kapasite kaybıdır.

#### Sapma Taranınca İki Bedel Ayrışıyor

Bildirim gerçek kullanımın katı olarak yazılıp taranınca iki yönün bedeli ayrı ayrı sayılabilir.
Aynı tarama, bildirimin bir kez yapılıp yerinde kalmasının ve sınır çarpanı seçiminin sonucunu da
verir. Katsayı bir bilgi kalitesi ölçüsü gibi okunabilir: birden uzaklaştıkça bildirimin gerçeği ne
kadar yanlış anlattığı büyür.

```js
// zamanlama/sapma.mjs — istegin gercek kullanimdan sapmasi taranir: asiri bildirimin israfi,
// eksik bildirimin cakismasi. Model ve is yuku onceki dosyadan alinir.
import { DUGUM, DUGUM_SAYISI, SINIR_CARPANI, isYuku, olc } from "./istek.mjs";

const kapsuller = isYuku();
const KAPASITE = DUGUM_SAYISI * DUGUM.islemci;

// Istek = gercek kullanim x katsayi. Katsayi 1 ise bildirim kusursuzdur.
const bildir = (k, kat, buyume = 1) => k.map((x) => {
  const c = Math.round(x.gercekC * kat), m = Math.round(x.gercekM * kat);
  return { ...x, istekC: c, istekM: m,
           gercekC: Math.round(x.gercekC * buyume), gercekM: Math.round(x.gercekM * buyume),
           sinirC: Math.round(c * SINIR_CARPANI), sinirM: Math.round(m * SINIR_CARPANI) };
});

const s = (x) => String(x).padStart(12);
console.log(`istegin gercek kullanimdan sapmasi (${kapsuller.length} kapsul, kapasite ${KAPASITE}):`);
console.log(`${"katsayi".padEnd(10)}${s("yerlesen")}${s("yerlesmeyen")}${s("israf")}` +
  `${s("cakisma")}${s("kisitlanan")}${s("sonlanan")}`);
for (const kat of [0.5, 0.75, 0.9, 1.0, 1.25, 1.5, 2.0]) {
  const o = olc(bildir(kapsuller, kat));
  console.log(`${("x" + kat.toFixed(2)).padEnd(10)}${s(o.yerlesen)}${s(o.yerlesmeyen)}` +
    `${s(o.israf)}${s(o.cakisma)}${s(o.kisitlanan)}${s(o.sonlanan)}`);
}

// Bildirim bir kez yapilir, kullanim buyur: eskiyen bildirimin bedeli.
console.log(`\nbildirim x1,00'de sabit kalirken gercek kullanim buyurse (ZO5):`);
console.log(`${"buyume".padEnd(10)}${s("yerlesen")}${s("cakisma")}${s("kisitlanan")}${s("sonlanan")}`);
for (const b of [1.0, 1.1, 1.2, 1.3, 1.5]) {
  const o = olc(bildir(kapsuller, 1.0, b));
  console.log(`${("%" + ((b - 1) * 100).toFixed(0)).padEnd(10)}${s(o.yerlesen)}${s(o.cakisma)}` +
    `${s(o.kisitlanan)}${s(o.sonlanan)}`);
}

// ZO6: kisa sureli tepede kullanim %30 artiyor. Sinir carpani taranir.
const TEPE = 1.3;
console.log(`\nsinir carpani (istek x1,00 bildirim, tepede kullanim %30 yuksek):`);
console.log(`${"carpan".padEnd(10)}${s("kisitlanan")}${s("sonlanan")}${s("cakisma")}${s("sinir topl.")}`);
for (const c of [1.0, 1.1, 1.25, 1.5, 2.0]) {
  const k2 = kapsuller.map((x) => ({ ...x, istekC: x.gercekC, istekM: x.gercekM,
    gercekC: Math.round(x.gercekC * TEPE), gercekM: Math.round(x.gercekM * TEPE),
    sinirC: Math.round(x.gercekC * c), sinirM: Math.round(x.gercekM * c) }));
  const o = olc(k2);
  console.log(`${("x" + c.toFixed(2)).padEnd(10)}${s(o.kisitlanan)}${s(o.sonlanan)}${s(o.cakisma)}` +
    `${s(k2.reduce((t, x) => t + x.sinirC, 0))}`);
}
console.log(`\nsinir toplami x2,00 carpanda ${(kapsuller.reduce((t, x) => t + x.gercekC, 0) * 2 /
  KAPASITE).toFixed(2)} kat kapasite; sinir bir rezervasyon degildir, bir tavandir`);
```

```
istegin gercek kullanimdan sapmasi (18 kapsul, kapasite 9000):
katsayi       yerlesen yerlesmeyen       israf     cakisma  kisitlanan    sonlanan
x0.50               18           0           0        2965          18          18
x0.75               18           0           0        1916          18          18
x0.90               18           0           0         557           0           0
x1.00               17           1           0           0           0           0
x1.25               14           4        1720           0           0           0
x1.50               13           5        2876           0           0           0
x2.00                9           9        4322           0           0           0

bildirim x1,00'de sabit kalirken gercek kullanim buyurse (ZO5):
buyume        yerlesen     cakisma  kisitlanan    sonlanan
%0                  17           0           0           0
%10                 17         470           0           0
%20                 17        1058           0           0
%30                 17        1646          17          17
%50                 17        2879          17          17

sinir carpani (istek x1,00 bildirim, tepede kullanim %30 yuksek):
carpan      kisitlanan    sonlanan     cakisma sinir topl.
x1.00               17          17        1646        8503
x1.10               17          17        1646        9355
x1.25               17          17        1646       10630
x1.50                0           0        1646       12760
x2.00                0           0        1646       17006

sinir toplami x2,00 carpanda 1.89 kat kapasite; sinir bir rezervasyon degildir, bir tavandir
```

#### Aşırı Bildirimin İsrafı, Eksik Bildirimin Çakışması

Tarama simetrik değildir. Katsayı 1'in altına indikçe kapsüllerin tamamı yerleşir ve fatura
çakışmada birikir: yarım bildirimde 2.965 birim, dörtte üç bildirimde 1.916 birim ve on sekiz
kapsülün on sekizi hem kısıtlanır hem sonlandırılır. Katsayı 1'in üstüne çıkınca çakışma sıfırlanır,
fatura bu kez yerleşmeyen kapsüle ve israfa geçer: bir buçuk katta beş kapsül yerleşemez ve 2.876
birim boşta durur, iki katta dokuz kapsül yerleşemez.

Kusursuz bildirim satırı da bir şey öğretiyor. Katsayı tam 1 olduğunda çakışma sıfırdır, israf
sıfırdır, ama yine **bir kapsül yerleşemiyor**. Bunun nedeni bilgi eksikliği değil, ilk uyan düğüme
yerleştiren kuralın geriye bakmamasıdır: kalan boşluklar tek tek yeterli olmadığı için parçalanma
kalır. Bilgi kusursuz olsa bile yerleştirme kuralı bir kayıp üretir.

İkinci tablo bildirimin **eskimesini** ölçüyor. Bildirim yerinde kalırken gerçek kullanım yüzde 10
büyüdüğünde 470 birimlik çakışma, yüzde 20'de 1.058 birim doğuyor; yüzde 30'da on yedi kapsül aynı
anda hem kısıtlanıyor hem sonlandırılıyor. Bildirim bir ölçüm değil bir beyandır ve ölçüm gibi
tazelenmediği sürece sistemin elindeki en eski bilgidir.

Üçüncü tablo sınırın ne olmadığını gösteriyor. Çarpan 1'den 2'ye çıkarıldığında kısıtlanan kapsül
sayısı on yediden sıfıra iner, **çakışma 1.646 birimde hiç değişmez**. Sınır yalnız tek kapsülün
tepesini keser; düğümün toplamını korumaz. Sınırların toplamı iki katı çarpanda kümenin
kapasitesinin 1,89 katına çıkabilir, çünkü sınır bir rezervasyon değil bir tavandır. Düğüm
toplamını koruyan tek sayı istektir.

#### Bilginin Maliyeti ve Görülmeyen Kalem

Yerleştirme kararı için sistemin elinde kırk iki bilgi kalemi vardır: on sekiz kapsülün ikişer
bildirimi (otuz altı kalem) ve üç düğümün ikişer ölçümü (altı kalem). Bu kalemlerin maliyeti eşit
değildir. Altı ölçüm düğümdeki aracı süreçten düzenli gelir ve tazedir. Otuz altı bildirim bir kez
yazılır, kimse doğrulamaz ve yük değiştikçe sessizce yanlışlaşır.

Bu kalemi ölçmek imkânsız değildir, bedellidir: her kapsül için sürekli bir kullanım serisi
toplanması, saklanması ve bildirimle karşılaştırılması gerekir. Bu ders o seriyi zamanlayıcıya
vermez; verildiğinde ne olduğu bu konunun son iki dersinin konusudur.

Kırk üçüncü kalem hiç yoktur: **gerçek kullanım**. Zamanlayıcı bu dersteki hiçbir tabloda gerçek
kullanımı görmez. Yanlış kararların üçü de aynı boşluktan çıkar — istek yok ayarında on sekiz
kapsülü tek düğüme yığmak, gerçekçi ayarda 557 birimlik çakışmayı fark etmemek, şişirilmiş ayarda
yarı boş düğümler dururken yedi kapsülü bekletmek. Üçünde de zamanlayıcının defteri tutarlıdır;
tutarsız olan defter ile düğümdür.

#### Özet

- Kaynak isteği zamanlayıcının defterini, sınır düğümdeki koşumu belirler; bir kapsül yerleşip yine
  kısıtlanabilir ya da sonlandırılabilir.
- Üç ayarın bedelleri ayrıdır: istek yok ayarında on sekiz kapsül tek düğümde ve yüzde 283 doluluk,
  gerçekçi ayarda 640 birim boş istek ile 557 birim çakışma, şişirilmiş ayarda yedi yerleşmeyen
  kapsül ile 3.934 birim israf.
- Eksik bildirimin bedeli çakışma ve kesmedir (yarım bildirimde 2.965 birim, on sekiz kapsülün
  tamamı kısıtlanır); aşırı bildirimin bedeli yerleşmeyen kapsül ve israftır (iki katta dokuz kapsül
  yerleşemez, 4.322 birim boşta durur).
- Kusursuz bildirimde bile bir kapsül yerleşemiyor: bilgi tam olsa da ilk uyan düğüme yerleştiren
  kural parçalanma üretir.
- Sınır çarpanını dört katına çıkarmak kısıtlanan kapsülü on yediden sıfıra indirir, düğümdeki
  1.646 birimlik çakışmayı hiç değiştirmez; sınırların toplamı kapasitenin 1,89 katı olabilir.
- Karar kırk iki bilgi kalemine dayanıyor, otuz altısı tazelenmeyen bildirim; kırk üçüncü kalem olan
  gerçek kullanım hiç görünmüyor ve üç yanlış kararın da kaynağı bu.

#### Sonraki Adım

Bu dersin zamanlayıcısı tek bir soru soruyor: kalan istek yeter mi. Yerleşim kararının başka
yanları da vardır ve hiçbiri kapasiteyle ilgili değildir. Doğrulayıcının hızlı diski olan düğümlerde
koşması, aynı servisin kopyalarının aynı düğüme yığılmaması, bir bölge kaybında ayakta kalan kopya
kalmasının garanti edilmesi — bunların her biri zamanlayıcıya yeni bir kısıt ekler ve uygun düğüm
kümesini daraltır. Sonraki ders zamanlayıcıyı bir kısıt çözücü olarak yazar ve kısıt eklendikçe kaç
kapsülün yerleşemez hâle geldiğini sayar.

### Zamanlama Kısıtları

Source: https://academia.sh/tr/kurslar/orkestrasyon/zamanlama-kisitlari

Zamanlayıcının bir kısıt çözücü olarak yazılması: etiket seçimi, yakınlık, uzaklık ve topoloji dağılımı eklendikçe uygun düğüm kümesinin daralması, yerleşemeyen kapsüllerin sayılması, iki kısıtın birbirini çözümsüz kılması ve topoloji dağılımının bir bölge kaybında ayakta kalan kopya sayısını nasıl değiştirdiği.

Önceki dersin zamanlayıcısı tek soru soruyordu: kalan istek yeter mi. Yerleşimin başka yanları da
vardır ve hiçbiri kapasiteyle ilgili değildir. Doğrulayıcının hızlı diski olan düğümlerde koşması,
aynı servisin iki kopyasının aynı düğüme yığılmaması, faturalamanın doğrulayıcıyla aynı düğümde
durması, bir bölge kaybında ayakta kopya kalması — bunların her biri, kapasitesi yeten bir düğümü
uygunsuz hâle getirir.

Bu kısıtlar zamanlayıcıyı bir **kısıt çözücüye** çevirir. Karar aynı kalır (hangi kapsül hangi
düğüme), ama karar artık bir arama uzayında yapılır: her kapsül için önce **uygun düğüm kümesi**
hesaplanır, sonra o kümeden biri seçilir. Küme boşalırsa karar verilemez ve kapsül yerleşmez. Bu
derste ölçülen şey budur: kısıt eklendikçe küme ne kadar daralıyor, hangi noktada boşalıyor.

Model üç bölgeye yayılmış dokuz düğümdür; iş yükü bölgesel ölçüm ağının (kurgu) üç servisidir.
Gerçek bir küme koşturulmaz.

#### Kısıt Çözücü ve Uygun Düğüm Kümesi

Dört kısıt türü birikimli eklenir. **Etiket seçimi** düğümün bir etiketini şart koşar, **yakınlık**
başka bir servisin varlığını, **uzaklık** aynı servisin yokluğunu, **topoloji dağılımı** ise
bölgeler arası kopya farkını sınırlar. Seçim kuralı önceki dersteki gibidir: uygun kümedeki ilk
düğüm.

Kısıtlar kendi küçük şemamızla yazılır. Düğüm bildirimi iki etiket taşır: bölge ve disk türü.
Kapsül bildirimi üç alanla kısıt koyar — `disk` alanı düğümün disk etiketini şart koşar, `uzaklik`
alanı aynı servisten kopya bulunmayan bir düğüm ister, `yakinlik` alanı adı verilen servisin
bulunduğu düğümü ister. Topoloji dağılımı kapsüle değil çözücüye ait bir kuraldır ve bir sapma
sayısıyla ayarlanır. Çözücü bu alanların dışında hiçbir şey okumaz; okumadığı her şey, düğümde ne kadar
gerçek olursa olsun, kararın dışındadır.

```js
// zamanlama/kisit.mjs — zamanlayici bir KISIT COZUCU olarak. Gercek kume degil, model.
// Kisitlar birikimli eklenir; her asamada uygun dugum kumesinin daralmasi olculur.
export const BOLGE = ["b1", "b2", "b3"];
// ZO7: uc bolge x uc dugum, dugum basina 1500 islemci birimi
// ZO8: hizli disk yalniz her bolgenin ilk dugumunde
export const DUGUMLER = BOLGE.flatMap((b, i) =>
  [0, 1, 2].map((j) => ({ ad: `${b}-d${j}`, bolge: b, disk: j === 0 ? "hizli" : "genel",
                          kapasite: 1500 })));

// ZO9: is yuku — dogrulayici hizli disk ister, faturalama dogrulayiciyla ayni dugumu ister
export const ISYUKU = [
  { servis: "dogrulayici", kopya: 6, birim: 650, disk: "hizli", uzaklik: true },
  { servis: "faturalama", kopya: 3, birim: 300, yakinlik: "dogrulayici", uzaklik: true },
  { servis: "okuma-toplayici", kopya: 9, birim: 420 },
];

export const kapsulleriAc = (yuk = ISYUKU) => yuk.flatMap((s) =>
  Array.from({ length: s.kopya }, (_, i) => ({ ...s, ad: `${s.servis}-${i + 1}` })));

// ZO10: topoloji dagilimi — bir servisin bolgeler arasi kopya farki en fazla 1
export const SAPMA = 1;

export function coz(kisit, yuk = ISYUKU, dugumler = DUGUMLER) {
  const durum = dugumler.map((d) => ({ ...d, dolu: 0, kapsul: [] }));
  const bolgeSayim = new Map();          // servis -> bolge -> adet
  const yerlesmeyen = [];
  const uygunlar = [];
  const say = (s, b) => (bolgeSayim.get(s) ?? {})[b] ?? 0;

  for (const k of kapsulleriAc(yuk)) {
    const uygun = durum.filter((d) => {
      if (d.dolu + k.birim > d.kapasite) return false;
      if (kisit.etiket && k.disk && d.disk !== k.disk) return false;
      if (kisit.uzaklik && k.uzaklik && d.kapsul.some((x) => x.servis === k.servis)) return false;
      if (kisit.yakinlik && k.yakinlik && !d.kapsul.some((x) => x.servis === k.yakinlik))
        return false;
      if (kisit.topoloji) {
        const enAz = Math.min(...BOLGE.map((b) => say(k.servis, b)));
        if (say(k.servis, d.bolge) + 1 - enAz > SAPMA) return false;
      }
      return true;
    });
    uygunlar.push(uygun.length);
    if (uygun.length === 0) { yerlesmeyen.push(k); continue; }
    const d = uygun[0];                  // ilk uyan dugum: kural geriye bakmaz
    d.dolu += k.birim; d.kapsul.push(k);
    const m = bolgeSayim.get(k.servis) ?? {};
    m[d.bolge] = (m[d.bolge] ?? 0) + 1; bolgeSayim.set(k.servis, m);
  }
  return { durum, yerlesmeyen, uygunlar, bolgeSayim };
}

export const dagilim = (o, servis) =>
  BOLGE.map((b) => (o.bolgeSayim.get(servis) ?? {})[b] ?? 0);

const ASAMA = [
  ["yalniz kapasite", {}],
  ["+ etiket secimi", { etiket: 1 }],
  ["+ yakinlik", { etiket: 1, yakinlik: 1 }],
  ["+ uzaklik", { etiket: 1, yakinlik: 1, uzaklik: 1 }],
  ["+ topoloji dagilimi", { etiket: 1, yakinlik: 1, uzaklik: 1, topoloji: 1 }],
];

if (process.argv[1].endsWith("kisit.mjs")) {
  const toplam = ISYUKU.reduce((t, s) => t + s.kopya, 0);
  console.log(`model: ${DUGUMLER.length} dugum / ${BOLGE.length} bolge, ${toplam} kapsul, ` +
    `hizli diskli dugum ${DUGUMLER.filter((d) => d.disk === "hizli").length}`);
  const s = (x, n = 13) => String(x).padStart(n);
  console.log(`${"asama".padEnd(22)}${s("uygun ort.")}${s("uygun en az")}${s("yerlesen")}` +
    `${s("yerlesemeyen")}${s("dolu dugum")}`);
  for (const [ad, kisit] of ASAMA) {
    const o = coz(kisit);
    const ort = o.uygunlar.reduce((t, x) => t + x, 0) / o.uygunlar.length;
    console.log(`${ad.padEnd(22)}${s(ort.toFixed(2))}${s(Math.min(...o.uygunlar))}` +
      `${s(toplam - o.yerlesmeyen.length)}${s(o.yerlesmeyen.length)}` +
      `${s(o.durum.filter((d) => d.kapsul.length > 0).length)}`);
  }
  console.log(`\nservis basina bolge dagilimi (${BOLGE.join("/")}):`);
  console.log(`${"asama".padEnd(22)}${s("dogrulayici")}${s("faturalama")}${s("toplayici", 16)}`);
  for (const [ad, kisit] of ASAMA) {
    const o = coz(kisit);
    console.log(`${ad.padEnd(22)}${s(dagilim(o, "dogrulayici").join("/"))}` +
      `${s(dagilim(o, "faturalama").join("/"))}${s(dagilim(o, "okuma-toplayici").join("/"), 16)}`);
  }
}
```

```
model: 9 dugum / 3 bolge, 18 kapsul, hizli diskli dugum 3
asama                    uygun ort.  uygun en az     yerlesen yerlesemeyen   dolu dugum
yalniz kapasite                5.83            3           18            0            7
+ etiket secimi                3.83            1           18            0            7
+ yakinlik                     3.17            0           15            3            6
+ uzaklik                      4.28            0           15            3            6
+ topoloji dagilimi            3.00            0           15            3            6

servis basina bolge dagilimi (b1/b2/b3):
asama                   dogrulayici   faturalama       toplayici
yalniz kapasite               6/0/0        0/3/0           0/7/2
+ etiket secimi               2/2/2        3/0/0           4/5/0
+ yakinlik                    2/2/2        0/0/0           6/3/0
+ uzaklik                     1/1/1        1/1/1           7/2/0
+ topoloji dagilimi           1/1/1        1/1/1           3/3/3
```

#### Daralma Tek Yönlü Değil

İlk tablo beklenen daralmayı gösteriyor: kapsül başına ortalama uygun düğüm sayısı 5,83'ten etiket
seçimiyle 3,83'e, yakınlıkla 3,17'ye iniyor. En az uygun düğüm sayısı sütunu daha keskin — etiket
seçimi bir kapsül için kümeyi tek düğüme indiriyor, yakınlık eklenince küme **sıfırlanıyor** ve üç
faturalama kapsülü yerleşemiyor. Nedeni ikinci tabloda: doğrulayıcı kopyaları hızlı diskli üç düğümü
ikişer ikişer doldurunca o düğümlerde faturalama için yer kalmıyor. Yakınlık kısıtı yer istemez,
ama yer bırakılmasını gerektirir.

Sonraki satır dersin ters sonucudur. Uzaklık kısıtı eklenince ortalama uygun düğüm sayısı düşmüyor,
3,17'den **4,28'e çıkıyor**. Kısıt sayısı arttığı hâlde arama uzayının genişlemesinin nedeni şudur:
uzaklık, doğrulayıcıyı düğüm başına bir kopyaya indirdiği için üç kopya yerleşemez hâle geliyor ve
onların tutmadığı kapasite sonraki kapsüllerin uygun kümesini büyütüyor. Yerleşen kapsül sayısı
on beşte kalırken bileşimi değişiyor: faturalamanın üç kapsülü artık yerleşiyor, doğrulayıcının üç
kopyası yerleşemiyor. **Bir kısıt bir servisi kurtarırken başka bir servisi düşürüyor** ve toplam
sayı bunu göstermiyor.

Topoloji dağılımı satırında yerleşen sayısı yine on beş, ortalama uygun küme 3,00. Değişen tek şey
son sütundadır: okuma toplayıcının bölge dağılımı 7/2/0 iken 3/3/3 oluyor. Bu kısıt hiçbir kapsülü
düşürmüyor, yalnız yerleşimin şeklini değiştiriyor — ve karşılığı ancak bir bölge kaybedildiğinde
görünür.

#### Bölge Kaybı, Çözümsüzlük ve Yanlış Etiket

```js
// zamanlama/bolge.mjs — topoloji dagiliminin bolge kaybindaki karsiligi, kisitlarin birbirini
// imkansiz kilmasi ve etiket bildiriminin yanlisligi. Model onceki dosyadan gelir.
import { BOLGE, DUGUMLER, ISYUKU, coz, dagilim } from "./kisit.mjs";

const TAM = { etiket: 1, yakinlik: 1, uzaklik: 1, topoloji: 1 };
const TOPOLOJISIZ = { etiket: 1, yakinlik: 1, uzaklik: 1 };
const s = (x, n = 12) => String(x).padStart(n);
const SERVISLER = ["dogrulayici", "faturalama", "okuma-toplayici"];

// ZO12: bolge kaybi, o bolgedeki uc dugumun ayni anda erisilemez olmasidir.
console.log("bir bolge kaybinda ayakta kalan kopya (yerlesen / kayiptan sonra):");
console.log(`${"ayar".padEnd(16)}${"kayip".padEnd(8)}` +
  ["dogrulayici", "faturalama", "toplayici"].map((x) => s(x, 14)).join("") +
  s("toplam kalan", 14));
for (const [ad, kisit] of [["topoloji yok", TOPOLOJISIZ], ["topoloji var", TAM]]) {
  const o = coz(kisit);
  for (const kayip of BOLGE) {
    const kalan = SERVISLER.map((sv) => {
      const d = dagilim(o, sv), i = BOLGE.indexOf(kayip);
      return [d.reduce((t, x) => t + x, 0), d.reduce((t, x, j) => t + (j === i ? 0 : x), 0)];
    });
    console.log(`${ad.padEnd(16)}${kayip.padEnd(8)}` +
      kalan.map(([t, k]) => s(`${t} / ${k}`, 14)).join("") +
      s(kalan.reduce((t, [, k]) => t + k, 0), 14));
  }
}

// Kisitlarin birbirini imkansiz kilmasi: dogrulayici 6 kopya, hizli diskli dugum 3, her dugumde
// en fazla bir kopya. Ucuncu satir cozumsuzdur; sonuncu satir dugum etiketini genisletir.
const HIZLI6 = DUGUMLER.map((d, i) => ({ ...d, disk: i % 3 < 2 ? "hizli" : "genel" }));
const YALNIZ_D = ISYUKU.filter((x) => x.servis === "dogrulayici");
console.log("\ndogrulayici 6 kopya, kisit bilesimleri:");
console.log(`${"bilesim".padEnd(34)}${s("hizli dugum")}${s("yerlesen")}${s("cozumsuz")}`);
for (const [ad, kisit, dgm] of [
  ["kisitsiz", {}, DUGUMLER],
  ["yalniz etiket secimi", { etiket: 1 }, DUGUMLER],
  ["yalniz uzaklik", { uzaklik: 1 }, DUGUMLER],
  ["etiket + uzaklik", { etiket: 1, uzaklik: 1 }, DUGUMLER],
  ["etiket + uzaklik, 6 hizli dugum", { etiket: 1, uzaklik: 1 }, HIZLI6],
]) {
  const o = coz(kisit, YALNIZ_D, dgm);
  console.log(`${ad.padEnd(34)}${s(dgm.filter((d) => d.disk === "hizli").length)}` +
    `${s(6 - o.yerlesmeyen.length)}${s(o.yerlesmeyen.length)}`);
}

// ZO11: etiket bir bildirimdir, olcum degil. Bir dugumun etiketi eksik yazilirsa ne oluyor.
console.log("\netiket bildirimi bozulunca (tam kisit kumesi):");
console.log(`${"bildirim".padEnd(34)}${s("yerlesen", 14)}${s("yerlesemeyen", 14)}${s("dolu dugum", 14)}`);
for (const [ad, dgm] of [
  ["dogru", DUGUMLER],
  ["b2-d0 hizli etiketi eksik", DUGUMLER.map((d) => d.ad === "b2-d0" ? { ...d, disk: "genel" } : d)],
  ["b3-d1 yanlislikla hizli", DUGUMLER.map((d) => d.ad === "b3-d1" ? { ...d, disk: "hizli" } : d)],
]) {
  const o = coz(TAM, ISYUKU, dgm);
  console.log(`${ad.padEnd(34)}${s(18 - o.yerlesmeyen.length, 14)}${s(o.yerlesmeyen.length, 14)}` +
    `${s(o.durum.filter((d) => d.kapsul.length > 0).length, 14)}`);
}
const etiketKalem = DUGUMLER.length * 2;
const kapsulKalem = ISYUKU.reduce((t, x) =>
  t + x.kopya * ((x.disk ? 1 : 0) + (x.uzaklik ? 1 : 0) + (x.yakinlik ? 1 : 0)) + 1, 0);
console.log(`\nkisit cozucunun okudugu bildirim: ${etiketKalem} dugum etiketi + ` +
  `${kapsulKalem} kapsul kisiti = ${etiketKalem + kapsulKalem}; hicbiri olcum degil`);
```

```
bir bolge kaybinda ayakta kalan kopya (yerlesen / kayiptan sonra):
ayar            kayip      dogrulayici    faturalama     toplayici  toplam kalan
topoloji yok    b1               3 / 2         3 / 2         9 / 2             6
topoloji yok    b2               3 / 2         3 / 2         9 / 7            11
topoloji yok    b3               3 / 2         3 / 2         9 / 9            13
topoloji var    b1               3 / 2         3 / 2         9 / 6            10
topoloji var    b2               3 / 2         3 / 2         9 / 6            10
topoloji var    b3               3 / 2         3 / 2         9 / 6            10

dogrulayici 6 kopya, kisit bilesimleri:
bilesim                            hizli dugum    yerlesen    cozumsuz
kisitsiz                                     3           6           0
yalniz etiket secimi                         3           6           0
yalniz uzaklik                               3           6           0
etiket + uzaklik                             3           3           3
etiket + uzaklik, 6 hizli dugum              6           6           0

etiket bildirimi bozulunca (tam kisit kumesi):
bildirim                                yerlesen  yerlesemeyen    dolu dugum
dogru                                         15             3             6
b2-d0 hizli etiketi eksik                     13             5             5
b3-d1 yanlislikla hizli                       16             2             6

kisit cozucunun okudugu bildirim: 18 dugum etiketi + 21 kapsul kisiti = 39; hicbiri olcum degil
```

#### Üç Ölçüm

**Bölge kaybı.** Topoloji dağılımı yokken sonuç kaybedilen bölgeye bağlıdır: b1 düşerse dokuz
okuma toplayıcıdan yalnız ikisi kalır; b3 düşerse dokuzu da kalır. Ayakta kalan toplam kopya altı
ile on üç arasında salınır ve hangi sayının çıkacağını kimse seçmemiştir. Topoloji dağılımıyla üç
satırın üçü de aynıdır: hangi bölge düşerse düşsün altı toplayıcı, toplam on kopya ayakta kalır.
**Kısıtın kazandırdığı şey ortalama değil, en kötü durumdur** — en kötü durum altıdan ona çıkıyor,
en iyi durum on üçten ona iniyor.

**Çözümsüzlük.** İkinci tablo iki kısıtın tek başına zararsız, birlikte çözümsüz olduğunu sayıyla
gösteriyor. Yalnız etiket seçimiyle altı kopya yerleşiyor, yalnız uzaklıkla altı kopya yerleşiyor,
ikisi birlikte yalnız üçü yerleşiyor ve üç kopya çözümsüz kalıyor. Çarpışan şey kısıtların kendisi
değil, bir sayıdır: uzaklık kısıtı kopya sayısı kadar **ayrı** düğüm ister, etiket seçimi ise uygun
düğüm sayısını üçe indirir. Son satır çözümü de sayıyla veriyor — hızlı diskli düğüm sayısı altıya
çıkarıldığında altı kopyanın altısı yerleşiyor. Çözümsüzlük bildirimde değil, kümenin
donanımındadır.

**Yanlış etiket.** Üçüncü tablo kısıtların dayandığı bilginin türünü ortaya koyuyor. Otuz dokuz
bildirimin hiçbiri ölçüm değildir: on sekiz düğüm etiketi bir insan tarafından yazılmıştır ve yirmi
bir kapsül kısıtı da öyle. Bir düğümün hızlı disk etiketi eksik kaldığında yerleşen kapsül on
beşten on üçe iniyor; hata görünür, çünkü bir şey yerleşemiyor.

Asıl sorun sonraki satırdadır. Hızlı diski olmayan bir düğüm yanlışlıkla hızlı diye etiketlenince
yerleşen kapsül sayısı on altıya **çıkıyor**. Çözücünün defterinde durum düzelmiştir; gerçekte bir
doğrulayıcı kopyası yavaş diskli bir düğümde koşmaktadır ve bunu hiçbir sayaç bildirmez.
Zamanlayıcı düğümün diskini ölçmez, etiketini okur. Yanlış kararın kaynağı yine bilgi kaleminin
kendisi değil, **kalemin bildirim olmasıdır**.

#### Özet

- Kısıt eklendikçe kapsül başına ortalama uygun düğüm sayısı 5,83'ten 3,83'e, sonra 3,17'ye iniyor;
  yakınlık kısıtında küme sıfırlanıyor ve üç faturalama kapsülü yerleşemiyor.
- Kısıt eklemek arama uzayını her zaman daraltmaz: uzaklık kısıtı ortalamayı 3,17'den 4,28'e
  çıkarıyor, çünkü yerleşemeyen üç doğrulayıcının tutmadığı kapasite sonraki kapsüllere kalıyor.
- Aynı yerleşen sayısı farklı bileşimleri gizleyebilir: on beş kapsül yerleşirken bir kısıt
  faturalamanın üçünü kurtarıp doğrulayıcının üçünü düşürüyor.
- Topoloji dağılımı hiçbir kapsülü düşürmeden en kötü durumu düzeltiyor: bölge kaybında ayakta kalan
  kopya 6–13 aralığından sabit 10'a geçiyor, okuma toplayıcı dağılımı 7/2/0 yerine 3/3/3 oluyor.
- İki kısıt tek başına zararsız, birlikte çözümsüzdür: altı kopya, üç hızlı diskli düğüm ve düğüm
  başına tek kopya kuralı üç çözümsüz kapsül verir; hızlı düğüm sayısı altıya çıkınca çözümsüzlük
  biter.
- Çözücünün okuduğu otuz dokuz kalemin hiçbiri ölçüm değildir; yanlış yazılmış bir etiket yerleşen
  sayısını on beşten on altıya çıkarır ve hatayı görünmez kılar.

#### Sonraki Adım

Buraya kadarki kısıtlar kapsülün düğüm hakkında ne istediğini yazıyor. Ters yön hiç yazılmadı:
düğümün hangi kapsülü kabul edeceği. Bölgesel ölçüm ağında gecelik toplu iş bütün diski ve belleği
tüketiyor ve onunla aynı düğüme düşen bir servis kopyası gece boyunca yavaşlıyor. Bu düğümleri toplu
işe ayırmanın yolu her kapsüle bir kısıt daha yazmak değildir; düğümün kendisine bir işaret koymak
ve yalnız o işarete tolerans gösteren kapsüllerin gelmesine izin vermektir. Sonraki ders bu ayrımı
ve ayrılan kapasitenin boş kalma oranını ölçer.

### İşaretler ve Toleranslar

Source: https://academia.sh/tr/kurslar/orkestrasyon/isaretler-ve-toleranslar

Düğüm ayrımının işaret ve toleransla kurulması: işaretlenmiş düğümler ayrıldığında genel iş yükünün kaç düğüme sığdığı, ayrılan kapasitenin boş kalma oranı, işaretin üç etkisinin (yerleştirme, koşmaya devam, tahliye) ayrı ayrı ölçülmesi ve yanlış verilen toleransın kaç kapsülü yanlış düğüme düşürdüğü.

Önceki dersteki kısıtların hepsi aynı yöne bakıyordu: kapsül düğüm hakkında bir şey istiyordu. Ters
yön hiç yazılmadı. Bölgesel ölçüm ağında (kurgu) gecelik toplu iş diski ve belleği doyurur; onunla
aynı düğüme düşen bir servis kopyası gece boyunca yavaşlar. Bu düğümleri toplu işe ayırmanın yolu on
sekiz kapsülün her birine "şu düğümlere gitme" kısıtı yazmak değildir; o çözüm her yeni serviste
yeniden yazılmayı gerektirir ve unutulan tek bildirim ayrımı bozar.

**İşaret** düğüme konur ve varsayılanı tersine çevirir: düğüm, aksini söylemeyen her kapsülü
reddeder. **Tolerans** kapsüle yazılır ve yalnız o reddi kaldırır. Bir kapsülün gelmesi için iki
bildirimin de olması gerekir, ama ikisi de yetmez — tolerans izin verir, çekmez. Kapsülü ayrılan
düğüme **götüren** şey hâlâ önceki dersin etiket seçimidir.

Ölçülen şey bir modeldir; gerçek küme koşturulmaz.

#### Düğümün Koyduğu Koşul

Model dokuz düğüm, on sekiz genel kapsül ve altı toplu iş kapsülüdür. İşaretli düğüm sayısı sıfırdan
beşe taranır ve her adımda üç şey sayılır: genel iş yükünün kaç düğüme sığdığı, kaç kapsülün
yerleşemediği, ayrılan kapasitenin ne kadarının boş kaldığı.

```js
// zamanlama/isaret.mjs — dugum ayrimi: isaret ve tolerans. Gercek kume degil, model.
// Isaret dugume konur, tolerans kapsule yazilir; tolerans izin verir, cekmez.
export const DUGUM_SAYISI = 9, KAPASITE = 1500;   // ZO13: dokuz dugum, dugum basina 1500 birim
export const SIRA = [0, 3, 6, 1, 4];              // isaretleme sirasi: once her bolgeden biri

export const dugumleriAc = (isaretli, etki = "engel") =>
  Array.from({ length: DUGUM_SAYISI }, (_, i) => ({
    ad: `d${i}`, kapasite: KAPASITE, dolu: 0, kapsul: [],
    isaret: SIRA.slice(0, isaretli).includes(i) ? { anahtar: "toplu-is", etki } : null,
  }));

// ZO14: genel is yuku ve gecelik toplu is (bolgesel olcum agi, kurgu)
export const GENEL = [["okuma-toplayici", 9, 420], ["dogrulayici", 6, 650],
                      ["faturalama", 3, 300]];
export const TOPLU = [["gecelik-toplu", 6, 700]];
export const kapsuller = (liste, ek = {}) => liste.flatMap(([ad, n, birim]) =>
  Array.from({ length: n }, (_, i) => ({ ad: `${ad}-${i + 1}`, servis: ad, birim, ...ek })));

// Isaretin birinci etkisi: toleransi olmayan kapsul isaretli dugume yerlesemez.
// Ucuncu etki (tercih edilmeme) isaretli dugumu son caraya iter, yasaklamaz.
export function yerlestir(kapsullerListesi, dugumler) {
  const yerlesmeyen = [], yanlisDugum = [];
  for (const k of kapsullerListesi) {
    const uygun = dugumler.filter((d) => {
      if (d.dolu + k.birim > d.kapasite) return false;
      if (k.secim && d.isaret?.anahtar !== k.secim) return false;
      return d.isaret === null || k.tolerans === true || d.isaret.etki === "tercih";
    });
    const oncelikli = uygun.filter((d) => d.isaret === null || d.isaret.etki !== "tercih" ||
      k.tolerans === true);
    const d = (oncelikli.length > 0 ? oncelikli : uygun)[0];
    if (d === undefined) { yerlesmeyen.push(k); continue; }
    d.dolu += k.birim; d.kapsul.push(k);
    if (d.isaret !== null && k.servis !== "gecelik-toplu") yanlisDugum.push(k);
  }
  return { dugumler, yerlesmeyen, yanlisDugum };
}

export const dolu = (dugumler) => dugumler.filter((d) => d.kapsul.length > 0).length;
export const TOPLAM_GENEL = GENEL.reduce((t, [, n]) => t + n, 0);

if (process.argv[1].endsWith("isaret.mjs")) {
  const gb = GENEL.reduce((t, [, n, b]) => t + n * b, 0);
  const tb = TOPLU.reduce((t, [, n, b]) => t + n * b, 0);
  console.log(`model: ${DUGUM_SAYISI} dugum x ${KAPASITE} birim = ${DUGUM_SAYISI * KAPASITE}; ` +
    `genel is yuku ${gb} birim / ${TOPLAM_GENEL} kapsul, gecelik toplu is ${tb} birim / 6 kapsul`);
  console.log("ZO15: toplu is gunde 4 saat kosar; ayrilan dugum gunun 24 saatini bekler\n");
  const s = (x, n = 16) => String(x).padStart(n);
  console.log(`${"isaretli".padEnd(10)}${s("genel yerlesen")}${s("yerlesemeyen")}` +
    `${s("genel dugum")}${s("toplu yerlesen")}${s("ayrilan s/gun")}${s("bos oran")}`);
  for (let k = 0; k <= 5; k++) {
    const d = dugumleriAc(k);
    const g = yerlestir(kapsuller(GENEL), d);
    const genelDugum = dolu(d);
    const t = yerlestir(kapsuller(TOPLU, { tolerans: true, secim: "toplu-is" }), d);
    const topluDugum = d.filter((x) => x.kapsul.some((y) => y.servis === "gecelik-toplu")).length;
    const ayrilan = k * 24, kullanilan = topluDugum * 4;
    console.log(`${String(k).padEnd(10)}${s(TOPLAM_GENEL - g.yerlesmeyen.length)}` +
      `${s(g.yerlesmeyen.length)}${s(genelDugum)}${s(6 - t.yerlesmeyen.length)}${s(ayrilan)}` +
      `${s(k === 0 ? "-" : "%" + (100 * (1 - kullanilan / ayrilan)).toFixed(1))}`);
  }
}
```

```
model: 9 dugum x 1500 birim = 13500; genel is yuku 8580 birim / 18 kapsul, gecelik toplu is 4200 birim / 6 kapsul
ZO15: toplu is gunde 4 saat kosar; ayrilan dugum gunun 24 saatini bekler

isaretli    genel yerlesen    yerlesemeyen     genel dugum  toplu yerlesen   ayrilan s/gun        bos oran
0                       18               0               7               0               0               -
1                       18               0               7               2              24           %83.3
2                       18               0               7               4              48           %83.3
3                       15               3               6               6              72           %83.3
4                       13               5               5               6              96           %87.5
5                       11               7               4               6             120           %90.0
```

#### Ayırmanın İki Faturası

İlk satır tolerans ile etiket seçiminin farkını sayıyla veriyor. İşaretli düğüm yokken toplu işin
altı kapsülünün **hiçbiri yerleşemiyor**, çünkü toplu iş kapsülleri işaretli düğüm arayan bir seçim
taşıyor ve öyle bir düğüm yok. Toleransları yerinde duruyor; tolerans tek başına hiçbir kapsülü
hiçbir yere götürmüyor.

Birinci fatura genel iş yükünündür. Bir ya da iki düğüm ayrıldığında genel iş yükü hâlâ yedi düğüme
sığıyor ve on sekiz kapsülün on sekizi yerleşiyor; üç düğüm ayrıldığında altı düğüme sıkışıyor ve
**üç kapsül yerleşemiyor**. Beş düğüm ayrılınca yerleşemeyen sayısı yediye çıkıyor. Ayırma bir
yalıtım kararıdır ve karşılığı doğrudan genel iş yükünün kapasitesinden ödenir.

İkinci fatura ayrılan kapasitenin kendisindedir. Toplu iş günde dört saat koşar, ayrılan düğüm ise
yirmi dört saat bekler: boş kalma oranı en iyi durumda yüzde 83,3'tür. Bu oran ayırmanın verimsizliği
değil, tanımıdır — ayırma zamanı değil düğümü ayırır. Üçten fazla düğüm ayrıldığında oran daha da
bozuluyor (yüzde 87,5, sonra yüzde 90), çünkü toplu iş üç düğümden fazlasını kullanmıyor ve fazladan
ayrılan her düğüm gününün tamamını boş geçiriyor. Üç düğüm ayrıldığında günde 72 düğüm-saat rezerve
edilip 12 düğüm-saat kullanılıyor.

Bu iki fatura, ayrımın bildirim maliyetiyle birlikte okunmalıdır. Aynı ayrımı kapsül tarafından
kurmak on sekiz genel kapsülün her birine bir kısıt yazmayı gerektirir; işaretle kurmak üç düğüm
işareti ve altı toleranstan, yani dokuz kalemden ibarettir. Fark yalnız sayıda değil, **kimin
unutabileceğindedir**: kapsül tarafındaki kurulumda kısıtı yazmayı unutan yeni bir servis ayrımı
sessizce bozar; düğüm tarafındaki kurulumda unutan servis yalnız ayrılan düğümlere giremez. Yanlış
yönde kurulmuş bir ayrım her yeni serviste yeniden bozulabilir.

Boş kalma oranı da tek bir sayıya bağlıdır. Ayrılan düğüm günün tamamını beklediği için oran
doğrudan pencerenin genişliğinden çıkar: dört saatlik pencerede yüzde 83,3, sekiz saatlikte yüzde
66,7, bir saatlikte yüzde 95,8. Ayırma kararı bu yüzden bir kaynak kararı değil, bir **pencere**
kararıdır; toplu işin süresi kısaldıkça ayrılan düğümün bedeli oransal olarak büyür.

#### İşaretin Üç Etkisi ve Yanlış Tolerans

İşaret tek bir şey yapmaz. Aynı işaret üç ayrı etkiyle konabilir: yeni kapsülün yerleşmesini
engellemek, hâlihazırda koşan kapsülleri de çıkarmak, ya da yalnız tercih sırasını düşürmek. Üçü
ayrı ayrı ölçülür ve ardından tolerans yanlış verildiğinde ne olduğu taranır. Üç etkinin ayrımı
yalnız bir ayar farkı değildir: birincisi gelecekteki yerleştirmeleri, ikincisi hâlihazırda koşan
kapsülleri, üçüncüsü ise yalnız sıralamayı bağlar. Aynı ayrım niyeti üç ayrı sonuç verir ve
aralarındaki fark ancak sayılırsa görünür.

```js
// zamanlama/tolerans.mjs — isaretin uc etkisi ayri ayri, ve yanlis verilen toleransin bedeli.
import { GENEL, TOPLU, SIRA, TOPLAM_GENEL, dugumleriAc, kapsuller, yerlestir } from "./isaret.mjs";

const ISARETLI = 3;                     // ZO16: uc dugum gecelik toplu ise ayrilir
const genelKapsuller = (toleransli = 0) =>
  kapsuller(GENEL).map((k, i) => (i < toleransli ? { ...k, tolerans: true } : k));
const topluKapsuller = () => kapsuller(TOPLU, { tolerans: true, secim: "toplu-is" });
const s = (x, n = 16) => String(x).padStart(n);

// Ikinci etki: kapsuller kostuktan SONRA isaret konursa toleransi olmayanlar cikarilir.
function sonradanIsaretle(toleransli = 0) {
  const d = dugumleriAc(0);
  yerlestir(genelKapsuller(toleransli), d);
  const kume = new Set(SIRA.slice(0, ISARETLI));
  const cikarilan = [];
  d.forEach((x, i) => {
    if (!kume.has(i)) return;
    x.isaret = { anahtar: "toplu-is", etki: "tahliye" };
    cikarilan.push(...x.kapsul.filter((k) => k.tolerans !== true));
    x.kapsul = x.kapsul.filter((k) => k.tolerans === true);
    x.dolu = x.kapsul.reduce((t, k) => t + k.birim, 0);
  });
  const yeniden = yerlestir(cikarilan, d);
  const korunan = d.filter((x, i) => kume.has(i))
    .reduce((t, x) => t + x.kapsul.filter((k) => k.tolerans === true).length, 0);
  return { cikarilan: cikarilan.length, yerlesemeyen: yeniden.yerlesmeyen.length, korunan };
}

console.log(`isaretin uc etkisi ayri ayri (${ISARETLI} dugum ayrilmis, tolerans dogru verilmis):`);
console.log(`${"etki".padEnd(24)}${s("genel yerlesen")}${s("ayrilanda genel")}${s("cikarilan")}` +
  `${s("yeniden yerlesmeyen", 21)}`);
for (const etki of ["engel", "tercih"]) {
  const d = dugumleriAc(ISARETLI, etki);
  const g = yerlestir(genelKapsuller(), d);
  console.log(`${(etki === "engel" ? "yerlestirme engeli" : "tercih edilmeme").padEnd(24)}` +
    `${s(TOPLAM_GENEL - g.yerlesmeyen.length)}${s(g.yanlisDugum.length)}${s(0)}${s(0, 21)}`);
}
const t2 = sonradanIsaretle();
console.log(`${"kosmaya devam engeli".padEnd(24)}` +
  `${s(TOPLAM_GENEL - t2.yerlesemeyen)}${s(0)}${s(t2.cikarilan)}${s(t2.yerlesemeyen, 21)}`);

// ZO17: tolerans kopyala-yapistirla yayilir. Yanlis tolerans sayisi taranir.
console.log(`\nyanlis verilen tolerans (${ISARETLI} dugum ayrilmis, yerlestirme engeli):`);
console.log(`${"toleransli genel".padEnd(20)}${s("ayrilanda genel")}${s("genel yerlesen")}` +
  `${s("toplu yerlesen")}${s("tahliyede korunan", 19)}`);
for (const n of [0, 2, 4, 6, 9]) {
  const d = dugumleriAc(ISARETLI);
  const g = yerlestir(genelKapsuller(n), d);
  const t = yerlestir(topluKapsuller(), d);
  const korunan = sonradanIsaretle(n);
  console.log(`${String(n).padEnd(20)}${s(g.yanlisDugum.length)}` +
    `${s(TOPLAM_GENEL - g.yerlesmeyen.length)}${s(6 - t.yerlesmeyen.length)}` +
    `${s(korunan.korunan, 19)}`);
}

// ZO18: karar icin okunan bildirimler. Isaret dugumde, tolerans kapsulde; ikisi de beyandir.
const kalem = ISARETLI + TOPLAM_GENEL + 6;
console.log(`\nokunan bildirim: ${ISARETLI} dugum isareti + ${TOPLAM_GENEL + 6} kapsul tolerans ` +
  `alani = ${kalem}; dogrulugunu olcen bir kalem yok`);
```

```
isaretin uc etkisi ayri ayri (3 dugum ayrilmis, tolerans dogru verilmis):
etki                      genel yerlesen ayrilanda genel       cikarilan  yeniden yerlesmeyen
yerlestirme engeli                    15               0               0                    0
tercih edilmeme                       18               3               0                    0
kosmaya devam engeli                  15               0               8                    3

yanlis verilen tolerans (3 dugum ayrilmis, yerlestirme engeli):
toleransli genel     ayrilanda genel  genel yerlesen  toplu yerlesen  tahliyede korunan
0                                  0              15               6                  0
2                                  2              18               4                  2
4                                  3              18               4                  3
6                                  3              18               4                  3
9                                  3              18               4                  3

okunan bildirim: 3 dugum isareti + 24 kapsul tolerans alani = 27; dogrulugunu olcen bir kalem yok
```

#### Üç Etki Ayrı Ayrı

**Yerleştirme engeli** yalnız geleceği bağlar: on beş genel kapsül yerleşiyor, ayrılan düğümlerde
tek bir genel kapsül bulunmuyor, hiçbir şey çıkarılmıyor. Ayrım temizdir ve bedeli yerleşemeyen üç
kapsüldür.

**Koşmaya devam engeli** bugünü bağlar. Kapsüller çoktan yerleşmişken işaret konulduğunda sekiz
kapsül düğümlerinden çıkarılıyor; kalan kapasiteye geri yerleşmeye çalıştıklarında üçü yer bulamıyor.
Aynı son durum (on beş ayakta kapsül) iki yoldan da elde ediliyor, ama ikinci yolda sekiz kapsül
yeniden başlatılmış oluyor. Bir işaretin ne zaman konduğu, hangi etkiyle konduğu kadar önemlidir.

**Tercih edilmeme** hiçbir şeyi engellemiyor. On sekiz kapsülün on sekizi yerleşiyor, ama üç genel
kapsül ayrılan düğümlere düşüyor. Yumuşak bir işaret kapasite bollaşana kadar işe yarar ve tam da
kapasite daraldığında, yani ayrımın gerektiği anda, kendiliğinden çözülür. Ayrımın bir belge değil
bir yaptırım olması gerekir.

Üç etkinin sayıları bir arada okunduğunda devredilen kararın kapsamı da netleşiyor. Sisteme
verilen yetki yalnız "nereye koy" değil, "kimi çıkar" ve "kimi tercih etme" yetkilerini de içeriyor.
Üçünün dayandığı bilgi tek bir alandır — düğümdeki işaretin etkisi — ve bu alan yanlış seçildiğinde
sonuç ya kâğıt üzerinde kalan bir ayrım (tercih edilmeme) ya da sekiz kapsüllük ani bir yeniden
başlatma dalgası (koşmaya devam engeli) olur. İkisi arasındaki farkı doğuran şey kümenin durumu
değil, tek bir sözcüklük bir bildirimdir.

#### Yanlış Tolerans Hatayı İyileşme Gibi Gösteriyor

Son tablo, kopyala-yapıştırla yayılan bir toleransın bedelini sayıyor. İki genel kapsüle gereksiz
tolerans yazıldığında bu kapsüller ayrılan düğümlere düşüyor ve gecelik toplu işin altı kapsülünden
ikisi yerleşemez hâle geliyor. Dört ya da daha fazla kapsülde tolerans varsa ayrılan düğümlerdeki
yabancı kapsül sayısı üçte doyuyor.

Bu tablonun tehlikeli sütunu ortadakidir. Yanlış tolerans verildiğinde genel yerleşen sayısı on
beşten **on sekize çıkıyor**. Yerleştirme kararına bakan hiçbir gösterge bir sorun bildirmez: daha
çok kapsül yerleşmiştir, hiçbir kapsül çözümsüz kalmamıştır, kümenin doluluğu artmıştır. Bozulan tek
şey ayrımın kendisidir ve o ancak gece, toplu iş eksik kapsülle koştuğunda görünür. Son sütun ikinci
bir kaybı ekliyor: koşmaya devam engeli konulduğunda bu kapsüller **tahliye edilmiyor**, çünkü
toleransları onları koruyor. Yanlış bildirim, düzeltme mekanizmasının önüne de geçiyor.

Kararın dayandığı bilgi yirmi yedi kalemdir: üç düğüm işareti ve yirmi dört kapsülün tolerans alanı.
Bu kalemlerin hiçbiri ölçüm değildir ve bir toleransın gerçekten gerekli olup olmadığını sınayan tek
bir sayaç yoktur. Sistem yanlış kapsülü ayrılan düğüme, bir yanlışlık olduğunu bilmediği için değil,
**bilebileceği bir kalem bulunmadığı için** koyar.

#### Özet

- İşaret düğüme, tolerans kapsüle yazılır; tolerans izin verir, çekmez. İşaretli düğüm yokken toplu
  işin altı kapsülü de yerleşemiyor, çünkü götüren şey etiket seçimidir.
- Ayırmanın birinci faturası genel iş yükünde: üç düğüm ayrılınca genel iş yükü altı düğüme sıkışıyor
  ve üç kapsül yerleşemiyor, beş düğüm ayrılınca yedi kapsül yerleşemiyor.
- İkinci fatura ayrılan kapasitede: dört saatlik pencere için yirmi dört saat rezerve edildiğinden
  boş kalma oranı en iyi durumda yüzde 83,3; ayrılan düğüm sayısı arttıkça yüzde 90'a çıkıyor.
- Üç etki üç ayrı şey ölçer: yerleştirme engeli ayrılan düğümde sıfır yabancı kapsül bırakıyor,
  koşmaya devam engeli sekiz kapsülü çıkarıyor ve üçü yeniden yerleşemiyor, tercih edilmeme üç
  yabancı kapsülü engellemiyor.
- Gereksiz tolerans ayrılan düğümlere üç yabancı kapsül sokuyor ve gecelik toplu işin iki kapsülünü
  yerleştiremez hâle getiriyor; yerleşen sayısı on beşten on sekize çıktığı için hata bir iyileşme
  gibi görünüyor.
- Karar yirmi yedi bildirim kalemine dayanıyor ve toleransın gerekliliğini ölçen kalem yok; yanlış
  tolerans tahliye etkisinde kapsülü koruduğu için düzeltmenin de önüne geçiyor.

#### Sonraki Adım

Buraya kadarki bütün kararlar yerleştirme anında veriliyor: kapsül bir düğüme düşüyor ve orada
kalıyor. Kaynak baskısı ise yerleştirmeden sonra doğar. Bir düğümün belleği dolduğunda birileri
çıkarılmak zorundadır ve bu kararı veren şey zamanlayıcı değil, düğümün kendisidir. Hangi kapsülün
çıkarılacağı, isteğin ne kadar altında ya da üstünde çalışıldığına ve kapsüle yazılmış bir öncelik
sınıfına bağlıdır. Sonraki ders tahliye sırasını modelleyecek, öncelik eklendiğinde yer açmanın kaç
kapsülü etkilediğini ve zincirin kaç kez uzadığını sayacak.

### Tahliye ve Öncelikler

Source: https://academia.sh/tr/kurslar/orkestrasyon/tahliye-ve-oncelikler

Kaynak baskısında davranışın modellenmesi: bellek baskısı altında tahliye sırasının isteğin altında, üstünde ve isteksiz kapsüller için hesaplanması, üç sıralama kuralının farklı kapsülleri çıkarması, öncelik sınıfı eklendiğinde yer açmanın kaç kapsülü etkilediği ve zincirin kaç kez uzadığı, sistemin görmediği kalem yüzünden yanlış kapsülü tahliye etmesi.

Buraya kadarki bütün kararlar yerleştirme anında veriliyordu: kapsül bir düğüme düşüyor ve orada
kalıyordu. Kaynak baskısı ise yerleştirmeden sonra doğar ve kararı veren artık zamanlayıcı değildir.
Düğümün belleği dolduğunda bir şey çıkarılmak zorundadır, çıkarma kararını düğüm verir ve kararın
girdisi ilk dersteki iki sayıdır: bildirilen istek ve ölçülen kullanım.

Devredilen karar burada ilk kez **geri alınamaz** bir karardır. Yanlış yerleştirilen kapsül
yerleşemez ve beklemeye devam eder; yanlış tahliye edilen kapsül çalışırken durdurulur. Bu ders iki
şeyi ölçer: baskı altında hangi kapsülün çıkarıldığı ve öncelik sınıfı eklendiğinde yüksek
öncelikli bir kapsüle yer açmanın kaç kapsülü etkilediği. Ölçülen şey bir modeldir; iş yükü bölgesel
ölçüm ağının (kurgu) servisleridir.

#### Baskı Zamanlayıcının Defterinde Görünmüyor

Modelde iki düğüm ve on yedi kapsül var. Gecelik toplu işin iki kapsülü hiç istek bildirmiyor ve
1.400 MiB kullanıyor; faturalama ve okuma toplayıcı isteğinin biraz üstünde, doğrulayıcı altında
çalışıyor. Tahliye üç ayrı sıralama kuralıyla denenir.

```js
// zamanlama/tahliye.mjs — bellek baskisinda tahliye sirasi. Kurulan sey bir MODELDIR.
// Dugum kimi cikaracagina karar verirken yalniz bildirilen istegi ve olculen kullanimi gorur.
export const BELLEK = 4096, DUGUM_SAYISI = 2;
export const ESIK = 0.9;            // ZO19: doluluk %90'i asinca bellek baskisi baslar
const TOHUM = 20260803;

// ad, adet, istek, gercek/taban carpani, bildirilen oncelik, gercek kritiklik (sistem gormez)
export const SERVIS = [
  ["faturalama", 3, 512, 1.15, 900, 1], ["dogrulayici", 4, 704, 0.90, 700, 2],
  ["okuma-toplayici", 6, 384, 1.10, 500, 2], ["gecelik-toplu", 2, 0, 0, 100, 3],
  ["arsiv-tarama", 2, 256, 1.00, 200, 3],   // ZO21: dusuk oncelikli, istegi bildirilmis servis
];
export const TOPLU_GERCEK = 1400;   // ZO20: istek bildirmeyen toplu is kapsulu 1400 MiB kullanir

export function isYuku(faturaIstek = 512) {
  let s = TOHUM % 2147483647;
  const r = () => (s = (s * 48271) % 2147483647) / 2147483647;
  return SERVIS.flatMap(([ad, n, istek, kat, onc, krit]) =>
    Array.from({ length: n }, (_, i) => {
      const it = ad === "faturalama" ? faturaIstek : istek;
      const g = kat === 0 ? TOPLU_GERCEK : Math.round(istek * kat * (0.95 + 0.1 * r()));
      return { ad: `${ad}-${i + 1}`, servis: ad, istek: it, gercek: g, oncelik: onc, kritik: krit };
    }));
}

export const yerlestir = (kapsuller, n = DUGUM_SAYISI) => {
  const d = Array.from({ length: n }, (_, i) => ({ ad: `d${i}`, istek: 0, kapsul: [] }));
  for (const k of kapsuller) {
    const x = d.find((y) => y.istek + k.istek <= BELLEK);
    if (x !== undefined) { x.istek += k.istek; x.kapsul.push(k); }
  }
  return d;
};

export const kullanim = (d) => d.kapsul.reduce((t, k) => t + k.gercek, 0);

// Uc siralama kurali. Ilk sirada olan once cikarilir.
export const KURAL = {
  "en cok kullanan": (a, b) => b.gercek - a.gercek,
  "istek farki": (a, b) => (b.gercek - b.istek) - (a.gercek - a.istek),
  "oncelik + istek farki": (a, b) =>
    a.oncelik - b.oncelik || (b.gercek - b.istek) - (a.gercek - a.istek),
};

export function tahliyeEt(dugum, sirala) {
  const hedef = BELLEK * ESIK, cikan = [];
  const sira = [...dugum.kapsul].sort(sirala);
  while (kullanim(dugum) > hedef && sira.length > 0) {
    const k = sira.shift();
    dugum.kapsul = dugum.kapsul.filter((x) => x !== k);
    cikan.push(k);
  }
  return cikan;
}

if (process.argv[1].endsWith("tahliye.mjs")) {
  const d = yerlestir(isYuku());
  console.log(`model: ${DUGUM_SAYISI} dugum x ${BELLEK} MiB, ${isYuku().length} kapsul ` +
    `(tohum ${TOHUM}); baski esigi ${BELLEK * ESIK} MiB`);
  d.forEach((x) => console.log(`  ${x.ad}: ${x.kapsul.length} kapsul, istek ${x.istek} MiB, ` +
    `gercek ${kullanim(x)} MiB, doluluk %${((kullanim(x) / BELLEK) * 100).toFixed(1)}`));
  const s = (x, n = 15) => String(x).padStart(n);
  console.log(`\nd0 uzerinde tahliye sirasi (${(BELLEK * ESIK).toFixed(0)} MiB'ye inene kadar):`);
  console.log(`${"kural".padEnd(34)}${s("tahliye")}${s("kazanilan MiB")}${s("kritik kayip")}` +
    `${s("kalan doluluk")}`);
  for (const [ad, sirala] of Object.entries(KURAL)) {
    const x = yerlestir(isYuku())[0];
    const c = tahliyeEt(x, sirala);
    console.log(`${ad.padEnd(34)}${s(c.length)}${s(c.reduce((t, k) => t + k.gercek, 0))}` +
      `${s(c.filter((k) => k.kritik === 1).length)}` +
      `${s("%" + ((kullanim(x) / BELLEK) * 100).toFixed(1))}`);
  }
  const x = yerlestir(isYuku(640))[0];
  const c = tahliyeEt(x, KURAL["istek farki"]);
  console.log(`${"istek farki, fatura istegi 640".padEnd(34)}${s(c.length)}` +
    `${s(c.reduce((t, k) => t + k.gercek, 0))}${s(c.filter((k) => k.kritik === 1).length)}` +
    `${s("%" + ((kullanim(x) / BELLEK) * 100).toFixed(1))}`);
  console.log(`\ncikarilan kapsuller (kural: istek farki): ` +
    yerlestir(isYuku()).slice(0, 1).flatMap((y) => tahliyeEt(y, KURAL["istek farki"]))
      .map((k) => `${k.ad}(${k.gercek}/${k.istek})`).join(", "));
}
```

```
model: 2 dugum x 4096 MiB, 17 kapsul (tohum 20260803); baski esigi 3686.4 MiB
  d0: 9 kapsul, istek 4032 MiB, gercek 6898 MiB, doluluk %168.4
  d1: 8 kapsul, istek 3136 MiB, gercek 3266 MiB, doluluk %79.7

d0 uzerinde tahliye sirasi (3686 MiB'ye inene kadar):
kural                                     tahliye  kazanilan MiB   kritik kayip  kalan doluluk
en cok kullanan                                 3           3452              0          %84.1
istek farki                                     3           3401              1          %85.4
oncelik + istek farki                           3           3224              0          %89.7
istek farki, fatura istegi 640                  2           2800              0          %89.7

cikarilan kapsuller (kural: istek farki): gecelik-toplu-1(1400/0), gecelik-toplu-2(1400/0), faturalama-2(601/512)
```

#### Üç Sıralama Kuralı, Üç Ayrı Kurban

İlk iki satır kararın neden düğüme kaldığını gösteriyor. Zamanlayıcının defterinde d0 dolu ve
tutarlıdır: 4.096 MiB'nin 4.032'si dağıtılmıştır, kalan 64 MiB için başka kapsül alınmaz. Gerçek
kullanım ise 6.898 MiB, yani **yüzde 168,4**. Aradaki bütün fark istek bildirmeyen iki kapsülden
gelir. Defter doğruyken düğüm baskı altındadır ve defteri tutan bileşenin bundan haberi yoktur.

Üç kural üç ayrı kapsülü çıkarıyor. **En çok kullanan** kuralı iki toplu iş kapsülünü ve bir
doğrulayıcıyı alıyor; 3.452 MiB kazanıyor, kritik bir kapsül kaybetmiyor. **İstek farkı** kuralı —
kullanımın isteği ne kadar aştığına bakan kural — iki toplu iş kapsülünden sonra faturalamayı
çıkarıyor. Son satırdaki dökümde nedeni görünür: faturalama 512 MiB bildirip 601 kullandığı için
aşımı 89 MiB, okuma toplayıcı 384 bildirip 422 kullandığı için aşımı 38 MiB. Kural, **daha dürüst
bildirimde bulunanı** değil, isteğine daha yakın bildirim yapanı korur.

**Öncelik sınıfı** eklendiğinde kural düzeliyor: kapsül başına bir bildirim kalemi daha (on yedi
kalem) eklenmiş oluyor ve kritik kayıp birden sıfıra iniyor. Kazanılan bellek 3.401 yerine 3.224
MiB, yani daha az; buna karşılık çıkarılanlar en düşük öncelikli kapsüller.

Dördüncü satır bu bilginin bir **beyan** olmasının bedelini veriyor. Faturalamanın isteği 512 yerine
640 yazılsaydı — hiçbir şey değişmeden, yalnız bildirim büyütülerek — kapsül isteğinin altında
görünür ve tahliye sırasında son sıraya düşerdi: iki tahliye, kritik kayıp sıfır. İsteği şişirmek
ilk derste kapasite israfıydı; burada bir **korunma** aracıdır ve sistem ikisini birbirinden ayırt
edemez.

#### Yer Açma ve Zincir

Baskı tek yönlü değildir. Yüksek öncelikli bir kapsül geldiğinde ve hiçbir düğümde yer kalmadığında
sistem kendi eliyle yer açar: daha düşük öncelikli kapsülleri çıkarır. Çıkarılan kapsül kaybolmaz,
kuyruğa geri döner ve kendisinden düşük öncelikli birini çıkarabilir. Zincir böyle uzar.

```js
// zamanlama/yer-acma.mjs — yuksek oncelikli kapsul icin dusuk oncelikliyi cikarma ve zincir.
import { BELLEK, isYuku, yerlestir } from "./tahliye.mjs";

// ZO22: gece yarisi gelen acil faturalama kapsulleri: oncelik 1000, istek 700 MiB
const ACIL = (n) => Array.from({ length: n }, (_, i) =>
  ({ ad: `acil-fatura-${i + 1}`, servis: "acil-fatura", istek: 700, gercek: 700,
     oncelik: 1000, kritik: 1, derinlik: 0 }));
const TUR_SINIRI = 60;                 // ZO23: zincir bu tur sayisinda kesilir

// ZO24: iki dugum secim kurali — en az kapsul cikaran dugum, ya da ilk uyan dugum.
function yerAc(gelenler, kural) {
  const d = yerlestir(isYuku());
  const kuyruk = [...gelenler];
  let tahliye = 0, zincir = 0, derin = 0, tur = 0;
  const yerlesemeyen = [];
  while (kuyruk.length > 0 && tur++ < TUR_SINIRI) {
    const k = kuyruk.shift();
    const bos = (x) => BELLEK - x.istek;
    const dogrudan = d.find((x) => bos(x) >= k.istek);
    if (dogrudan !== undefined) {
      dogrudan.istek += k.istek; dogrudan.kapsul.push(k); continue;
    }
    // Her dugum icin: kac kapsul cikarilirsa yer acilir. Yalniz DUSUK oncelikli cikarilabilir.
    const planlar = d.map((x) => {
      const aday = x.kapsul.filter((p) => p.oncelik < k.oncelik)
        .sort((a, b) => a.oncelik - b.oncelik || a.istek - b.istek);
      let acilan = bos(x); const cikan = [];
      for (const p of aday) { if (acilan >= k.istek) break; acilan += p.istek; cikan.push(p); }
      return { x, cikan, olur: acilan >= k.istek };
    }).filter((p) => p.olur);
    if (planlar.length === 0) { yerlesemeyen.push(k); continue; }
    const p = kural === "en az cikaran"
      ? planlar.reduce((a, b) => (b.cikan.length < a.cikan.length ? b : a))
      : planlar[0];
    for (const c of p.cikan) {
      p.x.kapsul = p.x.kapsul.filter((y) => y !== c);
      p.x.istek -= c.istek; tahliye++;
      if (k.derinlik > 0) zincir++;
      c.derinlik = (k.derinlik ?? 0) + 1;
      derin = Math.max(derin, c.derinlik);
      kuyruk.push(c);
    }
    p.x.istek += k.istek; p.x.kapsul.push(k);
  }
  const yerlesen = gelenler.filter((g) => d.some((x) => x.kapsul.includes(g))).length;
  return { tahliye, zincir, derin, yerlesemeyen: yerlesemeyen.length, yerlesen, tur: tur - 1 };
}

const s = (x, n = 14) => String(x).padStart(n);
console.log("yer acma: acil kapsul sayisi taraniyor (bos istek d0 64 MiB, d1 960 MiB)");
console.log(`${"kural".padEnd(16)}${"acil".padEnd(6)}${s("acil yerlesen")}${s("tahliye")}` +
  `${s("zincirleme")}${s("en derin")}${s("yerlesemeyen")}`);
for (const kural of ["en az cikaran", "ilk uyan"])
  for (const n of [1, 2, 3, 4, 5]) {
    const o = yerAc(ACIL(n), kural);
    console.log(`${kural.padEnd(16)}${String(n).padEnd(6)}${s(o.yerlesen)}${s(o.tahliye)}` +
      `${s(o.zincir)}${s(o.derin)}${s(o.yerlesemeyen)}`);
  }

// Sistemin gormedigi kalem: gercek kritiklik. Cikarilan kapsullerin kritiklik dagilimi.
const o = yerAc(ACIL(3), "ilk uyan");
console.log(`\nuc acil kapsul icin 'ilk uyan' kurali: ${o.tahliye} tahliye, ${o.zincir} zincirleme, ` +
  `${o.yerlesemeyen} kapsul acikta; 'en az cikaran' kuralinda ` +
  `${yerAc(ACIL(3), "en az cikaran").tahliye} tahliye`);
console.log(`bildirilen oncelik kalemi: 17 kapsul + gelen acil kapsuller; olculen kritiklik kalemi: 0`);
```

```
yer acma: acil kapsul sayisi taraniyor (bos istek d0 64 MiB, d1 960 MiB)
kural           acil   acil yerlesen       tahliye    zincirleme      en derin  yerlesemeyen
en az cikaran   1                  1             0             0             0             0
en az cikaran   2                  2             2             0             1             2
en az cikaran   3                  3             4             0             1             4
en az cikaran   4                  4             6             0             1             6
en az cikaran   5                  5            10             2             2             7
ilk uyan        1                  1             0             0             0             0
ilk uyan        2                  2             6             2             2             2
ilk uyan        3                  3             9             4             2             4
ilk uyan        4                  4            12             6             2             6
ilk uyan        5                  5            15             8             2             7

uc acil kapsul icin 'ilk uyan' kurali: 9 tahliye, 4 zincirleme, 4 kapsul acikta; 'en az cikaran' kuralinda 4 tahliye
bildirilen oncelik kalemi: 17 kapsul + gelen acil kapsuller; olculen kritiklik kalemi: 0
```

#### Aynı Sonuç, Üç Katı Sarsıntı

Tek acil kapsül hiçbir şeyi tahliye etmiyor; boş istek yetiyor. İkinci kapsülden itibaren yer açma
başlıyor ve iki düğüm seçim kuralı aynı sonucu çok farklı bedelle veriyor. **En az çıkaran** kuralı
iki acil kapsül için iki tahliye yapıyor; **ilk uyan** kuralı aynı iki kapsül için altı tahliye
yapıyor ve bunların ikisi zincirlemedir. Beş acil kapsülde fark on tahliyeye karşı on beş tahliyedir
ve iki kuralda da açıkta kalan kapsül sayısı yedidir. **Sonuç aynı, sarsıntı üç katı.** Düğüm seçimi
bir yerleştirme ayrıntısı gibi görünür ve doğrudan yeniden başlatılan kapsül sayısını belirler.

Zincirleme sütunu devrin ikinci bedelini gösteriyor: çıkarılan kapsül kuyruğa döndüğünde kendisi de
bir çıkarma başlatıyor ve zincir en fazla iki derinliğe iniyor. Derinliğin ikide kalması bir tasarım
başarısı değil, bir kaza sonucudur. Merdivende altı ayrı öncelik değeri vardır ve her basamak yalnız
kendisinden düşük basamakları çıkarabilir; zincir ikinci adımda kesiliyor, çünkü merdivenin en alt
basamağındaki kapsüller istek bildirmemiştir ve onları çıkarmak defterde hiç yer açmaz. Aynı model
en alttaki kapsüllere gerçekçi bir istek yazılsaydı zincir bir adım daha uzardı — yani zincirin
uzunluğunu belirleyen şey öncelik tasarımı kadar bildirimin kendisidir.

Üçüncü ve en sessiz sonuç, açıkta kalan kapsüllerdir. Beş acil kapsül yerleşirken yedi kapsül
düğümsüz kalıyor ve bunlar hiçbir yere geri dönmüyor, çünkü kendilerinden düşük öncelikli
çıkarılabilir kapsül kalmamıştır. Gecelik toplu işin kapsülleri bu tabloda hiç yer açmaz: istek
bildirmedikleri için onları çıkarmak defterde **sıfır MiB** boşaltır. Gerçekte 1.400 MiB serbest
kalır, ama yer açma kararı isteğe bakar, kullanıma değil.

Kararın dayandığı bilgi on yedi kapsülün öncelik bildirimi ve gelen kapsüllerin öncelikleridir.
Ölçülen kritiklik kalemi sıfırdır. Sistem faturalamayı, önemsiz olduğunu düşündüğü için değil,
**önemi hakkında hiçbir kalemi bulunmadığı** için çıkarır; öncelik sınıfı bu boşluğu kapatan bir
beyandır ve beyanın doğruluğunu sınayan bir ölçüm yoktur. Bütün kapsüllere en yüksek öncelik
yazıldığında sıralama tamamen kaybolur ve sistem yine istek farkına döner.

#### Özet

- Bellek baskısı zamanlayıcının defterinde görünmez: d0'ın defteri 4.096 MiB'nin 4.032'sini dağıtmış
  ve tutarlıdır, gerçek kullanım yüzde 168,4'tür ve fark istek bildirmeyen iki kapsülden gelir.
- Üç sıralama kuralı üç ayrı kapsülü çıkarıyor: en çok kullanan kuralı 3.452 MiB kazanıp kritik
  kapsül kaybetmiyor, istek farkı kuralı 3.401 MiB kazanıp bir kritik kapsül çıkarıyor, öncelik
  eklenince kritik kayıp sıfıra iniyor.
- İstek farkı kuralı isteğini şişireni ödüllendirir: faturalamanın bildirimi 512 yerine 640 olsaydı
  tahliye sayısı üçten ikiye, kritik kayıp birden sıfıra inerdi ve hiçbir şey gerçekte değişmezdi.
- Yer açmada düğüm seçim kuralı sonucu değil bedeli belirliyor: iki acil kapsül için en az çıkaran
  kuralı iki, ilk uyan kuralı altı tahliye yapıyor; beş kapsülde on ve on beş, açıkta kalan sayısı
  ikisinde de yedi.
- Zincirleme iki derinliğe kadar iniyor ve öncelik merdiveninin basamak sayısıyla sınırlı; istek
  bildirmeyen kapsülleri çıkarmak defterde sıfır MiB açtığı için yer açmada hiç kullanılmıyorlar.
- Karar on yedi öncelik bildirimine dayanıyor, ölçülen kritiklik kalemi sıfır; yanlış tahliyenin
  kaynağı kuralın kötülüğü değil, iş değerini taşıyan tek bir ölçümün bulunmamasıdır.

#### Sonraki Adım

Bu iki ders kümenin sabit kapasitesini paylaştırıyor: kim nereye girer, sıkışınca kim çıkar. Üçüncü
bir seçenek hiç sorulmadı — kopya sayısını değiştirmek. Bölgesel ölçüm ağının okuma toplayıcısı gün
içinde dalgalanan bir yük görür ve kopya sayısı sabit kaldığı sürece bu dalganın bedeli ya boş
kapasite ya da kuyruk olur. Bu kararı da bir denetleyiciye devretmek mümkündür: bir ölçüt izlenir,
hedefle karşılaştırılır, kopya sayısı ayarlanır. Sonraki ders o denetleyiciyi yazar ve ölçütün
gecikmesi arttıkça salınımın nasıl büyüdüğünü sayar.

### Yatay Ölçekleme

Source: https://academia.sh/tr/kurslar/orkestrasyon/yatay-olcekleme

Ölçüt tabanlı otomatik ölçeklemenin bir denetleyici olarak yazılması ve değişken yük altında koşturulması: ölçüt gecikmesi arttıkça salınımın, aşırı kopya-turun ve yetersiz kapasite turunun nasıl değiştiği, bekleme penceresi ile adım sınırının salınımı ne kadar düşürdüğü ve tepkiyi kaç tur yavaşlattığı.

Önceki iki ders kümenin sabit kapasitesini paylaştırdı: kim nereye girer, sıkışınca kim çıkar.
Üçüncü seçenek hiç sorulmadı — kopya sayısını değiştirmek. Bölgesel ölçüm ağının (kurgu) okuma
toplayıcısı gün içinde dalgalanan bir yük görür; kopya sayısı sabit kaldığı sürece bu dalganın
bedeli ya boş kapasite ya da kuyruktur.

Bu karar bir denetleyiciye devredilebilir: bir ölçüt izlenir, hedefle karşılaştırılır, kopya sayısı
ayarlanır. Kaç kopya gerektiğinin aritmetiği burada tekrarlanmaz — kopya başına doyum verimi ve
doluluk tavanı kapasite planlamasından gelen girdilerdir. Bu dersin ölçtüğü şey **kararın kendisi**:
denetleyici, ölçütü gecikmeli gördüğünde ne yapıyor.

Denetleyicinin kuralı tek satırdır: istenen kopya, güncel kopya sayısının ölçülen dolulukla çarpılıp
hedef dolulukla bölünmesidir. Bu satırdaki tuzak, **güncel** kopya sayısıyla **eski** bir ölçütün
çarpılmasıdır. Ölçülen şey bir modeldir; gerçek küme koşturulmaz.

#### Denetleyici ve Ölçüt Gecikmesi

Yük serisi 120 turluk bir dizidir: 40 turluk bir dalga, 60. turda ani bir artış ve kendi
üretecimizden gelen yüzde 8 bandında gürültü. Her tur için gereken kopya sayısı ayrıca hesaplanır ve
denetleyicinin ürettiği kopya sayısı ona göre puanlanır.

```js
// zamanlama/olcekleme.mjs — olcut tabanli yatay olcekleme denetleyicisi. MODELDIR, gercek
// kume kosturulmaz. Kopya basina doyum verimi ve doluluk tavani M19'un girdisidir.
export const DOYUM = 1176.47;      // kopya basina istek/s (M19, hesap; burada girdi)
export const HEDEF = 0.70;         // hedef doluluk (M19'un kapasite payi; burada girdi)
export const TUR = 120;            // ZO25: bir tur bir olcum araligi
export const MAKS = 12;            // ZO27: kopya ust siniri
const TOHUM = 20260805;

// ZO26: yuk serisi kurgudur — 40 turluk dalga, 60. turda ani artis, ±%8 gurultu.
export function seriUret() {
  let s = TOHUM % 2147483647;
  const r = () => (s = (s * 48271) % 2147483647) / 2147483647;
  return Array.from({ length: TUR }, (_, t) => {
    const dalga = 1200 + 900 * Math.sin((2 * Math.PI * t) / 40);
    const adim = t >= 60 && t < 90 ? 1800 : 0;
    return Math.max(200, Math.round((dalga + adim) * (0.92 + 0.16 * r())));
  });
}
export const SERI = seriUret();
export const gereken = (yuk) => Math.max(1, Math.ceil(yuk / (DOYUM * HEDEF)));

// Denetleyici: gecikmeli olcutu GUNCEL kopya sayisiyla carpar. Gecikme buyudukce asiri duzeltir.
export function kostur({ gecikme = 0, pencere = 1, adim = 0, seri = SERI } = {}) {
  let kopya = 2, sonYon = 0, dusuk = 0;
  const doluluklar = [];
  let salinim = 0, asiri = 0, yetersiz = 0, toplam = 0, adimYetersiz = 0;
  let acKapa = 0, enYuksek = 0, tepki = -1;
  for (let t = 0; t < seri.length; t++) {
    doluluklar.push(seri[t] / (kopya * DOYUM));
    const olcut = doluluklar[Math.max(0, t - gecikme)];
    let istenen = Math.min(MAKS, Math.max(1, Math.ceil((kopya * olcut) / HEDEF)));
    if (adim > 0) istenen = Math.min(kopya + adim, Math.max(kopya - adim, istenen));
    if (istenen < kopya) { dusuk++; if (dusuk < pencere) istenen = kopya; } else dusuk = 0;
    const yon = Math.sign(istenen - kopya);
    if (yon !== 0) {
      acKapa++;
      if (sonYon !== 0 && yon !== sonYon) salinim++;
      sonYon = yon;
    }
    kopya = istenen;
    const g = gereken(seri[t]);
    toplam += kopya;
    asiri += Math.max(0, kopya - g);
    if (kopya < g) { yetersiz++; if (t >= 60 && t < 90) adimYetersiz++; }
    if (t >= 60 && tepki < 0 && kopya >= g) tepki = t - 60;
    enYuksek = Math.max(enYuksek, kopya);
  }
  return { salinim, acKapa, asiri, yetersiz, toplam, adimYetersiz, enYuksek, tepki };
}

if (process.argv[1].endsWith("olcekleme.mjs")) {
  const g = SERI.map(gereken);
  console.log(`model: ${TUR} tur, yuk ${Math.min(...SERI)}–${Math.max(...SERI)} istek/s ` +
    `(tohum ${TOHUM}); kopya basina ${DOYUM} istek/s, hedef doluluk %${HEDEF * 100}`);
  console.log(`gereken kopya ${Math.min(...g)}–${Math.max(...g)}, ideal toplam ` +
    `${g.reduce((a, b) => a + b, 0)} kopya-tur\n`);
  const s = (x, n = 17) => String(x).padStart(n);
  console.log("olcut gecikmesi taraniyor (bekleme penceresi ve adim siniri yok):");
  console.log(`${"gecikme".padEnd(10)}${s("degisiklik")}${s("salinim")}${s("asiri kopya-tur")}` +
    `${s("yetersiz tur")}${s("toplam kopya-tur")}${s("en yuksek kopya", 16)}`);
  for (const gecikme of [0, 1, 2, 3, 4, 5, 6]) {
    const o = kostur({ gecikme });
    console.log(`${String(gecikme).padEnd(10)}${s(o.acKapa)}${s(o.salinim)}${s(o.asiri)}` +
      `${s(o.yetersiz)}${s(o.toplam)}${s(o.enYuksek)}`);
  }
}
```

```
model: 120 tur, yuk 278–3915 istek/s (tohum 20260805); kopya basina 1176.47 istek/s, hedef doluluk %70
gereken kopya 1–5, ideal toplam 301 kopya-tur

olcut gecikmesi taraniyor (bekleme penceresi ve adim siniri yok):
gecikme          degisiklik          salinim  asiri kopya-tur     yetersiz tur toplam kopya-tur en yuksek kopya
0                        14                8                0                0              301                5
1                        63               30               52               29              319                8
2                        67               23              186               40              422               12
3                        59               17              225               40              457               12
4                        56               15              261               44              489               12
5                        53               13              286               42              515               12
6                        43               11              275               41              510               12
```

#### Gecikme Salınımı Büyütüyor, Sonra Gizliyor

Gecikmesiz satır bir alt sınır veriyor: 14 değişiklik, sıfır aşırı kopya-tur, sıfır yetersiz tur ve
tam 301 kopya-tur, yani idealin kendisi. Ölçüt anında geldiğinde devredilen karar kusursuz
çalışıyor. Sekiz salınım da yükün kendi dalgasından gelir, denetleyicinin hatasından değil.

Tek turluk gecikme bu tabloyu bozuyor. Değişiklik sayısı 14'ten 63'e, salınım 8'den **30'a**
çıkıyor; 29 tur yetersiz kapasiteyle geçiyor ve en yüksek kopya sayısı beşten sekize tırmanıyor.
Nedeni denetleyicinin kuralındadır: kopya sayısı bir tur önce artırılmıştır, ölçüt hâlâ artıştan
önceki doluluğu göstermektedir ve denetleyici aynı yükü ikinci kez düzeltir. **Sistem kendi son
kararının ölçüte yansıyıp yansımadığını bilmiyor** ve bilmediği tek kalem bu.

Gecikme büyüdükçe okunması gereken sütun değişiyor. Salınım 30'dan 11'e **iniyor** ve bu bir
iyileşme değildir. Aşırı kopya-tur 52'den 275'e çıkıyor, toplam kaynak 319'dan 510 kopya-tura
tırmanıyor ve en yüksek kopya sayısı üst sınıra yapışıyor. Denetleyici artık salınmıyor, çünkü tavana
çıkıp orada kalıyor: yetersiz tur sayısı 41'de duruyor, yani hem kaynak idealin 1,7 katı hem de
turların üçte biri yetersiz. **Salınımın azalması tek başına bir başarı göstergesi değildir**;
yanında aşırı kopya-tur ve yetersiz tur okunmadıkça yanlış yorumlanır.

Gecikmenin kendisi bir ayar değil, bir toplamdır. Ölçüt önce kapsülde üretilir, bir aralık boyunca
biriktirilir, toplayıcıya aktarılır, denetleyicinin okuduğu ortalamaya girer ve ancak ondan sonra
karara dönüşür. Bu adımların her biri bir tur ekler. Tablodaki gecikme sütunu bu yüzden bir seçim
değil, izleme düzeninin sonucudur: toplama aralığını kısaltmak gecikmeyi düşürür ve karşılığında
ölçüt sayısını, saklama yükünü ve gürültüyü artırır. Devredilen kararın maliyeti burada iki ayrı
bütçeye bölünür — biri kopya-tur, öteki ölçüt.

#### İki Söndürücü: Bekleme Penceresi ve Adım Sınırı

Salınıma karşı iki ayar vardır. **Bekleme penceresi** küçültme kararını geciktirir: istenen kopya
sayısı arka arkaya belirli tur boyunca düşük gelmedikçe küçültme uygulanmaz. **Adım sınırı** bir
turdaki değişimin büyüklüğünü kısar. İkisi de aynı gecikmede, üç tur ölçüt gecikmesiyle ölçülür ve
tepki ayrıca gürültüsüz bir basamak testiyle sayılır.

```js
// zamanlama/denge.mjs — bekleme penceresi ve adim siniri: salinimin dususu ile tepkinin
// yavaslamasi birlikte sayilir. Denetleyici ve yuk serisi onceki dosyadan gelir.
import { kostur } from "./olcekleme.mjs";

const GECIKME = 3;                 // ZO28: olcut uc tur gecikmeli geliyor
const s = (x, n = 17) => String(x).padStart(n);
const satir = (ad, o) => console.log(`${ad.padEnd(22)}${s(o.acKapa)}${s(o.salinim)}${s(o.asiri)}` +
  `${s(o.yetersiz)}${s(o.adimYetersiz)}${s(o.toplam)}`);

console.log(`olcut gecikmesi ${GECIKME} turda sabit; sonuclar 120 turluk kosumdan:`);
console.log(`${"ayar".padEnd(22)}${s("degisiklik")}${s("salinim")}${s("asiri kopya-tur")}` +
  `${s("yetersiz tur")}${s("adimda yetersiz")}${s("toplam kopya-tur")}`);
satir("ayarsiz", kostur({ gecikme: GECIKME }));

// ZO29: bekleme penceresi — kucultme karari ancak w turdur ust uste dusuk gelirse uygulanir.
for (const pencere of [2, 3, 5, 8])
  satir(`bekleme penceresi ${pencere}`, kostur({ gecikme: GECIKME, pencere }));

// ZO30: adim siniri — bir turda kopya sayisi en fazla a kadar degisir.
for (const adim of [1, 2])
  satir(`adim siniri ${adim}`, kostur({ gecikme: GECIKME, adim }));

satir("pencere 3 + adim 1", kostur({ gecikme: GECIKME, pencere: 3, adim: 1 }));
satir("pencere 5 + adim 1", kostur({ gecikme: GECIKME, pencere: 5, adim: 1 }));

// Gurultusuz basamak testi: 60 tur 800 istek/s, sonra 60 tur 3200 istek/s (gereken 1 -> 4).
const BASAMAK = Array.from({ length: 120 }, (_, t) => (t < 60 ? 800 : 3200));
console.log("\nbasamak testi — yuk 60. turda 800'den 3200 istek/s'ye ciktiginda tepki turu:");
console.log(`${"ayar".padEnd(22)}${s("gecikme 0")}${s("gecikme 3")}${s("gecikme 6")}`);
for (const [ad, ek] of [["ayarsiz", {}], ["adim siniri 1", { adim: 1 }],
                        ["adim siniri 2", { adim: 2 }], ["pencere 3 + adim 1", { pencere: 3, adim: 1 }]])
  console.log(`${ad.padEnd(22)}` + [0, 3, 6]
    .map((g) => s(kostur({ ...ek, gecikme: g, seri: BASAMAK }).tepki)).join(""));

console.log("\nayni iki ayar gecikme yokken (gecikme 0):");
satir("ayarsiz", kostur({ gecikme: 0 }));
satir("pencere 3 + adim 1", kostur({ gecikme: 0, pencere: 3, adim: 1 }));

const a = kostur({ gecikme: GECIKME }), b = kostur({ gecikme: GECIKME, pencere: 3, adim: 1 });
console.log(`\nsalinim ${a.salinim} -> ${b.salinim} (%${(100 * (1 - b.salinim / a.salinim)).toFixed(0)} dusus), ` +
  `adim penceresinde yetersiz tur ${a.adimYetersiz} -> ${b.adimYetersiz}`);
console.log(`kaynak ${a.toplam} -> ${b.toplam} kopya-tur (ideal 301); ` +
  `denetleyicinin okudugu olcut sayisi 120, her biri ${GECIKME} tur gecikmeli`);
```

```
olcut gecikmesi 3 turda sabit; sonuclar 120 turluk kosumdan:
ayar                         degisiklik          salinim  asiri kopya-tur     yetersiz tur  adimda yetersiz toplam kopya-tur
ayarsiz                              59               17              225               40               15              457
bekleme penceresi 2                  46               17              257               37               12              493
bekleme penceresi 3                  45               15              315               33               13              552
bekleme penceresi 5                  40               13              343               31                9              596
bekleme penceresi 8                  31               11              371               23                7              632
adim siniri 1                        71               15               98               35               14              347
adim siniri 2                        71               15              173               35               15              410
pencere 3 + adim 1                   59               13              122               32               11              385
pencere 5 + adim 1                   53               11              152               27               10              417

basamak testi — yuk 60. turda 800'den 3200 istek/s'ye ciktiginda tepki turu:
ayar                          gecikme 0        gecikme 3        gecikme 6
ayarsiz                               0                3                6
adim siniri 1                         2                5                8
adim siniri 2                         1                4                7
pencere 3 + adim 1                    2                5                8

ayni iki ayar gecikme yokken (gecikme 0):
ayarsiz                              14                8                0                0                0              301
pencere 3 + adim 1                   14                6               17                0                0              318

salinim 17 -> 13 (%24 dusus), adim penceresinde yetersiz tur 15 -> 11
kaynak 457 -> 385 kopya-tur (ideal 301); denetleyicinin okudugu olcut sayisi 120, her biri 3 tur gecikmeli
```

#### Salınımın Düşüşü ve Tepkinin Yavaşlaması

İki ayar aynı sorunu iki farklı yerden tutuyor. **Bekleme penceresi** salınımı 17'den 11'e indiriyor
ve bunun bedelini kaynakta ödüyor: toplam kopya-tur 457'den 632'ye çıkıyor, aşırı kopya-tur 225'ten
371'e. Küçültmeyi geciktirmek kapasiteyi yukarıda tuttuğu için yetersiz tur sayısı da 40'tan 23'e
iniyor. Bu ayar salınımı azaltmaz, **bir yöne çevirir**.

**Adım sınırı** tersini yapıyor. Bir turda tek kopya değişimine izin verildiğinde aşırı kopya-tur
225'ten 98'e, toplam kaynak 457'den 347 kopya-tura düşüyor; salınım da 15'e iniyor. Değişiklik sayısı
ise 59'dan 71'e **çıkıyor**, çünkü aynı mesafe daha çok adımda alınıyor. Adım sınırı aşırı
düzeltmenin büyüklüğünü keser ve bu yüzden gecikmenin doğurduğu sorunu doğrudan hedefler.

Bedel basamak testinde görünüyor. Yük 800'den 3.200 istek/s'ye çıktığında ayarsız denetleyici
gecikme kadar tur sonra yetişiyor: gecikme 3 ise 3 tur, gecikme 6 ise 6 tur. Adım sınırı 1
eklendiğinde aynı sayılar 5 ve 8 oluyor — **tepki iki tur yavaşlıyor**, çünkü bir kopyadan dört
kopyaya çıkmak üç tur sürüyor. Adım sınırı 2 ile fark bir tura iniyor. Salınımın düşüşü ile tepkinin
yavaşlaması aynı ayarın iki yüzüdür ve ikisi ayrı ayrı sayılmadıkça ayar bir tercih değil, bir
tahmin olur.

İki ayarın birlikte kullanıldığı satır ikisinin toplamını veriyor: salınım 17'den 13'e iniyor,
kaynak 385 kopya-turda kalıyor ve adım penceresindeki yetersiz tur sayısı 15'ten 11'e düşüyor. Bu
satır ayarsız satırdan her sütunda daha iyidir, ama ideal 301 kopya-turun hâlâ yüzde 28 üstündedir.
Gecikme durdukça bu fark kapanmaz.

Son tablo ayarların ne olmadığını söylüyor. Gecikme sıfırken bekleme penceresi ve adım sınırı hiçbir
şeyi düzeltmiyor: salınım 8'den 6'ya iniyor, buna karşılık 17 kopya-tur fazladan harcanıyor ve ideal
301 yerine 318 kopya-tur ödeniyor. Bu iki ayar bir **ölçüm sorununun tamiridir**, bir yük sorununun
değil. Ölçütü tazelemek mümkünse ayarlara gerek kalmaz.

Ölçütün seçimi de aynı hesabın parçasıdır. Bu modelde izlenen şey doluluktur ve doluluk türetilmiş
bir sayıdır: kullanımın kopya sayısına ve kopya başına doyum verimine bölünmesiyle çıkar. Türetilmiş
her sayı, girdilerinin en eskisi kadar eskidir. Doğrudan sayılabilen bir ölçüt — bekleyen istek
sayısı gibi — daha az adımda toplanır ve gecikme sütununu sola kaydırır; karşılığında hedef değerin
ne olacağı artık kapasite planlamasından okunamaz.

Kararın dayandığı bilgi 120 ölçüttür ve her biri üç tur eskidir; yanına dört sabit eklenir — kopya
başına doyum verimi, hedef doluluk, alt ve üst kopya sınırı. Bu kalemlerin tazeliği doğrudan kaynağa
çevrilir: aynı yük, aynı denetleyici ve aynı hedefle, yalnız ölçüt gecikmesi yüzünden 301 kopya-tur
yerine 510 kopya-tur harcanabiliyor.

#### Özet

- Ölçüt anında geldiğinde devredilen karar kusursuz: 301 kopya-turluk ideal kaynakla birebir aynı,
  sıfır aşırı ve sıfır yetersiz tur.
- Tek turluk gecikme salınımı 8'den 30'a çıkarıyor ve 29 turu yetersiz kapasiteyle geçiriyor;
  denetleyici kendi son kararının ölçüte yansıyıp yansımadığını bilmediği için aynı yükü iki kez
  düzeltiyor.
- Gecikme büyüdükçe salınım 11'e iniyor, ama bu bir iyileşme değil: denetleyici üst sınıra yapışıyor,
  kaynak 510 kopya-tura (idealin 1,7 katı) çıkıyor ve turların üçte biri yine yetersiz kalıyor.
- Bekleme penceresi salınımı 17'den 11'e indirirken kaynağı 457'den 632 kopya-tura çıkarıyor;
  küçültmeyi geciktirdiği için yetersiz turu 40'tan 23'e düşürüyor.
- Adım sınırı aşırı düzeltmeyi kestiği için hem salınımı hem kaynağı düşürüyor (457'den 347
  kopya-tura), buna karşılık basamak testinde tepki 3 turdan 5 tura çıkıyor ve değişiklik sayısı
  59'dan 71'e yükseliyor.
- Gecikme sıfırken aynı iki ayar 17 kopya-tur fazladan harcayıp iki salınım kazandırıyor; söndürücü
  ayarlar bir ölçüm sorununun tamiridir, yük sorununun değil.

#### Sonraki Adım

Bu dersin denetleyicisi tek bir kolu çeviriyor: kopya sayısı. İki kol daha var ve ikisi de aynı yükü
başka bir yerden karşılıyor. Kopyanın kendisi büyütülebilir — kapsülün isteği gözlenen kullanıma
göre yeniden boyutlandırılabilir, ama bunun bir bedeli vardır ve bedel yeniden başlatmayla ödenir.
Kümenin kendisi büyütülebilir — düğüm eklenebilir, ama yeni düğüm anında hazır olmaz. Sonraki ders
bu iki kolu ölçer ve üçünün birbirini bozduğu durumu gösterir.

### Dikey ve Küme Ölçekleme

Source: https://academia.sh/tr/kurslar/orkestrasyon/dikey-ve-kume-olcekleme

Kaynak boyutlandırma ve düğüm eklemenin ölçülmesi: dikey boyutlandırmanın bedeli olan yeniden başlatma sayısı ile kazancı olan boş kapasite düşüşünün karşılaştırılması, yeni düğümün hazır olma gecikmesi taranarak kaç tur kapasitesiz kalındığının sayılması ve üç ölçekleme türünün birbirini bozduğu durumun bir örnekle gösterilmesi.

Önceki dersin denetleyicisi tek bir kolu çeviriyordu: kopya sayısı. İki kol daha var. Kopyanın
kendisi büyütülüp küçültülebilir — kapsülün isteği gözlenen kullanıma göre yeniden yazılabilir. Küme
büyütülüp küçültülebilir — düğüm eklenip çıkarılabilir. Üçü de aynı yükü karşılar ve üçünün bilgi
maliyeti farklıdır.

Bu iki kolun ortak yanı, karşılığın anında alınamamasıdır. Kopya sayısını değiştirmek bir sayaç
işlemidir; kapsülün isteğini değiştirmek onu **yeniden başlatmayı** gerektirir, düğüm eklemek ise
düğümün **hazır olmasını** bekletir. Bu ders iki gecikmeyi ayrı ayrı sayar ve sonunda üç kolun aynı
anda çevrildiğinde ne olduğunu gösterir. Ölçülen şey bir modeldir; iş yükü bölgesel ölçüm ağının
(kurgu) servisleridir ve kaç kopya gerektiğinin aritmetiği kapasite planlamasından gelen girdidir.

#### Dikey Boyutlandırma: Bedel Yeniden Başlatma

Modelde altı kapsül 120 tur boyunca izlenir. Başlangıç isteği 1.024 birimdir, yani gerçek kullanımın
epey üstünde bildirilmiştir. Bir öneri üretici son on turun tepesini alır ve bildirilen istekten
belirli bir eşikten fazla saparsa isteği yeniden yazar; her yazma kapsülü yeniden başlatır ve iki
tur hizmet dışı bırakır.

```js
// zamanlama/dikey.mjs — dikey boyutlandirma: bedel yeniden baslatma, kazanc bos kapasitenin
// dusmesi. Kurulan sey bir MODELDIR; gercek kume kosturulmaz.
export const TUR = 120, KAPSUL = 6;
export const PENCERE = 10;         // ZO31: oneri son 10 turun tepesinden cikar
export const KESINTI = 2;          // ZO32: her yeniden boyutlandirma kapsulu 2 tur hizmet disi birakir
const TOHUM = 20260806;

export function uretec(tohum = TOHUM) {
  let s = tohum % 2147483647;
  return () => (s = (s * 48271) % 2147483647) / 2147483647;
}

// ZO33: kullanim 480 birim cevresinde dalgalanir, iki kapsul yavasca suruklenir, ±%12 gurultu.
export function kullanimSerileri() {
  const r = uretec();
  return Array.from({ length: KAPSUL }, (_, k) =>
    Array.from({ length: TUR }, (_, t) => {
      const taban = 480 + 100 * Math.sin((2 * Math.PI * t) / 30) + (k % 3 === 0 ? 1.6 * t : 0);
      return Math.max(80, Math.round(taban * (0.88 + 0.24 * r())));
    }));
}
export const SERILER = kullanimSerileri();

// Oneri: son PENCERE turun tepesi. Sapma esigi asilirsa istek degisir ve kapsul yeniden baslar.
export function boyutlandir(esik) {
  let baslatma = 0, israf = 0, yetersiz = 0, kesintiTur = 0, istekTur = 0;
  for (const seri of SERILER) {
    let istek = 1024, kalan = 0;                // ZO34: ilk istek 1024 birim (siserek bildirilmis)
    for (let t = 0; t < TUR; t++) {
      const oneri = Math.max(...seri.slice(Math.max(0, t - PENCERE + 1), t + 1));
      if (esik >= 0 && Math.abs(oneri - istek) / istek > esik && kalan === 0) {
        istek = oneri; baslatma++; kalan = KESINTI;
      }
      if (kalan > 0) { kalan--; kesintiTur++; }
      istekTur += istek;
      israf += Math.max(0, istek - seri[t]);
      if (seri[t] > istek) yetersiz++;
    }
  }
  return { baslatma, israf, yetersiz, kesintiTur, istekTur };
}

if (process.argv[1].endsWith("dikey.mjs")) {
  const kullanimTur = SERILER.flat().reduce((a, b) => a + b, 0);
  console.log(`model: ${KAPSUL} kapsul x ${TUR} tur (tohum ${TOHUM}); gercek kullanim toplami ` +
    `${kullanimTur} birim-tur, ilk istek 1024 birim`);
  const s = (x, n = 16) => String(x).padStart(n);
  console.log(`\n${"esik".padEnd(14)}${s("yeniden baslatma")}${s("hizmet disi tur")}` +
    `${s("bos istek")}${s("bos oran")}${s("yetersiz tur")}`);
  for (const [ad, esik] of [["sabit istek", -1], ["%5", 0.05], ["%10", 0.10],
                            ["%20", 0.20], ["%35", 0.35], ["%50", 0.50]]) {
    const o = boyutlandir(esik);
    console.log(`${ad.padEnd(14)}${s(o.baslatma)}${s(o.kesintiTur)}${s(o.israf)}` +
      `${s("%" + ((o.israf / o.istekTur) * 100).toFixed(1))}${s(o.yetersiz)}`);
  }
  const a = boyutlandir(-1), b = boyutlandir(0.20);
  console.log(`\nsabit istekten %20 esigine: bos istek ${a.israf} -> ${b.israf} birim-tur ` +
    `(%${(100 * (1 - b.israf / a.israf)).toFixed(1)} dusus), bedeli ${b.baslatma} yeniden baslatma ` +
    `ve ${b.kesintiTur} hizmet disi tur`);
}
```

```
model: 6 kapsul x 120 tur (tohum 20260806); gercek kullanim toplami 367748 birim-tur, ilk istek 1024 birim

esik          yeniden baslatma hizmet disi tur       bos istek        bos oran    yetersiz tur
sabit istek                  0               0          369532           %50.1               0
%5                         141             280           57939           %13.7              75
%10                         87             174           56176           %13.3             113
%20                         38              76           54704           %13.2             190
%35                         10              20           64938           %15.4             180
%50                          8              16           51564           %13.2             336

sabit istekten %20 esigine: bos istek 369532 -> 54704 birim-tur (%85.2 dusus), bedeli 38 yeniden baslatma ve 76 hizmet disi tur
```

#### Üç Sütun Aynı Anda İyileşmiyor

Sabit istek satırı başlangıç noktasıdır: hiç yeniden başlatma yok, hiç yetersiz tur yok ve isteğin
yüzde 50,1'i boşta duruyor. Bildirim iki katına şişirildiğinde ödenen bedel budur — birinci dersin
israfı, burada bir zaman serisi olarak görünüyor.

Eşik yüzde 20'ye kurulduğunda boş oran yüzde 13,2'ye iniyor: 369.532 birim-turluk boş istek 54.704'e
düşüyor, yani **yüzde 85,2 kazanç**. Bedeli 38 yeniden başlatma ve 76 hizmet dışı turdur. Eşik yüzde
5'e indirildiğinde boş oran yalnız yüzde 13,7'de kalırken yeniden başlatma sayısı 141'e, hizmet dışı
tur 280'e çıkıyor. **Daha sıkı takip daha çok kazanç getirmiyor**, yalnız daha çok kesinti getiriyor.

Üçüncü sütun karşılıksız değil. Sabit istekte yetersiz tur sıfırken, yüzde 20 eşiğinde 190, yüzde
50'de 336 tur yetersiz kalıyor: istek gerçek kullanıma yaklaştıkça tepe anlarında sınır aşılıyor.
Dikey boyutlandırma boş kapasiteyi yetersizliğe çeviriyor ve aradaki dengeyi belirleyen tek şey
eşiktir. Eşiğin kendisi de bir tahmindir — yüzde 35 satırı yüzde 20'den daha çok israf üretiyor,
çünkü öneri bir tepe değerine takılıp orada kalıyor. **Sıralamanın tek yönlü olmaması, ayarın
ölçülmeden seçilemeyeceğini gösterir.**

#### Küme Ölçeklemesi: Bedel Hazır Olma Gecikmesi

İkinci kol düğüm sayısıdır. Yük 800 istek/s'den 12.000 istek/s'ye tırmanır; ölçekleme denetleyicisi
kopya ekler, kopyalar düğüme sığmadığında küme ölçekleyici düğüm sipariş eder ve yeni düğüm belirli
tur sonra hazır olur. Ölçüt gecikmesi bu modelde sıfırdır, böylece ölçülen tek gecikme düğümün hazır
olma süresidir.

```js
// zamanlama/kume.mjs — kume olceklemesi: yeni dugumun hazir olma gecikmesi yuke yetisiyor mu,
// ve uc olcekleme turunun birbirini bozdugu durum. Model; gercek kume kosturulmaz.
import { TUR, uretec } from "./dikey.mjs";

const DOYUM = 1176.47, HEDEF = 0.70;      // M19'un girdileri; aritmetik burada tekrarlanmaz
const KOPYA_BASINA = 4;                   // ZO35: bir dugume dort kopya sigar
const KUCULTME_PENCERESI = 5;

// Yuk 800'den 12000 istek/s'ye tirmaniyor, uzerine dalga ve ±%6 gurultu (kurgu).
const r = uretec(20260807);
const YUK = Array.from({ length: TUR }, (_, t) =>
  Math.round((800 + 95 * t + 600 * Math.sin((2 * Math.PI * t) / 25)) * (0.94 + 0.12 * r())));
const gereken = (y) => Math.max(1, Math.ceil(y / (DOYUM * HEDEF)));

// ZO36: dikey boyutlandirma her 10. turda bir kopyayi 2 tur hizmet disi birakir.
function kostur({ hazir, dugumSiniri = 99, dikey = false }) {
  let kopya = 1, hazirDugum = 1, bekleyen = [], bosSayac = 0;
  let kapasitesizTur = 0, enUzun = 0, seri = 0, dugumTur = 0, kopyaTur = 0;
  let olay = 0, siparis = 0, baslatma = 0;
  for (let t = 0; t < TUR; t++) {
    bekleyen = bekleyen.filter((v) => { if (v <= t) { hazirDugum++; return false; } return true; });
    const kisitli = Math.min(hazirDugum, dugumSiniri) * KOPYA_BASINA;
    const yenidenBaslayan = dikey && t % 10 < 2 ? 1 : 0;
    if (dikey && t % 10 === 0) baslatma++;
    const hizmetVeren = Math.max(1, Math.min(kopya, kisitli) - yenidenBaslayan);
    const doluluk = YUK[t] / (hizmetVeren * DOYUM);
    const istenen = Math.max(1, Math.ceil((kopya * doluluk) / HEDEF));
    if (istenen !== kopya) olay++;
    kopya = istenen;
    if (kopya > kisitli) {
      const ek = Math.ceil((kopya - kisitli) / KOPYA_BASINA);
      for (let i = 0; i < ek; i++) bekleyen.push(t + hazir);
      siparis += ek;
    } else if (kisitli - kopya >= KOPYA_BASINA && hazirDugum > 1) {
      if (++bosSayac >= KUCULTME_PENCERESI) { hazirDugum--; bosSayac = 0; }
    } else bosSayac = 0;
    const calisan = Math.min(kopya, Math.min(hazirDugum, dugumSiniri) * KOPYA_BASINA);
    kopyaTur += calisan;
    dugumTur += hazirDugum + bekleyen.length;
    if (calisan < gereken(YUK[t])) { kapasitesizTur++; enUzun = Math.max(enUzun, ++seri); }
    else seri = 0;
  }
  return { kapasitesizTur, enUzun, dugumTur, kopyaTur, olay, siparis, baslatma };
}

const s = (x, n = 16) => String(x).padStart(n);
console.log(`yuk ${Math.min(...YUK)}–${Math.max(...YUK)} istek/s, ${TUR} tur; gereken kopya ` +
  `${gereken(YUK[0])}–${Math.max(...YUK.map(gereken))}, dugum basina ${KOPYA_BASINA} kopya`);
console.log(`\nyeni dugumun hazir olma gecikmesi taraniyor:`);
console.log(`${"gecikme".padEnd(10)}${s("kapasitesiz tur")}${s("en uzun seri")}${s("dugum siparisi")}` +
  `${s("dugum-tur")}${s("kopya-tur")}`);
for (const hazir of [0, 1, 2, 4, 6, 8]) {
  const o = kostur({ hazir });
  console.log(`${String(hazir).padEnd(10)}${s(o.kapasitesizTur)}${s(o.enUzun)}${s(o.siparis)}` +
    `${s(o.dugumTur)}${s(o.kopyaTur)}`);
}

console.log(`\nuc olcekleme turu bir arada (hazir olma gecikmesi 4):`);
console.log(`${"ayar".padEnd(30)}${s("olcekleme olayi", 18)}${s("kapasitesiz tur", 18)}` +
  `${s("yeniden baslatma", 18)}${s("dugum-tur", 18)}`);
for (const [ad, ek] of [["yalniz yatay (dugum bol)", { hazir: 0, dugumSiniri: 99 }],
                        ["yatay + kume", { hazir: 4 }],
                        ["yatay + kume + dikey", { hazir: 4, dikey: true }]]) {
  const o = kostur(ek);
  console.log(`${ad.padEnd(30)}${s(o.olay, 18)}${s(o.kapasitesizTur, 18)}` +
    `${s(o.baslatma, 18)}${s(o.dugumTur, 18)}`);
}
const b = kostur({ hazir: 4 }), c = kostur({ hazir: 4, dikey: true });
console.log(`\ndikey eklenince: olcekleme olayi ${b.olay} -> ${c.olay}, dugum siparisi ` +
  `${b.siparis} -> ${c.siparis}, dugum-tur ${b.dugumTur} -> ${c.dugumTur}`);
```

```
yuk 792–12189 istek/s, 120 tur; gereken kopya 1–15, dugum basina 4 kopya

yeni dugumun hazir olma gecikmesi taraniyor:
gecikme    kapasitesiz tur    en uzun seri  dugum siparisi       dugum-tur       kopya-tur
0                        3               1               3             302            1003
1                        3               1               3             302            1003
2                        5               2               6             319            1001
4                       10               4              13             431             997
6                       10               6              21             837             998
8                        8               8              33            2353            1002

uc olcekleme turu bir arada (hazir olma gecikmesi 4):
ayar                             olcekleme olayi   kapasitesiz tur  yeniden baslatma         dugum-tur
yalniz yatay (dugum bol)                      36                 3                 0               302
yatay + kume                                  42                10                 0               431
yatay + kume + dikey                          54                 8                12               445

dikey eklenince: olcekleme olayi 42 -> 54, dugum siparisi 13 -> 13, dugum-tur 431 -> 445
```

#### Gecikme Kapasitesizliği Kaynağa Çeviriyor

İkinci sütun beklendiği gibi davranıyor: en uzun kapasitesiz seri, hazır olma gecikmesinin ta
kendisidir. Gecikme 4 turken en uzun kesintisiz yetersizlik 4 tur, gecikme 6 turken 6 turdur. Yeni
düğüm yola çıkana kadar yük bekler ve bekleme süresi bir tasarım tercihinin değil, düğüm hazırlama
süresinin sonucudur.

Birinci sütun beklenmedik davranıyor. Gecikme 6'da 10 tur kapasitesiz kalınırken gecikme 8'de bu
sayı 8'e **iniyor**. Sistemin daha iyi çalıştığı sonucu yanlış olur; dördüncü sütun asıl olanı
söylüyor. Düğüm siparişi 21'den 33'e, düğüm-tur 837'den **2.353'e** çıkıyor. Gecikme büyüdükçe
denetleyici aynı açığı defalarca görüp defalarca düğüm sipariş ediyor; sonunda kümede ihtiyacın
çok üstünde düğüm birikiyor ve kapasitesizlik kaynak harcanarak kapanıyor. Küçültme kuralı beş
turda bir düğüm çıkardığı için bu fazlalık koşum boyunca eriyip bitmiyor. **Kapasitesiz tur ile
düğüm-tur birlikte okunmadıkça gecikme iyileşiyormuş gibi görünür.**

Kopya-tur sütununun beş satırda da 1.000 civarında kalması ayrı bir sonuçtur: çalışan kopya sayısı
neredeyse hiç değişmiyor, değişen şey o kopyaların ne kadar geç yerleşebildiği ve arkalarında kaç
düğümün beklediğidir.

#### Üç Kol Aynı Anda Çevrilince

Son tablo üç ölçekleme türünü üst üste koyuyor. Düğüm bolken yalnız yatay ölçekleme 36 ölçekleme
olayı ve 3 kapasitesiz tur üretiyor. Küme ölçeklemesi eklendiğinde olay sayısı 42'ye, kapasitesiz tur
10'a, düğüm-tur 302'den 431'e çıkıyor: yatay denetleyicinin verdiği karar artık anında
uygulanamadığı için kendini tekrarlıyor.

Dikey boyutlandırma eklendiğinde bozulma açıkça sayılabiliyor. On iki yeniden başlatma, ölçekleme
olayını 42'den 54'e çıkarıyor — **fazladan on iki olay, tam olarak yeniden başlatma sayısı kadar**.
Zincir şudur: dikey boyutlandırma bir kopyayı iki tur hizmet dışı bırakır, hizmet veren kopya sayısı
düşer, kalanların doluluğu yükselir, yatay denetleyici yükün arttığını sanıp kopya ekler, eklenen
kopya düğüme sığmazsa küme ölçekleyici düğüm sipariş eder. Gerçek yük bu süre boyunca hiç değişmemiş,
düğüm-tur 431'den 445'e çıkmıştır.

Üç denetleyicinin hiçbiri hata yapmıyor. Her biri kendi ölçütünü doğru okuyor ve kendi kuralını
doğru uyguluyor. Sorun, birinin **eylemi**nin ötekinin **ölçüsü** olmasıdır: dikey boyutlandırmanın
yeniden başlatması, yatay denetleyicinin doluluk ölçütüne yük artışı olarak girer. Sistemin
görmediği kalem burada da tek bir şeydir — bir kopyanın hizmet dışı olmasının nedeni. Bu kalem
ölçüte eklenseydi, yani hizmet dışı kopyalar doluluk hesabından çıkarılsaydı, on iki olayın on ikisi
de doğmazdı.

Üç kolun bilgi maliyeti de eşit değildir. Yatay ölçekleme kopya başına tek bir doluluk ölçütüyle
çalışır ve verdiği karar bir sayaç değişikliğiyle geri alınır. Dikey boyutlandırma kapsül başına bir
kullanım penceresi ister — bu modelde altı kapsül için onar turluk pencere, yani her turda altmış
örnek — ve kararının bedeli bir yeniden başlatmadır. Küme ölçeklemesi bu ikisinin üstüne düğüm
hazırlama süresini ekler; o süre ölçülmez, bildirilir ve yanlış bildirildiğinde kapasitesiz tur
sayısı ile düğüm-tur birlikte kayar.

#### Özet

- Dikey boyutlandırmanın kazancı boş kapasitede ölçülür: sabit istekte boş oran yüzde 50,1 iken
  yüzde 20 eşiğiyle yüzde 13,2'ye iniyor, boş istek 369.532'den 54.704 birim-tura düşüyor.
- Bedeli yeniden başlatmadır ve eşik daraldıkça yalnız bedel büyüyor: yüzde 20'de 38 yeniden
  başlatma ve 76 hizmet dışı tur, yüzde 5'te 141 yeniden başlatma ve 280 hizmet dışı tur, kazanç ise
  yüzde 13,7'de aynı yerde kalıyor.
- Sıkı boyutlandırma boş kapasiteyi yetersizliğe çevirir: yetersiz tur sıfırdan 190'a, yüzde 50
  eşiğinde 336'ya çıkıyor.
- Küme ölçeklemesinde en uzun kapasitesiz seri hazır olma gecikmesine eşittir; gecikme 8'de
  kapasitesiz tur 8'e inerken düğüm siparişi 21'den 33'e, düğüm-tur 837'den 2.353'e çıkıyor, yani
  kapasitesizlik kaynakla kapatılıyor.
- Üç kol birlikte çevrildiğinde on iki yeniden başlatma tam on iki fazladan ölçekleme olayı üretiyor
  ve düğüm-tur 431'den 445'e çıkıyor; gerçek yük hiç değişmemiştir.
- Üç denetleyici de kendi kuralını doğru uygular; bozulmanın kaynağı birinin eyleminin ötekinin
  ölçütüne yük olarak girmesi ve hizmet dışı kalma nedeninin ölçütte bulunmamasıdır.

#### Sonraki Adım

Bu konu yerleştirme ve büyütme kararlarını sayıya bağladı: istek ve sınır, kısıtlar, işaretler,
tahliye, üç ölçekleme türü. Hepsinin ortak varsayımı, istenen durumun bir yerde yazılı olduğu ve
kümenin onu uygulamaya çalıştığıdır. O istenen durumun nasıl yayına alındığı, kapsülün ne zaman
sağlıklı sayıldığı, hangi öznenin hangi nesnede yetkili olduğu, ağın kimden kime açık olduğu ve bir
arıza anında bütün bunların nasıl geri alındığı henüz sorulmadı. Sonraki konu kümenin işletimini ele
alır: dağıtım kalıpları, denetim türleri, yetki ve ağ politikası, izleme, sorun giderme ve kümenin
kendi nesne türleriyle genişletilmesi.

## İşletim ve Genişletme

Kümenin işletilmesi ve genişletilmesi: aşamalı güncelleme, iki ortamlı geçiş ve kanarya dağıtım kalıplarının kaçan hata ve geri alma penceresi cinsinden karşılaştırılması, canlılık, hazır olma ve başlangıç denetimlerinin ayrımı, rol tabanlı erişim denetimiyle yetkilerin sınırlandırılması, ağ politikalarıyla trafiğin kısıtlanması, güvenlik bağlamı, yeniden kullanılabilir dağıtım paketleri ve şablonlama, kaynak türünün genişletilmesi, işletim bilgisinin denetleyiciye kodlanması, küme gözlemlenebilirliği ve çok kümeli işletim.

### Dağıtım Kalıpları

Source: https://academia.sh/tr/kurslar/orkestrasyon/dagitim-kaliplari

Aşamalı güncelleme, iki ortamlı geçiş ve kanarya aynı kusurlu sürüm dizisinde koşturulur: kaçan hatanın etkilediği istek, fark etmeden geçen tur, ayakta tutulan tepe kapasite ve geri almanın tur maliyeti sayılır. Kanaryada örneklem büyüklüğü taranır.

Yerleştirme ve ölçekleme kararları sisteme devredildi: hangi düğümün hangi kapsülü alacağına
zamanlayıcı, kaç kopyanın duracağına ölçekleme denetleyicisi karar veriyor. İkisi de ortak bir
varsayıma yaslanır — ortada **çalışan** bir sürüm vardır. Devredilmemiş iki karar kaldı. Yeni bir
sürüm kümeye **nasıl girer** ve ayağa kalkan bir kopyanın **gerçekten hizmet verip vermediğine**
kim bakar. Bu ders birincisini ölçer.

Yayın mekaniği daha önce ölçüldü: havuz değiştiğinde düşen istek, uçuştaki isteklerin bağlantı
boşaltmayla kurtarılması, sert ve zarif kapanmanın farkı. O ölçümler burada tekrarlanmıyor.
Buranın sorusu bir adım sonrasıdır: yayın sırasında **tek bir istek bile düşmese** kalıplar
birbirinden ayrılır mı? Ayrılır — ama ayrıldıkları yer kesinti değil, **yeni sürümün bozuk olduğu
durumdur**. Her dağıtımın bir miktar kaçan hata ürettiği ölçülmüş bir sonuçtur; bu ders o sonucu
kalıp seçimine bağlar ve üç kalıbı aynı kusurlu sürüm dizisinde koşturur.

Devredilen karar şudur: eski sürümü ne zaman durdurup yeniyi ne kadar trafiğe açacağına insan
değil bir denetleyici karar verir. Denetleyicinin bunun için bilmesi gereken kalemler dörttür:
hangi kopya hangi sürümde, kopya hazır mı, hata oranı ne, eşik aşılınca ne yapılacak. Sonuncusu
tanımlı değilse denetleyici ilerlemeye devam eder — bilmediği için değil, **durması söylenmediği
için**.

- **OI1.** Küme, kurgusal bölgesel ölçüm ağının doğrulayıcı servisini on iki kopyayla çalıştırır;
  tur başına altı yüz istek gelir. Ağ da rakamlar da kurgudur.
- **OI2.** Kusurlu sürüm, kendisine gelen isteğin yüzde altısında hata verir. Kusur ilk istekten
  başlar ve sürüm boyunca sabittir; ısınmayla geçen kusurlar bu modelin dışındadır.
- **OI3.** Gözlemci turun sonunda bakar. Bir turdan kısa gecikmeler, ölçüt toplama gecikmesi ve
  uyarı kanalının kendi gecikmesi modellenmiyor.
- **OI4.** Alarm eşiği yüzde bir buçuktur ve kümenin olağan hata payının üstünde seçilmiştir;
  eşiğin nereden geldiği bu dersin konusu değil.
- **OI5.** Geri alma turları boyunca yeni sürümün payı eşit adımlarla sıfıra iner; geri almanın
  kendisi hata üretmez.
- **OI6.** Ufuk on iki turdur. Bu süre içinde alarm çalmazsa kusur kaçmış sayılır.

#### Ölçüm Düzeneği

Ölçülen şey gerçek bir küme değil, `node` ile kurulan bir modeldir. Model üç şeyi taşır: bir
kalıbın tur tur hangi paylaşımı ürettiği, isteklerin bu paya göre dağılması ve gözlemcinin turun
sonunda ne gördüğü. Rastgelelik üreteci kendi yazılmıştır, tohumu görünürdür.

```js
// kalip.mjs — uc dagitim kalibinin tur tabanli modeli; gercek kume degil, bir modeldir
export const TOHUM = 20260801;
export const HIZMET = 12, TUR_ISTEK = 600, HATA_ORANI = 0.06, ESIK = 0.015, UFUK = 12;

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

// Her adim: yeni surumde hizmet veren kopya, eski surumde hizmet veren kopya,
// o an ayakta tutulan toplam kopya, alarm bu turda calarsa geri almanin tur maliyeti.
export const asamali = { ad: 'asamali guncelleme', plan: [
  { yeni: 3, eski: 9, ayakta: 15, geri: 1 }, { yeni: 6, eski: 6, ayakta: 15, geri: 2 },
  { yeni: 9, eski: 3, ayakta: 15, geri: 3 }, { yeni: 12, eski: 0, ayakta: 12, geri: 4 } ] };

export const ikiOrtam = { ad: 'iki ortamli gecis', plan: [
  { yeni: 0, eski: 12, ayakta: 24, geri: 0 }, { yeni: 12, eski: 0, ayakta: 24, geri: 1 },
  { yeni: 12, eski: 0, ayakta: 12, geri: 3 } ] };

export const kanarya = (k, gozlem = 3) => ({ ad: `kanarya (ornek ${k})`, plan: [
  ...Array.from({ length: gozlem }, () => ({ yeni: k, eski: 12, ayakta: 12 + k, geri: 1 })),
  { yeni: 12, eski: 0, ayakta: 24, geri: 1 }, { yeni: 12, eski: 0, ayakta: 12, geri: 3 } ] });

export function kostur({ ad, plan }, etiketli = false) {
  const rnd = uretec(TOHUM);
  let i = 0, alarm = 0, kalan = 0, pay = 0, maliyet = 0, tepe = HIZMET;
  let hatali = 0, dokunulan = 0, adim = { yeni: 0, eski: HIZMET, ayakta: HIZMET, geri: 0 };
  for (let tur = 1; tur <= UFUK; tur += 1) {
    if (kalan > 0) { adim = { ...adim, yeni: Math.max(0, adim.yeni - pay), eski: HIZMET }; kalan -= 1; }
    else if (alarm) adim = { yeni: 0, eski: HIZMET, ayakta: HIZMET, geri: 0 };
    else { adim = plan[Math.min(i, plan.length - 1)]; i += 1; }
    tepe = Math.max(tepe, adim.ayakta);
    let hataTur = 0, yeniTur = 0;
    const oran = adim.yeni / (adim.yeni + adim.eski);
    for (let r = 0; r < TUR_ISTEK; r += 1) {
      if (rnd() >= oran) continue;                 // istek eski surume gitti
      yeniTur += 1;
      if (rnd() < HATA_ORANI) hataTur += 1;
    }
    hatali += hataTur; dokunulan += yeniTur;
    if (!alarm) {                                  // gozlemci turun sonunda bakar
      const gorulen = etiketli ? (yeniTur ? hataTur / yeniTur : 0) : hataTur / TUR_ISTEK;
      const yeterli = !etiketli || yeniTur >= 100;
      if (yeterli && gorulen > ESIK) { alarm = tur; maliyet = adim.geri; kalan = maliyet; pay = Math.ceil(adim.yeni / Math.max(1, maliyet)); }
    }
  }
  return { ad, alarm, maliyet, pencere: alarm ? alarm - 1 : UFUK, tepe, hatali, dokunulan };
}
```

Üç kalıbın planı arasındaki bütün fark üç sütunda toplanıyor. Aşamalı güncelleme yeni sürümü
üçerli paylarla açar ve geçiş boyunca üç kopya fazladan ayakta tutar. İki ortamlı geçiş yeni
sürümün tamamını trafiğe açmadan ayağa kaldırır — ilk turda payı sıfırdır, ayakta yirmi dört kopya
vardır — sonra tek adımda çevirir. Kanarya küçük bir örneklemi trafiğe açar, birkaç tur bekler ve
alarm çalmazsa terfi eder.

#### Üç Kalıp, Tek Kusurlu Sürüm

```js
// kosum1.mjs — ayni kusurlu surum dizisi uc kalipta kosturulur
import { kostur, asamali, ikiOrtam, kanarya, TOHUM, HIZMET, TUR_ISTEK, HATA_ORANI, ESIK, UFUK } from './kalip.mjs';

console.log(`tohum ${TOHUM} | ${HIZMET} kopya, tur basina ${TUR_ISTEK} istek, ufuk ${UFUK} tur`);
console.log(`kusurlu surum: yeni surume giden istegin %${HATA_ORANI * 100}'si hata veriyor`);
console.log(`gozlemci: kume genelinde hata orani %${ESIK * 100}'i asarsa alarm\n`);
console.log('kalip                  alarm turu  fark etmeden  hatali istek  dokunulan  tepe kopya  geri alma turu');
for (const k of [asamali, ikiOrtam, kanarya(2)]) {
  const s = kostur(k);
  console.log(`${s.ad.padEnd(22)} ${String(s.alarm || '-').padEnd(11)} ${String(s.pencere).padEnd(13)} ` +
    `${String(s.hatali).padEnd(13)} ${String(s.dokunulan).padEnd(10)} ${String(s.tepe).padEnd(11)} ${s.maliyet || '-'}`);
}
```

```
tohum 20260801 | 12 kopya, tur basina 600 istek, ufuk 12 tur
kusurlu surum: yeni surume giden istegin %6'si hata veriyor
gozlemci: kume genelinde hata orani %1.5'i asarsa alarm

kalip                  alarm turu  fark etmeden  hatali istek  dokunulan  tepe kopya  geri alma turu
asamali guncelleme     2           1             33            555        15          2
iki ortamli gecis      2           1             30            600        24          1
kanarya (ornek 2)      4           3             53            851        24          1
```

Üç kalıp da aynı kusuru taşıdı, üçü de fark etti, ama bedelleri farklı yerlerde birikti.

Aşamalı güncelleme ilk turda yeni sürüme dörtte bir pay verdi; bu payda kümenin toplam hata oranı
eşiğin tam üstüne çıkmadı, alarm ikinci turda çaldı. İki ortamlı geçiş ilk turda hiç pay vermedi,
ikinci turda tamamını verdi — alarm da aynı turda çaldı, ama o tek turda **altı yüz isteğin
hepsi** kusurlu sürüme gitti. Aşamalıda aynı sürede beş yüz elli beş istek dokunuldu; fark küçük
görünüyor, çünkü aşamalı da ikinci turda yarı yarıya paylaşıyordu.

Ayrılık asıl iki sütunda. Tepe kapasite: aşamalı on beş kopyayla geçti, iki ortamlı yirmi dört —
yani geçiş anında kümenin yeni sürüm için **bir kat fazladan yer** bulması gerekti. Geri alma
maliyeti tersine döndü: iki ortamlı geçişte geri alma tek turdur, çünkü eski sürüm hâlâ ayaktadır;
aşamalıda ikinci turda yakalanan kusur iki tur geri alma ister, dördüncü turda yakalansaydı dört.
Aşamalı güncelleme ilerledikçe geri alma pahalılaşır; iki ortamlı geçişte pahalılaşma **bir anda**
olur — eski ortam kapatıldığı turda geri alma bir turdan üç tura sıçrar.

Kanarya satırı bu tablonun sürprizidir. İki kopyalık örneklem, üç gözlem turu boyunca kümenin
toplam hata oranını eşiğin altında tuttu: on dört hizmet veren kopyanın ikisi kusurluysa toplam
hata oranı yüzde bir civarındadır, eşik yüzde bir buçuktur. Gözlemci bir şey görmedi, kanarya
terfi etti ve dördüncü turda tamamı açıldı. Kaçan hatanın dokunduğu istek sekiz yüz elli bir —
üç kalıbın en kötüsü. Kanarya, örneklemi yanlış seçildiğinde kusuru yakalayan değil, **yakalamayı
geciktirip sonra tamamına açan** kalıp hâline gelir.

#### Örneklem Büyüklüğü

Bu yüzden kanaryanın tek ayarı taranmalı. Aynı model iki gözlemciyle koşturulur: birincisi
kümenin toplam hata oranına bakar, ikincisi istekleri sürüme göre ayırır ve yalnız yeni sürümün
hata oranına bakar. İkincisi ek bir bilgi kalemi ister — her isteğin hangi sürüme gittiği — ve
karar verebilmek için turda yeterli istek görmesi gerekir.

```js
// kosum2.mjs — kanaryada ornek buyuklugu taranir; ikinci gozlemci istekleri surume gore ayirir
import { kostur, kanarya, TUR_ISTEK } from './kalip.mjs';

console.log('ornek  kume genelinde bakan gozlemci          surume gore ayiran gozlemci');
console.log('kopya  alarm  fark etmeden  hatali  dokunulan  alarm  fark etmeden  hatali  dokunulan');
for (const k of [1, 2, 3, 4, 6, 8]) {
  const t = kostur(kanarya(k)), e = kostur(kanarya(k), true);
  const yaz = (s) => `${String(s.alarm || '-').padEnd(6)} ${String(s.pencere).padEnd(13)} ` +
    `${String(s.hatali).padEnd(7)} ${String(s.dokunulan).padEnd(10)}`;
  console.log(`${String(k).padEnd(6)} ${yaz(t)} ${yaz(e)}`);
}
console.log(`\ngozlem turunda kanaryaya dusen istek: ornek k icin ${TUR_ISTEK} x k/(12+k)`);
console.log('surume gore ayiran gozlemci turda en az 100 istek gormeden karar vermiyor');
for (const k of [1, 2, 3, 4, 6, 8]) {
  console.log(`  ornek ${k}: ${Math.round(TUR_ISTEK * k / (12 + k))} istek/tur` +
    ` -> ${TUR_ISTEK * k / (12 + k) >= 100 ? 'karar verebilir' : 'ornek yetersiz'}`);
}
```

```
ornek  kume genelinde bakan gozlemci          surume gore ayiran gozlemci
kopya  alarm  fark etmeden  hatali  dokunulan  alarm  fark etmeden  hatali  dokunulan
1      4      3             42      730        4      3             42      730       
2      4      3             53      851        4      3             53      851       
3      4      3             55      948        1      0             7       107       
4      3      2             24      461        1      0             8       147       
6      1      0             11      191        1      0             11      191       
8      1      0             14      243        1      0             14      243       

gozlem turunda kanaryaya dusen istek: ornek k icin 600 x k/(12+k)
surume gore ayiran gozlemci turda en az 100 istek gormeden karar vermiyor
  ornek 1: 46 istek/tur -> ornek yetersiz
  ornek 2: 86 istek/tur -> ornek yetersiz
  ornek 3: 120 istek/tur -> karar verebilir
  ornek 4: 150 istek/tur -> karar verebilir
  ornek 6: 200 istek/tur -> karar verebilir
  ornek 8: 240 istek/tur -> karar verebilir
```

Sol yarı tek başına okunduğunda kanaryanın kötü bir kalıp olduğu sonucuna götürür. Bir, iki ve üç
kopyalık örneklemlerde alarm dördüncü turda — yani terfiden **sonra** — çaldı; dokunulan istek
örneklem büyüdükçe arttı, çünkü kaçırma süresi aynı kalıp gözlem payı büyüdü. Dört kopyada alarm
üçüncü tura, altı ve sekiz kopyada birinci tura çekildi. Toplam hasarın en düşük olduğu yer sekiz
değil altı: sekiz kopyalık örneklem birinci turda yakalasa da o tek turda iki yüz kırk üç isteğe
dokundu, altı kopyalık örneklem yüz doksan bire.

Sağ yarı, taramanın asıl sonucunu veriyor. Sürüme göre ayıran gözlemci üç ve dört kopyalık
örneklemlerde birinci turda alarm verdi; hatalı istek yediye ve sekize düştü. Bir ve iki kopyada
sağ yarı sol yarıyla aynı kaldı — çünkü o örneklemlerde yeni sürüme turda kırk altı ve seksen altı
istek düşüyor, gözlemcinin karar eşiğinin altında. Küçük örneklemin sorunu ölçütün seyreltilmesi
değil yalnızca; **örneklemin kendisinin küçüklüğü**dür. Etiketli ölçüt seyrelme sorununu çözer,
örneklem sorununu çözmez.

Buradan okunacak ayar üç kopyadır: kusuru birinci turda yakalar, yüz yedi isteğe dokunur, ayakta
tuttuğu fazladan kapasite on beş kopya değil on üçtür. Bedeli, her isteğin sürüm etiketini
taşıması ve gözlemcinin bu etikete göre ayrı seri tutmasıdır — bir bilgi kalemi daha.

#### Kalıbın Sakladığı Şey

Üç kalıbın hiçbiri "daha güvenli" değil; üçü de aynı üç niceliği farklı yerlere yığıyor. İki
ortamlı geçiş **geri almayı** ucuzlatır ve bedelini kapasiteyle öder: yirmi dört kopya, yani bir
kat fazla yer ve o yer geçiş penceresi boyunca boş durur. Aşamalı güncelleme **kapasiteyi**
ucuzlatır ve bedelini geri almayla öder: ilerledikçe geri dönüş uzar. Kanarya **etki alanını**
küçültür ve bedelini gözlem süresiyle öder — üç tur boyunca hiçbir şey ilerlemez.

Sessiz olan şey, üçünün de bir eşiğin doğru ayarlandığını varsaymasıdır. Modelde alarm çalmadığı
her turda denetleyici plandaki bir sonraki adıma geçti; hiçbir kalıp "emin değilim, bekleyeyim"
demedi. Kanaryada iki kopyalık örneklemin terfisi bir arıza değil, **plana uygun davranıştı**:
gözlemci eşiği aşan bir şey görmedi, denetleyici de ilerledi. Devredilen kararın bedeli tam
buradadır — denetleyici hata oranını değil, **gözlemcinin raporladığı sayıyı** bilir. O sayı
seyreltilmişse yanlış karar, yanlış bilgiden değil, **eksik ayrımdan** doğar.

#### Özet

- Üç kalıp aynı kusurlu sürümde koşturuldu: aşamalı güncelleme ikinci turda otuz üç hatalı
  istekle, iki ortamlı geçiş ikinci turda otuz hatalı istekle, iki kopyalık kanarya dördüncü turda
  elli üç hatalı istekle yakaladı.
- Tepe kapasite ile geri alma maliyeti ters yönde çalışır: iki ortamlı geçiş yirmi dört kopya
  ister ve tek turda geri alır; aşamalı on beş kopyayla geçer ama geri alma ilerledikçe iki, üç,
  dört tura çıkar.
- İki ortamlı geçişte geri alma penceresi eski ortamın kapatıldığı turda biter; o turdan sonra
  geri alma bir turdan üç tura sıçrar.
- Kanaryada küçük örneklem kusuru kaçırır ve terfi ettirir: iki kopyalık örneklem sekiz yüz elli
  bir isteğe dokunarak üç kalıbın en kötüsü oldu.
- Gözlemcinin ayrımı örneklemden önce gelir: sürüme göre ayıran ölçüt üç kopyalık örneklemde alarmı
  dördüncü turdan birinciye, hatalı isteği elli beşten yediye indirdi; bir ve iki kopyada hiçbir
  şeyi değiştirmedi, çünkü örneklem karar eşiğinin altındaydı.
- Devredilen karar "ilerle ya da dur" kararıdır; denetleyici hata oranını değil gözlemcinin
  raporladığı sayıyı bilir, o sayı seyreltilmişse yanlış karar eksik ayrımdan doğar.

#### Sonraki Adım

Bu dersin modeli boyunca bir kopya trafiğe girdiği anda hizmet verebiliyordu. Gerçekte bir süreç
ayağa kalkmakla hazır olmak arasında bir aralık geçirir: bağlantı havuzunu kurar, önbelleğini
ısıtır, bağımlılıklarını yoklar. Denetleyici bu aralığı bilmiyorsa kopyayı erken trafiğe açar; ya
da tersine, yavaş açılan bir kopyayı arızalı sanıp öldürür. Sonraki ders bu aralığı üç ayrı
denetimle ölçer: kopyanın yaşadığını, istek alabildiğini ve hâlâ açılmakta olduğunu ayırt eden
denetimlerin eşiklerini tarar ve yanlış ayarın kaç gereksiz yeniden başlatma, kaç hatalı istek
ürettiğini sayar.

### Sağlık Denetimleri

Source: https://academia.sh/tr/kurslar/orkestrasyon/saglik-denetimleri

Canlılık, hazır olma ve başlangıç denetiminin ayrımı sayıyla kurulur: yanlış kapsamlı canlılık denetiminin gereksiz yeniden başlatması ve yeniden başlatma döngüsü, hazır olma denetimi olmadan erken trafiğe açılan kopyaya giden hatalı istek, başlangıç denetimi olmadan yavaş açılan kopyanın öldürülmesi ayrı ayrı sayılır.

Önceki dersin modeli boyunca bir kopya havuza girdiği anda hizmet verebiliyordu. Dağıtım
denetleyicisi de bu varsayımla ilerledi: bir kopya ayağa kalktıysa sayılır, sayıldıysa pay alır.
Gerçekte bir sürecin başlaması ile istek karşılayabilmesi arasında bir aralık vardır — bağlantı
havuzu kurulur, önbellek ısıtılır, bağımlılıklar yoklanır. Bu aralığı kimse bildirmezse
denetleyici kopyayı erken trafiğe açar. Tersi de olur: yavaş açılan bir kopyayı arızalı sayıp
öldürür ve bunu her açılışta yineler.

Devredilen karar burada iki tanedir ve çoğu zaman tek karar sanılırlar. Birincisi **bu kopya
yeniden başlatılsın mı**, ikincisi **bu kopyaya istek gönderilsin mi**. İlkinin cevabı yanlışsa
çalışan bir süreç öldürülür; ikincisininki yanlışsa çalışmayan bir sürece istek gider. Sistemin
bu iki kararı verebilmek için bilmesi gerekenler ayrı bilgi kalemleridir: sürecin kendisi yanıt
veriyor mu, bağımlılıkları elinde mi ve hâlâ açılmakta mı. Üç soru, üç denetim. Bu dersin ölçüsü,
soruları birleştirmenin ne kadara mal olduğudur.

Hazır olma denetimi terimi daha önce tek makinedeki bileşim bağlamında kullanıldı; burada aynı
kavram küme ölçeğinde, havuz üyeliğini belirleyen denetim olarak geçiyor.

- **OI7.** Küme, kurgusal bölgesel ölçüm ağının doğrulayıcı servisini sekiz kopyayla, sıcak
  başlangıçla çalıştırır; tur başına elli istek gelir. Ağ da rakamlar da kurgudur.
- **OI8.** Altı kopya altı turda, iki kopya yirmi beş turda hizmet verebilir hâle gelir. İkisi
  açılışta önbellek ısıtan kopyalardır; bu fark uygulamadan gelir, kümeden değil.
- **OI9.** Olaylar elle yazıldı, rastgelelik yok. Geçici bağımlılık kaybı süresi dolunca
  kendiliğinden düzelir; kalıcı takılma yalnız yeniden başlatmayla çözülür.
- **OI10.** Denetim yanıtı kesindir: kopya ya yanıt verir ya vermez. Ağ kaynaklı yanlış negatif,
  denetim ucunun kendi gecikmesi ve zaman aşımı ayarı modellenmiyor.
- **OI11.** Yeniden başlatma anında olur. Kapsülün yeniden çizelgelenmesi, görüntü çekme ve düğüm
  seçimi bu ölçümün dışındadır; hepsi gecikmeyi büyütür, yönünü değiştirmez.
- **OI12.** "Gerçekten hizmette" sütunu, tur başına sağlıklı kopya sayısının ortalamasıdır. Hedef
  sekizdir ve bu sayı denetimlere değil, kopyaların gerçek durumuna bakar.

#### Ölçüm Düzeneği

Ölçülen şey gerçek bir küme değil, `node` ile kurulan bir modeldir. Bir kopya her turda dört
durumdan birindedir: açılıyor, takıldı, bağımlılığı yok, sağlıklı. Denetimler bu durumu doğrudan
görmez; yalnız kendi kapsamlarına giren bir soruya evet ya da hayır alırlar.

```js
// saglik.mjs — canlilik, hazir olma ve baslangic denetimlerinin tur tabanli modeli
export const TUR = 180, TUR_ISTEK = 50, ACILIS = [6, 6, 6, 6, 6, 6, 25, 25];
export const PLANLI = [{ kopya: 6, tur: 20 }, { kopya: 7, tur: 20 }];  // iki kopya yeni surume gecer
export const ARIZA = [                                   // olaylar elle yazildi, rastgelelik yok
  { kopya: 3, tur: 50, tip: 'bagimlilikYok', sure: 18 }, // gecici: kendiliginden duzelir
  { kopya: 1, tur: 80, tip: 'takildi' },                 // kalici: ancak yeniden baslatma cozer
  { kopya: 4, tur: 120, tip: 'bagimlilikYok', sure: 10 },
  { kopya: 5, tur: 140, tip: 'takildi' } ];

export function kostur({ ad, canlilik, hazirOlma, baslangic }) {
  const k = ACILIS.map(() => ({ hazirTur: 0, takildi: false, cS: 0, hS: 0, bS: 0,
    basBitti: true, havuzda: true, yeniden: 0 }));
  const s = { ad, yeniden: 0, gereksiz: 0, acilista: 0, erken: 0, hatali: 0, havuzTur: 0, gec: [] };
  const takilmaTur = {};
  const durum = (i, t) => t < k[i].hazirTur ? 'aciliyor' : k[i].takildi ? 'takildi'
    : ARIZA.some((a) => a.kopya === i && a.sure && t >= a.tur && t < a.tur + a.sure)
      ? 'bagimlilikYok' : 'saglikli';
  const ac = (i, t) => Object.assign(k[i], { hazirTur: t + ACILIS[i], takildi: false,
    cS: 0, hS: 0, bS: 0, basBitti: !baslangic, havuzda: !hazirOlma });
  for (let t = 0; t < TUR; t += 1) {
    for (const p of PLANLI) if (p.tur === t) ac(p.kopya, t);          // planli acilis, sayaca girmez
    for (const a of ARIZA) if (a.tur === t && a.tip === 'takildi') { k[a.kopya].takildi = true; takilmaTur[a.kopya] = t; }
    for (let i = 0; i < k.length; i += 1) {
      const d = durum(i, t);
      if (!k[i].basBitti) {                              // baslangic denetimi bitmeden otekiler bakmaz
        if (t % baslangic.p) continue;
        if (d !== 'aciliyor') k[i].basBitti = true;
        else if ((k[i].bS += 1) >= baslangic.e) { s.yeniden += 1; s.acilista += 1; s.gereksiz += 1; k[i].yeniden += 1; ac(i, t); }
        continue;
      }
      if (canlilik && t % canlilik.p === 0) {
        const kotu = canlilik.kapsam === 'bagimlilik' ? d !== 'saglikli' : d === 'aciliyor' || d === 'takildi';
        if (!kotu) k[i].cS = 0;
        else if ((k[i].cS += 1) >= canlilik.e) {
          s.yeniden += 1; k[i].yeniden += 1;
          if (d === 'takildi') s.gec.push(t - takilmaTur[i]); else s.gereksiz += 1;
          if (d === 'aciliyor') s.acilista += 1;
          ac(i, t);
        }
      }
      if (hazirOlma && t % hazirOlma.p === 0) {
        if (d === 'saglikli') { k[i].hS = 0; k[i].havuzda = true; }
        else if ((k[i].hS += 1) >= hazirOlma.e) k[i].havuzda = false;
      }
    }
    const havuz = k.map((_, i) => i).filter((i) => k[i].havuzda);        // denetimin inandigi havuz
    s.havuzTur += k.filter((_, i) => durum(i, t) === 'saglikli').length; // gercekten hizmet verebilen
    for (let r = 0; r < TUR_ISTEK; r += 1) {
      if (!havuz.length) { s.hatali += 1; continue; }
      const d = durum(havuz[r % havuz.length], t);
      if (d === 'saglikli') continue;
      s.hatali += 1;
      if (d === 'aciliyor') s.erken += 1;
    }
  }
  s.dongu = k.filter((c) => c.yeniden >= 3).length;
  return s;
}
```

İki satır bu modelin bütün ayrımını taşıyor. Canlılık denetiminin `kapsam` alanı `surec` ise
denetim yalnız açılıyor ve takıldı durumlarında başarısız olur — bağımlılık kaybını görmez. Aynı
alan `bagimlilik` ise denetim hazır olma denetimiyle **aynı soruyu** sorar; tek bir denetim ucu
hem yeniden başlatmayı hem havuz üyeliğini sürdürür. İkinci satır `havuz` ile `havuzTur`
arasındaki farktır: birincisi denetimin inandığı havuz, ikincisi gerçekten hizmet verebilen kopya
sayısı. İkisinin ayrılabildiği her yerde bir yanlış karar vardır.

#### Dört Ayar, Tek Olay Dizisi

```js
// kosum3.mjs — dort ayar ayni olay dizisinde kosturulur
import { kostur, TUR, TUR_ISTEK } from './saglik.mjs';

const AYAR = [
  { ad: 'denetim yok', canlilik: null, hazirOlma: null, baslangic: null },
  { ad: 'tek birlesik denetim', canlilik: { p: 5, e: 3, kapsam: 'bagimlilik' },
    hazirOlma: { p: 5, e: 3 }, baslangic: null },
  { ad: 'canlilik + hazir olma', canlilik: { p: 5, e: 3, kapsam: 'surec' },
    hazirOlma: { p: 2, e: 1 }, baslangic: null },
  { ad: 'ustune baslangic', canlilik: { p: 5, e: 3, kapsam: 'surec' },
    hazirOlma: { p: 2, e: 1 }, baslangic: { p: 5, e: 6 } },
];
console.log(`8 kopya, ${TUR} tur, tur basina ${TUR_ISTEK} istek; iki kopya 25 turda aciliyor`);
console.log('tur 20: iki yavas kopya planli olarak yeniden acilir | tur 80 ve 140: kalici takilma');
console.log('tur 50 ve 120: gecici bagimlilik kaybi, 18 ve 10 tur surer, kendiliginden duzelir\n');
console.log('ayar                  yeniden  gereksiz  acilista  donguye  erken   toplam  gercekten  takilmayi');
console.log('                      baslatma yeniden   oldurulen giren    hatali  hatali  hizmette   fark etme');
for (const a of AYAR) {
  const s = kostur(a);
  console.log(`${s.ad.padEnd(21)} ${String(s.yeniden).padEnd(8)} ${String(s.gereksiz).padEnd(9)} ` +
    `${String(s.acilista).padEnd(9)} ${String(s.dongu).padEnd(8)} ${String(s.erken).padEnd(7)} ` +
    `${String(s.hatali).padEnd(7)} ${(s.havuzTur / TUR).toFixed(2).padEnd(10)} ${s.gec.join(', ') || '-'}`);
}
```

```
8 kopya, 180 tur, tur basina 50 istek; iki kopya 25 turda aciliyor
tur 20: iki yavas kopya planli olarak yeniden acilir | tur 80 ve 140: kalici takilma
tur 50 ve 120: gecici bagimlilik kaybi, 18 ve 10 tur surer, kendiliginden duzelir

ayar                  yeniden  gereksiz  acilista  donguye  erken   toplam  gercekten  takilmayi
                      baslatma yeniden   oldurulen giren    hatali  hatali  hizmette   fark etme
denetim yok           0        0         0         0        300     1408    6.79       -
tek birlesik denetim  23       21        20        2        0       330     5.89       10, 10
canlilik + hazir olma 22       20        20        2        0       0       5.89       10, 10
ustune baslangic      2        0         0         0        0       0       7.39       10, 10
```

Denetimsiz satır tabanı veriyor: hiçbir kopya yeniden başlatılmadı, iki kalıcı takılma yüz ve kırk
tur boyunca fark edilmeden sürdü, bin dört yüz sekiz istek hata aldı. Bunun üç yüzü açılmakta olan
kopyalara gitti — yani hazır olma denetiminin olmamasının tek başına bedeli üç yüz istektir. Geri
kalan bin yüz sekiz, takılan ve bağımlılığını yitiren kopyalara giden isteklerdir.

Tek birleşik denetim hatalı isteği bin dört yüzden üç yüz otuza indirdi ve takılmayı on turda fark
etti. Bedeli ikinci ve üçüncü sütunda: yirmi üç yeniden başlatmanın yirmi biri gereksizdi. Bu
denetim bağımlılık kaybını da arıza sayıyor, dolayısıyla dışarıdaki bir kesinti sağlıklı bir süreci
öldürüyor. Kalıcı takılmayla geçici bağımlılık kaybını ayırt edememenin fiyatı budur: kendiliğinden
düzelecek bir durum, yeniden başlatmayla düzeltiliyor.

Üçüncü satır canlılık denetiminin kapsamını süreçle sınırlıyor ve hazır olma denetimini ayırıyor.
Hatalı istek sıfıra indi — havuz artık bağımlılığını yitirmiş kopyayı iki turda dışarı alıyor, ama
onu öldürmüyor. Gereksiz yeniden başlatma yine de yirmi. Kaynağı geçici arıza değil: yirmisi de
**açılışta öldürme**. Canlılık denetimi beş turda bir bakıyor, üç ardışık başarısızlıkta
öldürüyor; on beş turluk bu pay, yirmi beş turda açılan iki kopya için yetmiyor. O iki kopya her
seferinde açılışın ortasında öldürülüp baştan başlıyor — iki kopya yeniden başlatma döngüsünde.

Bu satırın asıl ölçüsü sondan ikinci sütundur. Hatalı istek sıfır, ama gerçekten hizmet veren kopya
sayısı 5,89 — sekiz hedeflenen kümede **iki kopyadan fazlası kalıcı olarak yok**. Hazır olma
denetimi döngüdeki kopyaları havuzun dışında tuttuğu için bu kayıp tek bir hata kaydı üretmiyor.
Kümenin hata oranına bakan biri her şeyin yolunda olduğunu görür; kayıp yalnız kapasitede durur ve
yük arttığında kalan altı kopyanın üstüne biner.

Dördüncü satır başlangıç denetimini ekliyor: yeniden başlatma yirmi ikiden ikiye, yani **yalnız iki
gerçek takılmaya** iniyor, gereksiz yeniden başlatma sıfırlanıyor, hizmetteki kopya 7,39'a çıkıyor.
Takılmayı fark etme süresi değişmedi. Başlangıç denetiminin yaptığı şey yeni bir arıza yakalamak
değil, **canlılık denetimini açılış penceresi boyunca susturmaktır**.

#### Eşik ve Periyot

Üçüncü satırın açılışta öldürmesi canlılık denetiminin ayarını gevşeterek de giderilebilir.
Tarama bunun neye mal olduğunu gösteriyor.

```js
// kosum4.mjs — canlilik denetiminin periyodu ve esigi taranir, once baslangic denetimi olmadan
import { kostur, TUR } from './saglik.mjs';

const HAZIR = { p: 2, e: 1 };
const yaz = (etiket, baslangic) => {
  console.log(`\n${etiket}`);
  console.log('periyot  esik  hosgoru  takilmayi   acilista   donguye  gercekten');
  console.log('               (tur)    fark etme   oldurulen  giren    hizmette');
  for (const p of [2, 5, 10]) for (const e of [2, 3, 6]) {
    const s = kostur({ ad: '', canlilik: { p, e, kapsam: 'surec' }, hazirOlma: HAZIR, baslangic });
    console.log(`${String(p).padEnd(8)} ${String(e).padEnd(5)} ${String(p * e).padEnd(8)} ` +
      `${(s.gec.join(', ') || '-').padEnd(11)} ${String(s.acilista).padEnd(10)} ` +
      `${String(s.dongu).padEnd(8)} ${(s.havuzTur / TUR).toFixed(2)}`);
  }
};
console.log('yavas acilan iki kopya 25 turda hazir oluyor; kalici takilma tur 80 ve 140');
yaz('baslangic denetimi yok:', null);
yaz('baslangic denetimi var (periyot 5, esik 6 — 30 turluk acilis payi):', { p: 5, e: 6 });
```

```
yavas acilan iki kopya 25 turda hazir oluyor; kalici takilma tur 80 ve 140

baslangic denetimi yok:
periyot  esik  hosgoru  takilmayi   acilista   donguye  gercekten
               (tur)    fark etme   oldurulen  giren    hizmette
2        2     4        2, 2        113        4        5.29
2        3     6        4, 4        52         2        5.96
2        6     12       10, 10      26         2        5.89
5        2     10       5, 5        32         2        5.94
5        3     15       10, 10      20         2        5.89
5        6     30       25, 25      0          0        7.22
10       2     20       10, 10      16         2        5.89
10       3     30       20, 20      2          0        7.06
10       6     60       50          0          0        7.03

baslangic denetimi var (periyot 5, esik 6 — 30 turluk acilis payi):
periyot  esik  hosgoru  takilmayi   acilista   donguye  gercekten
               (tur)    fark etme   oldurulen  giren    hizmette
2        2     4        2, 2        0          0        7.48
2        3     6        4, 4        0          0        7.46
2        6     12       10, 10      0          0        7.39
5        2     10       5, 5        0          0        7.44
5        3     15       10, 10      0          0        7.39
5        6     30       25, 25      0          0        7.22
10       2     20       10, 10      0          0        7.39
10       3     30       20, 20      0          0        7.28
10       6     60       50          0          0        7.03
```

Üst tabloda tek bir ayar iki işi birden yapıyor ve iki iş ters yöne çekiyor. Hoşgörü penceresi
kısaldıkça takılma çabuk fark ediliyor — dört turluk pencerede iki turda — ama açılışta öldürme
yüz on üçe fırlıyor ve dört kopya döngüye giriyor; hizmetteki kopya 5,29'a düşüyor. Pencere
uzadıkça öldürme azalıyor, fark etme gecikmesi büyüyor. Açılışta hiç öldürmeyen iki satır var ve
hoşgörüleri otuz ile altmış tur: takılmayı yirmi beş ve elli turda fark ediyorlar. Son satırda
takılma sütununda tek bir sayı var — altmış turluk pencere, yüz kırkıncı turdaki ikinci takılmayı
ölçüm ufkunun sonuna kadar hiç fark etmedi.

Alt tablo aynı taramayı otuz turluk açılış payı veren bir başlangıç denetimiyle yineliyor. Açılışta
öldürme sütunu **her satırda sıfır**, döngü sütunu her satırda sıfır. Gerilim ortadan kalktı,
çünkü iki iş iki ayara bölündü: açılış penceresini başlangıç denetimi karşılıyor, canlılık denetimi
yalnız açılışı bitmiş kopyalara bakıyor. Artık periyot ve eşik tek bir ölçüte göre seçilebilir —
takılmayı fark etme gecikmesi. En hızlı satır dört turluk pencere: iki turda fark ediyor ve
hizmetteki kopya 7,48 ile taramanın en yükseği.

Üç denetimin ayrımı bu iki tablonun farkıdır. Aynı canlılık ayarı, üstte 113 gereksiz öldürme
üretirken altta sıfır üretiyor. Değişen tek şey, sistemin **açılmakta olmakla arızalı olmayı**
ayırt edebilmesi. Bu ayrım bir bilgi kalemidir ve bedeli bir denetim daha koşturmaktır; karşılığı,
canlılık ayarının uygulamanın açılış süresinden bağımsız hâle gelmesidir.

#### Özet

- Denetimsiz kümede iki kalıcı takılma hiç fark edilmedi ve 1408 istek hata aldı; bunun 300'ü
  açılmakta olan kopyalara giden isteklerdir, yani hazır olma denetiminin yokluğunun payıdır.
- Tek birleşik denetim hatalı isteği 330'a indirdi ama 23 yeniden başlatmanın 21'i gereksizdi:
  bağımlılık kaybını takılmadan ayırt edemeyen denetim, kendiliğinden düzelecek durumu
  yeniden başlatmayla düzeltir.
- Canlılık denetimini süreçle sınırlayıp hazır olma denetimini ayırmak hatalı isteği sıfıra
  indirdi, ama yavaş açılan iki kopya açılışın ortasında öldürülmeye devam etti ve döngüye girdi.
- Yeniden başlatma döngüsü hata oranında görünmez: hatalı istek sıfırken gerçekten hizmet veren
  kopya sayısı 8 hedefine karşı 5,89'du; kayıp kapasitede durur, hata kaydında değil.
- Tek ayarla iki iş yapıldığında hoşgörü penceresi kısaldıkça fark etme hızlanır ve açılışta
  öldürme 113'e çıkar; uzadıkça öldürme biter ama 60 turluk pencere ikinci takılmayı hiç görmez.
- Başlangıç denetimi eklendiğinde taramanın dokuz satırında da açılışta öldürme sıfırlanır;
  canlılık ayarı artık yalnız fark etme gecikmesine göre seçilir ve 4 turluk pencere hem en hızlı
  hem en yüksek kapasiteli satırdır.

#### Sonraki Adım

Bu iki dersin denetleyicileri kümede kısıtsız iş görüyor: sürüm nesnesini değiştiriyor, kopya
öldürüyor, havuz üyeliğini yazıyor. Aynı arayüzü insanlar ve otomatik süreçler de kullanıyor ve
şimdiye kadar hiçbiri "bunu yapmaya yetkin var mı" sorusuyla karşılaşmadı. Sonraki ders bu soruyu
sayıya çeviriyor: bir özne × fiil × nesne yetki matrisi kurulur, geniş yetkiden en az yetkiye
inince kaç işlemin düştüğü ve bunun kaç satır rol tanımına mal olduğu ölçülür — ve bir özneye
verilen yetkinin başka bir özneye yetki verebildiği yollar sayılır.

### Rol Tabanlı Erişim Denetimi

Source: https://academia.sh/tr/kurslar/orkestrasyon/rol-tabanli-erisim-denetimi

Bir özne × fiil × nesne × ad alanı yetki matrisi kurulur ve geniş yetkiden en az yetkiye inince kaç işlemin düştüğü sayılır: izinli işlem, rol tanımının satır maliyeti ve bir öznenin başka bir öznenin yetkisine ulaşabildiği yükseltme yolları ölçülür.

Önceki iki dersin denetleyicileri kümede kısıtsız iş gördü. Dağıtım denetleyicisi sürüm nesnesini
değiştirdi, kapsül sildi, havuz üyeliğini yazdı; sağlık denetimleri süreç öldürdü. Aynı arayüzü
insanlar ve öteki otomatik süreçler de kullanıyor ve şimdiye kadar hiçbiri "bunu yapmaya yetkin
var mı" sorusuyla karşılaşmadı. Kimlik ve en az yetki daha önce ölçüldü; buranın farkı, yetkinin
**küme nesneleri üzerinde** tanımlanması ve her nesnenin başka nesnelere ulaşma imkânı taşımasıdır.

Devredilen karar şudur: bir isteğin yürütülüp yürütülmeyeceğine, isteği yapanın kim olduğuna
bakarak küme arayüzü karar verir. Bunun için bilmesi gereken üç kalem vardır — kim, ne yapmak
istiyor, neyin üstünde — ve bu üçüne bir dördüncüsü eklenir: hangi ad alanında. Kalemlerin
çarpımı, sistemin doldurması gereken tablodur. Bu dersin ölçüsü o tablonun boyu, doldurmanın
maliyeti ve **boş bırakmanın** bedelidir.

- **OI13.** Model kurgusal bölgesel ölçüm ağının sekiz öznesini, yedi fiili, sekiz nesne türünü ve
  üç ad alanını taşır. Gerçek bir küme koşturulmuyor; ölçülen şey `node` ile kurulan modeldir.
- **OI14.** İşlem izi otuz günlük bir kayıttan çıkarılmış sayılır ve elle yazılmıştır. İzde
  görünmeyen işlem "gerekmiyor" kabul edilir. Seyrek koşan bakım işleri böyle bir izde görünmez;
  en az yetki onları da düşürür ve ilk koşumlarında engellenirler.
- **OI15.** Buradaki ad alanı **kümenin** ad alanıdır: nesnelerin gruplandığı ve yetkinin
  sınırlandığı bölme. Tek makinedeki yalıtımın görünürlük eşlemesi anlamındaki ad alanıyla aynı
  sözcüktür, farklı nesnedir.
- **OI16.** Yetki yükseltme iki kurala indirgendi: rol tanımı yazabilen özne o ad alanındaki her
  yetkiyi kendine verebilir; sır nesnesini okuyabilen özne o ad alanındaki bir öznenin kimliğini
  ele geçirebilir. Gerçekte daha çok yol vardır, bu yüzden sayılan değer bir alt sınırdır.
- **OI17.** Rol tanımı satırı kendi küçük şemamızla sayılır; şema ders içinde tanımlıdır. Satır
  sayısı biçim seçimine bağlıdır, büyüklük sırası değil.
- **OI18.** Aynı yetki kümesine sahip özneler tek role indirilir. Rol adları üretilmiştir; okunur
  adlar satır sayısını değiştirmez.

#### Yetki Matrisi

```js
// yetki.mjs — ozne x fiil x nesne x ad alani yetki matrisi; gercek kume degil, bir modeldir
export const OZNE = ['okuma-toplayici', 'dogrulayici', 'faturalama', 'is-emri',
  'gecelik-toplu-is', 'yayin-denetleyicisi', 'nobetci', 'pano-okuyucu'];
export const FIIL = ['oku', 'listele', 'izle', 'olustur', 'guncelle', 'sil', 'yetkilendir'];
export const NESNE = ['kapsul', 'surum-nesnesi', 'servis-nesnesi', 'yapilandirma-nesnesi',
  'sir-nesnesi', 'kota', 'rol-tanimi', 'dugum'];
export const ALAN = ['gelistirme', 'hazirlik', 'uretim'];
const U = ['uretim'], H = ['hazirlik', 'uretim'], T = ALAN;

// Otuz gunluk kayittan cikarilan islem izi; elle yazildi, rastgelelik yok.
export const IZ = [
  ['okuma-toplayici', 'oku', 'yapilandirma-nesnesi', U], ['okuma-toplayici', 'listele', 'kapsul', U],
  ['dogrulayici', 'oku', 'yapilandirma-nesnesi', H], ['dogrulayici', 'oku', 'sir-nesnesi', H],
  ['dogrulayici', 'listele', 'servis-nesnesi', H],
  ['faturalama', 'oku', 'yapilandirma-nesnesi', U], ['faturalama', 'oku', 'sir-nesnesi', U],
  ['is-emri', 'oku', 'yapilandirma-nesnesi', U], ['is-emri', 'listele', 'servis-nesnesi', U],
  ['gecelik-toplu-is', 'oku', 'sir-nesnesi', U], ['gecelik-toplu-is', 'olustur', 'kapsul', U],
  ['gecelik-toplu-is', 'listele', 'kapsul', U],
  ['yayin-denetleyicisi', 'guncelle', 'surum-nesnesi', T], ['yayin-denetleyicisi', 'listele', 'kapsul', T],
  ['yayin-denetleyicisi', 'sil', 'kapsul', T], ['yayin-denetleyicisi', 'izle', 'kapsul', T],
  ['nobetci', 'oku', 'kapsul', T], ['nobetci', 'listele', 'kapsul', T],
  ['nobetci', 'izle', 'kapsul', T], ['nobetci', 'oku', 'sir-nesnesi', U],
  ['pano-okuyucu', 'listele', 'kapsul', T], ['pano-okuyucu', 'listele', 'servis-nesnesi', T],
];

export const anahtar = (o, f, n, a) => `${o}|${f}|${n}|${a}`;
export function enAz() {
  const s = new Set();
  for (const [o, f, n, alanlar] of IZ) for (const a of alanlar) s.add(anahtar(o, f, n, a));
  return s;
}
export function genis() {                              // her ozneye her fiil, her nesne, her alan
  const s = new Set();
  for (const o of OZNE) for (const f of FIIL) for (const n of NESNE) for (const a of ALAN) s.add(anahtar(o, f, n, a));
  return s;
}
// Yukseltme: rol tanimi yazabilen o alandaki her yetkiyi kendine verebilir; sir nesnesini
// okuyabilen o alandaki bir oznenin kimligini ele gecirebilir.
export function yukseltme(izin) {
  const var_ = (o, f, n, a) => izin.has(anahtar(o, f, n, a));
  const alanOzne = (a) => OZNE.filter((o) => [...izin].some((k) => k.startsWith(`${o}|`) && k.endsWith(`|${a}`)));
  const kenar = new Set();
  for (const o of OZNE) for (const a of ALAN) {
    const rolYazar = ['olustur', 'guncelle', 'yetkilendir'].some((f) => var_(o, f, 'rol-tanimi', a));
    const sirOkur = var_(o, 'oku', 'sir-nesnesi', a);
    if (!rolYazar && !sirOkur) continue;
    for (const t of alanOzne(a)) if (t !== o) kenar.add(`${o}->${t}`);
  }
  let n = kenar.size, once;                            // gecisli kapanis
  do {
    once = n;
    for (const k1 of [...kenar]) for (const k2 of [...kenar]) {
      const [a1, b1] = k1.split('->'), [a2, b2] = k2.split('->');
      if (b1 === a2 && a1 !== b2) kenar.add(`${a1}->${b2}`);
    }
    n = kenar.size;
  } while (n !== once);
  return kenar;
}
```

İzin listesi ile matris arasındaki fark şudur: matris bütün hücreleri taşır, iz yalnız dolu
olanları. `genis` işlevi bütün hücreleri doldurur — hiçbir soru sormadan her özneye her şeyi
verir. `enAz` yalnız izde görüneni doldurur. İkisi arasındaki bütün fark, otuz günlük kayda
bakmanın maliyetidir.

#### Geniş Yetkiden En Az Yetkiye

```js
// kosum5.mjs — genis yetki ile en az yetki karsilastirilir
import { OZNE, FIIL, NESNE, ALAN, IZ, enAz, genis } from './yetki.mjs';

const g = genis(), e = enAz();
console.log(`ozne ${OZNE.length} x fiil ${FIIL.length} x nesne ${NESNE.length} x ad alani ${ALAN.length}` +
  ` = ${OZNE.length * FIIL.length * NESNE.length * ALAN.length} olasi islem`);
console.log(`gozlenen iz: ${IZ.length} satir, ad alanlarina acilinca ${e.size} ayri islem\n`);
console.log('olcut                         genis yetki  en az yetki  fark');
const satir = (ad, x, y) => console.log(`${ad.padEnd(29)} ${String(x).padEnd(12)} ${String(y).padEnd(12)} ${x - y}`);
satir('izinli islem', g.size, e.size);
satir('yetkili ozne', OZNE.length, new Set([...e].map((k) => k.split('|')[0])).size);
const ff = (s) => new Set([...s].map((k) => k.split('|').slice(0, 2).join('|'))).size;
satir('ozne-fiil cifti', ff(g), ff(e));
const nn = (s) => new Set([...s].map((k) => k.split('|')[2])).size;
satir('dokunulan nesne turu', nn(g), nn(e));
const sir = (s) => [...s].filter((k) => k.split('|')[1] === 'oku' && k.split('|')[2] === 'sir-nesnesi').length;
satir('sir nesnesi okuma izni', sir(g), sir(e));
const rol = (s) => [...s].filter((k) => k.split('|')[2] === 'rol-tanimi').length;
satir('rol tanimina dokunan izin', rol(g), rol(e));
```

```
ozne 8 x fiil 7 x nesne 8 x ad alani 3 = 1344 olasi islem
gozlenen iz: 22 satir, ad alanlarina acilinca 43 ayri islem

olcut                         genis yetki  en az yetki  fark
izinli islem                  1344         43           1301
yetkili ozne                  8            8            0
ozne-fiil cifti               56           18           38
dokunulan nesne turu          8            5            3
sir nesnesi okuma izni        24           5            19
rol tanimina dokunan izin     168          0            168
```

Bin üç yüz bir işlem düştü — matrisin yüzde doksan yedisi. Geriye kalan kırk üç işlem, sekiz
öznenin otuz gün boyunca gerçekten yaptığı her şeydir. İkinci satır bu düşüşün **hangi eksende
olmadığını** gösteriyor: yetkili özne sayısı sekizden sekize, yani hiç değişmedi. En az yetki
kimseyi kümeden çıkarmıyor; herkesin **ne yapabildiğini** daraltıyor.

Daralma nesne ekseninde en sert. Sekiz nesne türünden beşine dokunuluyor; üç tür — kota, rol
tanımı ve düğüm — otuz gün boyunca hiçbir özne tarafından kullanılmadı. Bunların iki tanesi
kümenin kendi işletimine ait nesnelerdir ve iş yükü öznelerinin bunlara erişmesi için bir neden
yoktur. Son satır bunun sayısını veriyor: geniş yetkide rol tanımına dokunan yüz altmış sekiz izin
vardı, en az yetkide sıfır. Yüz altmış sekiz iznin tamamı, hiç kullanılmadığı hâlde açık duran ve
her biri kendisini genişletmeye yarayan izinlerdi.

Sır nesnesi satırı ise düşüşün durduğu yeri gösteriyor: yirmi dörtten sıfıra değil, **beşe**
indi. Dört özne sırlara gerçekten erişiyor — doğrulayıcı iki ad alanında, faturalama, gecelik
toplu iş ve nöbetçi üretimde. Bu beş izin izde vardır, dolayısıyla en az yetki onları düşüremez.

#### Yazma Bedeli ve Yükseltme Yolları

En az yetkinin ikinci bedeli ilk tabloda görünmüyor: matrisin doldurulmayan hücreleri bedava,
doldurulanların her biri yazılmak zorunda. Bunu saymak için yetki kümesi kendi şemamızla metne
dökülür.

```js
// kosum6.mjs — iki modelin rol tanimi kendi semamizla yazilir ve satiri sayilir
import { OZNE, enAz, genis, yukseltme } from './yetki.mjs';

// Sema: "rol <ad>" / "  <nesne>: <fiil>,<fiil>" / "bag <rol> -> <ozne> @ <alan>"
function yaz(izin) {
  const kume = new Map();                              // (ozne, alan) -> nesne:fiiller
  for (const k of izin) {
    const [o, f, n, a] = k.split('|');
    const m = kume.get(`${o}|${a}`) ?? new Map();
    m.set(n, (m.get(n) ?? new Set()).add(f));
    kume.set(`${o}|${a}`, m);
  }
  const rol = new Map(), bag = [];                     // ayni yetki kumesi tek role indirilir
  for (const [oa, m] of kume) {
    const govde = [...m].sort().map(([n, fs]) => `  ${n}: ${[...fs].sort().join(',')}`).join('\n');
    if (!rol.has(govde)) rol.set(govde, `rol-${rol.size + 1}`);
    const [o, a] = oa.split('|');
    bag.push(`bag ${rol.get(govde)} -> ${o} @ ${a}`);
  }
  const metin = [...rol].map(([g, ad]) => `rol ${ad}\n${g}`).concat(bag).join('\n');
  return { metin, rol: rol.size, bag: bag.length, satir: metin.split('\n').length };
}
const g = yaz(genis()), e = yaz(enAz());
console.log('model        rol  bag  toplam satir  izinli islem  islem/satir');
for (const [ad, y, izin] of [['genis yetki', g, genis()], ['en az yetki', e, enAz()]]) {
  console.log(`${ad.padEnd(12)} ${String(y.rol).padEnd(4)} ${String(y.bag).padEnd(4)} ` +
    `${String(y.satir).padEnd(13)} ${String(izin.size).padEnd(13)} ${(izin.size / y.satir).toFixed(1)}`);
}
console.log('\nen az yetki tanimindan iki rol ve iki bag:');
console.log(e.metin.split('\n').slice(0, 6).join('\n'));
console.log(e.metin.split('\n').filter((l) => l.startsWith('bag')).slice(0, 2).join('\n'));

// Sir nesnesi okuma izni kaldirilirsa yukseltme yollari ne oluyor
const kis = new Set([...enAz()].filter((k) => !(k.split('|')[1] === 'oku' && k.split('|')[2] === 'sir-nesnesi')));
console.log('\nyukseltme yolu sayisi ve her ozneye ulasan ozne:');
for (const [ad, s] of [['genis yetki', genis()], ['en az yetki', enAz()], ['sir okuma kaldirildi', kis]]) {
  const k = yukseltme(s);
  const tam = OZNE.filter((o) => [...k].filter((x) => x.startsWith(`${o}->`)).length === OZNE.length - 1).length;
  console.log(`  ${ad.padEnd(22)} yol ${String(k.size).padEnd(4)} tam yetkiye ulasan ${tam}  izinli islem ${s.size}`);
}
```

```
model        rol  bag  toplam satir  izinli islem  islem/satir
genis yetki  1    24   33            1344          40.7
en az yetki  9    15   42            43            1.0

en az yetki tanimindan iki rol ve iki bag:
rol rol-1
  kapsul: listele
  yapilandirma-nesnesi: oku
rol rol-2
  servis-nesnesi: listele
  sir-nesnesi: oku
bag rol-1 -> okuma-toplayici @ uretim
bag rol-2 -> dogrulayici @ hazirlik

yukseltme yolu sayisi ve her ozneye ulasan ozne:
  genis yetki            yol 56   tam yetkiye ulasan 8  izinli islem 1344
  en az yetki            yol 28   tam yetkiye ulasan 4  izinli islem 43
  sir okuma kaldirildi   yol 0    tam yetkiye ulasan 0  izinli islem 38
```

Yazma bedeli otuz üç satırdan kırk iki satıra çıktı — yüzde yirmi yedi artış, dokuz satır. Bu,
bin üç yüz bir işlemi düşürmenin bütün maliyetidir. Son sütun ikisinin arasındaki ilişkiyi tek
sayıya indiriyor: geniş yetkide yazılan her satır kırk işlem açıyor, en az yetkide tam olarak
bir. Geniş yetkinin ucuzluğu **yazmadığı** satırlardan gelir; en az yetkide izin verilen her işlem
ayrı ayrı yazılmak zorundadır, çünkü genelleme yapan hiçbir kural yoktur. Kırk iki satırın
bakımı da buradan doğar: iz değiştiğinde tanım değişmek zorundadır.

Alt tablo bu dersin asıl sonucudur. Geniş yetkide elli altı yükseltme yolu var ve sekiz öznenin
sekizi de her özneye ulaşıyor — beklenen sonuç. En az yetkide izinli işlem kırk üçe indi ama
yükseltme yolu yalnız yarıya, yirmi sekize düştü ve **dört özne hâlâ her özneye ulaşıyor**. İzinli
işlemin yüzde doksan yedisini düşürmek, yükseltme yolunun yalnız yüzde ellisini düşürdü. İki sayı
aynı şeyi ölçmüyor.

Üçüncü satır nedeni veriyor. Sır nesnesi okuma izni kaldırıldığında izinli işlem kırk üçten
otuz sekize iniyor — beş işlem — ve yükseltme yolu yirmi sekizden **sıfıra** düşüyor. Yirmi sekiz
yolun tamamını beş izin taşıyordu. Kalan otuz sekiz iznin hiçbiri bir özneyi başka bir öznenin
yerine geçirmiyor.

Bu beş izin gereksiz değildi; izde vardılar, yani o süreçler sırlara gerçekten erişiyordu. Sayının
söylediği şey iznin kaldırılması değil, **sırrın kümeden okunmak yerine sürece başka bir yolla
ulaştırılması** gerektiğidir. Karar burada bir ölçüye bağlanabilir hâle geliyor: bir izni
kaldırmanın işlem maliyeti beş, yükseltme kazancı yirmi sekiz. Aynı hesap kota, rol tanımı ve
düğüm için yapılsaydı kazanç sıfır çıkardı, çünkü o izinler zaten kapalıydı.

#### Sistemin Bilmediği

Küme arayüzü bir isteği değerlendirirken tek bir soruya cevap arar: bu dörtlü tabloda var mı.
Niyeti, bağlamı, zamanı ve sırayı bilmez. Nöbetçinin üretimde sır nesnesi okuması, bir arıza
sırasında da olağan bir salı sabahı da aynı hücreye düşer; tablo ikisini ayırt edemez çünkü
ayırt edecek kalemi taşımıyor. Aynı nedenle "bu izni son ne zaman kullandı" sorusu da tablodan
cevaplanamaz — kırk üç iznin hangilerinin hâlâ canlı olduğu, ancak izin yeniden toplanmasıyla
bilinir. Bu, devredilen kararın sürekli beslenmesi gereken bir bilgi kalemi olduğu anlamına gelir:
tablo bir kez doğru kurulduğunda doğru kalmaz, iz değiştikçe eskir.

Eskimenin iki yönü var ve bedelleri simetrik değil. İz genişlediğinde — yeni bir servis, yeni bir
bakım işi — tablo dar kalır ve sistem **meşru bir işlemi reddeder**; bu hemen görünür, çünkü
birileri engellendiğini bildirir. İz daraldığında — bir süreç emekliye ayrılır, bir fiil
kullanılmaz olur — tablo geniş kalır ve sistem **gereksiz bir işlemi kabul etmeye devam eder**;
bu hiç görünmez, çünkü kimse şikâyet etmez. Yüz altmış sekiz rol tanımı izni geniş yetkide tam
olarak böyle duruyordu: kullanılmıyorlardı, kimseyi rahatsız etmiyorlardı ve elli altı yükseltme
yolunun büyük bölümünü taşıyorlardı. Otuz günlük izden türetilen en az yetkinin değeri, bu ikinci
yönü **bir kereliğine** kapatmasıdır; kapalı tutması için iz ölçümünün sürmesi gerekir.

#### Özet

- Sekiz özne, yedi fiil, sekiz nesne türü ve üç ad alanı 1344 hücrelik bir matris kurar; otuz
  günlük iz bunun 43'ünü dolduruyor, en az yetkiye inmek 1301 işlem düşürüyor.
- Düşüş özne ekseninde değil: yetkili özne sayısı sekizden sekize sabit kaldı, daralan şey her
  öznenin ne yapabildiğidir.
- Rol tanımına dokunan 168 izin en az yetkide sıfıra iniyor; hiçbiri otuz gün boyunca
  kullanılmamıştı.
- En az yetkinin yazma bedeli 33 satırdan 42 satıra, yüzde yirmi yedi artıştır; geniş yetkide
  yazılan satır başına 40,7 işlem açılırken en az yetkide tam olarak 1 işlem açılır.
- İzinli işlem sayısı ile yükseltme yolu sayısı aynı şeyi ölçmez: işlemlerin yüzde doksan yedisi
  düştüğünde yollar yalnız yarıya indi ve dört özne hâlâ her özneye ulaşıyordu.
- Kalan 28 yolun tamamını beş sır okuma izni taşıyordu; o beş izin kapandığında yol sayısı sıfıra
  iniyor. İzin kaldırmanın maliyeti ve kazancı ayrı ayrı ölçülebilir.

#### Sonraki Adım

Bu dersin matrisi kimin **küme arayüzü üzerinden** ne yapabileceğini sınırlıyor. İki kapsül
arasındaki trafik bu matristen geçmez: doğrulayıcı, faturalama servisinin ucuna doğrudan bağlanır
ve küme arayüzüne hiç uğramaz. Yetki matrisinde birbirine ulaşamayan iki özne, ağ üzerinde
birbirine serbestçe ulaşabilir. Sonraki ders erişilebilirlik matrisini politika ile kurar ve
varsayılan açık ile varsayılan kapalı arasındaki farkı sayar: kaç yol kapanıyor, kaç meşru yol
yanlışlıkla kapanıyor, politika kaç kural istiyor ve yeni bir servis eklendiğinde kaç kural
güncelleniyor.

### Ağ Politikaları

Source: https://academia.sh/tr/kurslar/orkestrasyon/ag-politikalari

Erişilebilirlik matrisi bu kez politika ile kurulur ve varsayılan açık ile varsayılan kapalı arasındaki fark sayılır: kaç yol kapanıyor, kaç meşru yol yanlışlıkla kapanıyor, politika kaç kural istiyor ve yeni bir servis eklendiğinde kaç kural güncelleniyor.

Önceki dersin matrisi kimin küme arayüzü üzerinden ne yapabileceğini sınırladı. İki kapsül
arasındaki trafik o matristen geçmez: doğrulayıcı, faturalama servisinin ucuna doğrudan bağlanır
ve küme arayüzüne hiç uğramaz. Yetki matrisinde birbirine ulaşamayan iki özne, ağ üzerinde
birbirine serbestçe ulaşabilir. Erişilebilirlik matrisi daha önce, tek makinedeki ağ ayrımı
bağlamında kurulup ölçüldü — hangi kapsül hangi kapsüle ulaşabiliyor. O ölçüm burada
tekrarlanmıyor; buranın sorusu aynı matrisin **politika ile** kurulmasıdır.

Devredilen karar şudur: bir bağlantı isteğinin kabul edilip edilmeyeceğine, kaynağın ve hedefin
kim olduğuna bakarak ağ vekili karar verir. Bunun için bilmesi gereken kalemler şunlardır: hangi
kapsül hangi gruba ait, hangi gruplar arası akış meşru, hangi uç üzerinden. İlk kalem kümede
zaten vardır — kapsül etiketleri. Üçüncüsü de vardır. Eksik olan ikincisidir ve onu kimse ölçmez;
**birinin yazması gerekir**. Bu dersin ölçüsü, yazmanın ve yazmamanın bedelidir.

- **OI19.** On servis grubu ve üç uç türü var; hepsi kurgusal bölgesel ölçüm ağına aittir. Gerçek
  bir küme koşturulmuyor, ölçülen şey `node` ile kurulan modeldir.
- **OI20.** Meşru akış kümesi yirmi ikidir ve dördü otuz günlük izde görünmez. Bu ayrım elle
  yazıldı; gerçekte hangi akışın seyrek olduğu ancak izleme süresi uzatılarak bilinir.
- **OI21.** Uç türü üç değere indirgendi. Gerçekte kapı numarası ve protokol ayrı eksenlerdir;
  matrisi büyütürler, sonucun yönünü değiştirmezler.
- **OI22.** Politika yalnız hedefe göre yazılır, yani gelen trafiği sınırlar. Çıkan trafiği ayrıca
  sınırlayan kurallar bu modelde yok; olsalardı kural sayısı artar, kapanan yol sayısı artmazdı.
- **OI23.** Kural sayısı kendi küçük şemamızla sayılır; şema ders içinde tanımlıdır. Etiket
  ataması kural sayılmaz, ayrı sütunda gösterilir.
- **OI24.** Bir yol ya açıktır ya kapalı. Hız sınırı, karşılıklı kimlik doğrulama ve bağlantı
  başına yetkilendirme modellenmiyor.

#### Politika Modeli

Politika kendi küçük şemamızla yazılıyor: bir kural, hedef etiketini, kaynağın taşıması gereken
etiketi ve ucu belirtir. Kurallar yalnız izin verir; varsayılan kapalı düzende yazılmayan her yol
kapalıdır.

```js
// ag.mjs — kapsul gruplari arasi erisilebilirlik matrisi ve politika; model, gercek kume degil
export const UC = ['api', 'veri', 'olcut'];
export const SERVIS = {                                // servis -> etiketler
  'giris-kurali': ['kenar'], 'okuma-toplayici': ['uygulama'], 'dogrulayici': ['uygulama'],
  'faturalama': ['uygulama'], 'is-emri': ['uygulama'], 'gecelik-toplu-is': ['toplu'],
  'veri-deposu': ['depo'], 'kuyruk': ['depo'], 'olcut-toplayici': ['izleme'], 'pano': ['izleme'],
};
// Gercekten mesru akislar; "seyrek" olanlar otuz gunluk izde gorunmedi.
export const MESRU = [
  ['giris-kurali', 'okuma-toplayici', 'api'], ['giris-kurali', 'faturalama', 'api'],
  ['giris-kurali', 'is-emri', 'api'], ['okuma-toplayici', 'kuyruk', 'veri'],
  ['dogrulayici', 'kuyruk', 'veri'], ['dogrulayici', 'veri-deposu', 'veri'],
  ['okuma-toplayici', 'veri-deposu', 'veri'], ['faturalama', 'veri-deposu', 'veri'],
  ['is-emri', 'veri-deposu', 'veri'], ['gecelik-toplu-is', 'veri-deposu', 'veri'],
  ['gecelik-toplu-is', 'kuyruk', 'veri'], ['olcut-toplayici', 'okuma-toplayici', 'olcut'],
  ['olcut-toplayici', 'dogrulayici', 'olcut'], ['olcut-toplayici', 'faturalama', 'olcut'],
  ['olcut-toplayici', 'is-emri', 'olcut'], ['pano', 'olcut-toplayici', 'api'],
  ['faturalama', 'is-emri', 'api'], ['is-emri', 'kuyruk', 'veri'],
  ['gecelik-toplu-is', 'faturalama', 'api', 'seyrek'], ['olcut-toplayici', 'gecelik-toplu-is', 'olcut', 'seyrek'],
  ['dogrulayici', 'faturalama', 'api', 'seyrek'], ['giris-kurali', 'pano', 'api', 'seyrek'],
];
// Etiket politikasi, kendi semamizla: "hedef <etiket> <- <kaynak etiketi> : <uc>"
export const ETIKET_KURAL = [
  ['depo', 'uygulama', 'veri'], ['depo', 'toplu', 'veri'], ['uygulama', 'kenar', 'api'],
  ['uygulama', 'izleme', 'olcut'], ['izleme', 'izleme', 'api'], ['uygulama', 'uygulama', 'api'],
];
export const yol = (k, h, u) => `${k}->${h}:${u}`;
export const tumYollar = (s = SERVIS) => {
  const a = [];
  for (const k of Object.keys(s)) for (const h of Object.keys(s)) if (k !== h) for (const u of UC) a.push(yol(k, h, u));
  return a;
};
export const varsayilanAcik = (s = SERVIS) => new Set(tumYollar(s));
export const izdenKural = () => MESRU.filter((m) => !m[3]).map((m) => [m[0], m[1], m[2]]);
export const izdenAcik = (kural) => new Set(kural.map(([k, h, u]) => yol(k, h, u)));
export function etiketAcik(kural = ETIKET_KURAL, s = SERVIS) {
  const acik = new Set();
  for (const [hE, kE, u] of kural)
    for (const [h, he] of Object.entries(s)) if (he.includes(hE))
      for (const [k, ke] of Object.entries(s)) if (k !== h && ke.includes(kE)) acik.add(yol(k, h, u));
  return acik;
}
export const say = (acik, mesru = MESRU) => {
  const m = new Set(mesru.map((x) => yol(x[0], x[1], x[2])));
  return { acik: acik.size, gereksizAcik: [...acik].filter((y) => !m.has(y)).length,
    kapananMesru: [...m].filter((y) => !acik.has(y)).length, kapanan: tumYollar().length - acik.size };
};
```

İki politika yazım biçimi var ve ikisi aynı matristen türemiyor. `izdenKural` gözlenen akışın
kendisini kurala çeviriyor: her satır bir kaynak, bir hedef, bir uç. `etiketAcik` ise etiketler
üzerinden yazıyor; bir kural, etiketi taşıyan bütün kaynak–hedef çiftlerini birden açıyor.

#### Varsayılan Açık ve Varsayılan Kapalı

```js
// kosum7.mjs — varsayilan acik ile varsayilan kapali karsilastirilir
import { SERVIS, UC, MESRU, ETIKET_KURAL, tumYollar, varsayilanAcik, izdenKural, izdenAcik, etiketAcik, say } from './ag.mjs';

const iz = izdenKural();
console.log(`${Object.keys(SERVIS).length} servis x ${Object.keys(SERVIS).length - 1} hedef x ${UC.length} uc` +
  ` = ${tumYollar().length} olasi yol`);
console.log(`mesru akis ${MESRU.length}, bunun ${MESRU.filter((m) => m[3]).length} tanesi otuz gunluk izde gorunmuyor\n`);
console.log('politika              kural  acik yol  kapanan yol  gereksiz acik  yanlislikla kapanan');
for (const [ad, kural, acik] of [
  ['varsayilan acik', 0, varsayilanAcik()],
  ['izden turetilen', iz.length, izdenAcik(iz)],
  ['etiket tabanli', ETIKET_KURAL.length, etiketAcik()],
]) {
  const s = say(acik);
  console.log(`${ad.padEnd(21)} ${String(kural).padEnd(6)} ${String(s.acik).padEnd(9)} ` +
    `${String(s.kapanan).padEnd(12)} ${String(s.gereksizAcik).padEnd(14)} ${s.kapananMesru}`);
}
console.log('\netiket politikasinin ilk uc kurali ve actigi yol sayisi:');
for (const k of ETIKET_KURAL.slice(0, 3))
  console.log(`  hedef ${k[0]} <- ${k[1]} : ${k[2]}   ->  ${etiketAcik([k]).size} yol`);
```

```
10 servis x 9 hedef x 3 uc = 270 olasi yol
mesru akis 22, bunun 4 tanesi otuz gunluk izde gorunmuyor

politika              kural  acik yol  kapanan yol  gereksiz acik  yanlislikla kapanan
varsayilan acik       0      270       0            248            0
izden turetilen       18     18        252          0              4
etiket tabanli        6      36        234          17             3

etiket politikasinin ilk uc kurali ve actigi yol sayisi:
  hedef depo <- uygulama : veri   ->  8 yol
  hedef depo <- toplu : veri   ->  2 yol
  hedef uygulama <- kenar : api   ->  4 yol
```

Varsayılan açık satırı sıfır kuralla iki mükemmel sayı üretiyor: hiçbir meşru yol kapanmıyor ve
kapanan yol yok. Üçüncü sayı bedelidir — iki yüz kırk sekiz yol, hiçbir meşru akışa karşılık
gelmediği hâlde açık duruyor. Yüzde olarak matrisin yüzde doksan ikisi. Bu, ağ ayrımı olmayan bir
kümede bir kapsülün ele geçirilmesi hâlinde ulaşabileceği yerlerin sayısıdır: sır barındıran veri
deposuna, kuyruğa, ödeme akışına, hepsine.

İzden türetilen politika bunu on sekiz kuralla iki yüz elli iki yol kapatarak bitiriyor ve
gereksiz açık yol bırakmıyor — açık olan on sekiz yolun on sekizi de gerçekten kullanılıyor. Ama
son sütunda dört var: dört meşru akış yanlışlıkla kapandı. Bunlar otuz günlük izde görünmeyen
seyrek akışlardır — ay sonu mutabakatı, düzeltme akışı, haftalık rapor. Politika yazıldığı gün
hiçbir şey bozulmaz; ay sonu geldiğinde bozulur ve bozulduğunda görünen şey bir ağ hatasıdır, bir
politika satırı değil. Yanlış alarmın gecikmeli olması onu pahalı yapan şeydir.

Etiket tabanlı politika üçte bir kuralla — altı — benzer bir kapanma elde ediyor: iki yüz otuz
dört yol. Bedeli ortadaki sütunda: on yedi gereksiz açık yol. Alt bloktaki üç satır bunun nereden
geldiğini gösteriyor. "Depo etiketli hedefe uygulama etiketli kaynaklardan veri ucu" tek bir
kuraldır ve sekiz yol açar; bunların yedisi izde vardır, biri yoktur. Etiketli kural, aynı etiketi
taşıyan her şeye aynı muameleyi yapar — ayrım yapamadığı yerde fazladan açar.

İlginç olan son sütun: etiket tabanlı politika dört değil **üç** meşru akışı kapatıyor. Etiketin
genelliği seyrek akışlardan birini kazara karşıladı. Aynı gevşeklik hem on yedi gereksiz yol
açıyor hem bir yanlış alarmı önlüyor; ikisi tek bir ayarın iki yüzüdür.

#### Yeni Servis Eklendiğinde

Politikanın asıl maliyeti yazıldığı gün değil, kümenin değiştiği gün ortaya çıkıyor.

```js
// kosum8.mjs — kumeye yeni bir servis eklenince her iki politikada ne guncelleniyor
import { SERVIS, MESRU, ETIKET_KURAL, izdenKural, izdenAcik, etiketAcik, yol, say } from './ag.mjs';

const YENI = [['gecelik-toplu-is', 'arsivleyici', 'api'], ['arsivleyici', 'veri-deposu', 'veri'],
  ['olcut-toplayici', 'arsivleyici', 'olcut']];
const kapsam = (kural, servis) => {                    // kac yeni akis mevcut kurallarla karsilaniyor
  const acik = etiketAcik(kural, servis);
  return YENI.filter(([k, h, u]) => acik.has(yol(k, h, u))).length;
};
console.log('yeni servis: arsivleyici, uc yeni mesru akis\n');
console.log('politika                  etiket   karsilanan  eklenecek  gereksiz acik');
console.log('                          atamasi  akis        kural      once -> sonra');
const izOnce = say(izdenAcik(izdenKural())).gereksizAcik;
const izSonra = say(izdenAcik([...izdenKural(), ...YENI]), [...MESRU, ...YENI]).gereksizAcik;
console.log(`${'izden turetilen'.padEnd(25)} ${'-'.padEnd(8)} ${String(0).padEnd(11)} ` +
  `${String(YENI.length).padEnd(10)} ${izOnce} -> ${izSonra}`);
for (const etiket of [['toplu'], ['toplu', 'uygulama']]) {
  const servis = { ...SERVIS, arsivleyici: etiket };
  const k = kapsam(ETIKET_KURAL, servis);
  const eksik = YENI.filter(([a, b, u]) => !etiketAcik(ETIKET_KURAL, servis).has(yol(a, b, u)));
  const kural = [...ETIKET_KURAL, ...eksik.map(([a, b, u]) => [servis[b][0], servis[a][0], u])];
  const once = say(etiketAcik(ETIKET_KURAL)).gereksizAcik;
  const sonra = say(etiketAcik(kural, servis), [...MESRU, ...YENI]).gereksizAcik;
  console.log(`${`etiket: ${etiket.join('+')}`.padEnd(25)} ${String(etiket.length).padEnd(8)} ` +
    `${String(k).padEnd(11)} ${String(kural.length - ETIKET_KURAL.length).padEnd(10)} ${once} -> ${sonra}`);
}
```

```
yeni servis: arsivleyici, uc yeni mesru akis

politika                  etiket   karsilanan  eklenecek  gereksiz acik
                          atamasi  akis        kural      once -> sonra
izden turetilen           -        0           3          0 -> 0
etiket: toplu             1        1           2          17 -> 21
etiket: toplu+uygulama    2        2           1          17 -> 29
```

İzden türetilen politikada yeni servisin üç akışının hiçbiri mevcut kurallarla karşılanmıyor —
karşılanan akış sıfır — ve üçü için üç kural yazılıyor. Karşılığında gereksiz açık yol sıfırda
kalıyor. Bu biçim değişikliğe **doğrusal** tepki verir: her yeni akış bir satır.

Etiket tabanlı politikada iki seçenek var ve ikisi arasındaki fark bu dersin sonucudur. Arşivleyici
yalnız `toplu` etiketiyle geldiğinde mevcut kurallar üç akıştan birini karşılıyor, iki kural
yazmak gerekiyor ve gereksiz açık yol on yediden yirmi bire çıkıyor. Arşivleyiciye ikinci bir
etiket, `uygulama`, verildiğinde karşılanan akış ikiye çıkıyor, yazılacak kural bire iniyor — ama
gereksiz açık yol yirmi dokuza fırlıyor.

Aradaki sekiz yol, ikinci etiketin fiyatıdır. `uygulama` etiketi arşivleyiciyi dört kuralın birden
kapsamına sokuyor; o kuralların açtığı yolların çoğu arşivleyici için gereksiz. Yani kural yazmaktan
kaçınmanın yolu etiketi genişletmekten geçiyor ve etiketi genişletmek matrisi açıyor. İki kurallı
seçenekle bir kurallı seçenek arasındaki tercih, bir satır yazma emeğiyle sekiz açık yol arasında
yapılıyor.

Sessiz olan taraf da burada. Fazladan açılan sekiz yol hiçbir hata üretmez, hiçbir kayda düşmez ve
hiç kullanılmayabilir; varlıkları ancak matris yeniden sayıldığında görünür. Buna karşılık eksik
bırakılan bir kural — izden türetilen biçimde üç satırdan biri unutulsa — hemen bir bağlantı hatası
verir ve düzeltilir. İki politika biçimi bu yüzden farklı yönde bozulur: biri **gürültülü ve
düzeltilebilir**, öteki **sessiz ve birikimli**.

#### Küme Büyüdükçe

Tek bir servis eklemek iki biçim arasında küçük bir fark üretti. Fark, ekleme yinelendiğinde
yönünü belli ediyor.

```js
// kosum9.mjs — kume buyudukce iki politikanin kural sayisi nasil artiyor
import { SERVIS, MESRU, ETIKET_KURAL, izdenKural, izdenAcik, etiketAcik, yol, say } from './ag.mjs';

const akis = (ad) => [['gecelik-toplu-is', ad, 'api'], [ad, 'veri-deposu', 'veri'],
  ['olcut-toplayici', ad, 'olcut']];
let servis = { ...SERVIS }, kural = [...ETIKET_KURAL], mesru = [...MESRU], izKural = izdenKural();
console.log('yeni  izden turetilen      etiket tabanli (yeni servis etiketi: toplu+uygulama)');
console.log('servis kural  gereksiz acik  kural  gereksiz acik  bu adimda eklenen kural');
for (let n = 1; n <= 6; n += 1) {
  const ad = `arsiv-${n}`;
  servis = { ...servis, [ad]: ['toplu', 'uygulama'] };
  const yeni = akis(ad);
  mesru = [...mesru, ...yeni]; izKural = [...izKural, ...yeni];
  const eksik = yeni.filter(([a, b, u]) => !etiketAcik(kural, servis).has(yol(a, b, u)));
  const eklendi = eksik.map(([a, b, u]) => [servis[b][0], servis[a][0], u]);
  kural = [...kural, ...eklendi];
  const i = say(izdenAcik(izKural), mesru), e = say(etiketAcik(kural, servis), mesru);
  console.log(`${String(n).padEnd(6)} ${String(izKural.length).padEnd(6)} ${String(i.gereksizAcik).padEnd(14)} ` +
    `${String(kural.length).padEnd(6)} ${String(e.gereksizAcik).padEnd(14)} ${eklendi.length}`);
}
```

```
yeni  izden turetilen      etiket tabanli (yeni servis etiketi: toplu+uygulama)
servis kural  gereksiz acik  kural  gereksiz acik  bu adimda eklenen kural
1      21     0              7      29             1
2      24     0              7      43             0
3      27     0              7      59             0
4      30     0              7      77             0
5      33     0              7      97             0
6      36     0              7      119            0
```

İki sütun iki ayrı eğri çiziyor. İzden türetilen politikada kural sayısı her serviste üçer artıyor
— yirmi birden otuz altıya — ve gereksiz açık yol altı serviste de sıfır kalıyor. Bakım maliyeti
doğrusal, açıklık sabit.

Etiket tabanlı politikada tersi oluyor. Kural sayısı ilk serviste bir artıyor ve orada duruyor:
yedi kural, sonraki beş serviste de yedi. Son sütun beş kez sıfır — yeni servis etiketleri
taşıdığı için mevcut kurallar onu kendiliğinden karşılıyor. Bakım maliyeti sıfıra iniyor. Bunun
karşılığı üçüncü sayı sütununda birikiyor: gereksiz açık yol yirmi dokuzdan yüz on dokuza çıkıyor
ve artış hızlanıyor — sırasıyla on dört, on altı, on sekiz, yirmi, yirmi iki. Her yeni `uygulama`
etiketli servis, kendinden önceki bütün `uygulama` etiketli servislerle karşılıklı yol açıyor;
artış bu yüzden servis sayısıyla doğrusal değil, çiftlerin sayısıyla orantılı.

Devredilen kararın bedeli bu tabloda okunuyor. Ağ vekiline "bu bağlantı meşru mu" kararını
devretmek için ona meşru akış kümesini bildirmek gerekir. Bildirimi tek tek yapmak her değişiklikte
emek ister ama bildirilen şey doğrudur. Bildirimi etiketle yapmak emeği sıfıra indirir ve
bildirilen şeyi **kabaca doğru** kılar; kabalığın büyüklüğü kümenin büyümesiyle birlikte artar ve
hiçbir yerde ölçülmediği sürece görünmez.

#### Özet

- On servis, üç uç ve dokuz hedef 270 yolluk bir matris kurar; meşru akış 22'dir, yani varsayılan
  açık düzende 248 yol karşılığı olmadan açık durur.
- İzden türetilen politika 18 kuralla 252 yol kapatır ve hiç gereksiz açık bırakmaz, ama izde
  görünmeyen 4 seyrek akışı yanlışlıkla kapatır; bu yanlış alarm ancak akış ilk kez denendiğinde
  görünür.
- Etiket tabanlı politika 6 kuralla 234 yol kapatır; bedeli 17 gereksiz açık yoldur, tek bir kural
  sekiz yolu birden açabilir ve aynı gevşeklik seyrek akışlardan birini kazara karşılayarak yanlış
  alarmı dörtten üçe indirir.
- Yeni servis eklendiğinde izden türetilen politika üç kural ister ve gereksiz açık yolu sıfırda
  tutar; etiket tabanlı politikada dar etiket iki kural ve 21 gereksiz yol, geniş etiket bir kural
  ve 29 gereksiz yol üretir.
- Altı servis eklendiğinde izden türetilen politika 36 kurala çıkar ve gereksiz açık yolu sıfırda
  tutar; etiket tabanlı politika 7 kuralda kalır ama gereksiz açık yol 29'dan 119'a çıkar, çünkü
  artış servis sayısıyla değil çiftlerin sayısıyla orantılıdır.
- Eksik kural gürültülü bozulur ve düzeltilir; fazla açık yol sessiz bozulur ve birikir. Politika
  biçimi seçimi bu iki bozulma türü arasındaki seçimdir.

#### Sonraki Adım

Bu dersin politikası kapsüller arasındaki trafiği sınırlıyor; kapsülün **kendi içinde** ne
yapabildiğini sınırlamıyor. Ayrıcalıklı çalışan, ana makinenin dosya sistemine uzanan ya da geniş
yetenek kümesiyle açılan bir süreç, ağ politikası eksiksiz yazılmış olsa bile durduğu düğümde
başka bir alan açar. Bu ayarların ne olduğu ve tek makinede neye mal olduğu daha önce ölçüldü.
Sonraki dersin sorusu ayarların kendisi değil, **kümenin onları nasıl dayattığı**dır: bir kabul
denetimi kuralı yazılır ve mevcut kapsül tanımlarına uygulanır; kaç tanımın politikaya uymadığı,
dayatmanın kaç dağıtımı durdurduğu, uyarma kipi ile engelleme kipinin farkı ve muafiyet verilirse
kaç tanımın açıkta kaldığı sayılır.

### Güvenlik Bağlamı

Source: https://academia.sh/tr/kurslar/orkestrasyon/guvenlik-baglami

Kümenin ayrıcalık ve yetenek ayarlarını nasıl dayattığı ölçülür: bir kabul denetimi kuralı yazılıp mevcut kapsül tanımlarına uygulanır, kaç tanımın politikaya uymadığı, dayatmanın kaç dağıtımı durdurduğu, uyarma ile engelleme kipinin farkı ve muafiyet verilirse kaç tanımın açıkta kaldığı sayılır.

Önceki dersin politikası kapsüller arasındaki trafiği sınırladı. Kapsülün kendi içinde ne
yapabildiğini sınırlamadı: ayrıcalıklı çalışan, ana makinenin ağını paylaşan ya da geniş bir
yetenek kümesiyle açılan bir süreç, ağ politikası eksiksiz yazılmış olsa bile durduğu düğümde
başka bir alan açar. Bu ayarların tek tek ne yaptığı ve tek makinede neye mal olduğu daha önce
ölçüldü — yetenek sayımı, salt okunur kök, kaynak sınırı. O ölçüm burada tekrarlanmıyor.

Buranın sorusu farklı ve daha dar: **küme bu ayarları nasıl dayatıyor.** Bir ayarın doğru değeri
bilinse bile, yirmi dört ayrı tanımın hepsinde o değerin bulunması kendiliğinden olmaz. Devredilen
karar şudur: bir kapsül tanımının kümeye kabul edilip edilmeyeceğine, tanımın içeriğine bakarak
bir kabul denetimi karar verir. Bilmesi gereken kalem tektir ve ucuzdur — tanımın kendisi, zaten
kümeye gönderilmiştir. Bu dersin ölçüsü bilginin maliyeti değil, **kararın sonucudur**: dayatma
açıldığında ne duruyor.

- **OI25.** Yirmi dört kapsül tanımı üç ad alanına dağılmıştır ve kurgusal bölgesel ölçüm ağına
  aittir. Tanımlar tohumu görünür bir üreteçle kuruldu; gerçek bir depodan okunmadılar. Gerçek
  bir küme koşturulmuyor.
- **OI26.** Güvenlik bağlamı altı alana indirgendi. Alanların anlamı ve tek makinedeki bedeli
  daha önce ölçüldü; burada yalnız kaç tanımda hangi değerin bulunduğu sayılıyor.
- **OI27.** Kabul denetimi **tanımın bildirdiğine** bakar. Görüntünün çalışma zamanında gerçekte
  ne yaptığı bu denetimin görüş alanı dışındadır; bu sınır ölçümün sonunda ayrıca ele alınıyor.
- **OI28.** Dağıtım akışı kırk denemedir ve ayrı bir tohumla üretildi. Aynı tanım akışta birden
  çok kez görünebilir; kırk deneme on dokuz ayrı tanıma dokunuyor.
- **OI29.** Muafiyet iki biçimde verildi: bir ad alanının tamamına ve "eski" işaretli tanımlara.
  Tanım başına tek tek muafiyet modellenmiyor; modellenseydi açıkta kalan sayısı düşer, yönü
  değişmezdi.
- **OI30.** Uyarma kipinde hiçbir dağıtım durmaz. Uyarı kaydı ihlal başına bir satırdır, tanım
  başına değil.

#### Tanımlar ve Kural

```js
// kabul.mjs — kapsul tanimlari ve kabul denetimi; gercek kume degil, node ile kurulan bir model
export const TOHUM = 20260805, ALAN = ['gelistirme', 'hazirlik', 'uretim'], TANIM_SAYISI = 24;
export function uretec(tohum) {                        // dogrusal eslesik uretec, tohum gorunur
  let x = tohum >>> 0;
  return () => { x = (Math.imul(x, 1664525) + 1013904223) >>> 0; return x / 4294967296; };
}
// Kendi semamiz: her tanim alti guvenlik baglami alani tasir.
export function tanimlar() {
  const r = uretec(TOHUM), t = [];
  for (let i = 0; i < TANIM_SAYISI; i += 1) {
    const alan = ALAN[i % ALAN.length];
    const eski = r() < 0.45;                           // eski tanimlar daha gevsek yazilmis
    t.push({ ad: `tanim-${String(i + 1).padStart(2, '0')}`, alan, eski,
      ayricalikli: r() < (eski ? 0.30 : 0.04),
      kokKullanici: r() < (eski ? 0.80 : 0.35),
      saltOkunurKok: r() < (eski ? 0.10 : 0.55),
      yukseltmeyeIzin: r() < (eski ? 0.85 : 0.40),
      anaMakineAgi: r() < (eski ? 0.25 : 0.04),
      ekYetenek: Math.floor(r() * (eski ? 5 : 2)) });
  }
  return t;
}
export const KURAL = [                                 // kabul denetimi kurallari
  ['ayricalikli calismasin', (d) => !d.ayricalikli],
  ['kok kullanici olmasin', (d) => !d.kokKullanici],
  ['kok dosya sistemi salt okunur olsun', (d) => d.saltOkunurKok],
  ['yetki yukseltmeye izin verilmesin', (d) => !d.yukseltmeyeIzin],
  ['ana makine agi kullanilmasin', (d) => !d.anaMakineAgi],
  ['ek yetenek istenmesin', (d) => d.ekYetenek === 0],
];
export const ihlal = (d, kural = KURAL) => kural.filter(([, f]) => !f(d)).map(([ad]) => ad);
export const uygun = (d, kural = KURAL) => ihlal(d, kural).length === 0;
```

Kural, tanımın bir alanına bakan bir yüklemdir; politika bu yüklemlerin listesidir. Tanımların
"eski" işareti modelin tek eğrisidir: daha önce yazılmış tanımların gevşek değerler taşıma
olasılığı yüksek tutuldu. Gerçek bir depoda bu eğri ölçülür, varsayılmaz.

#### Mevcut Tanımlar Kurala Vuruluyor

```js
// kosum10.mjs — mevcut tanimlar kurala vuruluyor: kac tanim uymuyor, hangi kural kac kez
import { tanimlar, KURAL, ALAN, TOHUM, ihlal, uygun } from './kabul.mjs';

const t = tanimlar();
console.log(`tohum ${TOHUM} | ${t.length} kapsul tanimi, ${ALAN.length} ad alani, ${KURAL.length} kural`);
console.log(`politikaya uymayan tanim: ${t.filter((d) => !uygun(d)).length}/${t.length}\n`);
console.log('kural                                 ihlal eden tanim');
for (const [ad, f] of KURAL) console.log(`${ad.padEnd(37)} ${t.filter((d) => !f(d)).length}`);
console.log('\nihlal sayisi  tanim');
const dagilim = new Map();
for (const d of t) dagilim.set(ihlal(d).length, (dagilim.get(ihlal(d).length) ?? 0) + 1);
for (const n of [...dagilim.keys()].sort((a, b) => a - b)) console.log(`${String(n).padEnd(13)} ${dagilim.get(n)}`);
console.log('\nad alani     tanim  uymayan  toplam ihlal');
for (const a of ALAN) {
  const g = t.filter((d) => d.alan === a);
  console.log(`${a.padEnd(12)} ${String(g.length).padEnd(6)} ${String(g.filter((d) => !uygun(d)).length).padEnd(8)} ` +
    `${g.reduce((s, d) => s + ihlal(d).length, 0)}`);
}
```

```
tohum 20260805 | 24 kapsul tanimi, 3 ad alani, 6 kural
politikaya uymayan tanim: 19/24

kural                                 ihlal eden tanim
ayricalikli calismasin                2
kok kullanici olmasin                 14
kok dosya sistemi salt okunur olsun   11
yetki yukseltmeye izin verilmesin     11
ana makine agi kullanilmasin          5
ek yetenek istenmesin                 10

ihlal sayisi  tanim
0             5
1             6
2             2
3             5
4             3
5             2
6             1

ad alani     tanim  uymayan  toplam ihlal
gelistirme   8      6        19
hazirlik     8      7        13
uretim       8      6        21
```

Yirmi dört tanımın on dokuzu politikaya uymuyor. Bu sayı tek başına bir şey söylemez; ilginç olan
ikinci tablodur. Uymayan on dokuz tanımın altısında tek ihlal var, birinde altısı birden. Yani
"politikaya uymayan tanım" tek bir sınıf değil: bir ucunda tek satırlık bir düzeltmeyle uygun hâle
gelecek tanımlar, öteki ucunda baştan yazılması gereken bir tanım duruyor. Toplam ihlal sayısı
elli üçtür, tanım sayısının iki katından fazla.

Kural tablosu dayatmanın nereden zorlaşacağını gösteriyor. En sert görünen kural — ayrıcalıklı
çalışmasın — yalnız iki tanımı vuruyor; en çok tanımı vuran kural, kök kullanıcı yasağı, on dördü.
Bir politikanın "ne kadar sıkı" olduğu kurallarının sertliğiyle değil, mevcut tanımlara **ne kadar
uzak** olduğuyla ölçülüyor. Ad alanı tablosu bunu doğruluyor: uymayan tanım sayısı üç ortamda da
altı ile yedi arasında, ama toplam ihlal üretimde yirmi bir, hazırlıkta on üç. Üretimdeki tanımlar
daha az sayıda değil, daha derin uyumsuz.

#### Uyarma, Engelleme, Muafiyet

```js
// kosum11.mjs — uyarma kipi, engelleme kipi ve muafiyet ayri ayri sayiliyor
import { tanimlar, KURAL, uretec, ihlal, uygun } from './kabul.mjs';

const AKIS_TOHUM = 77021, DAGITIM = 40;
const t = tanimlar(), r = uretec(AKIS_TOHUM);
const akis = Array.from({ length: DAGITIM }, () => t[Math.floor(r() * t.length)]);
console.log(`dagitim akisi: tohum ${AKIS_TOHUM}, ${DAGITIM} deneme, ${new Set(akis.map((d) => d.ad)).size} ayri tanim`);
console.log(`akistaki uymayan deneme: ${akis.filter((d) => !uygun(d)).length}\n`);

const SENARYO = [
  ['uyarma, muafiyet yok', KURAL, () => false, false],
  ['engelleme, muafiyet yok', KURAL, () => false, true],
  ['engelleme, gelistirme muaf', KURAL, (d) => d.alan === 'gelistirme', true],
  ['engelleme, eski tanimlar muaf', KURAL, (d) => d.eski, true],
  ['engelleme, yalniz iki kural', KURAL.slice(0, 1).concat([KURAL[4]]), () => false, true],
];
console.log('senaryo                        kural  durdurulan  gecen uymayan  tam politikaya  uyari');
console.log('                                      dagitim     dagitim        gore acikta     kaydi');
for (const [ad, kural, muaf, engelle] of SENARYO) {
  let durdurulan = 0, gecenUymayan = 0, uyari = 0;
  for (const d of akis) {
    const i = ihlal(d, kural);
    if (i.length === 0) continue;
    if (muaf(d)) { gecenUymayan += 1; uyari += i.length; continue; }
    if (engelle) durdurulan += 1; else { gecenUymayan += 1; uyari += i.length; }
  }
  const acikta = t.filter((d) => !uygun(d) && (muaf(d) || !engelle || uygun(d, kural))).length;
  console.log(`${ad.padEnd(30)} ${String(kural.length).padEnd(6)} ${String(durdurulan).padEnd(11)} ` +
    `${String(gecenUymayan).padEnd(14)} ${String(acikta).padEnd(15)} ${uyari}`);
}
console.log('\nalti kural birlikte degil tek tek dayatilsaydi, kural basina durdurulan dagitim:');
for (const k of KURAL) {
  const d = akis.filter((x) => ihlal(x, [k]).length).length;
  console.log(`  ${k[0].padEnd(37)} ${d}`);
}
```

```
dagitim akisi: tohum 77021, 40 deneme, 19 ayri tanim
akistaki uymayan deneme: 33

senaryo                        kural  durdurulan  gecen uymayan  tam politikaya  uyari
                                      dagitim     dagitim        gore acikta     kaydi
uyarma, muafiyet yok           6      0           33             19              89
engelleme, muafiyet yok        6      33          0              0               0
engelleme, gelistirme muaf     6      22          11             6               33
engelleme, eski tanimlar muaf  6      17          16             11              59
engelleme, yalniz iki kural    2      6           0              13              0

alti kural birlikte degil tek tek dayatilsaydi, kural basina durdurulan dagitim:
  ayricalikli calismasin                3
  kok kullanici olmasin                 24
  kok dosya sistemi salt okunur olsun   23
  yetki yukseltmeye izin verilmesin     17
  ana makine agi kullanilmasin          5
  ek yetenek istenmesin                 17
```

Aynı politika, aynı tanımlar, aynı akış; değişen tek şey dayatma kipi. Uyarma kipinde hiçbir
dağıtım durmadı, seksen dokuz uyarı kaydı üretildi ve on dokuz tanım açıkta kaldı. Engelleme
kipinde kırk denemenin otuz üçü durdu — yüzde seksen ikisi. Bu iki satır arasındaki mesafe,
politikayı yazmakla dayatmak arasındaki mesafedir; ikisi arasında bir gün bile geçmeden geçilirse
kümenin dağıtım akışı fiilen durur.

Muafiyet satırları bu mesafeyi kısaltmanın iki yolunu ölçüyor ve ikisi aynı şeyi yapmıyor.
Geliştirme ad alanı muaf tutulduğunda durdurulan dağıtım otuz üçten yirmi ikiye iniyor ve altı
tanım açıkta kalıyor. Eski tanımlar muaf tutulduğunda durdurulan dağıtım on yediye kadar iniyor —
akış daha rahat geçiyor — ama açıkta kalan tanım on bire, uyarı kaydı elli dokuza çıkıyor.
Ölçünün söylediği şu: **muafiyet ne kadar rahatlatıyorsa o kadar açık bırakıyor** ve "eski
tanımlar" muafiyeti tam olarak en kötü tanımları muaf tutuyor, çünkü ihlallerin çoğu zaten
onlarda.

Son satır üçüncü bir yolu ölçüyor: bütün politikayı değil, iki kuralını dayatmak. Durdurulan
dağıtım altıya iniyor, geçen uymayan dağıtım sıfır — o iki kurala göre hiçbir şey kaçmıyor. Ama
son sütun tam politikaya göre on üç tanımın açıkta olduğunu söylüyor. Bu, muafiyetten farklı bir
açıklık türüdür: muafiyette kural vardır ve bazı tanımlara uygulanmaz; kural alt kümesinde ise
kural hiç yoktur, dolayısıyla hiçbir uyarı da üretilmez. Uyarı sütununun sıfır olması bunun
kanıtıdır — on üç açık tanımın hiçbiri hiçbir yerde görünmüyor.

Alt blok hangi iki kuralın seçileceğini sayıya bağlıyor. Kök kullanıcı yasağı tek başına kırk
denemenin yirmi dördünü durdururdu, salt okunur kök yirmi üçünü. Ayrıcalık yasağı üçünü, ana
makine ağı yasağı beşini. İlk adımda dayatılacak kurallar bu sütuna bakılarak seçilir: en az
dağıtımı durduran kurallar, en az direnişle kapatılabilen kurallardır ve kapandıktan sonra geri
açılmazlar.

#### Aşamalı Dayatma

Alt bloğun sıraladığı sayılar bir program üretiyor: kurallar en az durduran sırayla, birikimli
olarak açılabilir. Her adımda durdurulan dağıtım, düzeltilmesi gereken tanım ve hâlâ açıkta olan
tanım ayrı ayrı sayılır.

```js
// kosum12.mjs — kurallar en az durduran sirayla, birikimli dayatiliyor
import { tanimlar, KURAL, uretec, ihlal, uygun } from './kabul.mjs';

const t = tanimlar(), r = uretec(77021);
const akis = Array.from({ length: 40 }, () => t[Math.floor(r() * t.length)]);
const sira = [...KURAL].sort((a, b) =>
  akis.filter((x) => !a[1](x)).length - akis.filter((x) => !b[1](x)).length);
console.log('adim  eklenen kural                        durdurulan  duzeltilecek  tam politikaya');
console.log('                                           dagitim     tanim         gore acikta');
for (let n = 1; n <= sira.length; n += 1) {
  const alt = sira.slice(0, n);
  const durdurulan = akis.filter((d) => ihlal(d, alt).length).length;
  const duzeltilecek = t.filter((d) => !uygun(d, alt)).length;
  const acikta = t.filter((d) => !uygun(d) && uygun(d, alt)).length;
  console.log(`${String(n).padEnd(5)} ${sira[n - 1][0].padEnd(36)} ${String(durdurulan).padEnd(11)} ` +
    `${String(duzeltilecek).padEnd(13)} ${acikta}`);
}
```

```
adim  eklenen kural                        durdurulan  duzeltilecek  tam politikaya
                                           dagitim     tanim         gore acikta
1     ayricalikli calismasin               3           2             17
2     ana makine agi kullanilmasin         6           6             13
3     yetki yukseltmeye izin verilmesin    20          13            6
4     ek yetenek istenmesin                30          17            2
5     kok dosya sistemi salt okunur olsun  30          17            2
6     kok kullanici olmasin                33          19            0
```

İlk iki adım ucuz: altı dağıtım durur, altı tanım düzeltilir ve on üç tanım açıkta kalır. Üçüncü
adım sıçramayı yapıyor — durdurulan dağıtım altıdan yirmiye çıkıyor — ama karşılığında açıkta
kalan tanım on üçten altıya iniyor. Eğrinin bu biçimi bir yerde durulabileceğini gösteriyor: üç
adımda tam politikanın açıklığının yaklaşık üçte ikisi, dağıtım akışının tam yarısı durdurularak
kapanıyor.

Dördüncü ve beşinci satırlar aynı üç sayıyı taşıyor. Salt okunur kök kuralı eklendiğinde hiçbir
şey değişmiyor: dördüncü adımdan sonra o kuralı ihlal eden her tanım zaten başka bir kuralı da
ihlal ediyor. Kural tek başına on bir tanımı vuruyordu, birikimli sırada **sıfır yeni tanım**
getiriyor. Bir kuralın değeri tek başına vurduğu tanım sayısıyla değil, ötekilerin üstüne ne
eklediğiyle ölçülüyor; sıralamayı bilmeden yazılan bir dayatma programı bu farkı göremez.

#### Denetimin Görmediği

Bu ölçümün tamamı tanımların **bildirdiği** değerler üzerinden yapıldı. Kabul denetimi kapsül
tanımını okur, altı alana bakar ve karar verir; kararın maliyeti bir okuma, gecikmesi bir
istektir. Bu ucuzluğun kaynağı, denetimin bakabildiği tek şeyin bildirim olmasıdır.

Bildirimin doğru olması, davranışın da doğru olduğu anlamına gelmez. Ek yetenek istemediğini
bildiren bir tanımın görüntüsü, açılışta o yeteneği gerektiren bir işlem deneyebilir; denetim bunu
göremez, çünkü denetim dağıtımdan önce çalışır ve süreç henüz yoktur. Tersi de geçerlidir: kök
kullanıcı olarak çalıştığını bildiren bir tanım, kökle hiçbir şey yapmıyor olabilir. İlk durumda
küme uyumlu sanır ve süreç çalışma zamanında başarısız olur; ikinci durumda küme uymuyor sayar ve
gereksiz yere durdurur. On dokuz uymayan tanımın kaçının ikinci sınıfa girdiği bu modelden
okunamaz — okunması için çalışma zamanı gözlemi gerekir, o da başka bir bilgi kalemidir.

Devredilen kararın sınırı budur. Kabul denetimi "bu tanım politikaya uyuyor mu" sorusunu kesin
cevaplar; "bu iş yükü güvenli mi" sorusunu cevaplamaz. İkisi arasındaki farkı kapatan şey bir
kural daha değil, bildirimlerin gerçeği yansıtmasını sağlayan bir üretim düzenidir.

#### Özet

- Yirmi dört tanımın on dokuzu altı kurallı politikaya uymuyor ve toplam ihlal elli üç; uymayan
  tanımların altısında tek ihlal, birinde altı ihlal var, yani uyumsuzluk tek bir sınıf değil.
  Politikanın sıkılığı da kuralların sertliğinden değil mevcut tanımlara uzaklığından gelir:
  ayrıcalık yasağı iki tanımı, kök kullanıcı yasağı on dördünü vuruyor.
- Uyarma kipinde sıfır dağıtım durur ve seksen dokuz uyarı üretilir; engelleme kipinde kırk
  denemenin otuz üçü, yüzde seksen ikisi durur. İki kip arasındaki geçiş bu mesafeyi kat eder.
- Muafiyet rahatlattığı ölçüde açık bırakır: geliştirme ad alanı muafiyeti durdurulanı yirmi ikiye
  indirip altı tanımı, eski tanım muafiyeti on yediye indirip on bir tanımı açıkta bırakır.
- Kural alt kümesi dayatmak muafiyetten farklı bir açıklık üretir: iki kuralla altı dağıtım durur
  ve tam politikaya göre on üç tanım açıkta kalır, ama uyarı kaydı sıfırdır — açıklık hiçbir yerde
  görünmez.
- Kurallar en az durduran sırayla açıldığında üç adımda açıklık on dokuzdan altıya iner; beşinci
  adımda eklenen kural hiçbir yeni tanım getirmez, çünkü ihlalleri öteki kurallar zaten kapsar.
- Kabul denetimi tanımın bildirdiğine bakar, sürecin yaptığına değil; "politikaya uyuyor mu"
  sorusunu kesin, "güvenli mi" sorusunu hiç cevaplamaz.

#### Sonraki Adım

Bu dersin altı alanı yirmi dört tanımın her birine ayrı ayrı yazılmak zorundaydı ve on dokuzunda
yanlış yazılmıştı. Aynı durum önceki üç dersin çıktıları için de geçerli: dağıtım kalıbının
adımları, üç denetimin periyot ve eşikleri, rol tanımları ve ağ kuralları hep aynı tanım
dosyalarında duruyor ve her servis için yeniden yazılıyor. Tekrarın kendisi bir ölçüdür — aynı
değerin kaç dosyada geçtiği, bir değeri değiştirmenin kaç dosyaya dokunmayı gerektirdiği. Sonraki
ders bu tekrarı sayar ve tanımları tek bir kaynaktan üretmenin neyi azaltıp neyi eklediğini ölçer.

### Paketleme ve Şablonlama

Source: https://academia.sh/tr/kurslar/orkestrasyon/paketleme-ve-sablonlama

Aynı uygulama beş ortama önce elle, sonra tek şablonla kurulur; yazılan satır, ortam başına değişen değer ve kopyala-yapıştır sürüklenmesi sayılır. Şablonun kendi bedeli de ölçülür: değişken sayısı, koşullu dal sayısı ve şablonu okuyarak kaç satırın kesin bilinebildiği.

Bir önceki ders güvenlik bağlamını politikaya çevirdi: ayrıcalıklı çalışma, salt okunur kök ve
yetenek kısıtı artık kümenin bildirim kabul ederken dayattığı kurallar. Dayatma çalışıyor, ama
dayatılan şeyi yazan taraf değişmedi. Aynı uygulamanın beş ortama kurulması için aynı nesne kümesi
hâlâ beş kez yazılıyor ve beş kopya arasında yalnız birkaç değer değişiyor.

**Dağıtım paketi**, bir uygulamanın küme üzerinde çalışması için gereken nesnelerin tümüdür: sürüm
nesnesi, servis nesnesi, yapılandırma nesnesi, giriş kuralı, kota. **Şablon**, o paketin ortamdan
bağımsız kısmını bir kez yazıp değişen kısmı dışarı çıkaran metindir. Devredilen karar şudur: her
ortamın nesne kümesinin son hâlini insan yazmayı bırakır, bir üretici yazar. Bu dersin ölçtüğü şey
o devrin bedeli — hem kazandırdığı satır hem de üreticinin kendi getirdiği yük.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir: su sayacı okumalarını toplayan, doğrulayan ve saha
iş emri açan **kurgu** yazılım. Gerçek küme koşturulmaz; ölçülen şey `node` ile kurulmuş bir
**modeldir** — metin üzerinde çalışan bir şablon motoru ve elle düzenlemenin adım adım taklidi.

**OI31.** Dağıtım paketi beş nesneden oluşur ve on altı satırla temsil edilir.
**OI32.** Beş ortam vardır: geliştirme, sınama, ön-üretim, üretim-batı, üretim-doğu.
**OI33.** Elle yolda taban paket bir kez yazılır, dört kez kopyalanır; kopyalar sonra düzeltilir.
**OI34.** Üç değişiklik turu koşulur; her turda kimin atladığı ya da yanlış yazdığı **önceden
yazılıdır**; rastgelelik yoktur.
**OI35.** Şablon motoru üç işi bilir — değer yerleştirme, koşullu blok, döngü — ve nesne şemasını
**bilmez**.
**OI36.** Şema ders içinde tanımlanır ve yalnız üretilmiş çıktıya uygulanır.

#### Beş Ortam, Tek Nesne Kümesi

```js
// veri.mjs — taban nesne kumesi, ortam basina degisen degerler, sablon ve sablon motoru.
export const TABAN = `nesne surum-nesnesi okuma-toplayici
  kopya 3
  imge-etiketi 4.2.0
  istek-cpu 200
  sinir-cpu 500
nesne servis-nesnesi okuma-toplayici
  kapi 8080
nesne yapilandirma-nesnesi toplayici-ayar
  kutuk-duzeyi ozet
  toplu-boyut 500
  dogrulayici-adres dogrulayici.olcum-agi:8080
nesne giris-kurali toplayici-giris
  konak toplayici.on.ic
nesne kota olcum-agi
  cpu-toplam 4000
  bellek-toplam 8192`;                               // on-uretim ortami icin elle yazildi

export const ALAN = ["kopya", "kutuk-duzeyi", "toplu-boyut", "konak", "cpu-toplam",
  "bellek-toplam", "sinir-cpu"];
const HAM = {                                        // ortam: [yedi deger] + acik dallar
  "gelistirme":  [1, "ayrinti", 50, "toplayici.gelistirme.ic", 1000, 2048, 300, []],
  "sinama":      [2, "ozet", 200, "toplayici.sinama.ic", 2000, 4096, 400, ["giris"]],
  "on-uretim":   [3, "ozet", 500, "toplayici.on.ic", 4000, 8192, 500, ["giris"]],
  "uretim-bati": [6, "uyari", 1000, "toplayici.bati.ic", 12000, 24576, 800, ["giris"]],
  "uretim-dogu": [6, "uyari", 1000, "toplayici.dogu.ic", 12000, 24576, 800, ["giris", "yedek"]] };
export const ORTAM = Object.keys(HAM);
export const DEGER = Object.fromEntries(ORTAM.map((o) => [o, Object.fromEntries(
  [...ALAN.map((a, i) => [a, HAM[o][i]]), ...HAM[o][7].map((x) => [x, true])])]));

export const SABLON = `nesne surum-nesnesi okuma-toplayici
  kopya {{kopya}}
  imge-etiketi 4.2.0
  istek-cpu 200
  sinir-cpu {{sinir-cpu}}
nesne servis-nesnesi okuma-toplayici
  kapi 8080
nesne yapilandirma-nesnesi toplayici-ayar
  kutuk-duzeyi {{kutuk-duzeyi}}
  toplu-boyut {{toplu-boyut}}
  dogrulayici-adres dogrulayici.olcum-agi:8080
{{#eger giris}}nesne giris-kurali toplayici-giris
  konak {{konak}}
{{/eger}}{{#eger yedek}}nesne surum-nesnesi okuma-toplayici-yedek
  kopya {{yedek-kopya}}
  imge-etiketi 4.2.0
{{/eger}}nesne kota olcum-agi
  cpu-toplam {{cpu-toplam}}
  bellek-toplam {{bellek-toplam}}
{{#her ek-etiket}}  etiket {{.}}
{{/her}}`;

export const uret = (s, d) => s                      // yerlestirme, kosullu blok, dongu
  .replace(/\{\{#eger ([\w-]+)\}\}([\s\S]*?)\{\{\/eger\}\}/g, (_, a, g) => (d[a] ? g : ""))
  .replace(/\{\{#her ([\w-]+)\}\}([\s\S]*?)\{\{\/her\}\}/g, (_, a, g) =>
    (d[a] ?? []).map((x) => g.replaceAll("{{.}}", x)).join(""))
  .replace(/\{\{([\w-]+)\}\}/g, (_, a) => String(d[a] ?? `<eksik:${a}>`))
  .split("\n").filter((s) => s.trim() !== "").join("\n");
export const satir = (m) => m.split("\n").filter((s) => s.trim() !== "").length;
```

Taban paket ön-üretim ortamı için yazılmıştır ve on altı satırdır. Beş ortam arasında değişen değer
yedi tanedir; geri kalan dokuz satır beş ortamda da birebir aynıdır. Şablon bu ayrımı metne
taşır: yedi değer `{{...}}` ile dışarı çıkar, iki nesne koşullu bloğa girer.

Ayrım burada iki türlü değişkenlik olduğunu gösterir. Birincisi **değer değişkenliğidir** —
kopya sayısı, kütük düzeyi, kota tavanı; nesne kümesi aynı kalır, içindeki sayı değişir. İkincisi
**yapı değişkenliğidir** — geliştirme ortamında giriş kuralı hiç yoktur, üretim-doğuda fazladan
bir sürüm nesnesi vardır; değişen şey değer değil, nesnenin varlığıdır. Değer değişkenliği düz bir
listeyle kapatılır; yapı değişkenliği koşullu dal ister ve dersin sonunda görüleceği gibi bedelin
büyük kısmı oradan gelir.

#### Yazılan Satır ve Kopyala-Yapıştır Sürüklenmesi

```js
// olc.mjs — ayni uygulama bes ortama elle ve sablonla kurulur; satir, dokunma, surukleme sayilir.
import { TABAN, SABLON, uret, satir, ALAN, ORTAM, DEGER } from "./veri.mjs";

const ortak = ["imge-etiketi", "istek-cpu", "kapi", "dogrulayici-adres", "hazir-olma-denetimi"];
let yazilan = satir(TABAN), kopyalanan = 0, duzenlenen = 0;
const elle = {};
for (const o of ORTAM) {                             // taban bir kez yazilir, dort kez kopyalanir
  let m = TABAN;
  if (o !== "on-uretim") {
    kopyalanan += satir(TABAN);
    for (const a of ALAN) {
      const y = m.replace(new RegExp(`(  ${a}) .*`), `$1 ${DEGER[o][a]}`);
      if (y !== m) duzenlenen++;
      m = y;
    }
    if (!DEGER[o].giris) { m = m.replace(/nesne giris-kurali.*\n  konak .*\n/, ""); duzenlenen += 2; }
    if (DEGER[o].yedek) { m += "\nnesne surum-nesnesi okuma-toplayici-yedek\n  kopya 6"; duzenlenen += 2; }
  }
  elle[o] = m;
}

const tur = [                            // uc tur; atlama ve yanlis yazma onceden yazilidir
  { f: (m) => m.replace(/(  sinir-cpu .*)/, "$1\n  hazir-olma-denetimi /saglik"), atla: "uretim-dogu" },
  { f: (m) => m.replaceAll(/(  imge-etiketi) .*/g, "$1 4.3.0"), atla: "sinama" },
  { f: (m) => m.replace(/(  istek-cpu) .*/, "$1 250"),
    yanlis: { "on-uretim": (m) => m.replace(/(  istek-cpu) .*/, "$1 300") } }];
let sablon = SABLON, sDuzenlenen = 0;
for (const t of tur) {
  for (const o of ORTAM) {
    if (t.atla === o) continue;
    elle[o] = (t.yanlis?.[o] ?? t.f)(elle[o]);
    duzenlenen++;
  }
  sablon = t.f(sablon);                              // sablon yolunda ayni tur tek dokunus
  sDuzenlenen++;
}
const uretilen = Object.fromEntries(ORTAM.map((o) => [o, uret(sablon, DEGER[o])]));

const ayrisma = (kume) => {                          // ortak alanlarda cogunluktan sapan kopyalar
  const sapan = {};
  let alan = 0;
  for (const a of ortak) {
    const d = ORTAM.map((o) => (kume[o].match(new RegExp(`  ${a} (.*)`)) ?? [, "-"])[1]);
    const cok = d.map((v) => [v, d.filter((x) => x === v).length]).sort((x, y) => y[1] - x[1])[0][0];
    ORTAM.forEach((o, i) => { if (d[i] !== cok) { alan++; (sapan[o] ??= []).push(a); } });
  }
  return { kopya: Object.keys(sapan).length, alan, sapan };
};
const e = ayrisma(elle), s = ayrisma(uretilen);
console.log(`elle yol   : yazilan ${yazilan}  kopyalanan ${kopyalanan}  elle duzenlenen ${duzenlenen}` +
  `  depodaki satir ${ORTAM.map((o) => satir(elle[o])).reduce((a, b) => a + b)}`);
console.log(`sablon yolu: yazilan ${satir(SABLON)}  deger satiri ${ORTAM.length}` +
  `  elle duzenlenen ${sDuzenlenen}  depodaki satir ${satir(SABLON) + ORTAM.length}`);
console.log(`ortam basina degisen deger ${ALAN.length}   ortak kalmasi gereken alan ${ortak.length}`);
console.log(`suruklenme (elle)  : ${e.kopya}/5 kopya ayrismis, ${e.alan} alan`);
for (const [o, a] of Object.entries(e.sapan)) console.log(`    ${o.padEnd(12)} ${a.join(", ")}`);
console.log(`suruklenme (sablon): ${s.kopya}/5 kopya ayrismis, ${s.alan} alan`);
```

```
elle yol   : yazilan 16  kopyalanan 64  elle duzenlenen 44  depodaki satir 84
sablon yolu: yazilan 21  deger satiri 5  elle duzenlenen 3  depodaki satir 26
ortam basina degisen deger 7   ortak kalmasi gereken alan 5
suruklenme (elle)  : 3/5 kopya ayrismis, 3 alan
    sinama       imge-etiketi
    on-uretim    istek-cpu
    uretim-dogu  hazir-olma-denetimi
suruklenme (sablon): 0/5 kopya ayrismis, 0 alan
```

Elle yolda depoda seksen dört satır durur ve bunların altmış dördü kopyadır. Asıl sayı kopya değil,
**elle düzenlenen kırk dört satırdır**: otuz biri ilk kuruluşta, on üçü üç değişiklik turunda.
Şablon yolunda aynı iş yirmi bir satırlık bir şablon, beş satırlık değer listesi ve üç turda üç
dokunuşla biter. Depodaki satır oranı üçe bir; değişiklik turlarındaki dokunuş oranı on üçe üç.

Sürüklenme bu oranın nedenini gösterir. Beş kopyanın ortak kalması gereken beş alanı vardır ve üç
tur sonunda **üç kopya üç alanda ayrışmıştır**: sınama eski görüntü etiketinde kalmış, ön-üretim
kaynak isteğine 250 yerine 300 yazmış, üretim-doğu hazır olma denetimini hiç almamış. Üçünün de
tek nedeni aynıdır — ortak değerin beş ayrı yerde durması. Ayrışmanın ölçülebilir yanı da burada:
kopyalar ayrışsa bile hiçbiri hata vermez, çünkü her biri kendi başına geçerli bir pakettir.
Şablon yolunda aynı üç tur sıfır ayrışma bırakır; ortak değer tek yerde durduğu için atlanacak bir
kopya yoktur.

#### Şablonun Kendi Bedeli

```js
// bedel.mjs — sablonun kendi bedeli: degisken, kosullu dal, okunabilirlik, sema kusuru.
import { SABLON, uret, ORTAM, DEGER } from "./veri.mjs";

const degisken = new Set([...SABLON.matchAll(/\{\{([\w-]+)\}\}/g)].map((m) => m[1]));
const dal = [...SABLON.matchAll(/\{\{#(?:eger|her) ([\w-]+)\}\}/g)].map((m) => m[1]);
const bicim = new Set(ORTAM.map((o) => dal.map((a) => (DEGER[o][a] ? 1 : 0)).join("")));
const im = SABLON.replace(/\{\{#(?:eger|her) [\w-]+\}\}([\s\S]*?)\{\{\/(?:eger|her)\}\}/g,
  (_, g) => g.split("\n").map((s) => (s.trim() ? "@" + s : s)).join("\n"));
const sS = im.split("\n").filter((s) => s.trim()), kosullu = sS.filter((s) => s.startsWith("@")).length;
console.log(`sablon ${sS.length} satir  degisken ${degisken.size}  kosullu dal ${dal.length}` +
  `  uretilebilir bicim ${2 ** dal.length}  bes ortamda kullanilan ${bicim.size}`);
console.log(`sablonu okuyarak kesin bilinen satir ${sS.length - kosullu}/${sS.length};` +
  ` ${kosullu} satir icin uretim gerekir`);

const SEMA = { kopya: "sayi", "imge-etiketi": "metin", "istek-cpu": "sayi", "sinir-cpu": "sayi",
  kapi: "sayi", "kutuk-duzeyi": "metin", "toplu-boyut": "sayi", "dogrulayici-adres": "metin",
  konak: "metin", "cpu-toplam": "sayi", "bellek-toplam": "sayi", etiket: "metin" };
const denetle = (m) => m.split("\n").filter((s) => s.startsWith("  ")).flatMap((s) => {
  const [a, d] = s.trim().split(/ (.+)/);            // sema motorun disindadir, ciktiya uygulanir
  if (!(a in SEMA)) return [`bilinmeyen alan ${a}`];
  if (d?.startsWith("<eksik:")) return [`${a} = ${d}`];
  return SEMA[a] === "sayi" && !/^\d+$/.test(d ?? "") ? [`${a} sayi degil`] : [];
});
let kusur = 0, olu = 0;
for (const o of ORTAM) {
  const c = uret(SABLON, DEGER[o]), h = denetle(c);
  kusur += h.length;
  if (h.length) console.log(`  ${o.padEnd(12)} uretildi, sema kusuru: ${h.join("; ")}`);
  if (!c.includes(String(DEGER[o].konak))) olu++;
}
console.log(`motorun yakaladigi ${0}/${kusur}   uretim sonrasi sema denetimi ${kusur}/${kusur}` +
  `   olu deger ${olu}   hic uretilmemis bicim ${2 ** dal.length - bicim.size}`);
```

```
sablon 20 satir  degisken 8  kosullu dal 3  uretilebilir bicim 8  bes ortamda kullanilan 3
sablonu okuyarak kesin bilinen satir 14/20; 6 satir icin uretim gerekir
  uretim-dogu  uretildi, sema kusuru: kopya = <eksik:yedek-kopya>
motorun yakaladigi 0/1   uretim sonrasi sema denetimi 1/1   olu deger 1   hic uretilmemis bicim 5
```

Şablonun bedeli üç sayıda toplanır. Birincisi **değişken sayısıdır**: sekiz değişken, yedisi değer
listesinde tanımlı, biri hiçbir yerde tanımlı değil. İkincisi **koşullu dal sayısıdır**: üç dal,
sekiz üretilebilir biçim, beş ortamda yalnız üçü kullanılıyor — kalan beş biçim şablonda duruyor
ama hiç üretilmiyor, dolayısıyla hiç sınanmıyor.

Üçüncüsü okunabilirliktir ve şu sayıya bağlanır: **yirmi satırlık şablonun on dördü okunarak kesin
bilinir, altısı için üretim gerekir**. Bu altı satır koşullu blokların içindedir; bir ortamın
çıktısında olup olmadıklarına şablona bakarak karar verilemez, değer listesiyle birlikte
üretilmeleri gerekir. Elle yazılan paket bu yükü taşımaz — orada yazılan şey çıktının kendisidir.
Şablon yolunda insan artık çıktıyı değil, **çıktıyı üreten programı** okur.

Sonuncu satır devrin asıl bedelini gösterir. Şablon motoru üç iş bilir ve nesne şemasını bilmez;
`yedek-kopya` değişkeni hiçbir değer listesinde tanımlı olmadığı için üretim-doğu çıktısına
`<eksik:yedek-kopya>` yazar ve **hata vermez**. Motor bu kusurun sıfırını yakalar; üretim sonrası
şema denetimi birini de yakalar. Aynı sessizlik ters yönde de görünür: geliştirme ortamı için
tanımlanmış `konak` değeri hiçbir çıktıda kullanılmaz, çünkü o ortam giriş kuralı dalına girmez —
**ölü değer**, hiçbir yerde uyarı üretmeden değer listesinde durur.

#### Devrin Bilançosu

| Ölçü | Elle | Şablonla |
|---|---|---|
| ilk kuruluşta elle düzenlenen satır | 31 | 21 (şablon) + 5 (değer) |
| üç değişiklik turunda elle dokunuş | 13 | 3 |
| depodaki satır | 84 | 26 |
| ortak alanda ayrışan kopya | 3/5 | 0/5 |
| okunarak kesin bilinen satır | 84/84 | 14/20 |
| hiç üretilmemiş biçim | yok | 5 |
| şema kusurunu yakalayan | insan | motor 0, sonradan şema denetimi 1 |

Devredilen karar tek cümleyle yazılır: **her ortamın nesne kümesinin son hâline insan değil bir
üretici karar verir.** Bunun için gereken bilgi kalemleri de sayılıdır — ortam başına yedi değer,
ortam başına açık dal listesi ve hangi alanın ortak kalması gerektiği. İlk ikisi değer
listesindedir; **üçüncüsü hiçbir yerde yazılı değildir**. Şablon "imge etiketi bütün ortamlarda
aynı olmalı" bilgisini taşımaz; o alan şablonda sabit yazıldığı için ortak kalır. Aynı alan yarın
bir dalın içine taşınırsa ortaklık sessizce biter ve bunu haber verecek bir denetim yoktur.

Bilginin maliyeti de bu tablodan okunur. Yedi değer ortam başına bir kez yazılır ve ortam
eklendikçe doğrusal büyür; dal listesi ortam başına bir satırdır ama şablonun dal sayısını
büyüttüğü anda üretilebilir biçim sayısı ikinin kuvvetiyle artar. Bugünkü üç dal sekiz biçim
demek; dördüncü bir dal eklendiğinde beş ortam yine aynı beş çıktıyı üretir, sınanmayan biçim
sayısı ise beşten on bire çıkar. Şablonun büyümesi değer listesinin büyümesiyle aynı hızda
gitmez.

Kazanç da bedel de aynı yerden çıkar: çıktı artık okunmuyor. Elle yolda seksen dört satırın
seksen dördü okunabilirdi ve kopyalar yine de ayrıştı; şablon yolunda ayrışma sıfır, ama okunan
metin çıktı değil üretici oldu ve üreticinin altı satırı ancak koşturularak biliniyor. Şablon
sürüklenmeyi ortadan kaldırmadı, **sürüklenmenin yerini değiştirdi**: beş kopya arasındaki farktan,
bir üreticinin hiç üretilmemiş beş biçimine taşıdı.

#### Özet

- Beş ortam elle kurulduğunda 16 satır yazıldı, 64 satır kopyalandı, 44 satır elle düzenlendi;
  şablonla aynı iş 21 satır şablon, 5 satır değer ve 3 dokunuşla bitti.
- Üç değişiklik turu sonunda elle yolda 5 kopyanın 3'ü, ortak kalması gereken 5 alanın 3'ünde
  ayrıştı; şablon yolunda ayrışma 0 kaldı.
- Şablonun bedeli 8 değişken ve 3 koşullu daldır: 8 üretilebilir biçimin yalnız 3'ü kullanılıyor,
  5'i hiç üretilmiyor ve hiç sınanmıyor.
- Şablonun 20 satırının 14'ü okunarak kesin bilinir, 6'sı için üretim gerekir; insan artık çıktıyı
  değil, çıktıyı üreten programı okur.
- Motor şemayı bilmediği için tanımsız değişkeni `<eksik:...>` diye çıktıya yazdı ve 1 kusurun
  0'ını yakaladı; aynı sessizlik ters yönde 1 ölü değer bıraktı.

#### Sonraki Adım

Şablon, var olan nesne türlerinden yeni birleşimler üretir; **yeni bir tür** üretemez. Bölgesel
ölçüm ağının okuma toplama düzeni beş nesnenin hiçbirine tam oturmuyor — sürüm nesnesi, kotası ve
zamanlanmış işi bir arada, tek bir kavram olarak anılması gerekiyor. Bir sonraki ders kümenin
tanıdığı kaynak türlerini genişletir: kurgu bir tür tanımlanır, alanları bir şemaya bağlanır ve
geçersiz bildirimlerin kaç tanesinin kabul anında yakalandığı, kaçının ancak koşumda patladığı
sayılır. Şema büyüdükçe yakalanan hata ile yazım yükünün birlikte nasıl arttığı ve eski
bildirimlerin yeni şemada kaç alanda kırıldığı da orada ölçülür.

### Özel Kaynak Tanımları

Source: https://academia.sh/tr/kurslar/orkestrasyon/ozel-kaynak-tanimlari

Kurgu bir kaynak türü tanımlanır ve üç şema sürümüyle doğrulanır; geçersiz bildirimlerin kaç tanesinin kabul anında yakalandığı, kaçının koşumda patladığı ve kaçının sessizce yanlış sonuç ürettiği sayılır. Şema büyüdükçe yakalanan hata ile yazım yükünün birlikte artışı ve eski bildirimlerin yeni şemada kaç alanda kırıldığı ölçülür.

Bir önceki ders şablonun var olan nesne türlerinden yeni birleşimler ürettiğini, ama yeni bir tür
üretemediğini ölçtü. Bölgesel ölçüm ağının okuma toplama düzeni de beş nesnenin hiçbirine tam
oturmuyor: bir sürüm nesnesi, bir kota ve bir zamanlanmış iş birlikte tek bir kavramı anlatıyor ve
o kavramın adı hiçbir yerde yazılı değil.

**Kaynak türü tanımı**, kümenin tanıdığı nesne türleri listesine yeni bir tür eklemektir. Devredilen
karar açıktır: bir bildirimin geçerli olup olmadığına artık gözden geçiren insan değil, **kabul
anında koşan bir şema doğrulayıcı** karar verir. Bu dersin ölçtüğü şey o devrin karşılığıdır —
şema büyüdükçe hangi hata sınıfı kabulde yakalanmaya başlıyor, karşılığında kaç alan yazmak
gerekiyor ve eski bildirimler yeni şemada ne kadar kırılıyor.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**. Gerçek küme koşturulmaz; tanımlanan
tür, şema doğrulayıcı ve hattın koşumu `node` ile kurulmuş bir **modeldir**.

**OI37.** Kurgu kaynak türü **okuma hattı**dır ve on bir alanı vardır.
**OI38.** On iki bildirim **önceden yazılıdır**; dokuzunda bir kusur bulunur ve kusurlar rastgele
seçilmemiştir.
**OI39.** Koşum modeli günde 1200 okuma işler ve sonucu üç sınıfa ayırır: doğru, patladı, sessizce
yanlış.
**OI40.** Üç şema sürümü vardır: A yalnız varlık, B varlık ile tür ve sıralı küme, C bunlara aralık
ve bağımlılık kuralı ekler.
**OI41.** Yazım yükü, zorunlu alan sayısının bildirim sayısıyla çarpımıdır.
**OI42.** Sürüm uyumu ölçümünde eski bildirimler yalnız şema A alanlarını taşır.

#### Kurgu Bir Kaynak Türü ve Üç Şema

```js
// tur.mjs — kurgu kaynak turu "okuma hatti": alanlar, uc sema surumu, on iki bildirim.
export const ALAN = ["ad", "kaynak", "hedef", "toplu-boyut", "pencere-dk", "bicim",
  "es-zamanli-isci", "yeniden-deneme", "geri-cekilme-sn", "gecikme-siniri-sn", "gunluk-tavan"];

const S = (...a) => a;
export const BILDIRIM = [
  //  ad              kaynak           hedef          toplu  pnc  bicim    isci deneme geri  gecikme  tavan
  S("bati-gece",     "sayac-kuyrugu", "dogrulayici",   500,  15, "ikili",   4,   3,    2,     960, 2000000),
  S("dogu-gece",     "sayac-kuyrugu", "dogrulayici",   500,  15, "ikili",   4,   3,    2,     960, 2000000),
  S("merkez-saatlik","sayac-kuyrugu", "faturalama",    250,  60, "metin",   2,   1,    5,    3700, 2000000),
  S("bati-saatlik",  "sayac-kuyrugu",  null,           250,  60, "metin",   2,   1,    5,    3700, 2000000),
  S("dogu-saatlik",   null,           "faturalama",    250,  60, "metin",   2,   1,    5,    3700, 2000000),
  S("kuzey-gece",    "sayac-kuyrugu", "dogrulayici", "besyuz", 15, "ikili", 4,   3,    2,     960, 2000000),
  S("guney-gece",    "sayac-kuyrugu", "dogrulayici",   500,  15, "ham",     4,   3,    2,     960, 2000000),
  S("bati-yedek",    "sayac-kuyrugu", "dogrulayici",   500,  15, "ikili", "-",   3,    2,     960, 2000000),
  S("dogu-yedek",    "sayac-kuyrugu", "dogrulayici",   500,   0, "ikili",   4,   3,    2,     960, 2000000),
  S("merkez-yedek",  "sayac-kuyrugu", "faturalama",    250,  60, "metin",   2,   5, null,    3700, 2000000),
  S("bati-hizli",    "sayac-kuyrugu", "is-emri",       500,  15, "ikili",   4,   3,    2,      60, 2000000),
  S("dogu-kisitli",  "sayac-kuyrugu", "is-emri",       500,  15, "ikili",   4,   3,    2,     960,    1000),
].map((d) => Object.fromEntries(ALAN.map((a, i) => [a, d[i]])));

const SAYI = { "toplu-boyut": "sayi", "pencere-dk": "sayi", "es-zamanli-isci": "sayi" };
const SAYI2 = { ...SAYI, "yeniden-deneme": "sayi", "geri-cekilme-sn": "sayi",
  "gecikme-siniri-sn": "sayi", "gunluk-tavan": "sayi" };
export const SEMA = {
  A: { zorunlu: ALAN.slice(0, 3), tur: {}, kume: {}, aralik: {}, kural: [] },
  B: { zorunlu: ALAN.slice(0, 7), tur: SAYI, kume: { bicim: ["ikili", "metin", "sikistirilmis"] },
       aralik: {}, kural: [] },
  C: { zorunlu: ALAN.filter((a) => a !== "geri-cekilme-sn"), tur: SAYI2,
       kume: { bicim: ["ikili", "metin", "sikistirilmis"] },
       aralik: { "pencere-dk": [1, 1440], "toplu-boyut": [1, 100000], "es-zamanli-isci": [1, 64],
                 "yeniden-deneme": [0, 10] },
       kural: [
         { ad: "geri cekilme bagimliligi", f: (b) => b["yeniden-deneme"] > 0 && b["geri-cekilme-sn"] == null },
         { ad: "gecikme siniri pencereden kucuk", f: (b) => b["gecikme-siniri-sn"] < b["pencere-dk"] * 60 },
         { ad: "gunluk tavan gunluk hacimden kucuk",
           f: (b) => b["gunluk-tavan"] < b["toplu-boyut"] * (1440 / b["pencere-dk"]) } ] },
};
```

Tür tanımı iki parçadır: alan listesi ve şema. Alan listesi türün ne söyleyebildiğini belirler;
şema, söylenenin ne zaman kabul edileceğini. Üç sürüm aynı on bir alan üzerinde farklı sıkılıkta
durur — A yalnız alanın var olup olmadığına, B ayrıca türüne ve sıralı küme üyeliğine, C bunlara
sayı aralığına ve alanlar arası bağımlılığa bakar.

#### Kabul Anı ve Koşum

```js
// dogrula.mjs — sema dogrulayici (kabul ani) ve okuma hattinin kurgu kosum modeli.
export function dogrula(b, s) {
  const h = [];
  for (const a of s.zorunlu) if (b[a] == null) h.push(`${a} eksik`);
  for (const [a, t] of Object.entries(s.tur))
    if (b[a] != null && t === "sayi" && typeof b[a] !== "number") h.push(`${a} sayi degil`);
  for (const [a, k] of Object.entries(s.kume))
    if (b[a] != null && !k.includes(b[a])) h.push(`${a} kume disi`);
  for (const [a, [alt, ust]] of Object.entries(s.aralik))
    if (typeof b[a] === "number" && (b[a] < alt || b[a] > ust)) h.push(`${a} aralik disi`);
  for (const k of s.kural) if (k.f(b)) h.push(k.ad);
  return h;
}

export function kos(b) {                             // kurgu okuma akisi: gunde 1200 okuma
  const TOPLAM = 1200;
  if (!b.kaynak || !b.hedef) throw new Error("kaynak ya da hedef cozulemedi");
  if (!["ikili", "metin", "sikistirilmis"].includes(b.bicim)) throw new Error("bilinmeyen bicim");
  const pencere = 1440 / b["pencere-dk"];
  if (!Number.isFinite(pencere)) throw new Error("pencere sayisi hesaplanamadi");
  if (b["yeniden-deneme"] > 0 && b["geri-cekilme-sn"] == null)
    throw new Error("geri cekilme tanimsiz, yeniden deneme donguye girdi");
  const parti = Math.ceil(TOPLAM / b["toplu-boyut"]);
  const islenen = Number.isFinite(parti) ? Math.min(TOPLAM, b["gunluk-tavan"]) : 0;
  const gecikme = b["pencere-dk"] * 60 + (parti * 2) / b["es-zamanli-isci"];
  const asim = !(gecikme <= b["gecikme-siniri-sn"]);
  return { islenen, dusen: TOPLAM - islenen, gecikme, asim,
    dogru: islenen === TOPLAM && Number.isFinite(gecikme) && !asim };
}
```

```js
// olc.mjs — uc sema surumunde kabulde yakalanan, kosumda patlayan ve sessizce yanlis olan sayilir.
import { BILDIRIM, SEMA } from "./tur.mjs";
import { dogrula, kos } from "./dogrula.mjs";

const kosum = BILDIRIM.map((b) => {                  // sema uygulanmadan gercek kosum sonucu
  try { return kos(b).dogru ? "dogru" : "sessiz"; } catch { return "patladi"; }
});
console.log("sema yokken on iki bildirimin kosumu: " +
  ["dogru", "patladi", "sessiz"].map((t) => `${t} ${kosum.filter((x) => x === t).length}`).join("  "));
BILDIRIM.forEach((b, i) => {
  if (kosum[i] === "dogru") return;
  let n = "hata vermedi, sonuc yanlis";
  try { kos(b); } catch (e) { n = e.message; }
  console.log(`   ${b.ad.padEnd(15)} ${kosum[i].padEnd(8)} ${n}`);
});

const kisit = (s) => s.zorunlu.length + Object.keys(s.tur).length + Object.keys(s.kume).length +
  Object.keys(s.aralik).length + s.kural.length;
console.log("\nsurum  zorunlu alan  sema kisiti  yazim yuku  kabulde  kosumda  sessizce  gecen");
for (const [ad, s] of Object.entries(SEMA)) {
  const red = BILDIRIM.map((b) => dogrula(b, s).length > 0);
  const k = kosum.filter((_, i) => !red[i]);
  const say = (t) => String(k.filter((x) => x === t).length).padStart(2);
  console.log(`  ${ad}         ${String(s.zorunlu.length).padStart(2)}           ${String(kisit(s)).padStart(2)}` +
    `          ${String(s.zorunlu.length * BILDIRIM.length).padStart(3)}      ${String(red.filter(Boolean).length).padStart(2)}` +
    `       ${say("patladi")}        ${say("sessiz")}      ${say("dogru")}`);
}
```

```
sema yokken on iki bildirimin kosumu: dogru 3  patladi 5  sessiz 4
   bati-saatlik    patladi  kaynak ya da hedef cozulemedi
   dogu-saatlik    patladi  kaynak ya da hedef cozulemedi
   kuzey-gece      sessiz   hata vermedi, sonuc yanlis
   guney-gece      patladi  bilinmeyen bicim
   bati-yedek      sessiz   hata vermedi, sonuc yanlis
   dogu-yedek      patladi  pencere sayisi hesaplanamadi
   merkez-yedek    patladi  geri cekilme tanimsiz, yeniden deneme donguye girdi
   bati-hizli      sessiz   hata vermedi, sonuc yanlis
   dogu-kisitli    sessiz   hata vermedi, sonuc yanlis

surum  zorunlu alan  sema kisiti  yazim yuku  kabulde  kosumda  sessizce  gecen
  A          3            3           36       2        3         4       3
  B          7           11           84       5        2         2       3
  C         10           25          120       9        0         0       3
```

İlk blok şemasız durumu verir: on iki bildirimin üçü doğru çalışır, beşi koşumda patlar, dördü
**hata vermeden yanlış sonuç üretir**. Dört sessiz durumun ayrı ayrı nedenleri vardır ve hiçbiri
bir kütükte görünmez: parti boyutu metin yazıldığı için sıfır okuma işlenir, işçi sayısı metin
olduğu için gecikme hesaplanamaz, gecikme sınırı pencereden küçük olduğu için sınır her turda
aşılır, günlük tavan hacimden küçük olduğu için iki yüz okuma düşer. Dördü de "hattı kurdum,
çalışıyor" cümlesiyle uyumludur.

Tablo şema büyüdükçe bu dağılımın nasıl kaydığını gösterir. Şema A yalnız iki bildirimi kabulde
reddeder; kalan yedi kusur koşuma iner. Şema B beşe çıkar, ama iki sessiz kusur yine geçer. Şema C
dokuzunun dokuzunu kabulde yakalar ve **koşumda hiçbir kusur kalmaz**. Karşılığı da aynı satırda
durur: yazım yükü otuz altıdan yüz yirmi alana çıkar, şema tanımındaki kısıt sayısı üçten yirmi
beşe çıkar. Kabulde yakalanan her yeni hata sınıfı, on iki bildirimin tümüne yazılan yeni bir alan
ya da yeni bir kuraldır.

Aradaki bağın yönü de okunur: A'dan B'ye geçerken üç hata daha yakalanır ve yazım yükü kırk sekiz
alan artar — hata başına on altı alan. B'den C'ye geçerken dört hata daha yakalanır ve yük otuz
altı alan artar — hata başına dokuz alan. Ucuzlayan şey alan sayısı değil, yakalanan kusurun
türüdür: C'nin eklediği üç bağımlılık kuralı tek tek alanlara bakmaz, alanlar arasındaki tutarlılığa
bakar ve sessiz kusurların ikisini oradan alır.

#### Sürüm Uyumu

```js
// uyum.mjs — sema A doneminde yazilmis bildirimler sema C'ye tasinir: kirilan alan ve varsayilanin bedeli.
import { ALAN, BILDIRIM, SEMA } from "./tur.mjs";
import { dogrula, kos } from "./dogrula.mjs";

const A_ALAN = SEMA.A.zorunlu, YENI = ALAN.filter((a) => !A_ALAN.includes(a));
const eski = BILDIRIM.map((b) => Object.fromEntries(A_ALAN.map((a) => [a, b[a]])));
const VARSAYILAN = { "toplu-boyut": 500, "pencere-dk": 15, bicim: "ikili", "es-zamanli-isci": 4,
  "yeniden-deneme": 3, "geri-cekilme-sn": 2, "gecikme-siniri-sn": 960, "gunluk-tavan": 2000000 };
const dolu = eski.map((b) => ({ ...VARSAYILAN, ...b }));
const kirik = (k) => k.reduce((t, b) => t + dogrula(b, SEMA.C).length, 0);

console.log(`eski bildirim ${eski.length}, her biri ${A_ALAN.length} alan;` +
  ` sema C ${SEMA.C.zorunlu.length} zorunlu alan istiyor (yeni alan ${YENI.length})`);
console.log(`kirilan alan ${kirik(eski)} (bildirim basina ${(kirik(eski) / eski.length).toFixed(1)});` +
  ` varsayilan tanimlaninca ${kirik(dolu)}`);

let ayrik = 0, bildirim = 0;                         // varsayilan yazili degerden kac alanda ayriliyor
for (let i = 0; i < eski.length; i++) {
  const f = YENI.filter((a) => VARSAYILAN[a] !== BILDIRIM[i][a]);
  if (f.length) { ayrik += f.length; bildirim++; }
}
console.log(`varsayilan, kayitli degerden ${bildirim}/${eski.length} bildirimde ve ${ayrik} alanda ayriliyor`);

const sonuc = (b) => { try { const r = kos(b); return `okuma ${r.islenen}, gecikme ${Math.round(r.gecikme)} sn`; }
  catch (e) { return `patladi (${e.message.split(",")[0]})`; } };
for (const i of [0, 2, 11]) console.log(`   ${eski[i].ad.padEnd(15)} yazili bildirim: ${sonuc(BILDIRIM[i]).padEnd(28)}` +
  ` varsayilanla: ${sonuc(dolu[i])}`);
```

```
eski bildirim 12, her biri 3 alan; sema C 10 zorunlu alan istiyor (yeni alan 8)
kirilan alan 86 (bildirim basina 7.2); varsayilan tanimlaninca 2
varsayilan, kayitli degerden 10/12 bildirimde ve 34 alanda ayriliyor
   bati-gece       yazili bildirim: okuma 1200, gecikme 902 sn   varsayilanla: okuma 1200, gecikme 902 sn
   merkez-saatlik  yazili bildirim: okuma 1200, gecikme 3605 sn  varsayilanla: okuma 1200, gecikme 902 sn
   dogu-kisitli    yazili bildirim: okuma 1000, gecikme 902 sn   varsayilanla: okuma 1200, gecikme 902 sn
```

Türü genişletmenin bedeli burada çıkar. Şema A döneminde yazılmış on iki bildirim üç alan taşır;
şema C on zorunlu alan ister. Bildirim başına ortalama **7,2 alan kırılır**, toplamda seksen altı.
Bu, tür sahibinin değil bildirim sahiplerinin işidir ve tek seferde ödenir.

Varsayılan tanımlamak kırığı seksen altıdan ikiye indirir — kalan iki kırık şema A döneminde de
eksik olan alanlardır. Ama varsayılan bedava değildir: **on iki bildirimin onunda, toplam otuz dört
alanda, varsayılan değer bildirimde yazılı olandan farklıdır.** Örnek satırlar farkın niteliğini
gösterir. Gece hattı varsayılanla aynı davranır, çünkü varsayılan zaten onun değerlerinden
seçilmiştir. Saatlik hat pencere değerini altmıştan on beşe düşürür ve gecikmesi 3605 saniyeden 902
saniyeye iner — hat aynı ada sahip, ama artık başka bir hattır. Kısıtlı hat günlük tavanını kaybeder
ve bin okuma yerine bin iki yüz okuma işler; tavanın var olma nedeni bildirimden silinmiştir.

Kırılmanın da varsayılanın da ölçüsü aynı yerden gelir: **eski bildirim yeni alanlar hakkında bir
şey söylemiyor ve söylemediği şeyi kimse bilmiyor.** Kırılma bilinmezliği görünür kılar ve bedelini
bildirim sahibine yükler; varsayılan bilinmezliği kapatır ve bedelini sessizce üstlenir.

#### Devrin Bilançosu

| Ölçü | Şema A | Şema B | Şema C |
|---|---|---|---|
| zorunlu alan | 3 | 7 | 10 |
| şema tanımındaki kısıt | 3 | 11 | 25 |
| on iki bildirimin yazım yükü (alan) | 36 | 84 | 120 |
| kabulde yakalanan bildirim | 2 | 5 | 9 |
| koşumda patlayan | 3 | 2 | 0 |
| sessizce yanlış | 4 | 2 | 0 |
| geçen ve doğru çalışan | 3 | 3 | 3 |

Devredilen karar tek cümledir: **bir bildirimin geçerliliğine insan değil şema karar verir.** Bunun
için sistemin bilmesi gereken kalemler sayılıdır — on bir alanın adı, üçünün türü ya da sıralı
kümesi, dördünün aralığı, üç bağımlılık kuralı. Bilginin maliyeti de sayılıdır: her kalem on iki
bildirimin tümüne yazılır ve bildirim sayısı arttıkça yük doğrusal büyür.

Sistemin bilmediği şeyin ne yaptığı da tablodadır. Şema A dünyasında dört bildirim kabul edilir,
koşar, sonuç üretir ve sonuç yanlıştır; şema tavanın hacimden küçük olamayacağını bilmediği için
iki yüz okumanın düşmesine izin verir. Şema C aynı kuralı öğrendiğinde o dört kusur kabulden geri
döner. Öğrenmenin karşılığı yüz yirmi alanlık yazım yüküdür ve bu yük, kusuru olmayan üç bildirime
de aynen biner: doğru yazılmış bildirim de yanlış yazılmışla aynı on alanı yazmak zorundadır.

#### Özet

- Şemasız durumda 12 bildirimin 3'ü doğru çalıştı, 5'i koşumda patladı, 4'ü hata vermeden yanlış
  sonuç üretti.
- Şema A 9 kusurun 2'sini, şema B 5'ini, şema C 9'unu kabul anında yakaladı; şema C'de koşuma inen
  kusur 0'a düştü.
- Karşılığı yazım yüküdür: zorunlu alan 3'ten 10'a, on iki bildirimin toplam yükü 36 alandan 120
  alana, şema tanımındaki kısıt 3'ten 25'e çıktı.
- A'dan B'ye hata başına 16 alan, B'den C'ye hata başına 9 alan ödendi; ucuzlatan şey alanlar arası
  tutarlılığa bakan 3 bağımlılık kuralıdır.
- Şema A döneminde yazılmış bildirimler şema C'de bildirim başına 7,2 alanda kırıldı; varsayılan
  kırığı 86'dan 2'ye indirdi ama 12 bildirimin 10'unda, 34 alanda yazılı değerden ayrıldı.

#### Sonraki Adım

Şema bildirimin geçerli olduğunu söyler, doğru olduğunu söylemez. Kabul edilmiş bir okuma hattı
bildirimi kümede tek başına hiçbir şey yapmaz; onu okuyup gerçek durumu istenen duruma getirecek
bir şey gerekir ve bugün o şey nöbetçi bir insandır. Bir sonraki ders bu tür için gerçekten koşan
bir **denetleyici** yazar: istenen durumu okur, gerçek durumu okur, farkı kapatır ve ikinci turda
sıfır iş yapar. Elle işletimde bir olayın kaç adımda ve kaç dakikada kapandığı ile denetleyicide
kaç turda kapandığı karşılaştırılır; denetleyiciye kodlanmış işletim bilgisi madde madde sayılır ve
kodlanmamış olanın üretimde ne yaptığı gösterilir.

### Denetleyici Kalıbı

Source: https://academia.sh/tr/kurslar/orkestrasyon/denetleyici-kalibi

Bir önceki dersin kaynak türü için gerçekten koşan bir denetleyici yazılır: istenen durumu okur, gerçek durumu okur, farkı kapatır ve ikinci turda sıfır iş yapar. Elle işletimde bir olayın kaç adım ve kaç dakika sürdüğü ile denetleyicide kaç tur sürdüğü karşılaştırılır; kodlanmış işletim bilgisi madde madde sayılır ve kodlanmamış tek maddenin ürettiği salınım seksen tur boyunca ölçülür.

Bir önceki ders okuma hattı türünü tanımladı ve şemanın bir bildirimin geçerli olduğunu söylediğini,
doğru olduğunu söylemediğini ölçtü. Kabul edilmiş bildirim kümede tek başına hiçbir şey yapmıyor:
gerçek durumu ona benzetecek bir şey gerekiyor ve bugün o şey nöbetçi bir insan.

**Denetleyici kalıbı**, bu nöbetin kendisini koda taşımaktır. Uzlaşma döngüsünün mekaniği —
istenen durum, gerçek durum, fark, düzeltme ve etkisizlik — M22/K01'in **Altyapı Sağlama
Modelleri** dersinde ölçüldü; burada tekrarlanmaz. Bu dersin konusu döngünün kendisi değil,
**döngünün içine ne yazıldığıdır**: nöbetçinin kafasındaki işletim bilgisinin kaç maddesi koda
geçti, kaçı geçmedi ve geçmeyenin bedeli ne.

Devredilen karar açıktır: **bir olaya ne yapılacağına insan değil denetleyici karar verir.** Ölçüm
yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; gerçek küme koşturulmaz, ölçülen şey `node`
ile kurulmuş bir **modeldir**.

**OI43.** Denetleyici bir önceki dersin okuma hattı türü için yazılır; istenen durum o bildirimden
gelir — dört işçi ve 960 saniyelik gecikme sınırı.
**OI44.** Bir tur bir dakika model zamanıdır; turda 80 okuma gelir, çalışan işçi başına 40 okuma
işlenir.
**OI45.** Seksen tur koşulur ve hedef servis 10.–59. turlar arasında bakımdadır; pencere **önceden
yazılıdır**, rastgelelik yoktur.
**OI46.** Denetleyicinin kodlanmış bilgisi beş maddedir ve madde madde listelenir.
**OI47.** Elle işletim tarifi dokuz adımdır; adım süreleri önceden yazılıdır ve bir **modeldir**.
**OI48.** Yeniden başlatma bir turda biter ve kırk okumayı kuyruğa geri koyar.

#### Denetleyicinin Bildiği Şey

```js
// dunya.mjs — okuma hattinin kurgu dunyasi ve denetleyicinin kodlanmis bilgisi.
export const ISTENEN = { isci: 4, durum: "calisiyor", sinir: 960 };   // 07'deki bildirimden

export const yeniDunya = () => ({ durum: "durdu", isci: 0, kuyruk: 400, gecikme: 300,
  hedef: "acik", inat: 0, bekleme: 3 });

export function ilerle(d) {                          // bir tur = bir dakika model zamani
  const kapasite = d.durum === "calisiyor" && d.hedef === "acik" ? d.isci * 40 : 0;
  const onceki = d.gecikme;
  d.kuyruk = Math.max(0, d.kuyruk + 80 - kapasite);   // turda 80 okuma gelir
  d.gecikme = Math.round((d.kuyruk / 80) * 60);
  d.inat = d.gecikme >= onceki ? d.inat + 1 : 0;
}

export const KURAL = [                               // denetleyiciye kodlanmis isletim bilgisi
  { ad: "durmus hat baslatilir",
    f: (d, i) => d.durum === "durdu" && ((d.durum = "calisiyor"), true) },
  { ad: "isci sayisi bildirilene tamamlanir",
    f: (d, i) => d.isci < i.isci && ((d.isci = i.isci), true) },
  { ad: "gecikme sinir ustundeyse isci artirilir",
    f: (d, i) => d.gecikme > i.sinir && d.isci < 8 && (d.isci++, true) },
  { ad: "gecikme sinir altindaysa fazla isci geri alinir",
    f: (d, i) => d.gecikme <= i.sinir && d.isci > i.isci && (d.isci--, true) },
  { ad: "inat eden gecikmede hat yeniden baslatilir",
    f: (d, i) => d.gecikme > i.sinir && d.inat >= d.bekleme &&
      ((d.inat = 0), (d.isci = i.isci), (d.kuyruk += 40), true) },
];
export const KODLANMAMIS = { ad: "hedef bakimdayken dokunulmaz", f: (d) => d.hedef === "bakim" };

export function denetle(d, i, kural, geriCekilme = false) {
  if (kural.bekle && kural.bekle(d)) { d.inat = 0; return []; }   // altinci madde eklendiginde
  const islem = [];
  for (const k of kural.liste) if (k.f(d, i)) islem.push(k.ad);
  if (geriCekilme && islem.includes("inat eden gecikmede hat yeniden baslatilir"))
    d.bekleme = Math.min(d.bekleme * 2, 48);          // artan yeniden deneme araligi
  return islem;
}
```

Beş kural, nöbetçinin kafasındaki beş cümledir. İlk ikisi bildirimden okunabilir: hat çalışmalı,
işçi sayısı dört olmalı. Son üçü bildirimden okunamaz — bunlar bildirimin değil, **hattı işleten
kişinin** bilgisidir: gecikme sınırı aşılınca ne yapılır, gecikme normale dönünce ne yapılır ve
gecikme inat ederse ne yapılır. Denetleyici kalıbının anlattığı devir tam olarak bu üç cümledir.

Dünya modelinin de tutmayı seçtiği kalemler sayılıdır. Denetleyicinin okuyabildiği dört kalem
vardır — durum, işçi sayısı, kuyruk boyu ve ondan türeyen gecikme. Beşinci bir kalem daha modelde
durur ve hattın davranışını doğrudan belirler: hedef servisin açık mı bakımda mı olduğu. O kalem
dünyada vardır ama **hiçbir kuralda geçmez**; denetleyici onu okumaz. Bu ders boyunca ölçülen her
sapmanın kaynağı bu tek satırdır.

#### Etkisizlik ve Elle İşletimle Karşılaştırma

```js
// olc.mjs — etkisizlik, elle isletimle karsilastirma, kodlanmamis bilginin bedeli, geri cekilme.
import { ISTENEN, yeniDunya, ilerle, KURAL, KODLANMAMIS, denetle } from "./dunya.mjs";

const TUR = 80, BAKIM = [10, 59];
const kosum = (kural, geriCekilme = false) => {
  const d = yeniDunya();
  const s = { islem: 0, yenidenBaslatma: 0, isciDegisimi: 0, enYuksekKuyruk: 0, asimTuru: 0,
    ilkTur: 0, ikinciTur: 0, olcum: 0, iz: [] };
  for (let t = 0; t < TUR; t++) {
    d.hedef = t >= BAKIM[0] && t <= BAKIM[1] ? "bakim" : "acik";
    const i = denetle(d, ISTENEN, kural, geriCekilme);
    s.olcum += 3;                                    // her turda uc kalem okunur
    s.islem += i.length;
    if (t === 0) s.ilkTur = i.length;
    if (t === 1) s.ikinciTur = i.length;
    s.yenidenBaslatma += i.filter((x) => x.startsWith("inat")).length;
    s.isciDegisimi += i.filter((x) => x.includes("isci")).length;
    ilerle(d);
    if (t >= 30 && t < 50) s.iz.push(d.isci);
    s.enYuksekKuyruk = Math.max(s.enYuksekKuyruk, d.kuyruk);
    if (d.gecikme > ISTENEN.sinir) s.asimTuru++;
  }
  return s;
};

const eksik = { liste: KURAL }, tam = { liste: KURAL, bekle: KODLANMAMIS.f };
const a = kosum(eksik), b = kosum(tam), c = kosum(eksik, true);
console.log(`kodlanmis bilgi ${KURAL.length} madde; kodlanmamis 1 madde: ${KODLANMAMIS.ad}`);
console.log(`etkisizlik: 1. turda ${a.ilkTur} islem, 2. turda ${a.ikinciTur} islem`);
console.log(`\n${TUR} tur, hedef ${BAKIM[0]}-${BAKIM[1]} arasi bakimda`);
console.log("kosum                       islem  yeniden baslatma  isci degisimi  en yuksek kuyruk  asim turu  okuma");
const yaz = (ad, s) => console.log(`${ad.padEnd(26)} ${String(s.islem).padStart(4)}` +
  `${String(s.yenidenBaslatma).padStart(17)}${String(s.isciDegisimi).padStart(15)}` +
  `${String(s.enYuksekKuyruk).padStart(18)}${String(s.asimTuru).padStart(11)}${String(s.olcum).padStart(7)}`);
yaz("5 madde (eksik bilgi)", a); yaz("5 madde + geri cekilme", c); yaz("6 madde (bakim bilinir)", b);
console.log(`\nbakim ortasinda isci sayisi izi (tur 30-49)`);
console.log(`  5 madde : ${a.iz.join(" ")}`);
console.log(`  6 madde : ${b.iz.join(" ")}`);

const ELLE = [["uyari kutugu acilir", 2], ["hattin durumu okunur", 3], ["kuyruk boyu okunur", 3],
  ["isci sayisi okunur", 2], ["hedef servisin durumu sorulur", 8], ["bakim penceresi dogrulanir", 6],
  ["karar verilir", 4], ["islem uygulanir", 3], ["kayit dusulur", 3]];
const dk = ELLE.reduce((t, [, m]) => t + m, 0);
console.log(`\nelle isletimde bir olay: ${ELLE.length} adim, ${dk} dakika` +
  `   denetleyicide: 1 tur tespit + 1 tur islem = 2 tur, tur basi 15 sn -> 0,5 dakika`);
console.log(`ayni olay ikinci kez: elle yine ${ELLE.length} adim/${dk} dk, denetleyicide yine 2 tur`);
```

```
kodlanmis bilgi 5 madde; kodlanmamis 1 madde: hedef bakimdayken dokunulmaz
etkisizlik: 1. turda 2 islem, 2. turda 0 islem

80 tur, hedef 10-59 arasi bakimda
kosum                       islem  yeniden baslatma  isci degisimi  en yuksek kuyruk  asim turu  okuma
5 madde (eksik bilgi)        56               12             43              4440         48    240
5 madde + geri cekilme       22                3             18              4120         45    240
6 madde (bakim bilinir)      10                0              9              4000         46    240

bakim ortasinda isci sayisi izi (tur 30-49)
  5 madde : 4 5 6 4 5 6 4 5 6 4 5 6 4 5 6 4 5 6 4 5
  6 madde : 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4

elle isletimde bir olay: 9 adim, 34 dakika   denetleyicide: 1 tur tespit + 1 tur islem = 2 tur, tur basi 15 sn -> 0,5 dakika
ayni olay ikinci kez: elle yine 9 adim/34 dk, denetleyicide yine 2 tur
```

Etkisizlik iki satırda görünür: ilk tur iki iş yapar — durmuş hattı başlatır ve işçi sayısını
sıfırdan dörde çıkarır — ikinci tur **sıfır iş yapar**. Denetleyici ne yaptığını hatırlamaz; her
turda gerçek durumu yeniden okur ve fark bulamadığı için dokunmaz.

Elle işletimle karşılaştırma da tek satıra iner. Aynı olay elle kapatılırken dokuz adım ve otuz
dört dakika sürer; dokuz adımın **beşi yalnız okumadır** — hattın durumu, kuyruk boyu, işçi sayısı,
hedef servisin durumu, bakım penceresi — ve bu beş adım otuz dört dakikanın yirmi ikisini yer.
Karar ve işlem birlikte yedi dakikadır. Elle işletimin pahalı yanı yapılan iş değil, işi yapmak
için toplanan bilgidir. Denetleyicide olay iki turda kapanır: bir tur farkı görmek, bir tur işlemi
uygulamak; tur başı on beş saniyeden yarım dakika. Asıl fark ikinci satırdadır: **aynı olay ikinci
kez olduğunda elle yol yine dokuz adım ve otuz dört dakikadır**, denetleyicide yine iki tur. Elle
işletimde maliyet olay sayısıyla çarpılır; denetleyicide bir kez ödenir.

Bilginin maliyeti de sayılıdır: denetleyici seksen turun her birinde üç kalem okur — durum, işçi
sayısı, gecikme — toplam **iki yüz kırk ölçüm**. Bu ölçümler olay olmadığında da yapılır; sessiz
turlarda denetleyicinin ürettiği tek şey okumadır.

#### Kodlanmamış Bilgi ve Salınım

Üç koşum aynı dünyayı görür ve aynı elli turluk bakımı yaşar. Aradaki tek fark denetleyicinin ne
bildiğidir.

Beş maddelik denetleyici bakım boyunca **elli altı işlem** yapar: kırk üç işçi değişikliği ve on iki
yeniden başlatma. İşçi izi salınımı çıplak gösterir — `4 5 6 4 5 6 4 5 6` — üç turluk bir döngü.
Gecikme sınırın üstünde olduğu için üçüncü kural işçi ekler; gecikme düşmediği için beşinci kural üç
tur sonra hattı yeniden başlatır; yeniden başlatma işçi sayısını dörde geri çeker ve kuyruğa kırk
okuma ekler. Sonra aynı üç tur tekrar başlar.

Buradaki asıl nokta işlem sayısı değildir. **Denetleyici bilmediği durumu düzeltemez, ama düzeltmeye
çalışmaktan da vazgeçemez.** Gecikmenin nedeni hattın kendisinde değildir; hedef servis bakımdadır
ve hattın kaç işçiyle koştuğu hiçbir şeyi değiştirmez. Denetleyicinin gördüğü tek şey "gecikme sınır
üstünde" olduğu için, elindeki iki aleti sırayla dener. On iki yeniden başlatmanın her biri kırk
okumayı kuyruğa geri koyar; en yüksek kuyruk dört bin dört yüz kırka çıkar — bilen denetleyicide
dört bin. Aradaki dört yüz kırk okuma **düzeltme girişiminin kendi ürettiği gecikmedir**.

İki ayrı çare vardır ve ikisi ayrı şey ölçer. Birincisi **yeniden deneme aralığını** büyütmektir:
bekleme süresi her yeniden başlatmadan sonra ikiye katlanınca (üç, altı, on iki, yirmi dört tur)
işlem elli altıdan yirmi ikiye, yeniden başlatma on ikiden üçe iner. Denetleyici hâlâ yanlış şeyi
yapmaktadır, yalnız daha seyrek yapmaktadır. İkincisi **altıncı bilgi maddesini** eklemektir: hedef
bakımdayken dokunulmaz. O zaman işlem ona, yeniden başlatma sıfıra iner ve işçi izi düz bir çizgi
olur.

İki çarenin ayrımı önemlidir, çünkü ikisi ayrı sınıftan şeydir. Geri çekilme **kodlanmamış bilgiyi
kodlamaz**; denetleyicinin ne bildiğini hiç değiştirmez, yalnız yanlış kararın sıklığını düşürür.
Altıncı madde ise bir bilgi kalemi ekler ve karşılığında bir okuma borcu doğurur: hedef servisin
bakım durumu artık her turda okunmalıdır. Sayıya dökülünce iki yol arasındaki fark on iki işlemdir
(yirmi ikiye karşı on), ama sayının söylemediği bir yan vardır — geri çekilme her yeni olay
türünde yeniden ayarlanmak zorundadır, altıncı madde ise bir kez yazılır.

Altıncı madde olayı **çözmez**. Aşım turu sayısı üç koşumda da kırk beş ile kırk sekiz arasındadır;
gecikme sınırı yine aşılır, çünkü hedef gerçekten kapalıdır. Kazanılan şey olayın süresi değil,
**olaya eklenen zarardır**: kırk altı işlem, on iki yeniden başlatma ve dört yüz kırk okumalık
fazladan kuyruk ortadan kalkar.

#### Devrin Bilançosu

| Ölçü | Elle işletim | 5 madde | 5 madde + geri çekilme | 6 madde |
|---|---|---|---|---|
| bir olayın kapanması | 9 adım, 34 dk | 2 tur | 2 tur | 2 tur |
| aynı olay ikinci kez | 9 adım, 34 dk | 2 tur | 2 tur | 2 tur |
| 80 turda işlem | — | 56 | 22 | 10 |
| yeniden başlatma | — | 12 | 3 | 0 |
| işçi değişikliği | — | 43 | 18 | 9 |
| en yüksek kuyruk | — | 4440 | 4120 | 4000 |
| aşım turu | — | 48 | 45 | 46 |
| okuma | 5 adım / olay | 240 | 240 | 240 |

Devrin bilgi kalemleri sayılabilir: beş kodlanmış madde, bir kodlanmamış madde. Kodlanmış maddelerin
ikisi bildirimden okunur, üçü okunmaz — üçü de nöbetçinin deneyiminden gelir ve denetleyiciye
yazılana kadar hiçbir yerde durmaz. Bilginin maliyeti de sayılıdır: tur başına üç ölçüm, seksen
turda iki yüz kırk okuma ve olay olmasa bile aynı iki yüz kırk okuma.

Tablonun son satırı devrin sessiz yanını taşır. Elle işletim yalnız olay olduğunda okur — olay
başına beş adım — denetleyici ise turların hepsinde okur. Kırk sekiz aşım turu için ödenen bedel
iki yüz kırk okumadır ve bunun büyük kısmı hiçbir şeyin değişmediği turlarda toplanmıştır. Kararı
devretmek, kararın dayandığı bilgiyi **olay yokken de** üretmeyi zorunlu kılar.

Yanlış kararın kaynağı tek bir yerdedir: **denetleyici hedef servisin bakım durumunu okumaz.**
Okumadığı için "gecikme yüksek" ile "gecikmenin nedeni bende" arasını ayıramaz ve elindeki bütün
aletleri sırayla dener. Bir kararı devretmek, o kararın dayandığı bütün bilgi kalemlerini sürekli ve
zamanında üretmeyi gerektirir; eksik bir kalem düzeltmeyi durdurmaz, yalnızca **yanlış yöne**
çevirir.

#### Özet

- Denetleyici ilk turda 2 iş yaptı, ikinci turda 0 iş yaptı; her turda gerçek durumu yeniden okur
  ve ne yaptığını hatırlamaz.
- Elle işletimde bir olay 9 adım ve 34 dakika, denetleyicide 2 tur; olay ikinci kez olduğunda elle
  maliyet aynen tekrarlanır, denetleyicide tekrarlanmaz.
- Kodlanmış işletim bilgisi 5 maddedir; 2'si bildirimden okunur, 3'ü yalnız işleten kişinin
  bilgisidir.
- Kodlanmamış tek madde 80 turda 56 işlem, 12 yeniden başlatma ve `4 5 6 4 5 6` biçiminde üç
  turluk bir salınım üretti; yeniden deneme aralığı ikiye katlanınca işlem 22'ye, yeniden başlatma
  3'e indi.
- Altıncı madde eklenince işlem 10'a, yeniden başlatma 0'a indi ama aşım turu 48'den 46'ya
  değişti: kazanılan şey olayın süresi değil, olaya eklenen 440 okumalık zarardır.

#### Sonraki Adım

Bu dersin bütün sayıları tek bir hattın seksen turluk izinden çıktı ve o izi tutan şey ölçümdü:
tur başına üç kalem, toplam iki yüz kırk okuma. Kümede bir değil yüzlerce kaynak vardır ve her
birinin denetleyicisi aynı okumayı yapar. Bir sonraki ders bu okumaların toplanmasını ölçer: kaç
kaynak, kaynak başına kaç seri, saklama süresiyle çarpıldığında kaç kayıt ve kaç bayt. Etiket
kardinalitesi arttığında seri sayısının neden toplamsal değil çarpımsal büyüdüğü ve örnekleme ile
toplulaştırma uygulandığında kaybedilen ayrıntı ile kazanılan baytın birlikte ne kadar olduğu orada
sayılır.

### Küme Gözlemlenebilirliği

Source: https://academia.sh/tr/kurslar/orkestrasyon/kume-gozlemlenebilirligi

Küme ölçeğinde günlük, ölçüt ve iz toplamanın bedeli sayılır: kaç kaynak, kaynak başına kaç seri, saklama süresiyle çarpıldığında kaç kayıt ve kaç bayt. Etiket kardinalitesi arttığında seri sayısının çarpımsal büyümesi gösterilir; örnekleme ve toplulaştırma uygulandığında kazanılan bayt ile kaybedilen ayrıntı birlikte ölçülür.

Bir önceki dersin bütün sayıları tek bir hattın seksen turluk izinden çıktı ve o izi tutan şey
ölçümdü: tur başına üç kalem, toplam iki yüz kırk okuma. Kümede bir değil onlarca kaynak vardır ve
her birinin denetleyicisi aynı okumayı yapar. Ölçümün kendisi de bir yük olur.

Bu ders ölçütün ne olduğunu tartışmaz — sayaç, ölçer ve dağılım M16/K07'de kuruldu ve burada
yalnız adlarıyla geçer. Ölçülen tek şey **küme ölçeğinde toplama bedelidir**: kaç kaynak, kaynak
başına kaç seri, saklama süresiyle çarpıldığında kaç kayıt ve kaç bayt. Devredilen karar da
buradan çıkar: **hangi sorunun sonradan yanıtlanabilir kalacağına** toplama anında karar verilir ve
bu karar geri alınamaz, çünkü toplanmayan ayrıntı hiçbir yerde durmaz.

Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**; gerçek küme koşturulmaz, sayılan şey
`node` ile kurulmuş bir **modeldir**.

**OI49.** Küme envanteri kurgudur: beş uygulamaya ait 34 kapsül ve 9 düğüm.
**OI50.** Ölçüt türleri M16/K07'de kuruldu; burada yalnız adıyla anılır.
**OI51.** Bir kayıt 16 bayttır (zaman damgası 8, değer 8), bir seri künyesi 120 bayttır; örnekleme
aralığı 15 saniye, saklama süresi 30 gündür.
**OI52.** Seri sayısı, kaynak sayısı ile ölçüt başına etiket kardinalitelerinin çarpımının
toplamıdır.
**OI53.** Gecikme sinyali kendi üretecimizle üretilir, tohum `20260801`; on iki ani **önceden
yazılıdır**.
**OI54.** On iki işletim sorusu ve her birinin gerektirdiği etiket önceden yazılıdır.

#### Küme Ölçeğinde Seri Aritmetiği

```js
// kume.mjs — kume envanteri, olcut tanimlari ve seri / kayit / bayt aritmetigi.
export const KAYNAK = { kapsul: 34, dugum: 9 };      // bes uygulama, 34 kapsul, 9 dugum
export const ORNEKLEME_SN = 15, SAKLAMA_GUN = 30;
export const KAYIT_BAYT = 16, SERI_BAYT = 120;       // zaman damgasi 8 + deger 8; seri kunyesi 120

export const OLCUT = {                               // ad: [tur, { etiket: kardinalite }]
  kapsul: [
    ["istek-sayisi", "sayac", { yol: 12, yontem: 3, sonuc: 4 }],
    ["istek-suresi", "dagilim", { yol: 12, kova: 12 }],
    ["kuyruk-boyu", "olcer", {}],
    ["islenen-okuma", "sayac", { hat: 4 }],
    ["bellek-kullanimi", "olcer", {}],
  ],
  dugum: [
    ["dugum-cpu", "olcer", { cekirdek: 8 }],
    ["dugum-bellek", "olcer", {}],
    ["disk-io", "sayac", { aygit: 3, yon: 2 }],
  ],
};

export const seriSayisi = (olcut, kaynak = KAYNAK) => Object.entries(olcut).reduce((t, [tur, liste]) =>
  t + kaynak[tur] * liste.reduce((s, [, , e]) =>
    s + Object.values(e).reduce((c, k) => c * k, 1), 0), 0);
export const etiketDusur = (olcut, ad) => Object.fromEntries(Object.entries(olcut).map(([t, l]) =>
  [t, l.map(([a, tur, e]) => [a, tur, Object.fromEntries(Object.entries(e).filter(([k]) => k !== ad))])]));

export const kayit = (seri, aralik = ORNEKLEME_SN, gun = SAKLAMA_GUN) =>
  seri * Math.floor(86400 / aralik) * gun;
export const bayt = (seri, aralik = ORNEKLEME_SN, gun = SAKLAMA_GUN) =>
  kayit(seri, aralik, gun) * KAYIT_BAYT + seri * SERI_BAYT;
export const gb = (b) => (b / 1024 ** 3).toFixed(1);

// etiket eklemek: ilgili olcutun seri sayisini carpar
export const etiketEkle = (olcut, hedef, ad, kardinalite) =>
  Object.fromEntries(Object.entries(olcut).map(([t, l]) => [t, l.map(([a, tur, e]) =>
    hedef.includes(a) ? [a, tur, { ...e, [ad]: kardinalite }] : [a, tur, e])]));
```

```js
// olc.mjs — kume olceginde toplama bedeli ve etiket kardinalitesinin carpimsal buyumesi.
import { KAYNAK, OLCUT, ORNEKLEME_SN, SAKLAMA_GUN, seriSayisi, kayit, bayt, gb, etiketEkle } from "./kume.mjs";

const seri = seriSayisi(OLCUT);
const carp = (l) => l.reduce((s, [, , e]) => s + Object.values(e).reduce((c, k) => c * k, 1), 0);
console.log(`kaynak ${KAYNAK.kapsul + KAYNAK.dugum} (kapsul ${KAYNAK.kapsul}, dugum ${KAYNAK.dugum})` +
  `   kapsul basina seri ${carp(OLCUT.kapsul)}   dugum basina seri ${carp(OLCUT.dugum)}   toplam seri ${seri}`);
console.log(`ornekleme ${ORNEKLEME_SN} sn, saklama ${SAKLAMA_GUN} gun` +
  ` -> kayit ${kayit(seri).toLocaleString("tr-TR")}   bayt ${gb(bayt(seri))} GB`);

console.log("\netiket eklendikce (yalniz adi gecen olcutlere)");
console.log("eklenen etiket                     toplam seri   carpan   kayit          GB");
const yaz = (ad, oo) => {
  const s = seriSayisi(oo);
  console.log(`${ad.padEnd(34)} ${String(s).padStart(9)}   ${(s / seri).toFixed(1).padStart(6)}` +
    `   ${kayit(s).toLocaleString("tr-TR").padStart(13)}  ${gb(bayt(s)).padStart(7)}`);
  return oo;
};
let o = yaz("taban", OLCUT);
o = yaz("+ bolge (7) istek olcutlerine", etiketEkle(o, ["istek-sayisi", "istek-suresi"], "bolge", 7));
o = yaz("+ sayac-tipi (23) islenen-okumaya", etiketEkle(o, ["islenen-okuma"], "sayac-tipi", 23));
o = yaz("+ surum (4) butun kapsul olcutlerine", etiketEkle(o, OLCUT.kapsul.map(([a]) => a), "surum", 4));
yaz("+ istek-kimligi (5000) sureye", etiketEkle(o, ["istek-suresi"], "istek-kimligi", 5000));

const gun = SAKLAMA_GUN * 86400;                     // uc sinyalin ayni kumede otuz gunluk bedeli
const SINYAL = [["olcut  (15 sn ornekleme)", kayit(seri) * 16],
  ["gunluk (kapsul basina 12 satir/sn, 180 bayt)", KAYNAK.kapsul * 12 * 180 * gun],
  ["iz     (220 istek/sn, 6 aralik, 260 bayt)", 220 * 6 * 260 * gun],
  ["iz     (yuzde bir orneklemeyle)", (220 * 6 * 260 * gun) / 100]];
console.log("\nuc sinyalin otuz gunluk toplama bedeli");
for (const [ad, b] of SINYAL) console.log(`  ${ad.padEnd(44)} ${gb(b).padStart(9)} GB`);
```

```
kaynak 43 (kapsul 34, dugum 9)   kapsul basina seri 294   dugum basina seri 15   toplam seri 10131
ornekleme 15 sn, saklama 30 gun -> kayit 1.750.636.800   bayt 26.1 GB

etiket eklendikce (yalniz adi gecen olcutlere)
eklenen etiket                     toplam seri   carpan   kayit          GB
taban                                  10131      1.0   1.750.636.800     26.1
+ bolge (7) istek olcutlerine          68883      6.8   11.902.982.400    177.4
+ sayac-tipi (23) islenen-okumaya      71875      7.1   12.420.000.000    185.1
+ surum (4) butun kapsul olcutlerine    287095     28.3   49.610.016.000    739.3
+ istek-kimligi (5000) sureye      685590007   67672.5   118.469.953.209.600  1765416.5

uc sinyalin otuz gunluk toplama bedeli
  olcut  (15 sn ornekleme)                          26.1 GB
  gunluk (kapsul basina 12 satir/sn, 180 bayt)     177.3 GB
  iz     (220 istek/sn, 6 aralik, 260 bayt)        828.5 GB
  iz     (yuzde bir orneklemeyle)                    8.3 GB
```

Kırk üç kaynak, kapsül başına iki yüz doksan dört seri, düğüm başına on beş seri — toplam **on bin
yüz otuz bir seri**. Otuz günlük saklamada bir milyar yedi yüz elli milyon kayıt ve yirmi altı
gigabayt. Bu, hiçbir etiketin eklenmediği taban durumdur ve kaynak sayısı otuz dörtte kaldığı
sürece doğrusal büyür: kapsül sayısı ikiye katlanırsa seri de ikiye katlanır.

Etiket eklemek doğrusal değildir. **Bölge** etiketinin yedi değeri iki ölçüte eklendiğinde seri on
binden altmış dokuz bine çıkar — kaynak sayısı değişmemiştir, eklenen bilgi yedi ayrı değerdir, ama
sonuç 6,8 katıdır. Nedeni tek satırdadır: bir ölçütün seri sayısı etiketlerinin kardinalitelerinin
**çarpımıdır**. `istek-sayisi` ölçütü zaten on iki yol, üç yöntem ve dört sonuç taşıyordu; yedi
bölge eklenince yüz kırk dört seri bin sekiz seriye çıkar.

Son iki satır sınırı gösterir. Sürüm etiketi bütün kapsül ölçütlerine eklendiğinde toplam yirmi
sekiz katına, yedi yüz otuz dokuz gigabayta çıkar. İstek kimliği — beş bin ayrı değer — tek bir
ölçüte eklendiğinde seri altı yüz seksen beş milyona, saklama bir buçuk petabayt mertebesine çıkar.
Bu satır bir öneri değil, bir **sınır işaretidir**: sınırsız kardinaliteli bir alan etiket olarak
kullanıldığında ölçüt deposu kayıt deposuna dönüşür.

Üç sinyalin karşılaştırması da bedelin nerede yattığını gösterir. Aynı kümede ölçüt yirmi altı,
günlük yüz yetmiş yedi, iz sekiz yüz yirmi sekiz gigabayttır. İz en pahalısıdır, çünkü tek tek
isteği taşır; yüzde bir örneklemeyle sekiz gigabayta iner ve o an her yüz istekten doksan
dokuzunun yolu kaybolur.

#### Örnekleme ve Toplulaştırma

```js
// orneklem.mjs — ornekleme ve toplulastirmada kaybedilen ayrinti ile kazanilan bayt birlikte sayilir.
import { KAYNAK, OLCUT, seriSayisi, etiketDusur, bayt, gb } from "./kume.mjs";

const uretec = (t) => () => (t = (t * 1103515245 + 12345) % 2147483648) / 2147483648;
const rast = uretec(20260801);                       // tohum gorunur
const ANI = [180, 420, 655, 900, 1210, 1480, 1755, 2010, 2290, 2640, 2980, 3310];
const sn = Array.from({ length: 3600 }, (_, i) => 118 + Math.round(rast() * 8) +
  (ANI.some((a) => i >= a && i < a + 20) ? 780 : 0));

console.log(`bir saatlik gecikme sinyali: 3600 saniye, ${ANI.length} ani (her biri 20 sn, +780 ms)`);
console.log("aralik   ornek   yakalanan ani   gorulen tepe   seri basina kayit/gun   toplam GB");
const seri = seriSayisi(OLCUT);
for (const k of [1, 15, 60, 300]) {
  const idx = [...sn.keys()].filter((i) => i % k === 0);
  const yakalanan = ANI.filter((a) => idx.some((i) => i >= a && i < a + 20 && sn[i] > 500)).length;
  const tepe = Math.max(...idx.map((i) => sn[i]));
  console.log(`${String(k).padStart(4)} sn ${String(idx.length).padStart(7)}` +
    `${String(`${yakalanan}/${ANI.length}`).padStart(14)}${String(`${tepe} ms`).padStart(15)}` +
    `${String(Math.floor(86400 / k)).padStart(24)}${gb(bayt(seri, k)).padStart(12)}`);
}

const SORU = [["hangi yol yavasladi", ["yol"]], ["hangi yontem hata veriyor", ["yontem"]],
  ["hangi sonuc kodu artti", ["sonuc"]], ["gecikmenin ust dilimi", ["kova"]],
  ["hangi hat geride kaldi", ["hat"]], ["hangi kapsul bellek tuketiyor", ["kaynak"]],
  ["hangi cekirdek doldu", ["cekirdek"]], ["toplam istek sayisi", []],
  ["hangi uygulama yavas", []], ["hangi kapsul yeniden basladi", ["kaynak"]],
  ["hangi yolda hangi sonuc", ["yol", "sonuc"]], ["disk yonu okuma mi yazma mi", ["yon"]]];

console.log("\ntoplulastirma            seri   GB   yanitlanan soru   kaybedilen ayrinti");
const duzey = [["yok", [], KAYNAK], ["kova dusuruldu", ["kova"], KAYNAK],
  ["+ yol dusuruldu", ["kova", "yol"], KAYNAK],
  ["+ kapsul uygulamaya toplandi", ["kova", "yol", "kaynak"], { kapsul: 5, dugum: 9 }]];
for (const [ad, dusen, kaynak] of duzey) {
  const o = dusen.filter((d) => d !== "kaynak").reduce((x, d) => etiketDusur(x, d), OLCUT);
  const s = seriSayisi(o, kaynak);
  const yanit = SORU.filter((q) => q[1].every((e) => !dusen.includes(e))).length;
  console.log(`${ad.padEnd(30)} ${String(s).padStart(5)} ${gb(bayt(s)).padStart(5)}` +
    `${String(`${yanit}/${SORU.length}`).padStart(15)}   ${dusen.length ? dusen.join(", ") : "-"}`);
}
```

```
bir saatlik gecikme sinyali: 3600 saniye, 12 ani (her biri 20 sn, +780 ms)
aralik   ornek   yakalanan ani   gorulen tepe   seri basina kayit/gun   toplam GB
   1 sn    3600         12/12         906 ms                   86400       391.3
  15 sn     240         12/12         905 ms                    5760        26.1
  60 sn      60          5/12         903 ms                    1440         6.5
 300 sn      12          1/12         903 ms                     288         1.3

toplulastirma            seri   GB   yanitlanan soru   kaybedilen ayrinti
yok                            10131  26.1          12/12   -
kova dusuruldu                  5643  14.5          11/12   kova
+ yol dusuruldu                  781   2.0           9/12   kova, yol
+ kapsul uygulamaya toplandi     230   0.6           7/12   kova, yol, kaynak
```

Örnekleme tablosu iki sütunu yan yana koyar. On beş saniyelik aralık, saniyelik toplamanın on
beşte biri kadar bayt tutar — üç yüz doksan bir gigabayt yerine yirmi altı — ve **on iki aninin
on ikisini de yakalar**, çünkü ani yirmi saniye sürüyor ve on beş saniyelik ızgara her yirmi
saniyelik pencereye en az bir kez düşüyor. Buraya kadar örnekleme bedava görünür.

Altmış saniyeye çıkıldığında bayt dörtte birine, altı buçuk gigabayta iner ve yakalanan ani on
ikiden **beşe** düşer. Üç yüz saniyede bayt bir virgül üç gigabayttır ve on iki aniden yalnız biri
görünür. Kaybın nereden geldiği açıktır: örnekleme aralığı olayın süresini geçtiği anda olayın
görünürlüğü rastlantıya kalır. Görülen tepe değeri üç aralıkta da dokuz yüz milisaniye
civarındadır — yani **yakalanan ani ölçüldüğünde doğru ölçülür** ve kaybolan şey büyüklük değil,
anilerin kaçının hiç görünmediğidir. Ölçütün ortalaması hâlâ doğrudur ve hâlâ yanıltıcıdır.

Toplulaştırma tablosu aynı ikiliği etiket tarafında kurar. Dağılım kovası düşürüldüğünde seri on
binden beş bin altı yüz kırk üçe iner, on iki sorunun on biri yanıtlanabilir kalır — kaybedilen tek
soru gecikmenin üst dilimidir. Yol etiketi de düşürüldüğünde seri yedi yüz seksen bire, bayt iki
gigabayta iner ve iki soru daha kapanır. Kapsüller uygulamaya toplandığında seri iki yüz otuza, bayt
altı yüz megabayta iner; artık hangi kapsülün belleği tükettiği ya da hangisinin yeniden başladığı
sorulamaz.

Üç adımın getirisi eşit değildir. İlk adım 11,6 gigabayt kazandırır ve bir soruya mal olur; ikinci
adım 12,5 gigabayt kazandırır ve iki soruya; üçüncü adım yalnız 1,4 gigabayt kazandırır ve yine iki
soruya. Soru başına kazanç 11,6'dan 6,3'e, oradan 0,7 gigabayta iner. Ucuz olan, **çarpımın büyük
çarpanını** düşürmektir — on iki kovalı dağılım ve on iki yollu ayrım. O iki çarpan gittikten sonra
kalan seriler zaten azdır ve her ek toplulaştırma neredeyse bedava bayt karşılığında soru kapatır.

#### Devrin Bilançosu

| Ölçü | Değer |
|---|---|
| kaynak | 43 (34 kapsül, 9 düğüm) |
| kapsül / düğüm başına seri | 294 / 15 |
| toplam seri, kayıt, bayt (15 sn, 30 gün) | 10.131 / 1,75 milyar / 26,1 GB |
| bir etiket (7 değer) iki ölçüte eklenince | seri 6,8 kat, bayt 177,4 GB |
| sınırsız kardinaliteli etiket (5000 değer) | seri 67.672 kat |
| ölçüt / günlük / iz (30 gün) | 26,1 / 177,3 / 828,5 GB |
| örnekleme 15 → 60 sn | bayt 26,1 → 6,5 GB, yakalanan ani 12/12 → 5/12 |
| toplulaştırma üç adım | bayt 26,1 → 0,6 GB, yanıtlanan soru 12/12 → 7/12 |

Devredilen karar şudur: **hangi sorunun sonradan yanıtlanabileceğine, soru sorulmadan önce karar
verilir.** Gereken bilgi kalemleri de sayılıdır — hangi ölçüt, hangi etiketler, hangi aralık, ne
kadar saklama. Bilginin maliyeti dört sayının çarpımıdır ve çarpımdaki tek bir kalemin değişmesi
sonucu kat kat büyütür.

Sistemin bilmediği şeyin ne yaptığı da tablodadır ve bu kez sessizdir. Altmış saniyelik örnekleme
kurulduğunda hiçbir uyarı çıkmaz; yedi ani hiç görünmediği için **görünmedikleri de görünmez**.
Kapsül etiketi düşürüldüğünde sorgu hata vermez, yalnız uygulama düzeyinde bir sayı döndürür. Bu iki
kayıp, kararın devredildiği andan aylar sonra ve ancak o soru gerçekten sorulduğunda fark edilir;
o an geriye dönüp toplanmamış veriyi almanın yolu yoktur.

#### Özet

- 43 kaynak, kapsül başına 294 ve düğüm başına 15 seri; toplam 10.131 seri, 30 günde 1,75 milyar
  kayıt ve 26,1 GB.
- Bir ölçütün seri sayısı etiket kardinalitelerinin çarpımıdır: 7 değerli bir etiket iki ölçüte
  eklenince toplam 6,8 kat, 4 değerli bir etiket bütün kapsül ölçütlerine eklenince 28,3 kat büyür.
- 5000 değerli bir alan etiket yapıldığında seri 67.672 kata çıkar; sınırsız kardinalite ölçüt
  deposunu kayıt deposuna çevirir.
- Aynı kümede 30 günlük bedel ölçütte 26,1, günlükte 177,3, izde 828,5 GB; yüzde bir örnekleme izi
  8,3 GB'a indirir ve her 100 isteğin 99'unun yolunu siler.
- Örnekleme 15'ten 60 saniyeye çıkınca bayt 26,1'den 6,5 GB'a, yakalanan ani 12/12'den 5/12'ye
  iner; üç toplulaştırma adımı baytı 0,6 GB'a indirirken yanıtlanan soruyu 12/12'den 7/12'ye
  düşürür.

#### Sonraki Adım

Buraya kadarki bütün ölçümler **tek küme** üzerindeydi: tek bir denetim düzlemi, tek bir kaynak
envanteri, tek bir seri deposu. Bölgesel ölçüm ağının üretimi iki bölgede koşuyor ve her bölgenin
kendi kümesi var — aynı dağıtım paketi, aynı kaynak türü, aynı denetleyici, ayrı denetim düzlemleri.
Bir sonraki ders bu çoğalmanın bedelini sayar: aynı istenen durumun kaç kümeye kaç ayrı yoldan
ulaştığı, kümeler arasındaki sapmanın nasıl ölçüldüğü ve bir kararın tek kümede değil küme
kümesinde verilmesi gerektiğinde hangi bilgi kaleminin kimden geleceği.

### Çoklu Küme Yönetimi

Source: https://academia.sh/tr/kurslar/orkestrasyon/coklu-kume-yonetimi

Bölge ve ortam ayrımı sayıya bağlanır: her ayrım ekseni için küme sayısı, sabit işletim saati, sürüm yükseltme penceresi ve patlama yarıçapı birlikte ölçülür. İstenen durum tek yerden çok kümeye dağıtıldığında yayılma penceresi, kısmi başarı ve sapan küme sayılır; iş yükünü kümelere dağıtan bir üst katman modellenip neyi bilmediği için hangi yanlış kararı verdiği gösterilir.

Bir önceki dersin bütün sayıları **tek bir kümeye** aitti. Küme tek bir arıza birimidir — tek
denetim düzlemi, tek durum deposu, tek yükseltme takvimi — ve bu konunun ikinci dersi düzlemin
tamamı düştüğünde kümenin çalışmayı sürdürüp **karar veremez** hâle geldiğini ölçmüştü.

**Çok kümeli işletim** iş yükünü birden çok küme arasında bölmektir; ekseni ortam, bölge ya da
kiracıdır. Devredilen karar bir üst kata çıkar: **bir iş yükünün hangi kümede koşacağına** insan
değil bir üst katman karar verir. Ölçüm yine **bölgesel ölçüm ağı** üzerindedir ve **kurgudur**;
gerçek küme koşturulmaz, sayılan şey `node` ile kurulmuş bir **modeldir**.

**OI55.** İş yükü on sekiz hücreye ayrılır: üç ortam, iki bölge, üç kiracı.
**OI56.** İşletim saatleri `kume-mimarisi` konusundan girdidir: küme başına aylık 67 saat, iş
yüküne ait 39 saat, otuz altı ayda küme başına 3 pencere.
**OI57.** İstenen durum tek depodadır; her küme 15 turluk kendi periyoduyla çeker. Çekme anı ve ağ
gecikmesi **önceden yazılıdır**.
**OI58.** Altı kümede birinin kabul denetimi yeni bildirimi reddeder; o küme sapan kalır.
**OI59.** Üst katman modeli 24 iş yükü ve 6 küme taşır; tohum `20260901` çıktıda görünür.
**OI60.** Sonuç üç sınıfa ayrılır: doğru karar, yanlış karar, karar verememe.

#### Ayrım Ekseni, Yayılma ve Arıza Sınıfı

```js
// bolme.mjs — 18 is yuku hucresi farkli eksenlerde bolunur; sabit maliyet, yayilma, ariza sinifi.
const ORTAM = 3, BOLGE = 2, HUCRE = ORTAM * BOLGE * 3;
const KUME_SAAT = 67, YUK_SAAT = 39, YUKSELTME = 3;   // 33+34 kume basina, 39 is yukune ait
const AYRIM = [["tek kume", 1], ["bolge", BOLGE], ["ortam", ORTAM],
  ["ortam x bolge", ORTAM * BOLGE], ["ortam x bolge x kiraci", HUCRE]];
const p = (x, n) => String(x).padStart(n);

console.log(`${HUCRE} hucre = ${ORTAM} ortam x ${BOLGE} bolge x 3 kiraci`);
console.log("ayrim           kume  hucre  patlama  saat/ay  36 ayda pencere");
for (const [ad, n] of AYRIM) {
  const h = Math.ceil(HUCRE / n);
  console.log(ad.padEnd(24) + p(n, 4) + p(h, 7) + p(`%${((100 * h) / HUCRE).toFixed(1)}`, 9) +
    p(YUK_SAAT + n * KUME_SAAT, 12) + p(n * YUKSELTME, 17));
}

const TUR = 120, U = 15, YAYIN = 10, OKUMA = 26;   // 26: bos dogrulama turunun okumasi
const ofset = (i) => (i * 4) % U, ag = (i) => [0, 1, 2, 1, 2, 0][i % 6];   // onceden yazili
const RED = 3;                                    // bu kumenin kabul denetimi reddediyor
function yayilma(n) {
  const alma = [...Array(n).keys()].map((i) => {
    if (i % 6 === RED) return null;                          // sapan kume: hic uygulayamiyor
    let t = YAYIN;
    while ((t - ofset(i)) % U !== 0) t++;
    return t + ag(i);
  });
  const g = alma.filter((x) => x !== null);
  const kismi = [...Array(TUR - YAYIN).keys()]
    .filter((k) => { const y = g.filter((x) => x <= YAYIN + k).length; return y > 0 && y < n; }).length;
  const tur = n * Math.floor(TUR / U);
  return [Math.min(...g), Math.max(...g), kismi, n - g.length, tur, tur * OKUMA];
}
console.log("\nistenen durum tek depoda; degisiklik 10. turda, periyot 15 tur");
console.log("kume  ilk  son  pencere  kismi tur  sapan  uzlasma turu  okuma");
for (const [, n] of AYRIM) {
  const [i, s, k, sp, t, o] = yayilma(n);
  console.log(p(n, 4) + p(i, 5) + p(s, 5) + p(s - i, 9) + p(k, 19) + p(sp, 7) + p(t, 14) + p(o, 16));
}

const ARIZA = [["denetim duzlemi", 1], ["dugum kaybi", 1], ["surum yukseltme", 1],
  ["kabul kurali degisikligi", 1], ["hatali bildirim", 0], ["paylasilan veri deposu", 0]];
const yal = ARIZA.filter((a) => a[1]);
console.log(`\nariza sinifi ${ARIZA.length}: bolunmeyle yalitilan ${yal.length} (etkilenen hucre ${HUCRE}` +
  ` -> ${HUCRE / 2}); yalitilmayan ${ARIZA.length - yal.length} — ` +
  ARIZA.filter((a) => !a[1]).map((a) => a[0]).join(", ") + ` — iki kumede de ${HUCRE}/${HUCRE}`);
```

```
18 hucre = 3 ortam x 2 bolge x 3 kiraci
ayrim           kume  hucre  patlama  saat/ay  36 ayda pencere
tek kume                   1     18   %100.0         106                3
bolge                      2      9    %50.0         173                6
ortam                      3      6    %33.3         240                9
ortam x bolge              6      3    %16.7         441               18
ortam x bolge x kiraci    18      1     %5.6        1245               54

istenen durum tek depoda; degisiklik 10. turda, periyot 15 tur
kume  ilk  son  pencere  kismi tur  sapan  uzlasma turu  okuma
   1   15   15        0                  0      0             8             208
   2   15   20        5                  5      0            16             416
   3   15   25       10                 10      0            24             624
   6   15   25       10                105      1            48            1248
  18   12   25       13                108      3           144            3744

ariza sinifi 6: bolunmeyle yalitilan 4 (etkilenen hucre 18 -> 9); yalitilmayan 2 — hatali bildirim, paylasilan veri deposu — iki kumede de 18/18
```

Birinci tablonun iki sütunu ters yöne gider. Patlama yarıçapı — bir kümenin kaybında etkilenen
hücre oranı — yüzde yüzden yüzde 5,6'ya iner; aylık sabit saat 106'dan 1.245'e, yükseltme penceresi
üçten elli dörde çıkar. Bölgeye bölmek yarıçapı yüzde elliye ve yükü 173 saate, ortama bölmek yüzde
33,3'e ve 240 saate taşır: fark yalnız eksendir — bölge ekseni arıza, ortam ekseni değişiklik
yalıtımı satın alır.

İkinci tabloda yayılma penceresi tek kümede sıfır, altı kümede on turdur ve o on tur boyunca küme
kümesi kısmen yeni, kısmen eskidir. Asıl sayı kısmi başarı sütunundadır: altı kümede on değil
**yüz beştir**, çünkü bir kümenin kabul denetimi bildirimi reddeder. **Sapan tek küme, geçici bir
pencereyi kalıcı bölünmeye çevirir.** Uzlaşma yükü de çarpılır: 208 kalem okuma 3.744'e çıkar.

Son satır çok kümenin **kazandırmadığı** yeri verir: altı arıza sınıfının dördü yalıtılır, ikisi
yalıtılmaz. Paylaşılan veri deposu ile tek depodan çıkıp iki kümeye birden yayılan hatalı bildirim,
on sekiz hücrenin on sekizini durdurmayı sürdürür. **Bölmek arıza birimini böler, veri katmanını
bölmez.**

#### Kararı Bir Üst Katmana Devretmek

```js
// ust-katman.mjs — is yukunun hangi kumeye dusecegine karar veren ust katman ve bilmedigi kalemler.
const HEPSI = ["olcum", "saha", "rapor"];
const KUME = [                            // ad, ortam, bolge, kapasite, kabul ettigi kiracilar
  ["gel-b1", "gelistirme", "b1", 34, HEPSI], ["gel-b2", "gelistirme", "b2", 34, HEPSI],
  ["haz-b1", "hazirlik", "b1", 36, HEPSI], ["haz-b2", "hazirlik", "b2", 36, HEPSI],
  ["ure-b1", "uretim", "b1", 50, ["olcum", "saha"]], ["ure-b2", "uretim", "b2", 26, ["rapor"]]];

const r = ((t) => () => (t = (t * 48271) % 2147483647) / 2147483647)(20260901);   // tohum gorunur
const ORTAM = ["gelistirme", "hazirlik", "uretim"];
const YUK = Array.from({ length: 24 }, (_, i) => ({ ortam: ORTAM[i % 3],
  bolge: r() < 0.5 ? "b1" : "b2", kiraci: HEPSI[Math.floor(r() * 3)], birim: 4 + Math.floor(r() * 9) }));

function kos({ yas = 0, bolgeVar = true, kiraciVar = true }) {
  const dolu = Object.fromEntries(KUME.map(([a]) => [a, 0]));
  let defter = { ...dolu };
  const s = { dogru: 0, red: 0, uzak: 0, ihlal: 0, yok: 0 };
  YUK.forEach((y, i) => {
    if (i % (yas + 1) === 0) defter = { ...dolu };            // defter yas kadar gec tazeleniyor
    let aday = KUME.filter(([, o]) => o === y.ortam);
    if (kiraciVar) aday = aday.filter(([, , , , k]) => k.includes(y.kiraci));
    if (bolgeVar) aday = [...aday].sort((a, b) => (b[2] === y.bolge) - (a[2] === y.bolge));
    const sec = aday.find(([a, , , k]) => defter[a] + y.birim <= k);
    if (!sec) { s.yok++; return; }                             // karar verilemedi
    const [ad, , bolge, kap, kiracilar] = sec;
    if (dolu[ad] + y.birim > kap) { s.red++; return; }         // gercek kapasite yetmedi
    dolu[ad] += y.birim;
    if (!kiracilar.includes(y.kiraci)) s.ihlal++;
    else if (bolge !== y.bolge) s.uzak++;
    else s.dogru++;
  });
  return s;
}

const SENARYO = [["tam bilgi", {}], ["kapasite 8 yerlestirme eski", { yas: 8 }],
  ["veri bolgesi bildirilmemis", { bolgeVar: false }], ["kiraci kisiti bildirilmemis", { kiraciVar: false }],
  ["ucu birden eksik", { yas: 8, bolgeVar: false, kiraciVar: false }]];
const p = (x, n) => String(x).padStart(n);
console.log(`${YUK.length} is yuku, ${KUME.length} kume (3 ortam x 2 bolge); tohum 20260901`);
console.log("senaryo                      dogru  yanlis  verilemedi  dolu  uzak  ihlal");
for (const [ad, se] of SENARYO) {
  const o = kos(se);
  console.log(ad.padEnd(28) + p(o.dogru, 5) + p(o.red + o.uzak + o.ihlal, 8) + p(o.yok, 12) +
    p(o.red, 6) + p(o.uzak, 6) + p(o.ihlal, 7));
}
console.log(`kalem: ${YUK.length} is yuku x 3 + ${KUME.length} kume x 2 = ${YUK.length * 3 + KUME.length * 2}` +
  `; yalnizca kume kapasitesi olcumdur`);
```

```
24 is yuku, 6 kume (3 ortam x 2 bolge); tohum 20260901
senaryo                      dogru  yanlis  verilemedi  dolu  uzak  ihlal
tam bilgi                      18       3           3     0     3      0
kapasite 8 yerlestirme eski    18       6           0     3     3      0
veri bolgesi bildirilmemis     13      10           1     0    10      0
kiraci kisiti bildirilmemis    18       4           2     0     0      4
ucu birden eksik               13      11           0     0     8      3
kalem: 24 is yuku x 3 + 6 kume x 2 = 84; yalnizca kume kapasitesi olcumdur
```

Tam bilgi satırı kusursuz değildir: yirmi dört iş yükünün on sekizi doğru yerleşir, üçü uzak
bölgeye düşer, üçü için karar verilemez — ilki kapasiteden, ikincisi kiracı kısıtından gelir.

Kapasite defterinin yaşlanması tanıdık kaymayı üretir. Defter sekiz yerleştirme eskidiğinde yanlış
karar üçten altıya çıkar ve **karar verememe üçten sıfıra iner**: eskiyen defter havuzu olduğundan
boş gösterir, üst katman "yer yok" demeyi bırakıp dolu kümeyi seçer.

İki bildirim kalemi ayrı ayrı ölçülür. Veri bölgesi bildirilmediğinde doğru karar on üçe iner ve
uzak yerleştirme ona çıkar; hiçbiri reddedilmez, iş yükleri çalışır ve yalnız gecikme sınırını aşar
— **sessiz sınıf**. Kiracı kısıtı bildirilmediğinde dört iş yükü kabul etmeyen kümeye gider ve bu
yanlış gürültülüdür, çünkü kümenin kabul denetimi onu yakalar. Üçü birden eksikken karar verememe
sıfırlanır: **hiçbir şey bilmeyen bir üst katman hiç tereddüt etmez.** Seksen dört kalemin yalnız
altısı ölçümdür.

#### Özet

- 18 hücre 1'den 18 kümeye bölündükçe patlama yarıçapı %100'den %5,6'ya iner; aylık işletim
  106'dan 1.245 saate, yükseltme penceresi 3'ten 54'e çıkar.
- Yayılma penceresi tek kümede 0, altı kümede 10 turdur; reddeden tek bir sapan küme kısmi başarıyı
  105 tura çıkarır. Uzlaşma yükü küme sayısıyla çarpılır: 208 kalem okuma 3.744'e çıkar.
- 6 arıza sınıfının 4'ü bölmeyle yalıtılır; paylaşılan veri deposu ve tek depodan yayılan hatalı
  bildirim iki kümede de 18 hücrenin 18'ini etkiler.
- Üst katman tam bilgiyle 24 iş yükünün 18'ini doğru yerleştirir; kapasite 8 yerleştirme eskidiğinde
  yanlış karar 3'ten 6'ya, karar verememe 3'ten 0'a gider ve veri bölgesi yazılmadığında 10 iş yükü
  sessizce uzak bölgeye düşer.

#### Kurs Kapanışı

| Ders | Devredilen karar | Gereken bilgi ve maliyeti | Yanlış kararın kaynağı |
|---|---|---|---|
| Orkestrasyon İhtiyacı | yerleştirme | 6 kalem, 4'ü ölçüm | yazısız kısıt, 4 yanlış yer |
| Denetim Düzlemi Bileşenleri | isteğin karara dönmesi | 50 okuma, 7 yazma | kayıtsız ölüm, sanılan 3 |
| Düğüm Bileşenleri | düğüm canlı mı | 10 saniyede 19 kalem | eşik, 26 yanlış ölü |
| Uzlaşma Döngüsü | farkın kapatılması | gecikmeli rapor, 0,13 iş/tur | kayıtsız niyet, 32 gereksiz kopya |
| Yerel ve Yönetilen Küme | düzlemin işletimi | 21 kalem, 106 saat | erişim kaybı, 5 ayar yok |
| Kapsül | paketleme sınırı | 3 kalem, biri tahmin | kopya oranı yok, 4 fazla örnek |
| Kopya Kümeleri ve Sürüm Nesneleri | kopya sayısı, geçiş hızı | 1 sayı, 2 ayar | kapsül içi kapalı, 6 boşa |
| Servis Nesneleri | isteğin gideceği kapsül | 3 kalem, 1 tur çözümleme | liste yaşı, 216 bayat istek |
| Dış Erişim | dış isteğin iç servisi | 4 bildirim, 14–36 yüzey | kapsama yazısız, 6 yanlış |
| Yapılandırma ve Sır Nesneleri | ayarın kapsüle ulaşması | 3 bildirim, 3 tur yayılım | okuma anı, 36 bayat |
| Depolama ve Birimler | talep–arz eşlemesi | 76 kalem, 72 bildirim/tur | envanter yaşı, 134 yanlış |
| Durum Bilgili Uygulamalar | hangi kopya hangi veri | kopya başına 3, 15 kalem | ad kalıcı değil, 7 öksüz birim |
| İşler ve Zamanlanmış İşler | bitti mi, yeniden mi | gece başına 4, 120 kalem | süre bilinmez, 5 atlanan gece |
| Ad Alanları ve Kotalar | isteğin kabulü | istek başına 3, 180 kalem | kullanım görünmez, 22 baskı |
| Kaynak İstekleri ve Sınırları | yerleştirme | 42 kalem, 36'sı bildirim | kullanım yok, 5.503 çakışma |
| Zamanlama Kısıtları | uygun düğüm kümesi | 39 kalem, ölçüm yok | yanlış etiket, yerleşen 15 → 16 |
| İşaretler ve Toleranslar | düğüm kimi kabul eder | 27 kalem, doğrulayan yok | fazla tolerans, 3 yabancı kapsül |
| Tahliye ve Öncelikler | baskıda kim çıkar | 17 öncelik, kritiklik 0 | değer ölçülmez, şişiren korunur |
| Yatay Ölçekleme | kopya sayısı | 120 ölçüt, 3 tur eski | kendi kararı görünmez, 510 kopya-tur |
| Dikey ve Küme Ölçekleme | boyut, düğüm sayısı | turda 60 örnek | neden ölçütte yok, 12 fazla olay |
| Dağıtım Kalıpları | ilerle ya da dur | 4 kalem, sürüm etiketi | seyrek ölçüt, 851 istek |
| Sağlık Denetimleri | yeniden başlat, trafiğe aç | 3 denetim, 3 eşik | açılış ayrılmaz, 113 öldürme |
| Rol Tabanlı Erişim Denetimi | isteği kim yapabilir | 1344 hücrenin 43'ü | iz eskir, 28 yükseltme yolu |
| Ağ Politikaları | bağlantı meşru mu | 18 kural ya da 6 | izde yok, 119 gereksiz açık |
| Güvenlik Bağlamı | tanım kabul edilsin mi | tek kalem, tanımın kendisi | beyana bakar, 13 sessiz açık |
| Paketleme ve Şablonlama | nesne kümesini kim yazar | 7 değer, 3 dal | ortaklık yazısız, 3/5 ayrık |
| Özel Kaynak Tanımları | bildirim geçerli mi | 10 alan, 120 alan yükü | şema dar, 4 sessizce yanlış |
| Denetleyici Kalıbı | olaya ne yapılacak | 5 madde, 240 okuma | bakım görünmez, 12 yeniden başlatma |
| Küme Gözlemlenebilirliği | hangi soru yanıtlanır | 10.131 seri, 26,1 GB | toplanmamış ayrıntı, 12'den 5'i |
| Çoklu Küme Yönetimi | iş yükü hangi kümede | 84 kalem, 1.245 saat | eski kapasite, 6 yanlış |

Otuz satır tek bir kuralın örneğidir: **bir kararı devretmek, o kararın dayandığı bilgiyi sürekli ve
zamanında üretmeyi gerektirir; sistemin bilmediği her kalem bir yanlış karar sınıfı üretir.** Son
sütunda dört kaynak tekrar eder. **Eskiyen bilgi** on satırdadır: karar anındaki sayı gerçeğin
gerisindedir ve gecikme büyüdükçe karar verememe yanlış karara dönüşür. **Kapsam dışında kalan
durum** sekiz satırdadır: sistem baktığı yerde doğru davranır ve bakmadığı yerde salınır ya da
sessizce sapar. **Bildirilmemiş kalem** yedi, **doğrulanmayan beyan** beş satırdadır — ve yanlış
yazılmış bir beyan çoğu zaman bir iyileşme gibi görünür. Sistem yanlış kararı bilgisiz olduğu için
değil, **bilebileceği bir kalem bulunmadığı için** verir. Bu kursun ölçü birimi olan **devrin
bedeli** budur: kazanç adım sayısında görünür, bedel bilgi kaleminde birikir.

Geriye tek soru kalır ve **M22/K04 Sürekli Tümleştirme ve Teslimat** onu üstlenir. Küme istenen
durumu uyguluyor: bildirimi okuyor, farkı kapatıyor, kabul denetiminden geçiriyor, yetkiyi sınıyor.
Ama o istenen durumu **kim, neye bakarak ve hangi denetimden geçirerek** değiştiriyor? Otuz
satırdaki bildirim kalemlerinin hepsini bir insan yazıyor; kümenin bütün titizliği, kendisine
verilen bildirimin doğruluğunu hiçbir yerde sınamıyor.

