---
title: 'Trafik Katmanı'
source: 'https://academia.sh/tr/kurslar/trafik-katmani'
language: tr
updated: '2026-08-17T04:43:11+00:00'
license: 'CC BY-SA 4.0'
lessons: 16
outcomes:
    - 'İsteğin kullanıcıdan uygulamaya ulaşana kadarki katmanlarını tasarlar'
    - 'Yük dengeleme ve içerik dağıtımı kararlarını gerekçelendirir'
    - 'Ağ geçidi sorumluluklarını doğru katmana yerleştirir'
---

# Trafik Katmanı

İsteğin kullanıcıdan uygulamaya ulaşana kadar geçtiği durakların tasarlanması: alan adı yönlendirme politikaları ve devralma, kenar önbelleğiyle içerik dağıtımı, itme ve çekme tabanlı yayma, yük dengeleyicinin katman 4 ile katman 7 kararları ve dağıtım algoritmaları, oturum yapışkanlığının ölçekleme maliyeti ve ağ geçidinin kenara aldığı sorumluluklar; her durak, giriş kursunda hesaplanan sayılardan hangisini değiştirdiğiyle birlikte ele alınır.

## Giriş Noktaları

İsteğin sisteme girdiği ilk duraklar: alan adı çözümlemesinin yönlendirme politikası ve devralma aracı olarak kullanılması, kenar önbelleğinin uygulamaya ulaşan istek sayısına etkisi, içeriğin itme ve çekme modelleriyle yayılması ve içerik yolunun uygulama yolundan ayrılması.

### Alan Adı Sistemi Tasarımı

Source: https://academia.sh/tr/kurslar/trafik-katmani/alan-adi-sistemi-tasarimi

Ad çözümlemesinin bir yönlendirme kararı olarak tasarlanması: coğrafi, gecikmeye göre ve ağırlıklı politikaların aynı istek akışında ölçülmesi, ağırlıklı politikanın hedef payı neden tutamadığının çözümleyici payları üzerinden gösterilmesi ve yaşam süresinin devralma penceresini belirlemesiyle düşen isteğin giriş kursunun kesinti bütçesine çevrilmesi.

Sistem Tasarımına Giriş kursu bütün nitelikleri tanımladı, eşikleri koydu ve devralma kalıplarını
seçti. Bir şey eksik kaldı: istek daha sisteme **girmedi**. Takip sorgusu bir alan adının
çözülmesiyle başlar, bir kenar önbelleğinden geçebilir, bir yük dengeleyiciye düşer ve bir ağ
geçidinden uygulamaya ulaşır. O kursta önbellek yalnız hesapta bir çarpandı, yönlendirme ise
modelde tek satırlık bir seçimdi.

Bu kurs o yolu ele alır ve ilk durak ad çözümlemesidir. Alan adı sisteminin kendisi Bilgisayar
Ağları müfredatının İnternet Nasıl Çalışır kursunda kuruldu: hiyerarşi, çözümleme zinciri, kayıt
türleri ve yaşam süresi orada anlatıldı ve burada yeniden anlatılmaz. Buradaki soru başkadır: bir
adın altında birden çok bölge varken **hangi adresin döndürüleceği bir tasarım kararıdır** ve o
kararın ölçülebilir sonuçları vardır.

#### Ad Katmanı Bir Karar Noktasıdır

Yetkili sunucu her sorguya aynı yanıtı vermek zorunda değildir. Sorunun nereden geldiğine ve
bölgelerin durumuna bakarak farklı adres döndürebilir. Bu seçime **yönlendirme politikası** denir
ve üç biçimi ayrılır.

**Coğrafi politika**, soranın bulunduğu bölgeye göre kaba bir tablodan yanıt verir: bu istemci
kümesi şu bölgeye gider. Tablo elle yazılır ve yanlış olabilir. **Gecikmeye göre politika**,
soranın hangi bölgeye daha yakın olduğunu ölçüme dayanarak seçer; coğrafi yakınlıkla ağ yakınlığı
aynı şey olmadığı için iki politika farklı yanıtlar üretir. **Ağırlıklı politika** bölgelere hedef
bir pay verir ve yanıtları o paya göre dağıtır; amacı yakınlık değil kapasite denetimidir.

Bir dördüncü kullanım politika değil arıza yanıtıdır: bir bölge erişilemez olduğunda yetkili
sunucu o bölgenin adresini yanıtlardan çıkarır. Bu **devralma**nın ad katmanındaki biçimidir ve
dersin ikinci yarısı onun bedelini ölçer.

#### Düzenek

Ölçüm bir süreç içi modelle yapılır. Model bir yetkili sunucu, kırk çözümleyici ve üç bölge
tutar; bölgeler Erişilebilirlik Kalıpları dersinin `b34` ve `b35` bölgelerine `b06` eklenerek
kurulur. İstek hızı giriş kursundan gelir: uçta tepe 513,89 istek/s, yukarı yuvarlanarak 514.
Model dört yeni varsayım alır ve bunlar giriş kursunun V1–V13 tablosuna **eklenmez**; bu kursun
kendi varsayımlarıdır.

| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| T1 | yaşam süresi (taban) | 300 sn | ad sahibinin seçtiği süre; ölçümde oynatılır |
| T2 | bölge sayısı | 3 | iki bölgeli devralmaya bir yedek bölge eklenmiştir |
| T3 | hedef pay | 0,50 / 0,30 / 0,20 | eski bölge ağır, yeni bölge hafif yüklenir |
| T4 | çözümleyici sayısı ve payı | 40, pay ~ 1/(j+1) | sorguların çoğu az sayıda büyük çözümleyiciden gelir |
| T5 | ölü bölgenin işaretlenme süresi | 10 sn | sağlık denetimi bir bölgeyi bu gecikmeyle ölü sayar |

Mesafe matrisi soyut birim cinsindendir ve **ölçülmüş gecikme değildir**; giriş kursunun tur
soyutlamasıyla aynı türdendir. Çözümleyicilerin önbellek fazları eşit aralıklarla dağıtılmıştır,
çünkü hepsinin aynı anda süre sonuna gelmesi ayrı bir sorundur ve Eşzamansız İşleme kursunda
sürü etkisi olarak ölçüldü.

```js
// ad/model.mjs — ad katmani modeli. Mesafe soyut birimdir, olculmus gecikme degildir;
// yasam suresi, algilama suresi ve ariza baslangici model parametresidir.
export const BOLGE = ["b34", "b35", "b06"];
export const GRUP = ["g1", "g2", "g3", "g4"];
export const MESAFE = {                       // birim; olculmus gecikme degil
  g1: { b34: 1, b35: 3, b06: 2 }, g2: { b34: 3, b35: 1, b06: 2 },
  g3: { b34: 2, b35: 4, b06: 1 }, g4: { b34: 2, b35: 3, b06: 4 },
};
export const COGRAFI = { g1: "b34", g2: "b35", g3: "b34", g4: "b06" };  // kaba bolge tablosu
export const YEDEK = { b34: "b06", b35: "b34", b06: "b35" };            // tablonun yedegi
export const DESEN = ["b34", "b35", "b06", "b34", "b35", "b34", "b35", "b06", "b34", "b34"];
export const AGIRLIK = { b34: 0.5, b35: 0.3, b06: 0.2 };  // T3: hedef pay, DESEN bunu verir
export const COZUMLEYICI = 40;    // T4
export const ALGILAMA = 10;       // T5: saglik denetiminin olu bolgeyi isaretlemesi (sn)
export const ISTEK_SANIYE = 514;  // K01 "tepe ucta 513,89 istek/s", yukari yuvarlanmis

// T4: cozumleyici paylari esit degil, pay ~ 1/(j+1); saniyedeki istek en buyuk kalanla bolunur.
const ham = Array.from({ length: COZUMLEYICI }, (_, j) => 1 / (j + 1));
const t0 = ham.reduce((a, b) => a + b, 0);
export const ISTEK = ham.map((p) => Math.floor((p / t0) * ISTEK_SANIYE));
for (const [, j] of ham.map((p, j) => [(p / t0) * ISTEK_SANIYE % 1, j]).sort((a, b) => b[0] - a[0])
  .slice(0, ISTEK_SANIYE - ISTEK.reduce((a, b) => a + b, 0))) ISTEK[j] += 1;

export function kosum({ politika, ttl, arizaBaslangic = null, sure = 3600, istek = ISTEK }) {
  const s = { kabul: 0, dusen: 0, yukariSorgu: 0, mesafe: 0, pencere: 0 };
  const bolgeIstek = Object.fromEntries(BOLGE.map((b) => [b, 0]));
  const bagli = new Array(COZUMLEYICI).fill(null);
  // isinma: onbellek fazlari esit araliklarla dagitilir, sayim t >= 1'de baslar
  const sonaErer = Array.from({ length: COZUMLEYICI }, (_, j) => 1 - ttl + ((j * 13) % ttl));
  let desenSira = 0;
  const olu = (b, t) => arizaBaslangic !== null && b === "b34" && t >= arizaBaslangic;
  const bilinen = (b, t) => olu(b, t) && t >= arizaBaslangic + ALGILAMA;

  const yetkili = (grup, t) => {
    if (politika === "cografi") {
      const b = COGRAFI[grup];
      return bilinen(b, t) ? YEDEK[b] : b;
    }
    if (politika === "gecikmeye-gore") {
      return BOLGE.filter((b) => !bilinen(b, t))
        .reduce((a, b) => (MESAFE[grup][b] < MESAFE[grup][a] ? b : a));
    }
    for (let k = 0; k < DESEN.length; k++) {         // agirlikli: desende siradaki canli bolge
      const b = DESEN[(desenSira + k) % DESEN.length];
      if (!bilinen(b, t)) { desenSira = (desenSira + k + 1) % DESEN.length; return b; }
    }
  };

  for (let t = 1 - ttl; t <= sure; t++) {
    for (let j = 0; j < COZUMLEYICI; j++) {
      if (t >= sonaErer[j]) {                       // yasam suresi doldu: yetkiliye sorulur
        bagli[j] = yetkili(GRUP[j % GRUP.length], t);
        sonaErer[j] = t + ttl;
        if (t >= 1) s.yukariSorgu += 1;
      }
      if (t < 1) continue;
      const n = istek[j], hedef = bagli[j];
      if (olu(hedef, t)) { s.dusen += n; s.pencere = t - arizaBaslangic + 1; continue; }
      s.kabul += n;
      s.mesafe += n * MESAFE[GRUP[j % GRUP.length]][hedef];
      bolgeIstek[hedef] += n;
    }
  }
  const pay = Object.fromEntries(BOLGE.map((b) => [b, bolgeIstek[b] / s.kabul]));
  const sapma = BOLGE.reduce((a, b) => a + Math.abs(pay[b] - AGIRLIK[b]), 0) / 2;
  return { ...s, pay, sapma, birimMesafe: s.mesafe / s.kabul };
}
```

#### Üç Politika Aynı Akışta

```js
// ad/politika.mjs — uc yonlendirme politikasi ayni istek akisinda: bolge payi, hedef paydan
// sapma, istek basina mesafe birimi ve cozumleyicilerin yetkiliye sordugu ad sayisi
import { kosum, ISTEK, ISTEK_SANIYE, AGIRLIK, BOLGE } from "./model.mjs";

const TTL = 300, SURE = 3600;
console.log(`${SURE} sn, ${ISTEK_SANIYE} istek/s, yasam suresi ${TTL} sn, ` +
  `en buyuk cozumleyicinin payi %${((ISTEK[0] / ISTEK_SANIYE) * 100).toFixed(2)}`);
console.log(`hedef pay: ${BOLGE.map((b) => `${b}=%${AGIRLIK[b] * 100}`).join(" ")}`);
console.log();
console.log("politika        |   b34   b35   b06 | sapma | birim mesafe | yukari sorgu");
console.log("----------------|-------------------|-------|--------------|-------------");
for (const politika of ["cografi", "gecikmeye-gore", "agirlikli"]) {
  const r = kosum({ politika, ttl: TTL, sure: SURE });
  console.log(`${politika.padEnd(15)} |` +
    `${BOLGE.map((b) => `%${(r.pay[b] * 100).toFixed(1)}`.padStart(6)).join("")} | ` +
    `${r.sapma.toFixed(3).padStart(5)} | ${r.birimMesafe.toFixed(3).padStart(12)} | ` +
    `${String(r.yukariSorgu).padStart(12)}`);
}
console.log();
for (const ttl of [30, 60, 300, 900]) {
  const r = kosum({ politika: "agirlikli", ttl, sure: SURE });
  console.log(`agirlikli, ttl ${String(ttl).padStart(3)} sn -> sapma ${r.sapma.toFixed(3)}, ` +
    `yukari sorgu ${String(r.yukariSorgu).padStart(4)}`);
}

// T4'un duyarliligi: cozumleyici paylari esit olsa ayni politika ne kadar sapardi
const ESIT = Array.from({ length: 40 }, (_, j) => (j < 34 ? 13 : 12));   // toplam 514
const e = kosum({ politika: "agirlikli", ttl: TTL, sure: SURE, istek: ESIT });
console.log(`\nT4 duyarliligi: paylar esit olsa (ttl ${TTL}) sapma ${e.sapma.toFixed(3)}`);
```

```
3600 sn, 514 istek/s, yasam suresi 300 sn, en buyuk cozumleyicinin payi %23.35
hedef pay: b34=%50 b35=%30 b06=%20

politika        |   b34   b35   b06 | sapma | birim mesafe | yukari sorgu
----------------|-------------------|-------|--------------|-------------
cografi         | %57.6 %25.3 %17.1 | 0.076 |        1.710 |          480
gecikmeye-gore  | %55.1 %25.3 %19.6 | 0.051 |        1.171 |          480
agirlikli       | %50.6 %27.8 %21.6 | 0.022 |        2.144 |          480

agirlikli, ttl  30 sn -> sapma 0.082, yukari sorgu 4800
agirlikli, ttl  60 sn -> sapma 0.195, yukari sorgu 2400
agirlikli, ttl 300 sn -> sapma 0.022, yukari sorgu  480
agirlikli, ttl 900 sn -> sapma 0.037, yukari sorgu  160

T4 duyarliligi: paylar esit olsa (ttl 300) sapma 0.000
```

Sayılar **ölçüm** sınıfındadır: bu makinede koşan modelden çıkmıştır. Mesafe birimi model
parametresine bağlıdır, istek sayıları ise değildir.

Birinci tablo iki ölçütün ters yönde çalıştığını gösteriyor. Gecikmeye göre politika istek başına
1,171 mesafe birimiyle en yakın yerleşimi buluyor; coğrafi politika 1,710, ağırlıklı politika
2,144. Ağırlıklı politika en yakını arayan politikanın 1,83 katı mesafe üretiyor — bu oran birim
seçiminden bağımsızdır, çünkü iki koşum aynı matrisi kullanır. Karşılığında hedef paya en yakın
dağılımı o veriyor: sapma 0,022, coğrafi politikada 0,076. **Yakınlık ile pay denetimi aynı
politikada birlikte elde edilmiyor.**

Coğrafi politikanın 1,710'u tablonun elle yazılmasından geliyor. Dört istemci kümesinden ikisinde
tablo en yakın bölgeyi göstermiyor: `g3` kümesi için tablo `b34` diyor, matriste en yakın bölge
`b06`; `g4` için tablo `b06` diyor, en yakın `b34`. Coğrafi yakınlık ile ağ yakınlığı ayrıştığında
politika sessizce yanlış bölgeye gönderiyor ve bu ancak ölçülerek görülüyor.

İkinci tablo ağırlıklı politikanın asıl sorununu açıyor. Yaşam süresi kısaldıkça sapma
düzelmiyor: 0,082, 0,195, 0,022, 0,037 sırasıyla — düzensiz salınıyor. Buna karşılık yukarı sorgu
sayısı 160'tan 4800'e, otuz kata çıkıyor. Yani kısa yaşam süresi ödenen bedeli otuza katlıyor ve
karşılığında hedef paya yaklaşmayı sağlamıyor.

Son satır nedeni veriyor. Çözümleyici payları eşitlendiğinde aynı politikanın sapması 0,000'a
iniyor. Sapma yaşam süresinden değil, **denetim biriminin yanlış olmasından** geliyor: politika
payı *çözümleme* başına dağıtıyor, oysa yük *istek* başına geliyor. En büyük çözümleyici tek
başına isteklerin yüzde 23,35'ini taşıyor; bu, `b06` bölgesinin yüzde 20'lik hedef payının
tamamından büyüktür. O çözümleyici hangi bölgeye bağlanırsa o bölge hedefini aşar. Ad katmanı
istek düzeyinde bir denetim aracı değildir.

#### Devralma Penceresi

Bir bölge erişilemez olduğunda yetkili sunucu onu yanıtlardan çıkarır, ama çıkarma anında
önbellekte duran yanıtlar geçerli kalır. Devralma penceresi bu yüzden iki parçadır: bölgenin ölü
işaretlenmesi (T5) ve önbellekteki yanıtın süresinin dolması (T1).

```js
// ad/devralma.mjs — b34 100. saniyede erisilemez oluyor. Yasam suresi devralma penceresini ve
// o pencerede dusen istegi belirliyor; butce sayilari K01 hesaplarindan alinmistir.
import { kosum, ALGILAMA, ISTEK_SANIYE } from "./model.mjs";

const ARIZA = 100, SURE = 1200;
const AYLIK_BUTCE_SN = (1 - 99.9 / 100) * 30 * 24 * 3600;  // K01: %99,9 -> aylik 43,2 dk
const K01_PASIF_DUSEN = 1541.67;                           // K01: etkin-pasif, 3 sn penceresi

console.log(`b34 ${ARIZA}. saniyede dusuyor, saglik denetimi ${ALGILAMA} sn sonra isaretliyor.`);
console.log(`aylik kesinti butcesi = ${(AYLIK_BUTCE_SN / 60).toFixed(1)} dk (%99,9)`);
console.log();
console.log("ttl | pencere | dusen istek | esdeger kesinti | butce payi | yukari sorgu");
console.log("----|---------|-------------|-----------------|------------|-------------");
for (const ttl of [30, 60, 300, 900]) {
  const r = kosum({ politika: "cografi", ttl, arizaBaslangic: ARIZA, sure: SURE });
  const esdeger = r.dusen / ISTEK_SANIYE;
  console.log(`${String(ttl).padStart(3)} | ${String(r.pencere).padStart(4)} sn | ` +
    `${String(r.dusen).padStart(11)} | ${esdeger.toFixed(2).padStart(12)} sn | ` +
    `${`%${((esdeger / AYLIK_BUTCE_SN) * 100).toFixed(2)}`.padStart(10)} | ` +
    `${String(r.yukariSorgu).padStart(12)}`);
}
const r = kosum({ politika: "cografi", ttl: 300, arizaBaslangic: ARIZA, sure: SURE });
console.log();
console.log(`ttl 300: pencere ${r.pencere} sn, esdeger kesinti ` +
  `${(r.dusen / ISTEK_SANIYE).toFixed(2)} sn -> pencerede trafigin ` +
  `%${((r.dusen / (r.pencere * ISTEK_SANIYE)) * 100).toFixed(1)}'i dustu`);
console.log(`K01 etkin-pasif devralmasi 3 sn'de ${K01_PASIF_DUSEN} istek dusurmustu; ` +
  `bu devralma onun ${(r.dusen / K01_PASIF_DUSEN).toFixed(1)} kati`);
```

```
b34 100. saniyede dusuyor, saglik denetimi 10 sn sonra isaretliyor.
aylik kesinti butcesi = 43.2 dk (%99,9)

ttl | pencere | dusen istek | esdeger kesinti | butce payi | yukari sorgu
----|---------|-------------|-----------------|------------|-------------
 30 |   39 sn |        6666 |        12.97 sn |      %0.50 |         1600
 60 |   69 sn |        9486 |        18.46 sn |      %0.71 |          800
300 |  305 sn |       57906 |       112.66 sn |      %4.35 |          160
900 |  905 sn |      190206 |       370.05 sn |     %14.28 |           64

ttl 300: pencere 305 sn, esdeger kesinti 112.66 sn -> pencerede trafigin %36.9'i dustu
K01 etkin-pasif devralmasi 3 sn'de 1541.67 istek dusurmustu; bu devralma onun 37.6 kati
```

Pencere yaşam süresini neredeyse birebir izliyor: 39, 69, 305 ve 905 saniye. Bu, yaşam süresinin
bir önbellek ayarı olmaktan çıkıp **devralma süresinin kendisi** olduğu anlamına gelir. Ad
sahibinin sorgu yükünü azaltmak için seçtiği sayı, aynı zamanda bir bölge düştüğünde trafiğin ne
kadar süre ölü adrese gitmeye devam edeceğini belirliyor.

Düşen istek ile eşdeğer kesinti arasındaki fark giriş kursunun bir ayrımını doğruluyor. Yaşam
süresi 300 saniyede pencere 305 saniye, ama düşen isteğin eşdeğeri yalnız 112,66 saniyedir:
pencerede trafiğin yüzde 36,9'u düşmüştür, tamamı değil. Erişilebilirliğin Sayısal İfadesi dersi
zaman tabanlı ile istek tabanlı ölçümün ayrıştığını söylemişti; bölgesel bir devralma tam olarak
o ayrımın düştüğü yerdir. Zaman tabanlı bakan biri 305 saniyelik kesinti sayar, istek tabanlı
bakan 112,66 saniyelik kesinti sayar ve ikisi de aynı olayı anlatır.

Bütçe payı sütunu kararı veriyor. Aylık bütçe yüzde 99,9 hedefinde 43,2 dakikadır. Yaşam süresi
900 saniyeyken tek bir bölge devralması bu bütçenin yüzde 14,28'ini harcıyor; 300 saniyede yüzde
4,35, 30 saniyede yüzde 0,50. Aynı olayın maliyeti yirmi sekiz kat değişiyor ve tek değişen ad
kaydındaki bir sayıdır.

Karşılaştırma son satırda tamamlanıyor. Erişilebilirlik Kalıpları dersindeki etkin–pasif devralma
üç saniyelik bir pencerede 1.541,67 istek düşürüyordu. Ad katmanındaki devralma, taban yaşam
süresiyle, onun 37,6 katını düşürüyor. **Ad katmanı elde bulunan en yavaş devralma aracıdır**;
kopya düzeyinde saniyelerle ölçülen bir geçiş, ad düzeyinde dakikalarla ölçülür. Bunun tasarım
sonucu, ad katmanının bölge seçimi için kullanılıp arıza yanıtı için tek başına
bırakılmamasıdır — pencereyi kapatan durak sonraki derslerin konusudur.

#### Özet

- Ad çözümlemesi bir yönlendirme kararıdır: coğrafi politika kaba bir tablo, gecikmeye göre
  politika ölçülen yakınlık, ağırlıklı politika hedef pay üzerinden yanıt verir.
- Aynı akışta gecikmeye göre politika istek başına 1,171 mesafe birimi, coğrafi 1,710, ağırlıklı
  2,144 üretti; hedef paya en yakın dağılımı ise ağırlıklı politika verdi (sapma 0,022).
- Coğrafi tablonun elle yazılması ölçülebilir bir kusurdur: dört istemci kümesinden ikisinde
  tablo en yakın bölgeyi göstermiyordu.
- Ağırlıklı politikanın sapması yaşam süresi kısaldıkça düzelmedi (0,082–0,195 bandında salındı)
  ama yukarı sorgu otuz kata çıktı; paylar eşitlendiğinde sapma 0,000 oldu. Denetim birimi
  çözümlemedir, oysa yük istek başına gelir.
- Devralma penceresi yaşam süresini izliyor (39, 69, 305, 905 sn) ve tek bir bölge devralması
  aylık kesinti bütçesinin yüzde 0,50'sinden yüzde 14,28'ine kadar yer tutuyor.
- Yaşam süresi 300 saniyede pencere 305 saniye ama eşdeğer kesinti 112,66 saniyedir; ad
  katmanındaki devralma kopya düzeyindekinin 37,6 katı istek düşürür.

#### Sonraki Adım

Ad katmanı isteğin **hangi bölgeye** gideceğini seçti ve bu seçimin bedelini iki yerde ödedi:
mesafe biriminde ve devralma penceresinde. Ama seçtiği şey bir adresti; istek o adrese vardığında
hâlâ uygulamaya ulaşmamıştır. Aradaki boşlukta isteği uygulamaya hiç ulaştırmadan yanıtlayabilecek
bir durak vardır. Önbellekleme Eşzamansız İşleme kursunda kurulmuştu, ama orada önbellek
uygulamanın yanındaydı; giriş kursunun hesabında da öyle varsayılmıştı ve yüzde 90 isabet oranı
`onbellek arkasi okuma/s` sayısını 41,67'ye indiriyordu. Sonraki ders aynı önbelleği bir yer
değiştirmeyle ele alır: aynı içerik uygulamanın yanında değil kullanıcının yanında tutulursa
uygulamaya ulaşan istek sayısına, sınırdan geçen bayta ve giriş kursunun hangi hesabına ne olur.

### İçerik Dağıtım Ağları

Source: https://academia.sh/tr/kurslar/trafik-katmani/icerik-dagitim-aglari

Kenar önbelleğinin bir konum kararı olarak ele alınması: yerel köken ve kenar süreçleriyle tel üzerindeki baytın ölçülmesi, süreç içi izle kenar isabet oranının ve uygulamaya ulaşan istek sayısının sayılması, iki önbelleğin seri bağlanmasının ikinciyi işlevsiz bırakması ve giriş kursunun hangi hesabının değiştiğinin gösterilmesi.

Ad katmanı isteğin hangi bölgeye gideceğini seçti, ama seçtiği şey bir adresti; istek o adrese
vardığında hâlâ uygulamaya ulaşmamıştır. Aradaki boşlukta isteği uygulamaya hiç ulaştırmadan
yanıtlayabilecek bir durak vardır. Önbellekleme Eşzamansız İşleme kursunda kuruldu ve orada
önbellek uygulamanın yanındaydı; Sistem Tasarımına Giriş kursunun hesabı da öyle varsayıyordu ve
yüzde 90'lık isabet oranı `onbellek arkasi okuma/s` sayısını 41,67'ye indiriyordu.

Bu ders aynı önbelleği bir **yer değiştirmeyle** ele alır. Strateji, geçersizleştirme ve anahtar
tasarımı yeniden anlatılmaz; burada değişen tek şey önbelleğin nerede durduğudur. **İçerik dağıtım
ağı** (content delivery network), aynı içeriği kullanıcıya yakın çok sayıda noktada tutan bir
düzendir ve o noktaların her birine **kenar önbelleği** (edge cache) denir. Sorulacak soru
şudur: aynı isabet oranı uygulamanın yanında değil kullanıcının yanında elde edilirse hangi sayı
değişir, hangisi değişmez.

#### Konum Kararı Ne Değiştirir

Bir önbelleğin uygulamanın yanında durması ile kullanıcının yanında durması, isabet oranı aynı
kalsa bile üç şeyi ayırır. Birincisi, isabet edilen istek uygulamaya **hiç varmaz**; kenarda
karşılanan bir istek uygulama süreçlerinin gördüğü yükten düşer. İkincisi, isabet edilen isteğin
yanıtı köken ile kenar arasındaki bağı kullanmaz; sınırdan geçen bayt azalır. Üçüncüsü, isabet
edilmeyen istek artık iki durak yerine üç duraktan geçer.

Bunların hiçbiri isabet oranını kendiliğinden büyütmez. Bu dersin ölçtüğü şey, konumun oranı
değiştirmediği ama oranın **karşılığını** değiştirdiğidir.

#### Tel Üzerindeki Bayt

İlk düzenek iki yerel süreçtir: köken ve kenar. Ölçülen, aynı gövdenin gerçek bir bağlantı
üzerinde kaç bayt tuttuğudur. Giriş kursunun hesabı bunu dışarıda bırakmış ve "başlık ve protokol
yükü ayrı bir varsayım olurdu" demişti; burada varsayım yerine ölçüm konur.

```js
// kenar/sunucu.mjs — iki yerel surec: koken 8471'de, kenar onbellegi 8472'de dinler. Onbellek
// kapasiteleri ornegi kucuk tutmak icin uc anahtardir; her ikisi de sayacini /sayac'ta acar.
import http from "node:http";

const GOVDE = 480;                         // K01 V5: takip yaniti govdesi
const govde = (no) => {
  const bas = JSON.stringify({ takip: no, durum: "aktarma", bolge: "b34" });
  return bas + " ".repeat(GOVDE - bas.length);
};
const yeniOnbellek = (kapasite) => ({
  kapasite, m: new Map(),
  al(no) { const g = this.m.get(no); if (g !== undefined) this.m.delete(no); return g; },
  koy(no, g) {
    if (this.m.size >= this.kapasite) this.m.delete(this.m.keys().next().value);
    this.m.set(no, g);
  },
});
const sayacYolu = (s) => (istek, yanit) => {
  yanit.writeHead(200, { "content-type": "application/json" });
  yanit.end(JSON.stringify(s));
};

const ks = { istek: 0, isabet: 0, depo: 0 };
const ko = yeniOnbellek(3);
http.createServer((istek, yanit) => {
  if (istek.url === "/sayac") return sayacYolu(ks)(istek, yanit);
  const no = istek.url.slice("/takip/".length);
  ks.istek += 1;
  let g = ko.al(no);
  if (g === undefined) { ks.depo += 1; g = govde(no); } else ks.isabet += 1;
  ko.koy(no, g);
  yanit.writeHead(200, { "content-type": "application/json", "content-length": GOVDE });
  yanit.end(g);
}).listen(8471);

const es = { istek: 0, isabet: 0, iska: 0, kokenIstek: 0, kokenBayt: 0 };
const eo = yeniOnbellek(3);
http.createServer(async (istek, yanit) => {
  if (istek.url === "/sayac") return sayacYolu(es)(istek, yanit);
  const no = istek.url.slice("/takip/".length);
  es.istek += 1;
  let g = eo.al(no), durum = "isabet";
  if (g === undefined) {
    durum = "iska";
    es.iska += 1; es.kokenIstek += 1;
    g = await (await fetch(`http://127.0.0.1:8471/takip/${no}`)).text();
    es.kokenBayt += Buffer.byteLength(g);
  } else es.isabet += 1;
  eo.koy(no, g);
  yanit.writeHead(200, { "content-type": "application/json",
    "content-length": Buffer.byteLength(g), "x-kenar": durum });
  yanit.end(g);
}).listen(8472);
```

```bash
# kenar-olc.sh — once kokene dogrudan bir istek, sonra kenar uzerinden ayni iki takip numarasi
# ucer kez sorulur. Baslik baytlari sunucunun urettigi baslik kumesine baglidir; govde ve tel
# arasindaki oran bagli degildir.
node kenar/sunucu.mjs & SUNUCU=$!
until curl -sf http://127.0.0.1:8472/sayac >/dev/null; do sleep 0.2; done
olc() { curl -s -o /dev/null -D - "$1" -w '%{size_download} %{size_header}\n' 2>/dev/null; }

printf '%-18s %-7s %6s %7s %5s\n' istek kenar govde baslik tel
olc http://127.0.0.1:8471/takip/TR900010 |
  awk 'END{printf "%-18s %-7s %6d %7d %5d\n", "koken dogrudan", "-", $1, $2, $1+$2}'
for tur in 1 2 3; do
  for no in TR900011 TR900012; do
    olc "http://127.0.0.1:8472/takip/$no" |
      awk -v n="$no" -v t="$tur" '/^x-kenar/{k=$2; sub(/\r/, "", k)}
        END{printf "%-18s %-7s %6d %7d %5d\n", "kenar " n " t" t, k, $1, $2, $1+$2}'
  done
done
printf '\nkenar sayaci = %s\n' "$(curl -s http://127.0.0.1:8472/sayac)"
printf 'koken sayaci = %s\n' "$(curl -s http://127.0.0.1:8471/sayac)"
kill $SUNUCU
```

```
istek              kenar    govde  baslik   tel
koken dogrudan     -          480     156   636
kenar TR900011 t1  iska       480     171   651
kenar TR900012 t1  iska       480     171   651
kenar TR900011 t2  isabet     480     173   653
kenar TR900012 t2  isabet     480     173   653
kenar TR900011 t3  isabet     480     173   653
kenar TR900012 t3  isabet     480     173   653

kenar sayaci = {"istek":6,"isabet":4,"iska":2,"kokenIstek":2,"kokenBayt":960}
koken sayaci = {"istek":3,"isabet":0,"depo":3}
```

Sayılar **ölçüm** sınıfındadır. Başlık baytları sunucunun ürettiği başlık kümesine bağlıdır ve
başka bir uygulamada başka çıkar; gövde ile tel arasındaki oran ise 653 / 480 = 1,360'tır ve bu
oran bir alt sınır olarak taşınabilir, çünkü başlık kümesi ancak büyür.

Sayaçlar konum kararının ilk sonucunu veriyor. Kenar altı istek gördü, ikisi ıska, dördü isabet.
Kökene giden istek sayısı ikidir: aynı iki takip numarasının ikinci ve üçüncü sorgusu kökene hiç
ulaşmadı. Kökenin kendi sayacı üç istek gösteriyor, çünkü doğrudan yapılan ilk ölçüm de sayıldı.
Kökenin `isabet` sayacı sıfırdır — kenarın arkasında kalan istekler öyle seyrekleşmiştir ki
kökenin kendi önbelleği hiç işe yaramamıştır. Bu, dersin ikinci yarısında ölçülecek olan sonucun
küçük bir örneğidir.

#### İsabet Oranı Nereden Gelir

İkinci düzenek bir süreç içi modeldir ve **model olduğu belirtilir**: aynı istek izi önce tek bir
önbellekle, sonra önüne kenar önbelleği konarak koşturulur. İz bu kursun varsayımıdır, oranlar ve
sayımlar ölçümdür.

Modelin girdisi giriş kursundan türetilir. Günde 12.000.000 takip sorgusu ve günde 400.000 yeni
gönderi vardı. Buraya bir varsayım eklenir — **T6: bir gönderinin yolda kaldığı gün 3** — ve etkin
gönderi sayısı 1.200.000 çıkar; gönderi başına günlük sorgu 12.000.000 / 1.200.000 = 10 olur. Bu
sayı **hesap** sınıfındadır.

On sorgu bir gönderinin üç günlük ömrüne yayılmıştır. Bir önbellek girdisinin üç gün yaşaması
beklenemez, dolayısıyla oranı belirleyen şey on sorgunun kaçının **aynı kısa pencerede** geldiğidir:
kullanıcı takip sayfasını açar ve birkaç kez yeniler. Bu, ikinci varsayımdır — **T7: öbek uzunluğu**,
yani on sorgudan kaçının aynı öbekte geldiği. Üçüncüsü **T8: aynı anda açık öbek sayısı 100**,
dördüncüsü **T9: her önbelleğin kapasitesi 1.000 anahtar**.

```js
// kenar/iz.mjs — surec ici model: ayni istek izi once tek onbellekle, sonra onune kenar
// onbellegi konarak kosturulur. Iz bir varsayimdir (T7), oranlar ve sayimlar olcumdur.
const ISTEK = 200_000;    // K01 tepe okuma 416,67 istek/s x 480 sn
const SORGU = 10;         // hesap: V1*V2 / (V3*T6) = 12.000.000 / 1.200.000
const ACIK = 100;         // T8: ayni anda acik takip sayfasi (obek) sayisi
const KAPASITE = 1_000;   // T9: her onbellegin anahtar kapasitesi

function* iz(obek) {      // obek: bir gonderinin 10 sorgusundan kaci ayni obekte geliyor
  const acik = [];
  let yeni = 1, tek = 1, dizin = 0;
  for (let i = 0; i < ISTEK; i++) {
    if (i % SORGU >= obek) { yield `D${tek++}`; continue; }  // pencerede bir kez gecen anahtar
    while (acik.length < ACIK) acik.push({ ad: `G${yeni++}`, kalan: obek });
    dizin = (dizin + 1) % acik.length;
    const o = acik[dizin];
    yield o.ad;
    if (--o.kalan === 0) acik.splice(dizin, 1);
  }
}

class Onbellek {          // en son kullanilan sonda durur; Map'in ekleme sirasi yeter
  constructor(k) { this.k = k; this.m = new Map(); this.isabet = 0; this.iska = 0; }
  ara(a) {
    if (this.m.has(a)) { this.isabet += 1; this.m.delete(a); this.m.set(a, 1); return true; }
    this.iska += 1;
    if (this.m.size >= this.k) this.m.delete(this.m.keys().next().value);
    this.m.set(a, 1);
    return false;
  }
  get oran() { return this.isabet / (this.isabet + this.iska); }
}

export function kosum(obek) {
  const tek = new Onbellek(KAPASITE);
  const kenar = new Onbellek(KAPASITE), uygulama = new Onbellek(KAPASITE);
  for (const a of iz(obek)) {
    tek.ara(a);
    if (!kenar.ara(a)) uygulama.ara(a);
  }
  return { istek: ISTEK, tekOran: tek.oran, tekDepo: tek.iska,
    kenarOran: kenar.oran, uygulamaIstek: kenar.iska,
    uygulamaOran: uygulama.oran, kenarliDepo: uygulama.iska };
}

if (process.argv[1].endsWith("iz.mjs")) {    // iceri alindiginda basmaz, yalniz kosum'u verir
  console.log(`${ISTEK} istek, gonderi basina ${SORGU} sorgu, ${ACIK} acik obek, ` +
    `onbellek kapasitesi ${KAPASITE} anahtar`);
  console.log();
  console.log("obek | tek onbellek | kenar isabet | uygulamaya ulasan | uyg. isabet | depoya ulasan");
  console.log("-----|--------------|--------------|-------------------|-------------|--------------");
  for (const obek of [10, 5, 2]) {
    const r = kosum(obek);
    console.log(`${String(obek).padStart(4)} | ${r.tekOran.toFixed(4).padStart(12)} | ` +
      `${r.kenarOran.toFixed(4).padStart(12)} | ${String(r.uygulamaIstek).padStart(17)} | ` +
      `${r.uygulamaOran.toFixed(4).padStart(11)} | ${String(r.kenarliDepo).padStart(13)}`);
  }
  const r = kosum(10);
  console.log();
  console.log(`obek 10: depoya ulasan istek kenarsiz ${r.tekDepo}, kenarli ${r.kenarliDepo} ` +
    `(x${(r.kenarliDepo / r.tekDepo).toFixed(3)})`);
  console.log(`uygulamaya ulasan istek ${r.istek} -> ${r.uygulamaIstek} ` +
    `(x${(r.uygulamaIstek / r.istek).toFixed(3)})`);
  console.log(`olculen kenar isabeti ${r.kenarOran.toFixed(4)}, V9 varsayimi 0,90 -> fark ` +
    `${(Math.abs(r.kenarOran - 0.9) * 100).toFixed(2)} puan`);
}
```

```
200000 istek, gonderi basina 10 sorgu, 100 acik obek, onbellek kapasitesi 1000 anahtar

obek | tek onbellek | kenar isabet | uygulamaya ulasan | uyg. isabet | depoya ulasan
-----|--------------|--------------|-------------------|-------------|--------------
  10 |       0.8998 |       0.8998 |             20046 |      0.0000 |         20046
   5 |       0.3998 |       0.3998 |            120044 |      0.0000 |        120044
   2 |       0.0759 |       0.0759 |            184815 |      0.0021 |        184418

obek 10: depoya ulasan istek kenarsiz 20046, kenarli 20046 (x1.000)
uygulamaya ulasan istek 200000 -> 20046 (x0.100)
olculen kenar isabeti 0.8998, V9 varsayimi 0,90 -> fark 0.02 puan
```

İlk satır giriş kursunun bir varsayımını açıyor. Önbellekten karşılanma oranı orada V9 = 0,90
olarak seçilmişti ve gerekçesi "aynı takip numarası kısa aralıkla yeniden sorulur" diye bir
cümleydi. Öbek uzunluğu 10 alındığında ölçülen oran 0,8998'dir: fark 0,02 puan. Yani **V9 = 0,90
gizlice şunu varsayıyordu: bir gönderinin on sorgusunun tamamı aynı öbekte geliyor.** Varsayımın
duyarlılığı ikinci ve üçüncü satırda: öbek 5 olduğunda oran 0,3998, öbek 2 olduğunda 0,0759.
Sorguların yarısı öbek dışına düşerse oran 0,90'dan 0,40'a iner. Bir isabet oranı bir önbellek
niteliği değil, **iz niteliğidir**.

İkinci sonuç konum kararının asıl bulgusudur. Kenar önbelleği eklendiğinde uygulamaya ulaşan
istek 200.000'den 20.046'ya, onda birine düştü. Buna karşılık depoya ulaşan istek **hiç
değişmedi**: kenarsız 20.046, kenarlı 20.046, oran 1,000. Sebebi uygulama önbelleğinin isabet
oranıdır: 0,0000. Kenar önbelleği tekrarların tamamını kendine aldığı için arkasındaki önbelleğe
yalnız ilk kez görülen anahtarlar kalıyor ve ilk kez görülen bir anahtar hiçbir önbellekte
bulunamaz.

Bu sonuç iki önbelleğin seri bağlanmasının genel bir özelliğidir: **son önbellek pencerenin
bütün ayrı anahtarlarını tutabiliyorsa, depoya ulaşan istek sayısı önündeki önbelleklerden
bağımsızdır.** Aynı satırların üçüncüsü sınırı gösteriyor: öbek 2 olduğunda kenar önbelleği zaten
başarısızdır (0,0759) ve arkadaki önbellek küçük bir katkı verebiliyor (0,0021), depoya ulaşan
istek 184.815'ten 184.418'e iniyor. İkinci önbellek ancak birincisi işini yapmadığında bir şey
kazandırıyor. Kapasite ile isabet oranı arasındaki ilişki Önbellek Ölçütleri dersinde ölçülmüştü;
burada eklenen, aynı anahtarı iki kez önbelleklemenin ikinci kez bedava olmadığıdır.

#### Hesaba Dönüş

```js
// kenar/hesap.mjs — olculen oran ve tel baytlarinin K01 hesaplarina geri konmasi
import { kosum } from "./iz.mjs";

const TEPE_OKUMA = 416.67, TEPE_YAZMA = 97.22;  // K01 hesabi
const V5 = 480, V9 = 0.90;                      // K01 varsayim tablosu
const K01_ARKA = 41.67, K01_DEPO = 138.89, K01_CIKIS = 1.60;
const TEL_KENAR = 653, TEL_KOKEN = 636;         // olcum: govde + baslik (yerel surecler)

const r = kosum(10);
const uygulama = TEPE_OKUMA * (1 - r.kenarOran);
const depoOkuma = TEPE_OKUMA * (r.kenarliDepo / r.istek);
const mbit = (istek, bayt) => (istek * bayt * 8) / 1e6;

console.log(`olculen kenar isabeti = ${r.kenarOran.toFixed(4)} (V9 varsayimi ${V9})`);
console.log();
console.log(`${"hesap".padEnd(26)}${"K01".padStart(10)}${"kenarli".padStart(10)}  not`);
const satir = (ad, once, sonra, not) =>
  console.log(`${ad.padEnd(26)}${once.toFixed(2).padStart(10)}${sonra.toFixed(2).padStart(10)}  ${not}`);
satir("uygulamaya ulasan ok./s", TEPE_OKUMA, uygulama, "kenar onbellegi cikardi");
satir("onbellek arkasi okuma/s", K01_ARKA, depoOkuma, "degismedi");
satir("depoya ulasan istek/s", K01_DEPO, depoOkuma + TEPE_YAZMA, "degismedi");
satir("okuma cikis Mbit/s", K01_CIKIS, mbit(TEPE_OKUMA, TEL_KENAR), "K01 yalniz govde saydi");
satir("kokenden cikis Mbit/s", K01_CIKIS, mbit(uygulama, TEL_KOKEN), "kenar sinirin arkasinda");
console.log();
console.log(`tel/govde orani = ${(TEL_KENAR / V5).toFixed(3)}; K01'in 1,60 Mbit/s'i alt sinirdir`);
console.log(`kokenden cikis / kullaniciya cikis = ` +
  `${(mbit(uygulama, TEL_KOKEN) / mbit(TEPE_OKUMA, TEL_KENAR)).toFixed(4)}`);
console.log(`uygulama onbelleginin katkisi = ${(r.uygulamaOran * 100).toFixed(2)}% isabet`);
```

```
olculen kenar isabeti = 0.8998 (V9 varsayimi 0.9)

hesap                            K01   kenarli  not
uygulamaya ulasan ok./s       416.67     41.76  kenar onbellegi cikardi
onbellek arkasi okuma/s        41.67     41.76  degismedi
depoya ulasan istek/s         138.89    138.98  degismedi
okuma cikis Mbit/s              1.60      2.18  K01 yalniz govde saydi
kokenden cikis Mbit/s           1.60      0.21  kenar sinirin arkasinda

tel/govde orani = 1.360; K01'in 1,60 Mbit/s'i alt sinirdir
kokenden cikis / kullaniciya cikis = 0.0976
uygulama onbelleginin katkisi = 0.00% isabet
```

Tablo dört sonucu bir arada veriyor. Uygulamaya ulaşan okuma hızı 416,67'den 41,76'ya iniyor; bu
sayı giriş kursunda hiç hesaplanmamıştı, çünkü orada önbellek uygulamanın içindeydi ve isteğin
uygulamaya varması kaçınılmazdı. `onbellek arkasi okuma/s` ile `depoya ulasan istek/s`
değişmiyor — 41,67'ye karşı 41,76 ve 138,89'a karşı 138,98; fark iz ölçümünün 0,02 puanlık
sapmasından geliyor. Kenar önbelleği aynı 0,90'ı bir yerden alıp başka bir yere koyuyor.

Bant genişliği iki yönde düzeltiliyor. Kullanıcıya giden çıkış, ölçülen tel baytıyla 1,60'tan
2,18 Mbit/s'e çıkıyor: giriş kursunun sayısı yalnız gövdeyi saydığı için bir alt sınırdı.
Kökenden çıkan bant genişliği ise 0,21 Mbit/s'tir, kullanıcıya giden çıkışın 0,0976'sı. Aynı
tasarımda bir bağ 2,18 Mbit/s, ötekisi 0,21 Mbit/s istiyor ve giriş kursunun tek sayısı ikisini
de temsil edemiyor.

#### Özet

- Kenar önbelleği bir konum kararıdır: isabet edilen istek uygulamaya varmaz ve köken ile kenar
  arasındaki bağı kullanmaz, ama isabet oranı bu kararla büyümez.
- Aynı gövdenin gerçek bağlantıda tuttuğu yer ölçüldü: 480 baytlık gövde tel üzerinde 653 bayt
  tutuyor, oran 1,360; giriş kursunun 1,60 Mbit/s'i bu yüzden bir alt sınırdır.
- Öbek uzunluğu 10 alındığında ölçülen isabet 0,8998 çıktı: V9 = 0,90 varsayımı, bir gönderinin
  on sorgusunun tamamının aynı öbekte geldiğini varsayıyordu. Öbek 5 olduğunda oran 0,3998'e iner.
- Kenar önbelleği uygulamaya ulaşan isteği 200.000'den 20.046'ya indirdi, ama depoya ulaşan istek
  20.046'da kaldı (oran 1,000) ve uygulama önbelleğinin isabeti 0,0000 oldu.
- Son önbellek pencerenin bütün ayrı anahtarlarını tutabiliyorsa depoya ulaşan istek önündeki
  önbelleklerden bağımsızdır; ikinci önbellek ancak birincisi başarısız olduğunda katkı verir.
- Hesaba dönüş: uygulamaya ulaşan okuma 416,67'den 41,76'ya indi, `depoya ulasan istek/s` 138,89
  olarak kaldı, kökenden çıkış 0,21 Mbit/s ile kullanıcıya giden çıkışın 0,0976'sı oldu.

#### Sonraki Adım

Bu dersteki kenar önbelleği isteği bekledi: bir anahtar ilk kez sorulduğunda ıska verdi, kökene
gitti ve yanıtı sakladı. Ölçüm o ilk isteklerin sayısını da verdi — 200.000 isteğin 20.046'sı
kenarda ıska oldu ve her biri kökene bir gidiş demek. Bu bekleme zorunlu değildir: içerik
sorulmadan önce de kenara gönderilebilir. İki model arasındaki seçim ıska sayısını, kenarda tutulan
içerik hacmini ve bir güncellemenin ne kadar sürede her kenarda görünür olduğunu değiştirir.
Sonraki ders iki modeli aynı düzenekte ölçer ve hangisinin hangi içerik türü için yerinde olduğunu
gösterir.

### İtme ve Çekme Tabanlı Dağıtım

Source: https://academia.sh/tr/kurslar/trafik-katmani/itme-ve-cekme-tabanli-dagitim

İçeriğin kenarlara iki ayrı modelle yayılması: çekme tabanlı dağıtımın ilk ıskayı ve eskimiş sürüm penceresini üretmesi, itme tabanlı dağıtımın boşa giden kopya ve ileti çarpanı doğurması, iki modelin içerik sınıfına göre seçilmesi ve seçimin giriş kursundaki yazma bant genişliği ile saklama hesabına etkisi.

Önceki dersteki kenar önbelleği isteği bekledi: bir anahtar ilk kez sorulduğunda ıska verdi,
kökene gitti ve yanıtı sakladı. Ölçüm o ilk isteklerin sayısını da verdi — 200.000 isteğin
20.046'sı kenarda ıska oldu ve her biri kökene bir gidiş demek. Bu bekleme zorunlu değildir.

İçerik sorulmadan önce de kenara gönderilebilir. İki yol vardır ve aralarındaki seçim bir
**yayma modeli** kararıdır. **Çekme tabanlı dağıtım** (pull based distribution) içeriği ilk
istekle çeker: kenar ıska verir, kökene gider, yanıtı saklar. **İtme tabanlı dağıtım** (push
based distribution) içeriği istek gelmeden önce kenarlara gönderir: kenar ıska vermez, ama
gönderilen içeriğin istenip istenmeyeceği bilinmez. Bu ders iki modeli aynı içerik kümesinde
ölçer.

#### Ayrımın Ölçütü

İki model arasındaki fark üç yerde görünür. Birincisi **köken isteği**: çekme modelinde her kenar
her nesne için en az bir kez kökene gider, itme modelinde hiç gitmez. İkincisi **boşa giden
kopya**: itme modeli bir nesneyi hiç istenmeyecek kenarlara da gönderir. Üçüncüsü **eskimiş
sürüm**: bir nesne değiştiğinde çekme modelinde kenarlar süreleri dolana kadar eski sürümü
sunmaya devam eder, itme modelinde yeni sürüm bir adımda her kenara gider.

Bu üçü tek bir niceliğe bağlanır: **bir nesnenin kaç kenardan istendiği.** Nesne bütün kenarlardan
isteniyorsa itme hiçbir şeyi boşa göndermez; tek bir kenardan isteniyorsa itmenin gönderdiği
kopyaların hepsi bir eksiği kadar boşadır. Ders bunu ölçer.

#### Düzenek

Model süreç içidir ve tur soyut bir adımdır; giriş kursunun tur soyutlamasıyla aynı türdendir.
İçerik iki sınıfa ayrılır. **Ortak** nesneler takip sayfasının kabuğu, biçem ve betik
dosyalarıdır: her kenardan istenirler. **Özel** nesneler gönderi başına takip yanıtlarıdır ve
sayıları önceki dersin ölçümünden gelir — pencerede 20.046 ayrı yanıt.

| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| T10 | kenar sayısı | 12 | üç bölgenin her birinde dört giriş noktası |
| T11 | ortak nesne sayısı | 20 | kabuk, biçem, betik ve simge dosyaları |
| T12 | özel nesneyi isteyen kenar | 1 | bir gönderinin sorguları aynı kullanıcıdan, aynı kenardan gelir |

```js
// yayma/model.mjs — surec ici model: ayni icerik kumesi once cekme, sonra itme tabanli
// dagitilir. Tur soyut bir adimdir; yasam suresi ve guncelleme turu parametredir.
export const KENAR = 12;        // T10: kenar sayisi
export const TTL = 300;         // T1: yasam suresi (tur)
export const TUR = 900, GUNCELLEME = 100;

// T11: ortak nesneler her kenardan istenir. T12: bir gonderinin sorgulari tek kenardan gelir,
// bu yuzden ozel nesne yalniz bir kenardan istenir. OZEL sayisi onceki dersin olcumudur.
export const SINIF = [
  { ad: "ortak", nesne: 20, isteyen: KENAR },
  { ad: "ozel", nesne: 20_046, isteyen: 1 },
];

export function maliyet(sinif) {
  const cekme = sinif.nesne * sinif.isteyen;        // ilk iskada kokene bir gidis
  const itme = sinif.nesne * KENAR;                 // kume her kenara itilir
  return { cekme, itme, bosa: itme - cekme, bosaPayi: 1 - sinif.isteyen / KENAR };
}

// kip: "cekme", "itme" ya da "melez" (ortak nesne itilir, ozel nesne cekilir)
const kipi = (kip, ad) => (kip === "melez" ? (ad === "ortak" ? "itme" : "cekme") : kip);

export function yayma(kip) {
  const s = { koken: 0, itilen: 0, bosa: 0, eskimis: 0, ileti: 0 };
  for (const sinif of SINIF) {
    const m = maliyet(sinif);
    if (kipi(kip, sinif.ad) === "itme") { s.itilen += m.itme; s.bosa += m.bosa; s.ileti += m.itme; }
    else { s.koken += m.cekme; s.ileti += m.cekme; }
  }
  const ortakKipi = kipi(kip, "ortak");
  const surum = new Array(KENAR).fill(1);           // kenarlarin gordugu ortak nesne surumu
  const sonaErer = Array.from({ length: KENAR }, (_, k) => 1 + ((k * 27) % TTL));
  for (let tur = 1; tur <= TUR; tur++) {
    if (ortakKipi === "itme" && tur === GUNCELLEME) { surum.fill(2); s.ileti += KENAR; }
    for (let k = 0; k < KENAR; k++) {
      if (ortakKipi === "cekme" && tur >= sonaErer[k]) {  // suresi doldu, yeniden alindi
        surum[k] = tur >= GUNCELLEME ? 2 : 1;
        sonaErer[k] = tur + TTL;
        s.koken += 1; s.ileti += 1;
      }
      if (tur >= GUNCELLEME && surum[k] === 1) s.eskimis += 1;   // eskimis surum sunulan tur
    }
  }
  return s;
}
```

```js
// yayma/olc.mjs — iki yayma kipinin ayni icerik kumesinde karsilastirilmasi
import { yayma, maliyet, SINIF, KENAR, TTL, TUR, GUNCELLEME } from "./model.mjs";

console.log(`${KENAR} kenar, yasam suresi ${TTL} tur, ${TUR} tur, ` +
  `ortak nesnenin surumu ${GUNCELLEME}. turda degisiyor`);
console.log();
console.log("sinif | nesne | isteyen kenar | cekme istegi | itme istegi | bosa giden | bosa payi");
console.log("------|-------|---------------|--------------|-------------|------------|----------");
for (const sinif of SINIF) {
  const m = maliyet(sinif);
  console.log(`${sinif.ad.padEnd(5)} | ${String(sinif.nesne).padStart(5)} | ` +
    `${String(sinif.isteyen).padStart(13)} | ${String(m.cekme).padStart(12)} | ` +
    `${String(m.itme).padStart(11)} | ${String(m.bosa).padStart(10)} | ` +
    `${`%${(m.bosaPayi * 100).toFixed(1)}`.padStart(9)}`);
}
console.log();
console.log("kip    | koken istegi | itilen nesne | bosa giden | eskimis surum turu |  ileti");
console.log("-------|--------------|--------------|------------|--------------------|-------");
const kayit = {};
for (const kip of ["cekme", "itme", "melez"]) {
  const r = kayit[kip] = yayma(kip);
  console.log(`${kip.padEnd(6)} | ${String(r.koken).padStart(12)} | ` +
    `${String(r.itilen).padStart(12)} | ${String(r.bosa).padStart(10)} | ` +
    `${String(r.eskimis).padStart(18)} | ${String(r.ileti).padStart(6)}`);
}
const c = kayit.cekme, i = kayit.itme;
console.log();
console.log(`ileti orani itme/cekme = ${(i.ileti / c.ileti).toFixed(2)}`);
console.log(`eskimis surum turu, kenar basina ortalama = ${(c.eskimis / KENAR).toFixed(1)} tur ` +
  `(yasam suresinin ${((c.eskimis / KENAR) / TTL).toFixed(2)} kati)`);
const iki = maliyet({ ...SINIF[1], isteyen: 2 });
console.log(`T12 duyarliligi: ozel nesne iki kenardan istenirse bosa payi ` +
  `%${(iki.bosaPayi * 100).toFixed(1)} (tek kenarda %${(maliyet(SINIF[1]).bosaPayi * 100).toFixed(1)})`);
```

```
12 kenar, yasam suresi 300 tur, 900 tur, ortak nesnenin surumu 100. turda degisiyor

sinif | nesne | isteyen kenar | cekme istegi | itme istegi | bosa giden | bosa payi
------|-------|---------------|--------------|-------------|------------|----------
ortak |    20 |            12 |          240 |         240 |          0 |      %0.0
ozel  | 20046 |             1 |        20046 |      240552 |     220506 |     %91.7

kip    | koken istegi | itilen nesne | bosa giden | eskimis surum turu |  ileti
-------|--------------|--------------|------------|--------------------|-------
cekme  |        20322 |            0 |          0 |               1794 |  20322
itme   |            0 |       240792 |     220506 |                  0 | 240804
melez  |        20046 |          240 |          0 |                  0 |  20298

ileti orani itme/cekme = 11.85
eskimis surum turu, kenar basina ortalama = 149.5 tur (yasam suresinin 0.50 kati)
T12 duyarliligi: ozel nesne iki kenardan istenirse bosa payi %83.3 (tek kenarda %91.7)
```

Sayılar **ölçüm** sınıfındadır; girdileri T10–T12 varsayımları ile önceki dersin 20.046 ölçümüdür.

Birinci tablo seçim ölçütünü doğruluyor. Ortak sınıfta çekme ile itmenin isteği eşittir (240'a
240) ve boşa giden kopya sıfırdır, çünkü nesne zaten on iki kenardan da isteniyor. Özel sınıfta
itme 240.552 kopya gönderiyor, bunların 220.506'sı hiç istenmeyecek: boşa giden pay yüzde 91,7.
Aynı ölçüt formülle de görünüyor — boşa giden pay, isteyen kenar sayısının kenar sayısına oranının
tümleyenidir. T12 oynatıldığında pay yüzde 91,7'den yüzde 83,3'e iniyor; varsayım iki katına
çıksa bile itme özel sınıfta hâlâ ağırlıkla boşa gidiyor.

İkinci tablo bedelin nereye taşındığını gösteriyor. Çekme kipi kökene 20.322 istek üretiyor ve
karşılığında 1.794 tur boyunca eskimiş sürüm sunuyor; kenar başına ortalama 149,5 tur, yani yaşam
süresinin yarısı. İtme kipi eskimiş sürüm üretmiyor ama 240.804 ileti gönderiyor: çekmenin 11,85
katı. **İki model aynı işi ayrı yerde ödüyor** — biri eskimiş yanıtla, öteki boşa giden iletiyle.
Bu, giriş kursundaki iki devralma kalıbının ödünleşimiyle aynı biçimdedir: orada bedel kesinti ile
kaybolan veri arasında bölünmüştü.

Üçüncü satır kararın sistem düzeyinde değil **içerik sınıfı düzeyinde** verildiğini gösteriyor.
Melez kip ortak nesneleri itiyor, özel nesneleri çekiyor: köken isteği 20.046, boşa giden kopya 0,
eskimiş sürüm turu 0 ve ileti 20.298. Üç sütunun üçünde de öteki iki kipten iyi. Tek bir model
seçmek zorunda olan bir tasarım, iki sınıfın birinde gereksiz bedel ödüyor.

#### Hesaba Dönüş

```js
// yayma/hesap.mjs — yayma kipi secildiginde K01'in hangi hesabi degisiyor
import { yayma, maliyet, SINIF, KENAR } from "./model.mjs";

const TEPE_OKUMA = 416.67, TEPE_YAZMA = 97.22, GUNLUK_OLAY = 2_800_000;  // K01 hesabi
const V5 = 480, ETKIN = 1_200_000;              // K01 V5; T6 ile hesaplanan etkin gonderi
const K01_ARKA = 41.67, K01_YAZMA = 0.17, K01_OKUMA = 1.60;
const PENCERE = 480;                            // sn: onceki dersin olcum penceresi

const c = yayma("cekme"), m = yayma("melez");
const mbit = (hiz, bayt) => (hiz * bayt * 8) / 1e6;
const itmeHizi = TEPE_YAZMA * KENAR;
const eskimisYanit = c.eskimis * (TEPE_OKUMA / KENAR);
const itmeGB = (ETKIN * V5 * KENAR) / 1e9, cekmeMB = (SINIF[1].nesne * V5) / 1e6;

console.log(`cekme: kokene ${c.koken} istek / ${PENCERE} sn = ${(c.koken / PENCERE).toFixed(2)} ` +
  `istek/s -- K01 onbellek arkasi okuma/s = ${K01_ARKA}`);
console.log(`melez: kokene ${(m.koken / PENCERE).toFixed(2)} istek/s, ortak nesne itildigi icin ` +
  `soguk baslangic iskasi yok`);
console.log();
console.log(`itme: her durum olayi ${KENAR} kenara gidiyor`);
console.log(`  tepe itme hizi = ${itmeHizi.toFixed(2)} itme/s, gunluk ${GUNLUK_OLAY * KENAR} itme`);
console.log(`  itme bant genisligi = ${mbit(itmeHizi, V5).toFixed(2)} Mbit/s = ` +
  `K01 yazma girisinin (${K01_YAZMA}) ${(mbit(itmeHizi, V5) / K01_YAZMA).toFixed(1)} kati, ` +
  `okuma cikisinin (${K01_OKUMA}) ${(mbit(itmeHizi, V5) / K01_OKUMA).toFixed(2)} kati`);
console.log(`  kenarlarda tutulan ozel icerik = ${itmeGB.toFixed(2)} GB ` +
  `(${(ETKIN * V5 / 1e6).toFixed(0)} MB x ${KENAR} kenar)`);
console.log(`  cekme kipinde ayni icerik = ${cekmeMB.toFixed(2)} MB, oran ` +
  `${((itmeGB * 1e3) / cekmeMB).toFixed(0)}`);
console.log();
console.log(`cekme kipinde bir surum degisikliginin eskimis yaniti = ` +
  `${eskimisYanit.toFixed(0)} (${c.eskimis} tur x ${(TEPE_OKUMA / KENAR).toFixed(2)} istek/s)`);
console.log(`ozel nesnenin bosa giden itme payi = ` +
  `%${(maliyet(SINIF[1]).bosaPayi * 100).toFixed(1)}; itme ancak nesne ${KENAR} kenardan da ` +
  `istendiginde bosa gitmiyor`);
```

```
cekme: kokene 20322 istek / 480 sn = 42.34 istek/s -- K01 onbellek arkasi okuma/s = 41.67
melez: kokene 41.76 istek/s, ortak nesne itildigi icin soguk baslangic iskasi yok

itme: her durum olayi 12 kenara gidiyor
  tepe itme hizi = 1166.64 itme/s, gunluk 33600000 itme
  itme bant genisligi = 4.48 Mbit/s = K01 yazma girisinin (0.17) 26.4 kati, okuma cikisinin (1.6) 2.80 kati
  kenarlarda tutulan ozel icerik = 6.91 GB (576 MB x 12 kenar)
  cekme kipinde ayni icerik = 9.62 MB, oran 718

cekme kipinde bir surum degisikliginin eskimis yaniti = 62292 (1794 tur x 34.72 istek/s)
ozel nesnenin bosa giden itme payi = %91.7; itme ancak nesne 12 kenardan da istendiginde bosa gitmiyor
```

İlk satır çekme modelinin giriş kursuyla tutarlı olduğunu gösteriyor. Kökene giden istek hızı
42,34, kursun `onbellek arkasi okuma/s` sayısı 41,67. İki sayı ayrı yollardan çıkmıştır — biri
varsayım tablosundan, öteki bu dersin model koşumundan — ve yüzde iki içinde buluşuyorlar. Çekme
modeli seçildiğinde giriş kursunun hesabı olduğu gibi geçerli kalıyor.

İtme modeli aynı hesabı bozuyor. Her durum olayı ilgili takip yanıtını değiştirdiğine göre yeni
sürümün on iki kenara da gitmesi gerekir: tepe itme hızı 1.166,64 itme/s, günde 33.600.000 itme.
Bunun bant genişliği 4,48 Mbit/s'tir — kursun `yazma giris Mbit/s` sayısının (0,17) 26,4 katı ve
`okuma cikis Mbit/s` sayısının (1,60) 2,80 katı. **İtme modeli okuma yükünü yazma yüküne çevirir
ve kenar sayısıyla çarpar.** Bir tasarımın en büyük bant genişliği kalemi, itme seçilmesiyle,
saniyede 97 olayla akan yazma tarafına geçiyor.

Saklama tarafı da aynı yönde. Etkin 1.200.000 gönderinin takip yanıtları her kenarda tutulursa
kenar başına 576 MB, on iki kenarda 6,91 GB eder. Çekme modelinde aynı içeriğin kenarlardaki
toplam karşılığı 9,62 MB'tır: 718 kat fark. Bu sayı kursun `saklanan veri GB` hesabına eklenmez,
çünkü kenarlardaki kopya deponun yerine geçmez — üstüne biner.

Son satır çekme modelinin faturasını veriyor. Ortak bir nesnenin sürümü değiştiğinde 1.794 tur
boyunca eskimiş sürüm sunuluyor ve kenar başına saniyede 34,72 istek düştüğüne göre bu 62.292
eskimiş yanıt demektir. Sayı yaşam süresine doğrudan bağlıdır ve ilk dersin sonucunu tekrar
ediyor: yaşam süresi bir önbellek ayarı değil, hem devralma süresini hem de sürüm yayılma süresini
belirleyen tek bir karardır.

#### Özet

- Yayma modeli bir karardır: çekme tabanlı dağıtım içeriği ilk istekle çeker, itme tabanlı dağıtım
  istek gelmeden gönderir.
- Seçim ölçütü bir nesnenin kaç kenardan istendiğidir; boşa giden itme payı, isteyen kenar
  oranının tümleyenidir. Ortak sınıfta pay yüzde 0, özel sınıfta yüzde 91,7 ölçüldü.
- Çekme kipi kökene 20.322 istek üretti ve 1.794 tur eskimiş sürüm sundu; itme kipi eskimiş sürüm
  üretmedi ama 240.804 ileti gönderdi — çekmenin 11,85 katı.
- Melez kip üç sütunda da öteki ikisinden iyidir (köken isteği 20.046, boşa giden 0, eskimiş tur
  0): karar sistem düzeyinde değil içerik sınıfı düzeyinde verilir.
- Çekme modeli giriş kursunun hesabını korur: kökene 42,34 istek/s gidiyor, kursun
  `onbellek arkasi okuma/s` sayısı ise 41,67.
- İtme modeli hesabı bozar: tepe 1.166,64 itme/s ve 4,48 Mbit/s — yazma girişinin 26,4 katı;
  kenarlarda tutulan içerik 6,91 GB, çekme kipindekinin 718 katı.

#### Sonraki Adım

Bu iki ders içeriği kenarda tuttu ama içeriğin nereden geldiği hep aynı yerdi: uygulamanın
kendisi. Ortak sınıftaki yirmi nesne — kabuk, biçem, betik ve simge dosyaları — uygulamanın hiçbir
mantığına dokunmuyor; sabit bayt dizileri olarak duruyorlar ve yine de uygulama süreçlerinin
adresinden isteniyorlar. Sonraki ders bu yolu ayırır: içerik uygulamadan ayrı bir yerden
sunulduğunda uygulamaya ulaşan istek sayısına, isteğin dokunduğu durak sayısına ve giriş kursunun
uçtaki tepe istek hızına ne olduğunu ölçer.

### Statik İçerik Barındırma

Source: https://academia.sh/tr/kurslar/trafik-katmani/statik-icerik-barindirma

İçerik yolunun uygulama yolundan ayrılması: birleşik ve ayrık düzenlemenin yerel süreçlerle ölçülmesi, bir sayfa yüklemesinin uygulama sürecine düşürdüğü istek ve baytın sayılması ve varlık trafiğinin giriş kursundaki uçtaki tepe istek hızı ile okuma çıkışı hesabına eklenmesi.

Önceki iki ders içeriği kenarda tuttu ama içeriğin nereden geldiği hep aynı yerdi: uygulamanın
kendisi. Ortak sınıftaki yirmi nesne — kabuk, biçem, betik ve simge dosyaları — uygulamanın
hiçbir mantığına dokunmuyor; sabit bayt dizileri olarak duruyorlar ve yine de uygulama
süreçlerinin adresinden isteniyorlar.

Bu ders o yolu ayırır. **İçerik yolu**, değişmeyen dosyaların isteğe kadar izlediği yoldur;
**uygulama yolu**, bir isteğin kod çalıştırılarak yanıtlandığı yoldur. Statik dosya sunumu Sunucu
Tarafı Temelleri kursunda, varlık adlandırma ve sürümleme Oluşturma Stratejileri ve Altyapı
kursunda kuruldu; burada ne derleme ne paketleme anlatılır. Sorulan tek şey şudur: iki yol ayrıldığında
uygulama sürecine kaç istek ve kaç bayt ulaşır ve bu sayı giriş kursunun hesabında neyi
değiştirir.

#### İki Düzenleme

**Birleşik düzenleme**, aynı sürecin hem `/takip` yolunu hem `/varlik` yolunu taşımasıdır. Tek
bir dağıtım birimi vardır, yapılandırma azdır; karşılığında uygulama süreci her sayfa yüklemesinde
yirmi dosya okuması yapar.

**Ayrık düzenleme**, varlık yolunu ayrı bir sürece vermektir. Uygulama süreci yalnız kod
çalıştırılan istekleri görür. İki düzenleme arasındaki fark bir yetenek farkı değildir — ikisi de
aynı baytları döndürür — bir **yerleşim** farkıdır ve sonucu sayılabilir.

```js
// statik/sunucu.mjs — iki duzenlemeyi ayni anda ayaga kaldirir: uygulama sureci 8473'te hem
// /takip hem /varlik yollarini tasiyabilir, icerik sureci 8474'te yalniz /varlik tasir.
// Varlik dosyalari baslangicta uretilir. /sayac cagrildiginda sayaci dondurur ve sifirlar.
import http from "node:http";
import fs from "node:fs";

const V5 = 480;                                    // K01 V5: takip yaniti govdesi
const VARLIK = [["kabuk.html", 6_000], ["bicem.css", 40_000], ["uygulama.js", 120_000],
  ["yazitipi.woff2", 28_000], ["logo.svg", 4_000]];
for (let i = 1; i <= 15; i += 1) VARLIK.push([`simge-${i}.svg`, 1_200]);   // T13

fs.mkdirSync("varlik", { recursive: true });
for (const [ad, bayt] of VARLIK) fs.writeFileSync(`varlik/${ad}`, "x".repeat(bayt));

const yeni = () => ({ takip: 0, varlik: 0, bayt: 0 });
const sayacYaz = (s, yanit) => {                   // kabuktan okunsun diye duz metin
  yanit.writeHead(200, { "content-type": "text/plain" });
  yanit.end(`${s.takip} ${s.varlik} ${s.bayt}`);
  Object.assign(s, yeni());                        // okundu, sifirlandi
};

function surec(bagNoktasi, varligiTasi) {
  const s = yeni();
  http.createServer((istek, yanit) => {
    if (istek.url === "/sayac") return sayacYaz(s, yanit);
    if (istek.url.startsWith("/varlik/")) {
      if (!varligiTasi) { yanit.writeHead(404); return yanit.end(); }
      const g = fs.readFileSync(`varlik/${istek.url.slice("/varlik/".length)}`);
      s.varlik += 1; s.bayt += g.length;
      yanit.writeHead(200, { "content-length": g.length });
      return yanit.end(g);
    }
    const g = JSON.stringify({ takip: istek.url.slice("/takip/".length), durum: "aktarma" });
    const govde = g + " ".repeat(V5 - g.length);
    s.takip += 1; s.bayt += V5;
    yanit.writeHead(200, { "content-type": "application/json", "content-length": V5 });
    yanit.end(govde);
  }).listen(bagNoktasi);
  return s;
}

surec(8473, true);    // birlesik duzenleme: uygulama sureci varligi da tasir
surec(8474, true);    // ayrik duzenlemede icerik sureci
```

```bash
# statik-olc.sh — bir sayfa yuklemesi iki duzenlemede: once uygulama sureci varligi da tasir,
# sonra varlik yolu ayri bir surece verilir. Sayac okundugunda sifirlanir.
node statik/sunucu.mjs & SUNUCU=$!
until curl -sf http://127.0.0.1:8473/sayac >/dev/null; do sleep 0.2; done
VARLIK=$(ls varlik)
yukle() { # $1 = varlik surecinin bag noktasi
  curl -s -o /dev/null "http://127.0.0.1:8473/takip/TR900011"
  for v in $VARLIK; do curl -s -o /dev/null "http://127.0.0.1:$1/varlik/$v"; done
}
curl -s -o /dev/null http://127.0.0.1:8473/sayac; curl -s -o /dev/null http://127.0.0.1:8474/sayac

printf '%s varlik, toplam %s bayt\n\n' "$(ls varlik | wc -l | tr -d ' ')" "$(cat varlik/* | wc -c | tr -d ' ')"
printf '%-10s %-10s %7s %8s %9s\n' duzenleme surec takip varlik bayt
yukle 8473
printf '%-10s %-10s %7s %8s %9s\n' birlesik uygulama $(curl -s http://127.0.0.1:8473/sayac)
printf '%-10s %-10s %7s %8s %9s\n' birlesik icerik $(curl -s http://127.0.0.1:8474/sayac)
yukle 8474
printf '%-10s %-10s %7s %8s %9s\n' ayrik uygulama $(curl -s http://127.0.0.1:8473/sayac)
printf '%-10s %-10s %7s %8s %9s\n' ayrik icerik $(curl -s http://127.0.0.1:8474/sayac)
kill $SUNUCU
```

```
20 varlik, toplam 216000 bayt

duzenleme  surec        takip   varlik      bayt
birlesik   uygulama         1       20    216480
birlesik   icerik           0        0         0
ayrik      uygulama         1        0       480
ayrik      icerik           0       20    216000
```

Sayılar **ölçüm** sınıfındadır; varlık kümesi bu kursun varsayımıdır — **T13: sayfa başına 20
varlık, toplam 216.000 bayt**, gerekçesi bir takip sayfasının kabuk, biçem, betik, yazı tipi ve
simge dosyalarından oluşmasıdır.

Ölçüm bir sayfa yüklemesinin iki düzenlemede uygulama sürecine ne düşürdüğünü veriyor. Birleşik
düzenlemede uygulama süreci 21 istek ele aldı ve 216.480 bayt gönderdi. Ayrık düzenlemede aynı
sayfa yüklemesi için uygulama süreci 1 istek ele aldı ve 480 bayt gönderdi; kalan 20 istek ve
216.000 bayt içerik sürecine geçti. **Uygulama sürecine düşen istek 21'den 1'e, bayt 216.480'den
480'e indi** ve bunu sağlayan tek şey yolun ayrılmasıdır — hiçbir önbellek, hiçbir sıkıştırma
eklenmedi.

Ayrımın ikinci sonucu ölçekleme birimidir. Birleşik düzenlemede uygulama süreçlerinin sayısı iki
ayrı ihtiyacın toplamına göre belirlenir: kod çalıştıran istekler ve dosya okuyan istekler. İki
ihtiyaç aynı yönde büyümez — bir sayfa varlığı arttığında kod yükü değişmez. Ayrık düzenlemede
iki sayı bağımsız ayarlanır.

#### İki Ad, İki Yaşam Süresi

Yolun ayrılmasının doğrudan bir sonucu, içerik yolunun kendi adını almasıdır ve bu, konunun ilk
dersindeki karara geri döner. Orada yaşam süresi tek bir sayıydı ve iki işi birden yapıyordu:
sorgu yükünü azaltmak ve devralma penceresini belirlemek. Ölçüm ödünleşimi vermişti — 900
saniyelik yaşam süresi yukarı sorguyu 64'e indiriyor ama tek bir bölge devralması aylık kesinti
bütçesinin yüzde 14,28'ini harcıyordu; 30 saniyelik süre bütçe payını yüzde 0,50'ye indiriyor ama
yukarı sorguyu 1.600'e çıkarıyordu.

Tek ad varken bu ödünleşimin tek bir noktası seçilir. İki ad varken iki ayrı nokta seçilebilir,
çünkü iki adın devralma ihtiyacı aynı değildir. Uygulama adı bir bölge düştüğünde hızlı devralmak
zorundadır; kısa yaşam süresi ve onun getirdiği sorgu yükü ödenir. İçerik adı ise on iki kenarda
tutulan değişmeyen dosyaları gösterir: bir kenar düştüğünde ötekiler aynı baytları taşır ve
devralma penceresi bir kesintiye dönüşmez. O adın uzun yaşam süresi taşımasında bir sakınca
yoktur.

Sonuç, ilk dersteki tablonun iki ayrı satırının aynı anda seçilebilmesidir: kısa süre yalnız
uygulamayı çözen ad için, uzun süre içerik adı için. Bir ödünleşimin iki ucunun birden alınması,
ödünleşimi doğuran sorumluluğun bölünmesiyle olur.

#### Hesaba Dönüş

Ölçülen yirmi bir isteğin giriş kursunda bir karşılığı yoktur. Kursun uçtaki tepe istek hızı
513,89, yalnız takip sorgusu ve durum olayını sayıyordu; sayfanın kendisi ve varlıkları hesaba
hiç girmemişti. Bu boşluğu doldurmak için bir varsayım daha gerekir — **T14: kullanıcı başına
günlük 2 sayfa yüklemesi**, gerekçesi altı takip sorgusunun ikisinin yeni bir sayfa açılışı,
dördünün aynı sayfadaki yenileme olmasıdır.

```js
// statik/hesap.mjs — icerik yolunun ayrilmasinin K01 hesaplarina etkisi. Sayfa basina varlik
// sayisi ve bayti onceki bloktaki olcumden alinmistir.
const V1 = 2_000_000, TEPE = 3, GUN = 86_400;      // K01 V1, V8
const TEPE_UC = 513.89, K01_CIKIS = 1.60;          // K01 hesabi
const T14 = 2;                                     // kullanici basina gunluk sayfa yuklemesi
const VARLIK = 20, VARLIK_BAYT = 216_000;          // olcum: onceki blok
const KENAR = 12;                                  // T10: onceki dersin kenar sayisi

const sayfaTepe = ((V1 * T14) / GUN) * TEPE;
const varlikTepe = sayfaTepe * VARLIK;
const mbit = (hiz, bayt) => (hiz * bayt * 8) / 1e6;
const sat = (ad, istek, bayt) =>
  console.log(`${ad.padEnd(30)}${istek.toFixed(2).padStart(10)}${bayt.toFixed(2).padStart(12)}`);

console.log(`gunluk sayfa yuklemesi = ${V1 * T14}, tepe = ${sayfaTepe.toFixed(2)} sayfa/s`);
console.log(`sayfa basina ${VARLIK} varlik, ${VARLIK_BAYT} bayt -> ` +
  `tepe varlik istegi = ${varlikTepe.toFixed(2)} istek/s`);
console.log();
console.log(`${"duzenleme".padEnd(30)}${"istek/s".padStart(10)}${"Mbit/s".padStart(12)}`);
sat("K01 hesabi (varlik sayilmadi)", TEPE_UC, K01_CIKIS);
sat("birlesik yol, uygulama sureci", TEPE_UC + varlikTepe, K01_CIKIS + mbit(sayfaTepe, VARLIK_BAYT));
sat("ayrik yol, uygulama sureci", TEPE_UC, K01_CIKIS);
sat("ayrik yol, icerik sureci", varlikTepe, mbit(sayfaTepe, VARLIK_BAYT));
console.log();
console.log(`ayrik yol + kenar: varlik ${KENAR} kenarda tutulunca koken gunde ` +
  `${VARLIK * KENAR} varlik istegi gorur, ${((VARLIK_BAYT * KENAR) / 1e6).toFixed(2)} MB`);
console.log(`birlesik yolda uygulama sureci K01'in ${((TEPE_UC + varlikTepe) / TEPE_UC).toFixed(2)} ` +
  `kati istek, ${((K01_CIKIS + mbit(sayfaTepe, VARLIK_BAYT)) / K01_CIKIS).toFixed(1)} kati bayt goruyor`);
console.log(`bir sayfa yuklemesinde uygulamanin gordugu istek: birlesik ${1 + VARLIK}, ayrik 1`);
console.log(`T14 duyarliligi: kullanici basina 1 sayfa yuklemesi olsa varlik istegi ` +
  `${(varlikTepe / 2).toFixed(2)} istek/s, uctaki toplam ` +
  `${(TEPE_UC + varlikTepe / 2).toFixed(2)} istek/s`);
```

```
gunluk sayfa yuklemesi = 4000000, tepe = 138.89 sayfa/s
sayfa basina 20 varlik, 216000 bayt -> tepe varlik istegi = 2777.78 istek/s

duzenleme                        istek/s      Mbit/s
K01 hesabi (varlik sayilmadi)     513.89        1.60
birlesik yol, uygulama sureci    3291.67      241.60
ayrik yol, uygulama sureci        513.89        1.60
ayrik yol, icerik sureci         2777.78      240.00

ayrik yol + kenar: varlik 12 kenarda tutulunca koken gunde 240 varlik istegi gorur, 2.59 MB
birlesik yolda uygulama sureci K01'in 6.41 kati istek, 151.0 kati bayt goruyor
bir sayfa yuklemesinde uygulamanin gordugu istek: birlesik 21, ayrik 1
T14 duyarliligi: kullanici basina 1 sayfa yuklemesi olsa varlik istegi 1388.89 istek/s, uctaki toplam 1902.78 istek/s
```

Tablonun ilk satırı giriş kursunun eksiğini adlandırıyor: 513,89 istek/s ve 1,60 Mbit/s, varlık
yolu hiç sayılmadan hesaplanmıştı. İkinci satır varlık trafiği eklendiğinde ne olduğunu
gösteriyor. Birleşik düzenlemede uygulama süreci saniyede 3.291,67 istek görür — kursun sayısının
6,41 katı — ve 241,60 Mbit/s gönderir, kursun okuma çıkışının 151,0 katı. **Bir tasarımın en
büyük kaynak kalemi, hiç hesaplanmamış olan kalem çıkabilir.** Giriş kursu aynı sonuca gün sonu
işiyle varmıştı: seyrek koşan iş, sürekli koşan akışın 3,75 katı bant genişliği istiyordu. Buradaki
oran 151,0'dır ve kalem hesaba hiç girmemiştir.

Üçüncü ve dördüncü satırlar ayrımın ne yaptığını söylüyor: toplam iş azalmıyor, **bölünüyor.**
Uygulama süreci kursun hesapladığı 513,89 istek/s ve 1,60 Mbit/s'e geri dönüyor; 2.777,78 istek/s
ve 240,00 Mbit/s içerik sürecine geçiyor. İçerik yolunun ayrılması giriş kursunun hesabını
düzeltmiyor — **hesabın geçerli kaldığı düzenlemeyi adlandırıyor.** Kursun 513,89 sayısı, ancak
varlık yolu uygulamadan ayrıldığında uygulama sürecinin gördüğü sayıdır.

Beşinci satır önceki iki dersle birleşiyor. Yirmi varlık, önceki dersin ölçümünde her kenardan
istenen ortak sınıftı ve itme tabanlı dağıtımda boşa giden payı sıfırdı. On iki kenara itildiğinde
köken günde yalnız 240 varlık isteği görür ve 2,59 MB gönderir. Kullanıcı tarafında akan 240,00
Mbit/s'in kökene ulaşan kısmı bu kadardır. Üç kararın birleşimi — ayrık içerik yolu, kenar
önbelleği ve ortak sınıfta itme — 240,00 Mbit/s'lik bir kalemi kökende günlük 2,59 MB'a indiriyor.

Son satır varsayımın duyarlılığıdır. T14 yarıya inseydi varlık isteği 1.388,89 istek/s, uçtaki
toplam 1.902,78 istek/s olurdu: hâlâ kursun sayısının üç katından fazla. Varsayım iki katına ya da
yarısına çekilse de sonuç değişmiyor — varlık yolu sayılmadığında hesap yanlıştır.

#### Özet

- İçerik yolu ile uygulama yolunun ayrılması bir yerleşim kararıdır; ikisi de aynı baytları
  döndürür, değişen isteğin hangi sürece düştüğüdür.
- Ölçüm: bir sayfa yüklemesinde uygulama süreci birleşik düzenlemede 21 istek ve 216.480 bayt,
  ayrık düzenlemede 1 istek ve 480 bayt gördü.
- Ayrık düzenlemede ölçekleme birimleri bağımsızlaşır ve içerik yolu kendi adını alır; ilk
  dersteki yaşam süresi ödünleşiminin iki ucu — uygulama adı için kısa, içerik adı için uzun —
  aynı anda seçilebilir.
- Giriş kursunun uçtaki 513,89 istek/s sayısı varlık yolunu hiç saymamıştı; varlık trafiği
  eklendiğinde birleşik düzenlemede uygulama süreci 3.291,67 istek/s ve 241,60 Mbit/s görür —
  6,41 kat istek, 151,0 kat bayt.
- Ayrım toplamı azaltmaz, böler: uygulama süreci 513,89 istek/s ve 1,60 Mbit/s'e döner, 2.777,78
  istek/s ve 240,00 Mbit/s içerik sürecine geçer. Kursun sayısı ancak bu düzenlemede geçerlidir.
- Ayrık yol, kenar önbelleği ve ortak sınıfta itme birleştiğinde köken günde 240 varlık isteği ve
  2,59 MB görür; T14 yarıya inse bile varlık yolu sayılmadan hesap yanlıştır.

#### Sonraki Adım

Bu konu isteklerin bir kısmını uygulamaya **hiç ulaştırmamayı** başardı: kenar önbelleği takip
yanıtlarının onda dokuzunu sınırda karşıladı, ayrılan içerik yolu bir sayfa yüklemesinin yirmi bir
isteğinden yirmisini uygulamadan uzaklaştırdı ve alan adı katmanı isteğin hangi bölgeye gideceğini
seçti. Geriye uygulamaya gerçekten ulaşması gereken istekler kaldı — ölçülen düzenlemede saniyede
513,89 tanesi. Bunlar için hâlâ tek bir soru yanıtsızdır: bölge seçildikten sonra, aynı işi yapan
birden çok kopya varken istek **hangisine** düşer ve o kopya ayakta değilse bunu kim fark eder.
Sonraki ders bu iki soruyu tek bir bileşene bağlar ve o bileşenin sorumluluklarını sayar.

## Yük Dengeleme

İsteğin hangi kopyaya düşeceğine karar veren katman: yük dengeleyicinin dağıtım, sağlık denetimi ve TLS sonlandırma sorumlulukları, bağlantı düzeyinde dağıtım ile içerik farkındalıklı yönlendirmenin ayrılması, sıralı, en az bağlantı ve tutarlı karma algoritmalarının karşılaştırılması, ters vekille işlev örtüşmesi ve oturum yapışkanlığının ölçeklemeye maliyeti.

### Yük Dengeleyici Rolü

Source: https://academia.sh/tr/kurslar/trafik-katmani/yuk-dengeleyici-rolu

Aynı işi yapan kopyalar arasında isteği paylaştıran katmanın üç sorumluluğu: dağıtımın yerel süreçlerle ölçülmesi, bir kopya düştüğünde sağlık denetimi olan ve olmayan düzeneklerin yanıtlanan istek oranıyla karşılaştırılması, TLS sonlandırmanın konum kararı olarak ele alınması ve giriş kursunda hesaplanan tepe istek hızının kopya sayısına bölünmesi.

Önceki konu isteklerin bir kısmını uygulamaya **hiç ulaştırmamayı** başardı: kenar önbelleği takip
yanıtlarının onda dokuzunu sınırda karşıladı, ayrılan içerik yolu bir sayfa yüklemesinin isteklerinin
neredeyse tamamını uygulamadan uzaklaştırdı ve alan adı katmanı isteğin hangi bölgeye gideceğini
seçti. Geriye uygulamaya gerçekten ulaşması gereken istekler kaldı — uçta saniyede 513,89 tanesi.
Bunlar için bir soru yanıtsızdır: bölge seçildikten sonra, aynı işi yapan birden çok kopya varken
istek **hangisine** düşer ve o kopya ayakta değilse bunu kim fark eder.

Bu ders o iki soruyu tek bir bileşene bağlar. **Yük dengeleyici** (load balancer), aynı işi yapan
kopyaların önünde durup gelen isteği içlerinden birine yönlendiren aygıttır. Dersin işi bu
aygıtın sorumluluklarını saymak, her birinin kod düzeyinde ölçülebilen sonucunu almak ve Sistem
Tasarımına Giriş kursunda hesaplanan tepe istek hızının kopya sayısına bölünmesinin ne verdiğini
göstermektir.

#### Üç Sorumluluk

Dengeleyicinin taşıdığı işler ayrı ayrı adlandırılabilir ve her biri ayrı bir karar gerektirir.

**Dağıtım.** Gelen isteğin hangi kopyaya gideceğinin seçilmesi. Seçimin kuralı bir sonraki
derslerin konusudur; bu derste kural en yalın biçimiyle **sıralı** dağıtımdır — kopyalar sırayla
seçilir.

**Sağlık denetimi.** Bir kopyanın hâlâ istek alabilir durumda olup olmadığının bağımsız olarak
sınanması ve olmayanın havuzdan çıkarılması. Denetim isteği kullanıcının isteğinden ayrıdır:
dengeleyici belirli aralıklarla kopyalara sorar, yanıt alamadığında o kopyayı dağıtımdan düşürür.

**TLS sonlandırma.** Şifreli bağlantının nerede biteceğinin seçilmesi. Bağlantı dengeleyicide
biterse dengeleyici isteğin içeriğini görür; kopyaya kadar şifreli taşınırsa görmez.

Bu üç işin bir kısmını Sunucu Tarafı Temelleri kursunda kurulan **ters vekil** de yapar; ikisinin
işlev örtüşmesi ve ayrımı bu konunun beşinci dersinin konusudur. Burada dengeleyici tek bir rolle
ele alınır: aynı işi yapan kopyalar arasında paylaştırma.

#### Düzenek

Ölçüm yerel süreçlerle kurulur. Üç kopya birer `node:http` sunucusudur ve her biri yanıtına
kendi adını yazar; dengeleyici sıralı dağıtım yapar ve sağlık denetimi açık ya da kapalı
çalışabilir. Gerçek bir yük dengeleyici, bulut ortamı ya da kapsayıcı kurulmaz.

```js
// denge/kopya.mjs — bir uygulama kopyasi: takip yanitini dondurur, kendi adini basliga yazar
import { createServer } from "node:http";

const [port, ad] = [Number(process.argv[2]), process.argv[3]];

const GOVDE = (no) => JSON.stringify({
  no, durum: "aktarma merkezinde", bolge: "35", adim: 4,
  rota: ["kabul", "cikis", "aktarma-34"],
});

if (Number.isInteger(port) === false) console.log("kullanim: node denge/kopya.mjs <nokta> <ad>");
else createServer((istek, yanit) => {
  const url = new URL(istek.url, "http://yerel");
  if (url.pathname === "/saglik") { yanit.writeHead(200, { "x-kopya": ad }).end("ayakta"); return; }
  const govde = GOVDE(url.searchParams.get("no") ?? "-");
  yanit.writeHead(200, { "content-type": "application/json", "x-kopya": ad });
  yanit.end(govde);
}).listen(port, "127.0.0.1");
```

Dengeleyici üç işten ikisini yapıyor: sıraya göre bir kopya seçiyor ve kopyaların sağlığını ayrı
bir zamanlayıcıda denetliyor. Denetim aralığı 200 milisaniye, düşmüş sayılma eşiği tek bir
başarısız turdur; ikisi de bu konunun varsayımıdır ve aşağıda Y3 olarak anılır.

```js
// denge/dengeleyici.mjs — sirali dagitim + saglik denetimi. Kullanim:
//   node denge/dengeleyici.mjs <nokta> <acik|kapali> <kopya-noktalari...>
import { createServer, request, get } from "node:http";

const ARALIK = 200;                  // varsayim Y3: saglik denetimi araligi (ms)
const ESIK = 1;                      // varsayim Y3: ust uste kac basarisizlik dusmus sayilir

const nokta = Number(process.argv[2]);
const saglikAcik = process.argv[3] === "acik";
const kopya = process.argv.slice(4).map((p) => ({ nokta: Number(p), ayakta: true, hata: 0 }));

let sira = 0, dusen = 0;

function denetle(k) {
  const r = get({ port: k.nokta, path: "/saglik", timeout: 100 }, (y) => {
    y.resume();
    if (y.statusCode === 200) { k.hata = 0; k.ayakta = true; } else basarisiz(k);
  });
  r.on("error", () => basarisiz(k));
  r.on("timeout", () => r.destroy());
}
function basarisiz(k) { k.hata += 1; if (k.hata >= ESIK) k.ayakta = false; }

if (Number.isInteger(nokta) === false || kopya.length === 0) {
  console.log("kullanim: node denge/dengeleyici.mjs <nokta> <acik|kapali> <kopya-noktalari...>");
} else {
  if (saglikAcik) setInterval(() => kopya.forEach(denetle), ARALIK).unref();
  createServer((istekDisi, yanitDisi) => {
    if (istekDisi.url === "/yonet/durum") {
      yanitDisi.writeHead(200, { "content-type": "application/json" });
      yanitDisi.end(JSON.stringify({ ulasilamayan: dusen,
        ayakta: kopya.filter((k) => k.ayakta).map((k) => k.nokta) }));
      return;
    }
    const havuz = kopya.filter((k) => k.ayakta);
    if (havuz.length === 0) { yanitDisi.writeHead(503).end("havuz bos"); return; }
    const secilen = havuz[sira++ % havuz.length];
    const istekIc = request({ port: secilen.nokta, path: istekDisi.url,
      method: istekDisi.method, headers: istekDisi.headers }, (yanitIc) => {
      yanitDisi.writeHead(yanitIc.statusCode, yanitIc.headers);
      yanitIc.pipe(yanitDisi);
    });
    istekIc.on("error", () => { dusen += 1; yanitDisi.writeHead(502).end("kopyaya ulasilamadi"); });
    istekDisi.pipe(istekIc);
  }).listen(nokta, "127.0.0.1");
}
```

İstemci istekleri **sırayla** gönderir; eşzamanlılık 1'de tutulması dağıtım sayılarını
belirlenimli kılar, yoksa aynı düzenek her koşumda başka bir bölünme verir.

```js
// denge/istemci.mjs — sirayla istek gonderir, yaniti hangi kopyanin verdigini sayar
import { Agent, request } from "node:http";

const [nokta, adet, etiket] = [Number(process.argv[2]), Number(process.argv[3]), process.argv[4]];
const agent = new Agent({ keepAlive: true, maxSockets: 1 });

function bir(no) {
  return new Promise((coz, sap) => {
    const r = request({ port: nokta, path: `/takip?no=${no}`, agent }, (y) => {
      y.resume();
      y.on("end", () => coz({ kod: y.statusCode, kopya: y.headers["x-kopya"] ?? "-" }));
    });
    r.on("error", sap);
    r.end();
  });
}

if (Number.isInteger(nokta) === false) console.log("kullanim: node denge/istemci.mjs <nokta> <adet> <etiket>");
else {
  const sayac = new Map();
  let basarili = 0, basarisiz = 0;
  for (let i = 0; i < adet; i += 1) {
    const s = await bir(`G${i}`);
    if (s.kod === 200) basarili += 1; else basarisiz += 1;
    const anahtar = s.kod === 200 ? s.kopya : `kod ${s.kod}`;
    sayac.set(anahtar, (sayac.get(anahtar) ?? 0) + 1);
  }
  const dagitim = [...sayac].sort().map(([a, n]) => `${a}=${n}`).join("  ");
  console.log(`${etiket.padEnd(30)} yanitlanan ${String(basarili).padStart(4)}/${adet}` +
    `  basarisiz ${String(basarisiz).padStart(3)}  |  ${dagitim}`);
  agent.destroy();
}
```

Sürücü betik aynı üç kopyanın önüne iki dengeleyici koyar: birinde sağlık denetimi açık,
ötekinde kapalı. Sonra `k2` kopyası öldürülür ve aynı yük her iki dengeleyiciye gönderilir.
Bağlantı noktası numaraları ortama bağlıdır; makinede kullanımdaysa değiştirilmelidir.

```bash
# olc.sh — uc kopya, iki dengeleyici (saglik denetimi acik ve kapali); k2 kopyasi dusurulur
node denge/kopya.mjs 8861 k1 & K1=$!
node denge/kopya.mjs 8862 k2 & K2=$!
node denge/kopya.mjs 8863 k3 & K3=$!
node denge/dengeleyici.mjs 8851 acik   8861 8862 8863 & DA=$!
node denge/dengeleyici.mjs 8852 kapali 8861 8862 8863 & DK=$!
sleep 1

node denge/istemci.mjs 8851 300 "uc kopya ayakta"
kill $K2; sleep 1
node denge/istemci.mjs 8851 300 "k2 dustu, denetim acik"
node denge/istemci.mjs 8852 300 "k2 dustu, denetim kapali"
echo "havuz (denetim acik)  : $(curl -s localhost:8851/yonet/durum)"
echo "havuz (denetim kapali): $(curl -s localhost:8852/yonet/durum)"
kill $K1 $K3 $DA $DK
```

```
uc kopya ayakta                yanitlanan  300/300  basarisiz   0  |  k1=100  k2=100  k3=100
k2 dustu, denetim acik         yanitlanan  300/300  basarisiz   0  |  k1=150  k3=150
k2 dustu, denetim kapali       yanitlanan  200/300  basarisiz 100  |  k1=100  k3=100  kod 502=100
havuz (denetim acik)  : {"ulasilamayan":0,"ayakta":[8861,8863]}
havuz (denetim kapali): {"ulasilamayan":100,"ayakta":[8861,8862,8863]}
```

#### Ölçülen Etki

Bu sayılar **ölçüm** sınıfındadır: yerel süreçlerden alınmıştır. Belirlenimlidir, çünkü istekler
sırayla gönderilir ve dağıtım kuralı sıralıdır; başka bir makinede de aynı bölünme çıkar, ama
bağlantı noktaları ortama bağlıdır.

İlk satır dağıtımı gösteriyor: üç kopya ayaktayken 300 istek 100–100–100 bölünüyor. Dengeleyici
tek başına bir kazanç üretmiyor, yalnız yükü üçe ayırıyor — ve bu ayırma bir sonraki bölümde bir
kapasite hesabına dönüşecek.

İkinci ve üçüncü satır dersin asıl ölçümüdür. Aynı arıza, aynı yük, aynı kopyalar. Sağlık
denetimi açık dengeleyici 300 isteğin 300'ünü yanıtladı ve yükü kalan iki kopyaya 150–150 böldü;
havuz durumu `k2` kopyasının bağlantı noktasını listeden düşürmüş durumda. Sağlık denetimi kapalı
dengeleyici 300 isteğin yalnız 200'ünü yanıtladı: sıralı dağıtım her üç istekten birini ölü
kopyaya gönderdi ve 100 istek 502 ile döndü. Havuz durumu üç kopyanın da ayakta sayıldığını
gösteriyor.

Buradan çıkan sonuç dengeleyicinin tanımını değiştirir. **Dağıtım tek başına hizmet
erişilebilirliği üretmez.** Kopya sayısını artırmak, düşen kopyayı fark eden bir denetim yoksa yalnızca arızayı
seyrelten bir şeydir: bir kopya düştüğünde sistem tamamen durmaz, ama isteklerin üçte biri
düşmeye devam eder ve bu durum kendini bir toplu kesinti olarak duyurmaz. Sağlık denetimi,
kopyalamayı bir hizmet erişilebilirliği aracına çeviren parçadır.

#### TLS Sonlandırma Nerede Biter

Şifreli bağlantının nerede bittiği bir **konum kararıdır** ve bu kursta ölçülen sonucu bir
süre değil, bir görünürlüktür. Yukarıdaki dengeleyici `istekDisi.url` değerini okuyor —
`/yonet/durum` yolunu ayırt edebilmesi buna dayanıyor. Bu satırın var olabilmesinin koşulu
bağlantının dengeleyicide sonlanmasıdır: şifreli akış kopyaya kadar taşınıyorsa dengeleyicinin
elinde yol, başlık ve gövde değil yalnız baytlar olur. TLS ve el sıkışma Ağ Modelleri ve
Protokoller kursunda kuruldu ve burada yeniden anlatılmaz; kararın bu derse ait sonucu şudur:
**sonlandırma, içeriğe bakan bir dağıtım kuralının önkoşuludur.**

Kararın ikinci sonucu sayılabilir. Sertifikayı tutan uç sayısı, sonlandırma dengeleyicide
yapıldığında 1, kopyalarda yapıldığında kopya sayısı kadardır; havuza bir kopya eklemek ilkinde 0
sertifika işi, ikincisinde 1 sertifika işi doğurur. Şifreleme işinin işlemci maliyeti burada
ölçülmez, çünkü seçilen şifre takımına ve donanıma bağlıdır — bu kursun kuralı gereği
ölçülmeyen bir sayı yazılmaz.

#### Hesaba Geri Dönüş

Sistem Tasarımına Giriş kursu uçta tepe istek hızını 513,89 istek/s olarak hesaplamıştı. O sayı
tek bir kopyanın taşıyacağı yük değildir; kopya sayısına bölünür. Bölmenin yapılabilmesi için bu
konunun kendi varsayımları gerekir ve bunlar K01'in V1–V13 tablosuna **eklenmez**:

**Y1 — kopya başına doyum verimi: 400 istek/s.** Gerekçe: K01'in Gecikme ve Verim dersinde çıplak
bir uçta ölçülen üst sınır 4268 istek/s'ydi; gerçek takip ucu depoya bakar, seri hâle getirir ve
yetkilendirme yapar, bu yüzden plan sayısı ölçülenin çok altında seçilir. **Y2 — hedef doluluk
0,50.** Gerekçe: aynı dersin kuyruk modelinde doluluk yüzde 50'de süreyi 1,4 katına, yüzde 90'da
7 katına çıkarıyordu. **Y3 — sağlık denetimi aralığı 200 ms, eşik 1 tur.** Gerekçe: düzenekte
kullanılan değerler.

```js
// denge/kapasite.mjs — K01 hesabinin kopya sayisina bolunmesi ve saglik denetiminin butceye etkisi
const TEPE_UC = 513.89;            // K01 Kabaca Buyukluk Hesabi: tepe ucta istek/s
const GUNLUK_ISTEK = 12_000_000 + 2_800_000;   // K01: gunluk takip sorgusu + durum olayi
const DOYUM = 400;                 // varsayim Y1: kopya basina doyum verimi (istek/s)
const HEDEF_DOLULUK = 0.5;         // varsayim Y2: kopyanin hedef dolulugu
const DENETIM_MS = 200;            // varsayim Y3: saglik denetimi araligi, esik 1 tur
const KURTARMA_DK = 10;            // K01 Erisilebilirligin Sayisal Ifadesi: kurtarma suresi
const ARIZA_AY = 2.82;             // K01: ayda butceye sigan ariza sayisi

const guvenli = DOYUM * HEDEF_DOLULUK;
const enAz = Math.ceil(TEPE_UC / guvenli);
console.log(`kopya basina guvenli hiz = ${guvenli} istek/s (${DOYUM} x ${HEDEF_DOLULUK})`);
console.log(`en az kopya = ceil(${TEPE_UC} / ${guvenli}) = ${enAz}\n`);

console.log("kopya  kopya basina istek/s  doluluk  bir kopya dususunde istek/s  o an doluluk");
for (const n of [enAz, enAz + 1, enAz + 2]) {
  const pay = TEPE_UC / n, kalan = TEPE_UC / (n - 1);
  console.log(`${String(n).padStart(5)}  ${pay.toFixed(2).padStart(20)}  ` +
    `${(pay / DOYUM).toFixed(3).padStart(7)}  ${kalan.toFixed(2).padStart(27)}  ` +
    `${(kalan / DOYUM).toFixed(3).padStart(12)}`);
}

const ortalama = GUNLUK_ISTEK / 86_400;
console.log(`\nortalama uc hizi = ${ortalama.toFixed(2)} istek/s; tepe / ${enAz} kopya = ` +
  `${(TEPE_UC / enAz).toFixed(2)} istek/s (tepe carpani ${enAz} oldugu icin ayni sayi)`);

const ayIstek = GUNLUK_ISTEK * 30;
console.log(`\npencere            dusen istek/ariza   aylik dusen istek   istek tabanli erisilebilirlik`);
for (const [ad, sn] of [["saglik denetimi", DENETIM_MS / 1000], ["elle kurtarma", KURTARMA_DK * 60]]) {
  const bir = (TEPE_UC / enAz) * sn, aylik = bir * ARIZA_AY;
  console.log(`${ad.padEnd(18)} ${bir.toFixed(2).padStart(17)} ${aylik.toFixed(0).padStart(19)}   ` +
    `%${(100 * (1 - aylik / ayIstek)).toFixed(5)}`);
}

const denetimHizi = (enAz * 1000) / DENETIM_MS;
console.log(`\ndenetim yuku = ${denetimHizi} istek/s, tepe ucun %${((denetimHizi / TEPE_UC) * 100).toFixed(1)}'i`);
console.log(`duyarlilik: Y1 iki katina cikarsa en az kopya = ${Math.ceil(TEPE_UC / (2 * DOYUM * HEDEF_DOLULUK))}, ` +
  `yarilanirsa = ${Math.ceil(TEPE_UC / (0.5 * DOYUM * HEDEF_DOLULUK))}`);
```

```
kopya basina guvenli hiz = 200 istek/s (400 x 0.5)
en az kopya = ceil(513.89 / 200) = 3

kopya  kopya basina istek/s  doluluk  bir kopya dususunde istek/s  o an doluluk
    3                171.30    0.428                       256.94         0.642
    4                128.47    0.321                       171.30         0.428
    5                102.78    0.257                       128.47         0.321

ortalama uc hizi = 171.30 istek/s; tepe / 3 kopya = 171.30 istek/s (tepe carpani 3 oldugu icin ayni sayi)

pencere            dusen istek/ariza   aylik dusen istek   istek tabanli erisilebilirlik
saglik denetimi                34.26                  97   %99.99998
elle kurtarma              102778.00              289834   %99.93472

denetim yuku = 15 istek/s, tepe ucun %2.9'i
duyarlilik: Y1 iki katina cikarsa en az kopya = 2, yarilanirsa = 6
```

Bu sayıların hepsi **hesap** sınıfındadır. En az kopya sayısı üçtür ve o üç kopyada her biri
171,30 istek/s taşır. İkinci tablonun ilk sütunu bir kopya düştüğü **anda** ne olduğunu
gösteriyor: kalan iki kopya 256,94 istek/s'ye ve 0,642 doluluğa çıkar; üç kopya seçilen bir
tasarım, tek bir arızada hedef doluluğunun üstüne taşar. Dört kopyada aynı durumda doluluk
0,428'de kalır — yani "en az kopya sayısı" ile "bir kopya düşse de hedefi tutan kopya sayısı"
ayrı iki sayıdır ve aradaki fark bir kopyadır.

Ortalama satırı bir çakışmayı kaydediyor: tepenin üç kopyaya bölümü 171,30 istek/s ve sistemin
ortalama uç hızı da 171,30 istek/s. İki sayı eşittir çünkü tepe çarpanı 3'tür ve kopya sayısı da
3 seçilmiştir; bu bir bağıntı değildir, varsayımların ürettiği bir çakışmadır. Kopya sayısı
değiştiğinde eşitlik bozulur.

Son tablo sağlık denetiminin kesinti bütçesindeki karşılığıdır. K01'in Erişilebilirliğin Sayısal
İfadesi dersi aylık 43,2 dakikalık bütçenin 28,2 dakikasını arızaya ayırmış, on dakikalık
kurtarma süresiyle ayda 2,82 arıza saymıştı. O hesap her arızanın **tam kesinti** olduğunu
varsayıyordu. Üç kopyalı bir havuzda tek bir kopyanın düşmesi tam kesinti değildir: sağlık
denetimi varsa arıza başına 34,26 istek düşer ve aylık toplam 97 istektir. Denetim yoksa aynı
arıza kurtarmaya kadar sürer, arıza başına 102 778 istek düşer ve aylık toplam 289 834'e çıkar —
aradaki oran 3000 kattır. Denetimin faturası da hesaplanmıştır: kopyalara giden 15 istek/s, tepe
uçtaki yükün yüzde 2,9'u.

İstek tabanlı sütun bir uyarı içeriyor. Denetimsiz düzenin oranı yüzde 99,93472'dir ve yüzde
99,9'luk hedefin üstünde görünür; oysa aynı arızalar zaman tabanlı bütçenin arıza payının
tamamını harcar. Aynı arıza iki tabanda iki farklı büyüklükte görünüyor, çünkü isteklerin
yalnızca üçte biri düşüyor. K01 bu iki tabanı ayırmıştı; buradaki sayılar ayrımın neden gerekli
olduğunu gösteriyor.

#### Özet

- Yük dengeleyici üç sorumluluk taşır: dağıtım, sağlık denetimi ve TLS sonlandırma; ilki yükü
  paylaştırır, ikincisi düşen kopyayı havuzdan çıkarır, üçüncüsü şifreli bağlantının nerede
  bittiğini belirler.
- Aynı arızada sağlık denetimi açık düzenek 300/300 isteği yanıtladı ve yükü 150–150 böldü;
  kapalı düzenek 200/300 yanıtladı ve 100 istek 502 ile döndü.
- Dağıtım tek başına hizmet erişilebilirliği üretmez: düşen kopyayı fark eden bir denetim yoksa
  isteklerin üçte biri düşmeye devam eder ve bu bir toplu kesinti olarak görünmez.
- TLS sonlandırmanın bu dersteki ölçülen sonucu görünürlüktür: bağlantı dengeleyicide bitmezse
  yol ve başlık okunamaz, dolayısıyla içeriğe bakan bir dağıtım kuralı kurulamaz.
- Tepe 513,89 istek/s, kopya başına güvenli hız 200 istek/s (Y1 ve Y2) ile en az 3 kopya verir ve
  her kopya 171,30 istek/s taşır; bir kopya düştüğünde kalanlar 256,94 istek/s ve 0,642 dolulukla
  hedefin üstüne taşar, dört kopyada taşmaz.
- Sağlık denetimi arıza başına düşen isteği 102 778'den 34,26'ya indiriyor (aylık 289 834'e karşı
  97, oran 3000 kat); denetimin kendi yükü 15 istek/s, tepe uçtaki yükün yüzde 2,9'u.

#### Sonraki Adım

Bu dersin dengeleyicisi kararını her istek için verdi ve kararı verebilmek için isteğin yolunu
okudu — `/yonet/durum` ayrımı buna dayanıyordu. Okumak bir seçimdir, zorunluluk değil. Bir
dengeleyici isteğin içine hiç bakmadan da çalışabilir: kararı bağlantı kurulurken bir kez verir,
sonra o bağlantıdan akan her şeyi aynı kopyaya geçirir. Bu daha az iş yapar ve daha az şey bilir.
Sonraki ders bu düzeyi kurar: bağlantı düzeyinde dağıtımın ne bilemediğini, kalıcı bağlantıların
dağıtımı nasıl bozduğunu ve bağlantı başına verilen bir kararın istek başına dağılımı hangi
sapmayla ürettiğini ölçer.

### Katman 4 Dengeleme

Source: https://academia.sh/tr/kurslar/trafik-katmani/katman-4-dengeleme

Kararın bağlantı kurulurken bir kez verilmesi ve bunun bedeli: aynı toplam yükün eşit ve eşitsiz istemci paylarıyla ölçülmesi, kusursuz bağlantı dağıtımının dört kat istek sapması üretmesi, kararı vermek için okunan bilginin sayılması ve ölçülen dengesizliğin giriş kursundaki tepe hızda kaç kopyaya karşılık geldiğinin hesaplanması.

Önceki dersin dengeleyicisi kararını her istek için verdi ve kararı verebilmek için isteğin
yolunu okudu. Okumak bir seçimdir, zorunluluk değildir. Bir dengeleyici isteğin içine hiç
bakmadan da çalışabilir: kararı bağlantı kurulurken bir kez verir, sonra o bağlantıdan akan her
şeyi aynı kopyaya geçirir.

Bu düzeyin adı **katman 4 dengeleme**dir. Katman modeli Ağ Modelleri ve Protokoller kursunda
kuruldu: katman 4 taşıma katmanıdır ve orada görülen şey adres, bağlantı noktası ve bayt
akışıdır; yol, başlık ve gövde bir katman yukarıdadır. Bu ders o düzeyi kurar, ne bilemediğini
sayar ve bilmemenin dağıtıma ne yaptığını ölçer.

#### Bağlantı Başına Bir Karar

Katman 4 dengeleyici bir bağlantı kabul eder, bir kopya seçer, o kopyaya kendi bağlantısını açar
ve iki yön arasında baytları oldukça aktarır. Seçim bir kez yapılır; bağlantı kapanana kadar
geçerlidir.

```js
// k4/dengeleyici.mjs — katman 4 dengeleyici: karar baglanti kurulurken bir kez verilir, sonra
// iki yon oldugu gibi aktarilir. Kullanim: node k4/dengeleyici.mjs <nokta> <sayac.json> <kopyalar...>
import { createServer, connect } from "node:net";
import { writeFileSync } from "node:fs";

const nokta = Number(process.argv[2]);
const sayacYolu = process.argv[3];
const kopya = process.argv.slice(4).map(Number);
const sayac = { karar: 0, baglanti: Object.fromEntries(kopya.map((p) => [p, 0])), bayt: 0 };
let sira = 0;

if (Number.isInteger(nokta) === false || kopya.length === 0) {
  console.log("kullanim: node k4/dengeleyici.mjs <nokta> <sayac.json> <kopyalar...>");
} else {
  const s = createServer((disi) => {
    const hedef = kopya[sira++ % kopya.length];   // tek karar: bu baglanti hangi kopyaya ait
    sayac.karar += 1;
    sayac.baglanti[hedef] += 1;
    const ici = connect(hedef, "127.0.0.1");
    disi.on("data", (p) => { sayac.bayt += p.length; });   // gecen bayt sayilir, icerigi okunmaz
    disi.pipe(ici);
    ici.pipe(disi);
    for (const [a, b] of [[disi, ici], [ici, disi]]) {
      a.on("error", () => b.destroy());
      a.on("close", () => b.destroy());
    }
  });
  s.listen(nokta, "127.0.0.1");
  process.on("SIGTERM", () => { writeFileSync(sayacYolu, JSON.stringify(sayac)); process.exit(0); });
}
```

Kodun taşıdığı ayrım `node:net` ile `node:http` arasındaki ayrımdır. Bu dosyada bir HTTP isteği
nesnesi yoktur, dolayısıyla bir yol, bir başlık ya da bir takip numarası da yoktur. Sayaçta
tutulabilen tek içerik ölçüsü **geçen bayt** sayısıdır — ve o bile ne olduğu bilinmeyen baytların
sayısıdır.

Kopyalar bir katman yukarıda çalışır ve gördükleri isteği yola göre sayar. Sayaçlarını `/sayac`
yolundan bildirirler; bu yol dengeleyiciden değil doğrudan sorulur, bu yüzden ölçüme karışmaz.

```js
// k4/kopya.mjs — uygulama kopyasi: gordugu istekleri yola gore sayar, /sayac ile bildirir
import { createServer } from "node:http";

const [port, ad] = [Number(process.argv[2]), process.argv[3]];
const sayac = { ad, istek: 0, yol: {} };

if (Number.isInteger(port) === false) console.log("kullanim: node k4/kopya.mjs <nokta> <ad>");
else createServer((istek, yanit) => {
  yanit.sendDate = false;
  const yol = new URL(istek.url, "http://yerel").pathname;
  if (yol === "/sayac") {
    yanit.writeHead(200, { "content-type": "application/json" }).end(JSON.stringify(sayac));
    return;
  }
  sayac.istek += 1;
  sayac.yol[yol] = (sayac.yol[yol] ?? 0) + 1;
  yanit.writeHead(200, { "content-type": "application/json", "x-kopya": ad });
  yanit.end(JSON.stringify({ durum: "aktarma merkezinde", bolge: "35", adim: 4 }));
}).listen(port, "127.0.0.1");
```

İstemci düzeneğin asıl parametresini taşır: her istemci **tek bir kalıcı bağlantı** açar ve
payındaki istekleri o bağlantıdan gönderir. Payların eşit olup olmaması ölçümün girdisidir.
İstemciler sırayla koşar; böylece bağlantı kurulma sırası, dolayısıyla sıralı dağıtımın verdiği
eşleme belirlenimli olur.

```js
// k4/istemci.mjs — her istemci tek kalici baglanti acar ve payindaki istekleri sirayla gonderir
import { Agent, request } from "node:http";

const nokta = Number(process.argv[2]);
const PAY = (process.argv[3] ?? "1").split(",").map(Number);   // istemci basina istek sayisi

function bir(agent, no, yol) {
  return new Promise((coz, sap) => {
    const r = request({ port: nokta, path: `${yol}?no=${no}`, agent }, (y) => {
      y.resume();
      y.on("end", () => coz(y.headers["x-kopya"] ?? "-"));
    });
    r.on("error", sap);
    r.end();
  });
}

if (Number.isInteger(nokta) === false) console.log("kullanim: node k4/istemci.mjs <nokta> <pay,pay,...>");
else {
  let toplam = 0;
  for (let i = 0; i < PAY.length; i += 1) {            // istemciler sirayla kosar: baglanti sirasi belirlenimli
    const agent = new Agent({ keepAlive: true, maxSockets: 1 });
    for (let j = 0; j < PAY[i]; j += 1) {
      await bir(agent, `I${i}-${j}`, j % 2 === 0 ? "/takip" : "/olay");
      toplam += 1;
    }
    agent.destroy();
  }
  console.log(`${PAY.length} istemci, ${toplam} istek gonderildi (pay: ${PAY.join(",")})`);
}
```

Rapor betiği iki kaynağı birleştirir: dengeleyicinin bağlantı sayaçları ile kopyaların istek
sayaçları.

```js
// k4/rapor.mjs — dengeleyicinin sayac dosyasi ile kopyalarin /sayac ciktisini tek tabloda birlestirir
import { existsSync, readFileSync } from "node:fs";

const [sayacYolu, ...noktalar] = process.argv.slice(2);
if (sayacYolu === undefined || existsSync(sayacYolu) === false) {
  console.log("kullanim: node k4/rapor.mjs <sayac.json> <kopya-noktalari...>");
  process.exit(0);
}
const d = JSON.parse(readFileSync(sayacYolu, "utf8"));

const satir = [];
for (const p of noktalar) {
  const y = await fetch(`http://127.0.0.1:${p}/sayac`).then((r) => r.json());
  satir.push({ ad: y.ad, nokta: p, baglanti: d.baglanti[p], istek: y.istek,
    yol: Object.entries(y.yol).sort().map(([a, n]) => `${a.slice(1)}=${n}`).join(" ") });
}

const istek = satir.map((s) => s.istek);
console.log("kopya  baglanti  istek  yol dagilimi");
for (const s of satir) {
  console.log(`${s.ad.padEnd(5)}  ${String(s.baglanti).padStart(8)}  ${String(s.istek).padStart(5)}  ${s.yol}`);
}
console.log(`karar sayisi = ${d.karar} (baglanti basina 1), istek basina karar = ` +
  `${(d.karar / istek.reduce((a, b) => a + b, 0)).toFixed(3)}`);
console.log(`baglanti sapmasi = ${(Math.max(...satir.map((s) => s.baglanti)) / Math.min(...satir.map((s) => s.baglanti))).toFixed(2)}, ` +
  `istek sapmasi = ${(Math.max(...istek) / Math.min(...istek)).toFixed(2)}`);
console.log(`dengeleyiciden gecen istek bayti = ${d.bayt}`);
```

Düzenek iki kez koşar. İkisinde de altı istemci ve üç kopya vardır; değişen tek şey isteklerin
istemcilere nasıl dağıldığıdır. Bağlantı noktaları ortama bağlıdır.

```bash
# olc.sh — ayni toplam yuk iki istemci karisimiyla: esit paylar ve esitsiz paylar
for karisim in "10,10,10,10,10,10" "1,2,4,8,16,32"; do
  node k4/kopya.mjs 8871 k1 & K1=$!
  node k4/kopya.mjs 8872 k2 & K2=$!
  node k4/kopya.mjs 8873 k3 & K3=$!
  node k4/dengeleyici.mjs 8841 sayac.json 8871 8872 8873 & D=$!
  sleep 1
  node k4/istemci.mjs 8841 "$karisim"
  kill -TERM $D; sleep 0.3
  node k4/rapor.mjs sayac.json 8871 8872 8873
  kill $K1 $K2 $K3; sleep 0.3
  echo
done
```

```
6 istemci, 60 istek gonderildi (pay: 10,10,10,10,10,10)
kopya  baglanti  istek  yol dagilimi
k1            2     20  olay=10 takip=10
k2            2     20  olay=10 takip=10
k3            2     20  olay=10 takip=10
karar sayisi = 6 (baglanti basina 1), istek basina karar = 0.100
baglanti sapmasi = 1.00, istek sapmasi = 1.00
dengeleyiciden gecen istek bayti = 4590

6 istemci, 63 istek gonderildi (pay: 1,2,4,8,16,32)
kopya  baglanti  istek  yol dagilimi
k1            2      9  olay=4 takip=5
k2            2     18  olay=9 takip=9
k3            2     36  olay=18 takip=18
karar sayisi = 6 (baglanti basina 1), istek basina karar = 0.095
baglanti sapmasi = 1.00, istek sapmasi = 4.00
dengeleyiciden gecen istek bayti = 4848
```

#### İki Sapma Aynı Tabloda

Bu sayılar **ölçüm** sınıfındadır ve belirlenimlidir; istemciler sırayla koştuğu ve dağıtım
kuralı sıralı olduğu için başka bir makinede de aynı bölünme çıkar.

İki koşumda da bağlantı sapması 1,00'dır: dengeleyici altı bağlantıyı üç kopyaya ikişer ikişer
paylaştırdı ve bu paylaşımda hiçbir kusur yok. Kendisine verilen işi kusursuz yapıyor. Birinci
koşumda istek sapması da 1,00: paylar eşit olduğu için bağlantı dengesi istek dengesine
çeviriyor.

İkinci koşumda aynı kusursuz bağlantı dağıtımı **4,00 kat** istek sapması üretiyor. Kopyalar 9,
18 ve 36 istek gördü; en yüklü kopya en az yüklü olanın dört katını taşıdı. Değişen tek şey
isteklerin bağlantılara nasıl dağıldığıdır. **Katman 4 dengeleyici bağlantıları dengeler, isteği
dengelemez;** ikisi aynı şey olmadığı için ölçüm iki ayrı sapma sütunu gerektirir.

Sapmanın kaynağı kalıcı bağlantıdır. Bir bağlantı bir istek taşıyorsa iki sayı aynıdır; bir
bağlantı otuz iki istek taşıyorsa dengeleyicinin bir kararı otuz iki isteği birden bağlar. Karar
bir kez verildiği için de düzeltilemez: dengeleyici 36 isteğin aynı kopyaya gittiğini fark
etmez, çünkü onları hiç saymaz.

#### Ne Bilinmiyor

Karar sütunu bilmemenin ölçüsüdür: 63 istek için 6 karar, istek başına 0,095 karar. Katman 4
dengeleyicinin işi bu orandan ucuzdur — bir bağlantı için bir kez seçim yapıp sonra baytları
geçirmek, her isteği ayrıştırıp yeniden yazmaktan daha az iştir.

Ödenen bedel yol dağılımı sütununda görünüyor. Her kopya hem `takip` hem `olay` isteği aldı ve
oranlar bağlantı paylarının aynısı. Kopyaların bir kısmını okumaya, bir kısmını yazmaya
ayırmak bu düzeyde **olanaksızdır**: karar bağlantı kurulurken verilir ve o anda henüz bir yol
gönderilmemiştir. Aynı kısıt daha ince ayrımlar için de geçerlidir — takip numarasına, istemci
türüne ya da bir başlığa bakan bir kural yazılamaz, çünkü bunların hiçbiri katman 4'te
görünmez. Dengeleyicinin gördüğü 4848 bayt, içeriği bilinmeyen bir akıştır.

Bilinmemenin bir de olumlu yüzü var. Katman 4 dengeleyici HTTP bilmediği için HTTP'ye bağlı
değildir: aynı kod başka bir bağlantı tabanlı protokol için de çalışır ve gövdeyi
tamponlamadığı için akış hâlinde giden veri araya girmeden geçer.

#### Hesaba Geri Dönüş

Önceki ders 513,89 istek/s tepe hızı üç kopyaya bölmüş ve kopya başına 171,30 istek/s bulmuştu.
O bölme, dağıtımın kusursuz olduğunu varsayıyordu. Ölçülen sapma varsayımı bozar. Aşağıdaki
hesap ölçülen paylardan bir **dengesizlik çarpanı** çıkarır: en yüklü kopyanın payı ile kopya
sayısının çarpımı, kusursuz dengede 1'dir.

Bir varsayım daha gerekir. **Y4 — kalıcı bağlantı başına ortalama istek: 10.** Gerekçe: bir
kullanıcı takip sayfasını açtığında aynı bağlantıdan birkaç sorgu geçer; sayı bu konunun kendi
varsayımıdır, K01'in tablosuna eklenmez.

```js
// k4/kapasite.mjs — olculen dengesizligin K01 tepe hizindaki karsiligi ve gereken kopya sayisi
const TEPE_UC = 513.89;            // K01 Kabaca Buyukluk Hesabi: tepe ucta istek/s
const GUVENLI = 200;              // 01. ders: Y1 x Y2 = 400 x 0.50
const ISTEK_BAGLANTI = 10;        // varsayim Y4: kalici baglanti basina ortalama istek

const OLCUM = { esit: [20, 20, 20], esitsiz: [9, 18, 36] };   // 02. dersin olcumu

const dengesizlik = (d) => (Math.max(...d) / d.reduce((a, b) => a + b, 0)) * d.length;
const gereken = (d) => Math.ceil((dengesizlik(d) * TEPE_UC) / GUVENLI);

console.log("karisim   paylar        en yuklu pay   dengesizlik   en yuklu kopya istek/s   doluluk   gereken kopya");
for (const [ad, d] of Object.entries(OLCUM)) {
  const enYuklu = Math.max(...d) / d.reduce((a, b) => a + b, 0);
  const hiz = enYuklu * TEPE_UC;
  console.log(`${ad.padEnd(9)} ${d.join("/").padEnd(13)} ${enYuklu.toFixed(4).padStart(12)} ` +
    `${dengesizlik(d).toFixed(3).padStart(13)} ${hiz.toFixed(2).padStart(24)} ` +
    `${(hiz / 400).toFixed(3).padStart(9)} ${String(gereken(d)).padStart(15)}`);
}

console.log(`\nkusursuz dengede kopya = ${gereken(OLCUM.esit)}, olculen dengesizlikte = ` +
  `${gereken(OLCUM.esitsiz)}: fark ${gereken(OLCUM.esitsiz) - gereken(OLCUM.esit)} kopya, ` +
  `yalnizca dagilim sapmasi icin`);

console.log(`\nkarar hizi (baglanti basina 1 karar, Y4 = ${ISTEK_BAGLANTI}): ` +
  `${(TEPE_UC / ISTEK_BAGLANTI).toFixed(2)} karar/s`);
console.log(`istek basina karar verilse: ${TEPE_UC} karar/s, ${ISTEK_BAGLANTI} kat`);
console.log(`duyarlilik: Y4 = 1 ise iki hiz esitlenir, Y4 = 100 ise oran 100 kat olur`);
```

```
karisim   paylar        en yuklu pay   dengesizlik   en yuklu kopya istek/s   doluluk   gereken kopya
esit      20/20/20            0.3333         1.000                   171.30     0.428               3
esitsiz   9/18/36             0.5714         1.714                   293.65     0.734               5

kusursuz dengede kopya = 3, olculen dengesizlikte = 5: fark 2 kopya, yalnizca dagilim sapmasi icin

karar hizi (baglanti basina 1 karar, Y4 = 10): 51.39 karar/s
istek basina karar verilse: 513.89 karar/s, 10 kat
duyarlilik: Y4 = 1 ise iki hiz esitlenir, Y4 = 100 ise oran 100 kat olur
```

Hesap sınıfındaki bu sayılar önceki dersin sonucunu düzeltiyor. Kusursuz dengede en yüklü kopya
171,30 istek/s ve 0,428 doluluk taşır; ölçülen dengesizlikte 293,65 istek/s ve 0,734 doluluk
taşır. İkinci sayı Y2 ile konan 0,50 hedefinin üstündedir, yani üç kopyalı tasarım tepe yükte
hedefi tutmaz. Hedefi tutmak için gereken kopya sayısı 3 yerine **5**'tir ve fazladan iki kopya
yükün büyümesi için değil, yalnızca dağılım sapması için ödenir.

Karar hızı satırı bir sonraki dersin fiyat etiketini de veriyor. Bağlantı başına karar
verildiğinde dengeleyici saniyede 51,39 karar üretir; istek başına karar verilse 513,89 karar
üretir, on kat fazla. Sapmayı düzeltmenin yolu bu on katı ödemekten geçiyor.

#### Özet

- Katman 4 dengeleme kararı bağlantı kurulurken bir kez verir; o bağlantıdan akan bütün istekler
  aynı kopyaya gider ve karar sonradan düzeltilmez.
- Aynı toplam yük eşit paylarla 20–20–20, eşitsiz paylarla 9–18–36 bölündü: bağlantı sapması iki
  koşumda da 1,00, istek sapması 1,00'a karşı 4,00.
- Bağlantıyı dengelemek isteği dengelemek değildir; sapmanın kaynağı kalıcı bağlantıların eşit
  sayıda istek taşımamasıdır ve dengeleyici bunu ölçemez, çünkü istekleri saymaz.
- Karar sayısı 63 istek için 6'dır (istek başına 0,095); bu ucuzluk yol, başlık ve takip
  numarasının görünmemesiyle satın alınır — okuma ile yazmayı ayrı kopyalara ayırmak bu düzeyde
  olanaksızdır.
- Ölçülen dengesizlik çarpanı 1,714 tepe hızda en yüklü kopyayı 293,65 istek/s ve 0,734 dolulukla
  hedefin üstüne çıkarıyor; hedefi tutmak 3 yerine 5 kopya gerektiriyor.
- İstek başına karar vermenin bedeli Y4 = 10 varsayımıyla 51,39 karar/s yerine 513,89 karar/s,
  yani on kattır.

#### Sonraki Adım

Ölçülen 4,00 kat sapma ve ayrılamayan iki akış aynı nedenden geliyor: karar, karar için gereken
bilgi ortaya çıkmadan önce veriliyor. Bilgi bir katman yukarıda vardır — yol, başlık, yöntem ve
sorgu dizgisi bağlantı kurulduktan hemen sonra akmaya başlar. Bir dengeleyici bunları okumayı
seçerse her istek için yeniden karar verebilir, isteği içeriğine göre başka bir kopya kümesine
gönderebilir ve on kat karar üretmenin faturasını öder. Sonraki ders bu düzeyi kurar: aynı
istemci karışımının içerik farkındalıklı bir dengeleyiciden geçirilmesiyle sapmanın ne olduğunu,
okuma ile yazmanın ayrı havuzlara bölünmesinin kopya sayısını nasıl değiştirdiğini ve
dengeleyicinin isteği ayrıştırmasının hangi yeni sorumlulukları getirdiğini ölçer.

### Katman 7 Dengeleme

Source: https://academia.sh/tr/kurslar/trafik-katmani/katman-7-dengeleme

Kararın her istek için yeniden verilmesi ve isteğin içeriğine bakılması: aynı istemci karışımında istek sapmasının dört kattan bire inmesi, okuma ile yazma akışlarının ayrı kopya havuzlarına bölünmesi, dış bağlantıların iç bağlantılara indirgenmesi ve bölmenin giriş kursu hesabında kaç kopyaya mal olduğunun ölçülmesi.

Önceki dersin ölçtüğü 4,00 kat sapma ve ayrılamayan iki akış aynı nedenden geliyordu: karar,
karar için gereken bilgi ortaya çıkmadan önce veriliyordu. Bilgi bir katman yukarıda vardır. Yol,
yöntem, başlıklar ve sorgu dizgisi bağlantı kurulduktan hemen sonra akmaya başlar; bir dengeleyici
bunları okumayı seçerse her istek için yeniden karar verebilir.

Bu düzeyin adı **katman 7 dengeleme**dir. Katman 7 uygulama katmanıdır ve HTTP orada tanımlıdır;
protokolün kendisi Ağ Modelleri ve Protokoller kursunun konusudur ve burada yeniden anlatılmaz.
Bu dersin işi kararın **istek başına** ve **içeriğe bakılarak** verilmesinin ne kazandırdığını ve
ne ödettiğini ölçmektir.

#### Kararın Her İstek İçin Verilmesi

Katman 7 dengeleyici bir bağlantıyı iki parçaya böler: istemciyle kurduğu bağlantı ve kopyayla
kurduğu bağlantı. Arada isteği ayrıştırır, yolu okur, bir havuz seçer ve isteği yeniden yazarak
gönderir.

```js
// k7/dengeleyici.mjs — katman 7 dengeleyici: her istek icin yol okunur, havuz secilir, sirali
// dagitim yapilir. Kullanim: node k7/dengeleyici.mjs <nokta> <sayac.json> <okuma> <yazma>
import { createServer, request, Agent } from "node:http";
import { writeFileSync } from "node:fs";

const nokta = Number(process.argv[2]);
const sayacYolu = process.argv[3];
const HAVUZ = {
  okuma: (process.argv[4] ?? "").split(",").filter(Boolean).map(Number),
  yazma: (process.argv[5] ?? "").split(",").filter(Boolean).map(Number),
};
const sira = { okuma: 0, yazma: 0 };
const ajan = new Map();                       // kopya basina tek kalici ic baglanti
const gorulen = new WeakSet();                // ic baglantilarin tekil sayimi
const sayac = { karar: 0, disBaglanti: 0, icBaglanti: 0, dagilim: {} };

function say(kopya, havuz) {
  const a = (sayac.dagilim[kopya] ??= { okuma: 0, yazma: 0 });
  a[havuz] += 1;
}

if (Number.isInteger(nokta) === false || HAVUZ.okuma.length === 0) {
  console.log("kullanim: node k7/dengeleyici.mjs <nokta> <sayac.json> <okuma> <yazma>");
} else {
  const s = createServer((istekDisi, yanitDisi) => {
    const yol = new URL(istekDisi.url, "http://yerel").pathname;   // her istekte okunur
    const havuz = yol === "/olay" ? "yazma" : "okuma";
    const liste = HAVUZ[havuz];
    const hedef = liste[sira[havuz]++ % liste.length];
    sayac.karar += 1;
    say(hedef, havuz);
    if (ajan.has(hedef) === false) ajan.set(hedef, new Agent({ keepAlive: true, maxSockets: 1 }));
    const istekIc = request({ port: hedef, path: istekDisi.url, method: istekDisi.method,
      headers: { ...istekDisi.headers, forwarded: `for="${istekDisi.socket.remoteAddress}"` },
      agent: ajan.get(hedef) }, (yanitIc) => {
      yanitDisi.writeHead(yanitIc.statusCode, yanitIc.headers);
      yanitIc.pipe(yanitDisi);
    });
    istekIc.on("socket", (sok) => {
      if (gorulen.has(sok) === false) { gorulen.add(sok); sayac.icBaglanti += 1; }
    });
    istekIc.on("error", () => yanitDisi.writeHead(502).end("kopyaya ulasilamadi"));
    istekDisi.pipe(istekIc);
  });
  s.on("connection", () => { sayac.disBaglanti += 1; });
  s.listen(nokta, "127.0.0.1");
  process.on("SIGTERM", () => { writeFileSync(sayacYolu, JSON.stringify(sayac)); process.exit(0); });
}
```

Kopyalar bu düzenekte yalnız kendi adını bildirir; sayım artık dengeleyicidedir, çünkü kararı o
veriyor ve hangi isteği nereye gönderdiğini biliyor.

```js
// k7/kopya.mjs — uygulama kopyasi: yalnizca kendi adini bildirir, sayim dengeleyicide tutulur
import { createServer } from "node:http";

const [port, ad] = [Number(process.argv[2]), process.argv[3]];

if (Number.isInteger(port) === false) console.log("kullanim: node k7/kopya.mjs <nokta> <ad>");
else createServer((istek, yanit) => {
  yanit.sendDate = false;
  yanit.writeHead(200, { "content-type": "application/json", "x-kopya": ad });
  yanit.end(JSON.stringify({ durum: "aktarma merkezinde", bolge: "35", adim: 4 }));
}).listen(port, "127.0.0.1");
```

İstemci önceki dersin karışımını aynen tekrarlar — altı istemci, eşitsiz paylar, istemci başına
tek kalıcı bağlantı — ve bir şey ekler: yol karışımı. Beş istekten biri durum olayıdır, böylece
düzenekteki okuma/yazma oranı K01'in hesapladığı orana yakın durur.

```js
// k7/istemci.mjs — 02. dersin ayni karisimi: her istemci tek kalici baglanti, esitsiz paylar.
// Yol karisimi K01'in okuma/yazma oranini yaklasik tutar: bes istekten biri durum olayidir.
import { Agent, request } from "node:http";

const nokta = Number(process.argv[2]);
const PAY = (process.argv[3] ?? "1").split(",").map(Number);

function bir(agent, no, yol) {
  return new Promise((coz, sap) => {
    const r = request({ port: nokta, path: `${yol}?no=${no}`, agent }, (y) => {
      y.resume();
      y.on("end", () => coz(y.headers["x-kopya"] ?? "-"));
    });
    r.on("error", sap);
    r.end();
  });
}

if (Number.isInteger(nokta) === false) console.log("kullanim: node k7/istemci.mjs <nokta> <pay,pay,...>");
else {
  let g = 0, takip = 0, olay = 0;
  for (let i = 0; i < PAY.length; i += 1) {
    const agent = new Agent({ keepAlive: true, maxSockets: 1 });
    for (let j = 0; j < PAY[i]; j += 1) {
      const yol = g % 5 === 4 ? "/olay" : "/takip";
      if (yol === "/olay") olay += 1; else takip += 1;
      await bir(agent, `I${i}-${j}`, yol);
      g += 1;
    }
    agent.destroy();
  }
  console.log(`${PAY.length} istemci, ${g} istek: takip ${takip}, olay ${olay} ` +
    `(oran ${(takip / olay).toFixed(2)}; K01'de tepe okuma/yazma = 4.29)`);
}
```

```js
// k7/rapor.mjs — dengeleyicinin sayac dosyasini tabloya cevirir
import { existsSync, readFileSync } from "node:fs";

const yol = process.argv[2];
if (yol === undefined || existsSync(yol) === false) {
  console.log("kullanim: node k7/rapor.mjs <sayac.json>");
  process.exit(0);
}
const d = JSON.parse(readFileSync(yol, "utf8"));
const satir = Object.entries(d.dagilim).sort();
const toplam = satir.map(([, v]) => v.okuma + v.yazma);

console.log("kopya  takip  olay  toplam");
for (const [k, v] of satir) {
  console.log(`${k.padEnd(5)}  ${String(v.okuma).padStart(5)}  ${String(v.yazma).padStart(4)}  ` +
    `${String(v.okuma + v.yazma).padStart(6)}`);
}
console.log(`karar = ${d.karar} (istek basina 1), dis baglanti = ${d.disBaglanti}, ` +
  `ic baglanti = ${d.icBaglanti}`);
console.log(`istek sapmasi = ${(Math.max(...toplam) / Math.min(...toplam)).toFixed(2)}`);
```

Düzenek aynı dört kopyayı iki kez ayağa kaldırır. Birinci koşumda dördü de tek havuzdadır;
ikincisinde üçü okuma, biri yazma havuzundadır. Bağlantı noktaları ortama bağlıdır.

```bash
# olc.sh — ayni istemci karisimi iki yerlesimle: dort kopya tek havuzda, sonra okuma/yazma ayri
for yerlesim in "8881,8882,8883,8884:8881,8882,8883,8884" "8881,8882,8883:8884"; do
  OKUMA=${yerlesim%%:*}; YAZMA=${yerlesim##*:}
  node k7/kopya.mjs 8881 k1 & K1=$!
  node k7/kopya.mjs 8882 k2 & K2=$!
  node k7/kopya.mjs 8883 k3 & K3=$!
  node k7/kopya.mjs 8884 k4 & K4=$!
  node k7/dengeleyici.mjs 8845 sayac.json "$OKUMA" "$YAZMA" & D=$!
  sleep 1
  echo "okuma havuzu = $OKUMA   yazma havuzu = $YAZMA"
  node k7/istemci.mjs 8845 "1,2,4,8,16,32"
  kill -TERM $D; sleep 0.3
  node k7/rapor.mjs sayac.json
  kill $K1 $K2 $K3 $K4; sleep 0.3
  echo
done
```

```
okuma havuzu = 8881,8882,8883,8884   yazma havuzu = 8881,8882,8883,8884
6 istemci, 63 istek: takip 51, olay 12 (oran 4.25; K01'de tepe okuma/yazma = 4.29)
kopya  takip  olay  toplam
8881      13     3      16
8882      13     3      16
8883      13     3      16
8884      12     3      15
karar = 63 (istek basina 1), dis baglanti = 6, ic baglanti = 4
istek sapmasi = 1.07

okuma havuzu = 8881,8882,8883   yazma havuzu = 8884
6 istemci, 63 istek: takip 51, olay 12 (oran 4.25; K01'de tepe okuma/yazma = 4.29)
kopya  takip  olay  toplam
8881      17     0      17
8882      17     0      17
8883      17     0      17
8884       0    12      12
karar = 63 (istek basina 1), dis baglanti = 6, ic baglanti = 4
istek sapmasi = 1.42
```

#### Sapmanın Kaybolması

Bu sayılar **ölçüm** sınıfındadır ve belirlenimlidir. Karşılaştırma önceki dersin tablosuyla
yapılır: aynı altı istemci, aynı eşitsiz paylar, aynı toplam istek sayısı.

Katman 4'te istek sapması 4,00'dı. Katman 7'de 1,07. Sapmanın kaybolmasının nedeni tabloda
görünüyor: karar sayısı 63, yani istek başına 1. Otuz iki isteği tek bir bağlantıdan gönderen
istemci artık otuz iki ayrı karara konu oluyor ve o istekler dört kopyaya dağılıyor. Kalan 1,07
tam bölünememekten geliyor — 63 istek dörde bölündüğünde 16, 16, 16 ve 15 olur.

İkinci koşum ayrı bir kazanç gösteriyor. Aynı dengeleyici yolu okuduğu için `/takip` isteklerini
okuma havuzuna, `/olay` isteklerini yazma havuzuna gönderiyor: okuma kopyaları 17'şer takip
isteği, yazma kopyası 12 olay isteği aldı ve çapraz sızma yok. Katman 4'te olanaksız olan ayrım
burada bir liste ayrımına indi. Toplam sapmanın 1,42'ye çıkması bir kusur değil: havuzlar artık
farklı akışlara hizmet ettiği için tek bir sapma sayısıyla karşılaştırılmaları anlamsızdır, her
havuz kendi akış hızına göre boyutlanır.

Bağlantı sütunu üçüncü bir farkı taşıyor. Dış bağlantı 6, iç bağlantı 4. Dengeleyici istemcilerin
altı bağlantısını kopya başına tek kalıcı bağlantıya indiriyor; katman 4'te böyle bir indirgeme
olanaksızdı, çünkü orada her dış bağlantının bir iç bağlantı karşılığı vardı. Kopyaların gördüğü
bağlantı sayısı istemci sayısından bağımsız hâle geliyor.

#### Ödenen Bedel

Kazançların hepsi aynı satırda fiyatlanıyor: **63 karar**. Katman 4 aynı yükü 6 kararla geçirdi.
Karar başına yapılan iş de artmıştır — dengeleyici istek satırını ayrıştırır, başlıkları kopyalar,
kendi `forwarded` başlığını ekler ve isteği yeniden yazar. Bu işin süresi ölçülmüyor, çünkü
ayrıştırma maliyeti gerçekleştirime ve makineye bağlıdır; ölçülen şey işin **kaç kez**
yapıldığıdır.

İkinci bedel sorumluluk devridir. Dengeleyici isteği ayrıştırdığı andan itibaren istekle ilgili
kararların bir kısmının sahibi olur: hangi başlıkların iletileceği, gövdenin tamponlanıp
tamponlanmayacağı, bir kopya yanıt vermezken isteğin başka bir kopyaya yeniden gönderilip
gönderilmeyeceği. Katman 4 dengeleyicide bu soruların hiçbiri yoktu, çünkü orada bir istek
kavramı yoktu. İçeriğe bakan bir dengeleyici, uygulamanın bir parçası hâline gelir.

Üçüncü bedel bağımlılıktır. Katman 7 kuralları protokole ve yol adlarına bağlıdır. `/olay` yolu
`/durum-olayi` olarak yeniden adlandırıldığında dengeleyicinin yapılandırması da değişmelidir;
katman 4 dengeleyici bu değişiklikten hiç etkilenmezdi.

#### Hesaba Geri Dönüş

Önceki iki ders tek bir havuz varsayıp 513,89 istek/s tepe hızı böldü. İçerik farkındalıklı
yönlendirme bu bölmeyi ikiye ayırma seçeneğini açıyor ve K01'in iki akış hızı ayrı ayrı
hesaplanmıştı: tepe okuma 416,67 istek/s, tepe yazma 97,22 istek/s.

```js
// k7/havuz.mjs — K01 akis hizlarinin tek havuz ile ayri havuzlara bolunmesi ve yazma tasmasinin etkisi
const OKUMA = 416.67;              // K01 Kabaca Buyukluk Hesabi: tepe okuma istek/s
const YAZMA = 97.22;               // K01: tepe yazma istek/s
const DOYUM = 400;                 // 01. ders varsayim Y1
const GUVENLI = 200;               // 01. ders: Y1 x Y2

const kopya = (hiz) => Math.ceil(hiz / GUVENLI);
const doluluk = (hiz, n) => hiz / (n * DOYUM);

const tek = kopya(OKUMA + YAZMA);
const ok = kopya(OKUMA), ya = kopya(YAZMA);
console.log(`tek havuz : ${tek} kopya, doluluk ${doluluk(OKUMA + YAZMA, tek).toFixed(3)}`);
console.log(`ayri havuz: okuma ${ok} + yazma ${ya} = ${ok + ya} kopya, ` +
  `doluluk okuma ${doluluk(OKUMA, ok).toFixed(3)}, yazma ${doluluk(YAZMA, ya).toFixed(3)}`);
console.log(`bolmenin bedeli = ${ok + ya - tek} kopya\n`);

console.log("yazma carpani   tek havuz doluluk   ayri havuz okuma   ayri havuz yazma   yazma havuzu tasti");
for (const c of [1, 2, 3, 4]) {
  const y = YAZMA * c;
  console.log(`${`x${c}`.padStart(13)}   ${doluluk(OKUMA + y, tek).toFixed(3).padStart(17)}   ` +
    `${doluluk(OKUMA, ok).toFixed(3).padStart(16)}   ${doluluk(y, ya).toFixed(3).padStart(16)}   ` +
    `${String(y / ya > GUVENLI).padStart(18)}`);
}

console.log(`\nkarar hizi: katman 4'te ${((OKUMA + YAZMA) / 10).toFixed(2)} karar/s (Y4 = 10), ` +
  `katman 7'de ${(OKUMA + YAZMA).toFixed(2)} karar/s`);
console.log(`duyarlilik: yazma hizi ${(GUVENLI * ya).toFixed(0)} istek/s'yi gecince yazma havuzu ` +
  `${ya + 1} kopyaya cikar, okuma havuzu degismez`);
```

```
tek havuz : 3 kopya, doluluk 0.428
ayri havuz: okuma 3 + yazma 1 = 4 kopya, doluluk okuma 0.347, yazma 0.243
bolmenin bedeli = 1 kopya

yazma carpani   tek havuz doluluk   ayri havuz okuma   ayri havuz yazma   yazma havuzu tasti
           x1               0.428              0.347              0.243                false
           x2               0.509              0.347              0.486                false
           x3               0.590              0.347              0.729                 true
           x4               0.671              0.347              0.972                 true

karar hizi: katman 4'te 51.39 karar/s (Y4 = 10), katman 7'de 513.89 karar/s
duyarlilik: yazma hizi 200 istek/s'yi gecince yazma havuzu 2 kopyaya cikar, okuma havuzu degismez
```

İlk iki satır bölmenin faturasını **hesap** olarak veriyor: tek havuz 3 kopya ister, ayrı havuzlar
3 artı 1 eder 4. Bölmek bir kopyaya mal oluyor, çünkü her havuz kendi hızına göre ayrı ayrı
yukarı yuvarlanır ve yazma havuzunun 97,22 istek/s'si bir kopyanın 200 istek/s'lik payının
yarısını boş bırakır. İçerik farkındalıklı yönlendirmenin kendi başına bir kapasite kazancı
yoktur; tersine, kaynak ister.

Karşılığında aldığı şey ikinci tablodadır. Taşıyıcıdan gelen durum olayı akışı üç katına
çıktığında — bir aktarma merkezi birikmiş taramaları toptan gönderdiğinde — tek havuzun doluluğu
0,428'den 0,590'a çıkıyor ve bu artış **takip sorgularını da** etkiler, çünkü aynı kopyalar
ikisine de hizmet ediyor. Ayrı havuzlarda okuma doluluğu her çarpanda 0,347'de sabit kalıyor;
taşma yalnız yazma havuzunda oluyor ve orada da üçüncü satırdan itibaren o havuzun kopya sayısını
artırmak yeterli oluyor. **Bölmenin satın aldığı şey kapasite değil, yalıtımdır:** bir akışın
taşması ötekinin doluluğunu değiştirmiyor.

Son satırlar dersin fiyat etiketini K01 ölçeğine taşıyor. Katman 4'te dengeleyici saniyede 51,39
karar verirdi; katman 7'de 513,89 karar verir. On kat karar, bir kopya fazla ve bir akış
yalıtımı — üçü aynı kararın parçalarıdır.

#### Özet

- Katman 7 dengeleme kararı her istek için yeniden verir ve kararı isteğin içeriğine bakarak
  verir; kopyayla kurulan bağlantı istemciyle kurulan bağlantıdan ayrıdır.
- Aynı istemci karışımında istek sapması katman 4'te 4,00, katman 7'de 1,07; kalan sapma 63
  isteğin dörde tam bölünememesinden gelir.
- Yolu okumak akışları ayrı havuzlara bölmeyi olanaklı kılıyor: okuma kopyaları 17'şer takip,
  yazma kopyası 12 olay isteği aldı ve çapraz sızma olmadı.
- Dengeleyici altı dış bağlantıyı dört iç bağlantıya indirdi; kopyaların gördüğü bağlantı sayısı
  istemci sayısından bağımsız hâle geldi.
- Bedel karar sayısıdır: 6 yerine 63, K01 ölçeğinde 51,39 yerine 513,89 karar/s; ayrıca isteğin
  ayrıştırılması dengeleyiciyi başlık, tampon ve yeniden gönderme kararlarının sahibi yapar.
- Akışları bölmek bir kopyaya mal oluyor (3 yerine 4) ama yalıtım satın alıyor: yazma akışı üç
  katına çıktığında tek havuzun doluluğu 0,428'den 0,590'a çıkarken ayrı havuzlarda okuma
  doluluğu 0,347'de kalıyor.

#### Sonraki Adım

Buraya kadarki üç ders dağıtım kuralını sabit tuttu: kopyalar sırayla seçildi. Sıralı kural
kopyaların birbirinin eşi olduğunu ve her isteğin aynı işi yaptığını varsayar. İkisi de her zaman
doğru değildir — bir kopya yavaşlamış olabilir, bir istek ötekinden on kat pahalı olabilir ve bir
isteğin hangi kopyaya düştüğü önbelleğin işine yarayacak biçimde **kararlı** tutulmak istenebilir.
Sonraki ders kuralın kendisini değiştirir: sıralı dağıtımı, açık bağlantı sayısına bakan bir
kuralla ve anahtara bakan bir kuralla aynı yük altında karşılaştırır, üçüncüsünün kopya sayısı
değiştiğinde kaç anahtarın yer değiştirdiğini sayar.

### Dengeleme Algoritmaları

Source: https://academia.sh/tr/kurslar/trafik-katmani/dengeleme-algoritmalari

Dağıtım kuralının kendisinin değiştirilmesi: sıralı ile en az bağlantı kuralının eşit ve yavaşlamış kopyalarda bekleme ve kuyruk cinsinden karşılaştırılması, bölme kalanı ile tutarlı karmanın düğüm değiştiğinde yer değiştiren anahtar oranının sayılması, sanal düğüm sayısının dağılıma etkisi ve yer değiştirmenin önbellek isabet oranı üzerinden giriş kursu hesabına dönmesi.

Buraya kadarki üç ders dağıtım kuralını sabit tuttu: kopyalar sırayla seçildi. Sıralı kural iki
şeyi varsayar — kopyaların birbirinin eşi olduğunu ve her isteğin aynı işi yaptığını. İkisi de her
zaman doğru değildir. Bir kopya yavaşlamış olabilir, bir istek ötekinden on kat pahalı olabilir ve
bir isteğin hangi kopyaya düştüğü, o kopyanın önbelleğinin işine yarayacak biçimde **kararlı**
tutulmak istenebilir.

Bu ders kuralın kendisini değiştirir. Üç kural ele alınır: **sıralı** (round robin), **en az
bağlantı** (least connections) ve **tutarlı karma** (consistent hashing). İlk ikisi yükün nasıl
paylaştırılacağını, üçüncüsü aynı anahtarın hep aynı kopyaya düşmesini hedefler.

#### Kuyruk Modeli

İlk iki kural bir süreç içi modelle karşılaştırılır. Model, isteklerin sabit aralıklarla geldiği
ve her kopyanın tek sıralı bir sunucu olduğu bir kuyruktur. Tur soyut bir adımdır; varış aralığı,
istek maliyeti ve kopya yavaşlığı model parametreleridir, ölçülmüş süreler değildir. Maliyetler
sabit tohumlu bir üreteçten gelir, böylece iki kural **aynı** istek dizisiyle karşılaşır.

```js
// alg/kuyruk.mjs — sirali ve en az baglanti kurallarinin ayni yuk altinda karsilastirilmasi.
// Bu bir MODELDIR: tur soyut bir adimdir, varis araligi, istek maliyeti ve kopya yavasligi
// model parametreleridir; olculmus sureler degildir.
const KOPYA = 3, ISTEK = 300, VARIS = 2;   // varis araligi (tur)
const TOHUM = 20240730;

function maliyetler(n) {                   // sabit tohumlu uretec: her kosumda ayni dizi
  let s = TOHUM;
  const d = [];
  for (let i = 0; i < n; i += 1) { s = (s * 1103515245 + 12345) % 2147483648; d.push(1 + (s >>> 8) % 10); }
  return d;
}

function kosum(kural, maliyet, carpan) {
  const k = Array.from({ length: KOPYA }, () => ({ bosalma: 0, is: 0, bitis: [], p: 0 }));
  let toplamBekleme = 0, enYuksekKuyruk = 0;
  for (let i = 0; i < maliyet.length; i += 1) {
    const t = i * VARIS;
    for (const c of k) while (c.p < c.bitis.length && c.bitis[c.p] <= t) c.p += 1;
    const acik = k.map((c) => c.bitis.length - c.p);
    enYuksekKuyruk = Math.max(enYuksekKuyruk, ...acik);
    const hedef = kural === "sirali" ? i % KOPYA : acik.indexOf(Math.min(...acik));
    const c = k[hedef];
    const bas = Math.max(t, c.bosalma);
    toplamBekleme += bas - t;
    c.bosalma = bas + maliyet[i] * carpan[hedef];
    c.is += maliyet[i] * carpan[hedef];
    c.bitis.push(c.bosalma);
  }
  return { bekleme: toplamBekleme / maliyet.length, enYuksekKuyruk,
    is: k.map((c) => c.is), bitis: Math.max(...k.map((c) => c.bosalma)) };
}

const maliyet = maliyetler(ISTEK);
const toplamIs = maliyet.reduce((a, b) => a + b, 0);
console.log(`${ISTEK} istek, ${KOPYA} kopya, varis araligi ${VARIS} tur, toplam is ${toplamIs} tur`);
console.log(`esit kopyalarda model dolulugu = ${((toplamIs / (ISTEK * VARIS)) / KOPYA).toFixed(3)}\n`);

for (const [ad, carpan] of [["esit kopyalar", [1, 1, 1]], ["k1 uc kat yavas", [3, 1, 1]]]) {
  console.log(`durum: ${ad}`);
  console.log("  kural            ortalama bekleme  en yuksek kuyruk  bitis turu  kopya basina is");
  for (const kural of ["sirali", "en-az-baglanti"]) {
    const r = kosum(kural, maliyet, carpan);
    console.log(`  ${kural.padEnd(16)} ${r.bekleme.toFixed(2).padStart(16)} ` +
      `${String(r.enYuksekKuyruk).padStart(17)} ${String(r.bitis).padStart(11)}  ${r.is.join("/").padStart(15)}`);
  }
  console.log();
}
```

```
300 istek, 3 kopya, varis araligi 2 tur, toplam is 1679 tur
esit kopyalarda model dolulugu = 0.933

durum: esit kopyalar
  kural            ortalama bekleme  en yuksek kuyruk  bitis turu  kopya basina is
  sirali                       4.04                 4         614      545/581/553
  en-az-baglanti               1.90                 2         610      589/567/523

durum: k1 uc kat yavas
  kural            ortalama bekleme  en yuksek kuyruk  bitis turu  kopya basina is
  sirali                     170.97                63        1635     1635/581/553
  en-az-baglanti              56.99                18         843      843/697/701
```

Eşit kopyalar durumunda iki kural aynı toplam işi yapıyor ve bitiş turları neredeyse aynı: 614'e
karşı 610. Fark beklemede: ortalama bekleme 4,04 turdan 1,90 tura, en yüksek kuyruk 4'ten 2'ye
iniyor. Sıralı kural bir isteği meşgul bir kopyaya gönderirken bir başkası boş durabiliyor, çünkü
sırasını sayarken kopyaların durumuna bakmıyor.

Kopya başına iş sütunu bir ters sonuç taşıyor: en az bağlantı kuralının iş dağılımı **daha
dengesizdir** (589/567/523'e karşı 545/581/553). Kural işi eşitlemeye çalışmıyor, bekleyen istek
sayısını eşitliyor; pahalı istekler nereye düşerse toplam iş orada birikir. **En az bağlantı bir
adalet kuralı değil, bir bekleme kuralıdır.**

İkinci durum farkı büyütüyor. Bir kopya üç kat yavaşladığında sıralı kural yine isteklerin üçte
birini ona göndermeye devam ediyor: ortalama bekleme 170,97 tura, en yüksek kuyruk 63'e ve bitiş
1635. tura çıkıyor. En az bağlantı kuralında aynı yavaşlamada bekleme 56,99, kuyruk 18, bitiş 843
oluyor — üçü de yaklaşık üç kat düşük. Kural yavaş kopyanın kuyruğunun uzadığını **gördüğü** için
oraya daha az istek gönderiyor. Sağlık denetiminin yakalamadığı arıza biçimi budur: kopya yanıt
veriyor, yalnız yavaş yanıt veriyor, dolayısıyla havuzdan düşürülmüyor.

#### Aynı Anahtar Hep Aynı Kopyaya

Üçüncü kural başka bir soruyu yanıtlıyor. Kopyaların her birinde yerel bir önbellek varsa, aynı
takip numarasının hep aynı kopyaya düşmesi o önbelleğin işine yarar; numara her seferinde başka
bir kopyaya düşerse aynı kayıt kopya sayısı kadar yerde tutulur. Anahtardan kopyaya bir eşleme
gerekir ve en yalın biçimi anahtarın karmasının kopya sayısına bölümünden kalandır.

Karma fonksiyonu Karma Tabloları dersinde kuruldu ve burada yeniden anlatılmaz; aşağıda yalnız bir
araç olarak kullanılıyor. Ölçülen şey **düğüm sayısı değiştiğinde kaç anahtarın yer
değiştirdiğidir**. Sayılar belirlenimlidir ve makineden bağımsızdır, bu yüzden ölçüm değil
**hesap** sınıfındadır.

```js
// alg/karma.mjs — bolme kalani ile tutarli karmanin karsilastirilmasi: dugum degistiginde yer
// degistiren anahtar orani, sanal dugum sayisina gore dagilim ve K01 onbellek hesabina etkisi
const ANAHTAR = 100_000;           // takip numarasi sayisi
const OKUMA = 416.67;              // K01 Kabaca Buyukluk Hesabi: tepe okuma istek/s
const YAZMA = 97.22;               // K01: tepe yazma istek/s
const ISABET = 0.90;               // K01 varsayim V9: onbellekten karsilanma orani
const TABAN_DEPO = 138.89;         // K01: depoya ulasan istek/s
const ISINMA_SN = 60;              // varsayim Y5: onbellek isinma penceresi

function karma(metin) {            // FNV-1a + son karistirma adimi; cig etkisi Karma Tablolari
  let h = 2166136261;               // dersinde tanimlandi: benzer anahtarlar uzak degerler vermeli
  for (let i = 0; i < metin.length; i += 1) h = Math.imul(h ^ metin.charCodeAt(i), 16777619) >>> 0;
  h ^= h >>> 15; h = Math.imul(h, 2246822507) >>> 0; h ^= h >>> 13;
  return h >>> 0;
}

const anahtarlar = Array.from({ length: ANAHTAR }, (_, i) => `G${1_000_000 + i}`);

const kalanla = (a, kopya) => kopya[karma(a) % kopya.length];

function halka(kopya, sanal) {     // her kopya icin sanal dugum konumlari, konuma gore sirali
  const h = [];
  for (const k of kopya) for (let v = 0; v < sanal; v += 1) h.push([karma(`${k}#${v}`), k]);
  return h.sort((x, y) => x[0] - y[0]);
}
function halkada(a, h) {           // anahtarin karmasindan sonraki ilk konum, yoksa basa doner
  const c = karma(a);
  let alt = 0, ust = h.length - 1;
  if (c > h[ust][0]) return h[0][1];
  while (alt < ust) { const o = (alt + ust) >> 1; if (h[o][0] < c) alt = o + 1; else ust = o; }
  return h[alt][1];
}

const dengesizlik = (yerlesim, kopya) => {
  const s = new Map(kopya.map((k) => [k, 0]));
  for (const k of yerlesim) s.set(k, s.get(k) + 1);
  return (Math.max(...s.values()) / anahtarlar.length) * kopya.length;
};
const oynayan = (a, b) => a.filter((k, i) => k !== b[i]).length / a.length;

const UC = ["k1", "k2", "k3"], DORT = [...UC, "k4"];
const sonuc = {};

console.log("kural                  3 kopya dengesizlik  4 kopya dengesizlik  3->4 oynayan  4->3 oynayan");
{
  const u = anahtarlar.map((a) => kalanla(a, UC));
  const d = anahtarlar.map((a) => kalanla(a, DORT));
  sonuc["bolme kalani"] = oynayan(u, d);
  console.log(`${"bolme kalani".padEnd(22)} ${dengesizlik(u, UC).toFixed(3).padStart(19)} ` +
    `${dengesizlik(d, DORT).toFixed(3).padStart(20)} ${oynayan(u, d).toFixed(4).padStart(13)} ` +
    `${oynayan(d, u).toFixed(4).padStart(13)}`);
}
for (const sanal of [1, 10, 100, 1000]) {
  const hu = halka(UC, sanal), hd = halka(DORT, sanal);
  const u = anahtarlar.map((a) => halkada(a, hu));
  const d = anahtarlar.map((a) => halkada(a, hd));
  if (sanal === 1000) sonuc["tutarli karma"] = oynayan(u, d);
  console.log(`${`tutarli karma (v=${sanal})`.padEnd(22)} ${dengesizlik(u, UC).toFixed(3).padStart(19)} ` +
    `${dengesizlik(d, DORT).toFixed(3).padStart(20)} ${oynayan(u, d).toFixed(4).padStart(13)} ` +
    `${oynayan(d, u).toFixed(4).padStart(13)}`);
}

console.log(`\nkusursuz dagilimda dengesizlik 1.000, kusursuz tasimada 3->4 oran = ${(1 / 4).toFixed(4)}\n`);
console.log("kural            oynayan   isinmada isabetsizlik   onbellek arkasi okuma/s   depoya ulasan/s   taban kati   fazladan depo istegi");
for (const [ad, oran] of Object.entries(sonuc)) {
  const isabetsiz = oran + (1 - oran) * (1 - ISABET);
  const arka = OKUMA * isabetsiz, depo = arka + YAZMA;
  console.log(`${ad.padEnd(15)} ${oran.toFixed(4).padStart(8)} ${isabetsiz.toFixed(4).padStart(23)} ` +
    `${arka.toFixed(2).padStart(25)} ${depo.toFixed(2).padStart(17)} ` +
    `${(depo / TABAN_DEPO).toFixed(2).padStart(12)} ${((depo - TABAN_DEPO) * ISINMA_SN).toFixed(0).padStart(22)}`);
}
console.log(`taban (isinma yok): onbellek arkasi ${(OKUMA * (1 - ISABET)).toFixed(2)} istek/s, ` +
  `depoya ulasan ${TABAN_DEPO} istek/s`);
```

```
kural                  3 kopya dengesizlik  4 kopya dengesizlik  3->4 oynayan  4->3 oynayan
bolme kalani                         1.008                1.004        0.7485        0.7485
tutarli karma (v=1)                  2.021                2.231        0.5577        0.5577
tutarli karma (v=10)                 1.548                1.722        0.1557        0.1557
tutarli karma (v=100)                1.122                1.204        0.2563        0.2563
tutarli karma (v=1000)               1.010                1.059        0.2648        0.2648

kusursuz dagilimda dengesizlik 1.000, kusursuz tasimada 3->4 oran = 0.2500

kural            oynayan   isinmada isabetsizlik   onbellek arkasi okuma/s   depoya ulasan/s   taban kati   fazladan depo istegi
bolme kalani      0.7485                  0.7736                    322.35            419.57         3.02                  16841
tutarli karma     0.2648                  0.3383                    140.96            238.18         1.71                   5957
taban (isinma yok): onbellek arkasi 41.67 istek/s, depoya ulasan 138.89 istek/s
```

#### İki Ölçüt Aynı Yönde İyileşmiyor

Birinci tablo iki ayrı ölçüt taşıyor ve kurallar ikisinde ters sıralanıyor.

**Dağılım.** Bölme kalanı anahtarları neredeyse kusursuz paylaştırıyor: dengesizlik 1,008 ve
1,004. Tutarlı karmanın tek sanal düğümle dağılımı çok kötüdür — üç kopyada 2,021, dört kopyada
2,231, yani bir kopya kusursuz payın iki katından fazlasını taşıyor. Halkadaki konumlar rastgele
düştüğü için aralar eşit uzunlukta olmuyor. Sanal düğüm sayısı arttıkça ara sayısı artıyor ve
dağılım düzeliyor: 100'de 1,122 ve 1,204, 1000'de 1,010 ve 1,059. **Sanal düğüm sayısı tutarlı
karmanın dağılım ayarıdır** ve bedeli halkanın boyudur: dört kopya ve 1000 sanal düğüm 4000
konum demektir.

**Taşıma.** Sıralama tersine dönüyor. Üç kopyadan dörde geçildiğinde bölme kalanı anahtarların
yüzde 74,85'ini oynatıyor; taşınması **gereken** oran 0,2500'dür, yani yeni kopyanın payı. Bölme
kalanı gerekenin üç katını oynatıyor, çünkü bölen değiştiğinde bütün kalanlar değişir. Tutarlı
karma 1000 sanal düğümle 0,2648 oynatıyor ve bu sayı kuramsal 0,2500'e yakındır; az sanal düğümle
sapma iki yönde birden büyür (v=1'de dengesizlik 2,021, oynayan 0,5577). Düğüm çıkarma sütunu aynı
sayıyı veriyor, çünkü sayılan şey iki yerleşim arasında farklı olan anahtarlardır ve fark iki
yönde aynıdır.

İki tablonun birlikte söylediği şudur: bölme kalanı **dağılımda** iyi, **kararlılıkta** kötüdür;
tutarlı karma kararlılıkta iyidir ve dağılımı sanal düğüm sayısıyla satın alır.

#### Hesaba Geri Dönüş

Yer değiştiren anahtar oranı tek başına bir tasarım sonucu değildir; sonuç önbellekle
birleştiğinde çıkar. K01'in V9 varsayımı takip sorgusunun yüzde 90'ının önbellekten karşılandığını
söylüyordu ve o oran depoya ulaşan istek hızını 138,89 istek/s'de tutuyordu. Anahtarına göre
yönlendirilen bir kopya kümesinde yer değiştiren anahtarın önbelleği yeni kopyada **yoktur**;
o anahtarların isabet oranı, önbellek yeniden ısınana kadar sıfırdır.

Bunun için bir varsayım daha gerekir. **Y5 — önbellek ısınma penceresi: 60 saniye.** Gerekçe:
taşınan anahtarların yeniden sorulup önbelleğe girmesi için gereken süre; sayı bu konunun kendi
varsayımıdır ve K01'in tablosuna eklenmez. Duyarlılığı doğrusaldır — pencere iki katına çıkarsa
fazladan depo isteği de iki katına çıkar.

Son tablo ısınma penceresindeki durumu **hesap** olarak veriyor. Bölme kalanıyla bir kopya
eklendiğinde isabetsizlik 0,7736'ya çıkıyor: taşınan yüzde 74,85 hiç isabet etmiyor, kalan yüzde
25,15 ise normal yüzde 10 isabetsizliğiyle geliyor. Önbelleğin arkasındaki okuma 41,67 istek/s'den
322,35 istek/s'ye, depoya ulaşan istek hızı 138,89'dan 419,57'ye çıkıyor — taban değerin 3,02
katı. Altmış saniyelik pencerede depoya fazladan 16 841 istek gidiyor.

Tutarlı karmayla aynı olay isabetsizliği 0,3383'te tutuyor: önbellek arkası okuma 140,96,
depoya ulaşan 238,18 istek/s, tabanın 1,71 katı ve pencerede fazladan 5957 istek. İki kural
arasındaki fark 10 884 istektir ve bu farkın tamamı **bir kopya eklemenin** faturasıdır.

Sonucun tasarım karşılığı doğrudandır. Yatay ölçekleme kopya eklemekle olur; kopya eklemek
önbelleği bozar; önbelleği bozmak depoya ulaşan yükü kat kat artırır. Yani bir sistemin
büyütülebilirliği yalnız kopya sayısına değil, **kopya eklendiğinde ne kadar şeyin yer
değiştirdiğine** de bağlıdır. Bölme kalanı seçilmiş bir tasarımda büyüme anı, sistemin en kırılgan
anıdır: yük artışına yanıt olarak eklenen kopya, depoya üç kat yük bindirir.

#### Özet

- Sıralı kural kopyaların durumuna bakmaz; eşit kopyalarda ortalama bekleme 4,04 tur ve en yüksek
  kuyruk 4 iken en az bağlantı kuralında 1,90 tur ve 2 oldu.
- En az bağlantı bir bekleme kuralıdır, adalet kuralı değil: beklemeyi yarıya indirirken kopya
  başına iş dağılımını biraz daha dengesiz yaptı (589/567/523'e karşı 545/581/553).
- Bir kopya üç kat yavaşladığında sıralı kuralda bekleme 170,97 tura ve kuyruk 63'e çıkıyor; en az
  bağlantıda 56,99 ve 18. Yavaşlama, sağlık denetiminin yakalamadığı arıza biçimidir.
- Bölme kalanı dağılımda neredeyse kusursuz (dengesizlik 1,008) ama kararsız: üç kopyadan dörde
  geçişte anahtarların yüzde 74,85'i yer değiştiriyor, gereken oran 0,2500.
- Tutarlı karma 1000 sanal düğümle 0,2648 oynatıyor ve dengesizliği 1,010'a iniyor; sanal düğüm
  sayısı dağılım ayarıdır, tek düğümde dengesizlik 2,021'e çıkar.
- Bir kopya eklendiğinde ısınma penceresinde depoya ulaşan istek hızı bölme kalanıyla 138,89'dan
  419,57'ye (3,02 kat), tutarlı karmayla 238,18'e (1,71 kat) çıkıyor; 60 saniyelik pencerede
  aradaki fark 10 884 istektir.

#### Sonraki Adım

Bu üç kural da isteği bir kopyaya bağlarken tek bir şeye bakıyordu: sıraya, kuyruk uzunluğuna ya
da anahtara. Kararın kendisi hep aynı bileşende, dengeleyicide veriliyordu. Oysa aynı işi yapan
başka bir bileşen daha var ve önceki kurslarda kurulmuştu: isteği bir kurala göre arka
sunuculardan birine ileten ters vekil. İki bileşenin yaptığı iş büyük ölçüde örtüşüyor; bir süreç
ikisini birden üstlenebilir. Sonraki ders bu örtüşmeyi ele alır: iki rolün aynı süreçte
toplanmasıyla ayrı süreçlere bölünmesini durak sayısı ve bileşik hizmet erişilebilirliği cinsinden
karşılaştırır ve ayrımın nerede olduğunu sorumluluk ile konum üzerinden söyler.

### Yük Dengeleyici ve Ters Vekil

Source: https://academia.sh/tr/kurslar/trafik-katmani/yuk-dengeleyici-ve-ters-vekil

İki bileşenin aynı programla anlatılması ve ayrımın nerede olduğu: tek bir aktarma programının kural tablosuyla iki rolü de üstlenmesi, rollerin ayrı süreçlere bölünmesiyle tek süreçte toplanmasının durak zinciri ve durdurma etkisi üzerinden ölçülmesi, ayrımın sorumluluk ve konum olarak yazılması ve durak eklemenin giriş kursundaki bileşik erişilebilirlik hesabına faturasının çıkarılması.

Önceki üç ders dengeleyiciyi bir yönlendirme aygıtı olarak kurdu: isteği alır, bir kural
uygular, bir sürece iletir, yanıtı geri yazar. Aynı tanım Sunucu Tarafı Temelleri kursunda başka
bir bileşen için de verilmişti. **Ters vekil** (reverse proxy) de isteği alır, bir kurala göre
arka sunuculardan birine iletir ve yanıtı geri yazar. İki tanım birbirinden ayrılmıyor.

Bu ders örtüşmeyi kabul ederek başlar ve ayrımı başka bir yerde arar. İkisi de yeniden
tanımlanmaz; ölçülen şey, iki rolün aynı süreçte toplanmasıyla ayrı süreçlere bölünmesinin ne
değiştirdiğidir.

#### Aynı Program, İki Kural Tablosu

Örtüşmenin en kısa kanıtı tek bir programdır. Aşağıdaki aktarıcı bir kural tablosu alır: yol
öneki, hedef listesi. Liste tek elemanlıysa yapılan iş **yönlendirmedir** — hangi bileşene.
Listede aynı bileşenin birden çok kopyası varsa yapılan iş **dağıtımdır** — hangi kopyaya. İkisi
aynı tabloda yan yana durabilir.

```js
// vekil/aktarici.mjs — tek bir aktarma programi. Kural tablosu iki rolu de anlatir:
//   "/varlik=8891;*=8850"            -> yola gore ayri bilesenlere yonlendirme (ters vekil)
//   "*=8892,8893,8894"               -> ayni bilesenin kopyalari arasinda dagitim (yuk dengeleyici)
//   "/varlik=8891;*=8892,8893,8894"  -> ikisi birden (birlesik surec)
// Kullanim: node vekil/aktarici.mjs <nokta> <ad> <kural>
import { createServer, request } from "node:http";

const [nokta, ad, kuralMetni] = [Number(process.argv[2]), process.argv[3], process.argv[4] ?? ""];
const KURAL = kuralMetni.split(";").filter(Boolean)
  .map((p) => { const [onek, liste] = p.split("="); return { onek, hedef: liste.split(",").map(Number), sira: 0 }; });

if (Number.isInteger(nokta) === false || KURAL.length === 0) {
  console.log("kullanim: node vekil/aktarici.mjs <nokta> <ad> <onek=hedef[,hedef];...>");
} else createServer((istekDisi, yanitDisi) => {
  yanitDisi.sendDate = false;
  const yol = new URL(istekDisi.url, "http://yerel").pathname;
  const k = KURAL.find((r) => r.onek !== "*" && yol.startsWith(r.onek)) ?? KURAL.find((r) => r.onek === "*");
  if (k === undefined) { yanitDisi.writeHead(404).end("kural yok"); return; }
  const hedef = k.hedef[k.sira++ % k.hedef.length];
  const onceki = istekDisi.headers["x-durak"];
  const istekIc = request({ port: hedef, path: istekDisi.url, method: istekDisi.method,
    headers: { ...istekDisi.headers, "x-durak": onceki === undefined ? ad : `${onceki} > ${ad}` } },
  (yanitIc) => { yanitDisi.writeHead(yanitIc.statusCode, yanitIc.headers); yanitIc.pipe(yanitDisi); });
  istekIc.on("error", () => yanitDisi.writeHead(502, { "x-durak": `${ad} > ulasilamadi` }).end("yok"));
  istekDisi.pipe(istekIc);
}).listen(nokta, "127.0.0.1");
```

Zincirin sonundaki süreçler yalnız adlarını bildirir; `x-durak` başlığı istek boyunca birikerek
isteğin dokunduğu durakları taşır.

```js
// vekil/uc.mjs — zincirin sonundaki surec: adini x-durak basligina ekler
import { createServer } from "node:http";

const [port, ad] = [Number(process.argv[2]), process.argv[3]];

if (Number.isInteger(port) === false) console.log("kullanim: node vekil/uc.mjs <nokta> <ad>");
else createServer((istek, yanit) => {
  yanit.sendDate = false;
  const onceki = istek.headers["x-durak"];
  yanit.writeHead(200, { "content-type": "application/json",
    "x-durak": onceki === undefined ? ad : `${onceki} > ${ad}` });
  yanit.end(JSON.stringify({ durum: "aktarma merkezinde", bolge: "35" }));
}).listen(port, "127.0.0.1");
```

```js
// vekil/istemci.mjs — iki yolu da dener, dokunulan durak zincirini ve yanitlanan istegi yazar
import { request } from "node:http";

const [nokta, etiket] = [Number(process.argv[2]), process.argv[3] ?? "-"];
const YOL = ["/varlik/stil.css", "/takip"];
const ADET = 6;

function bir(yol) {
  return new Promise((coz) => {
    const r = request({ port: nokta, path: yol }, (y) => {
      y.resume();
      y.on("end", () => coz({ kod: y.statusCode, durak: y.headers["x-durak"] ?? "-" }));
    });
    r.on("error", () => coz({ kod: 0, durak: "baglanti yok" }));
    r.end();
  });
}

if (Number.isInteger(nokta) === false) console.log("kullanim: node vekil/istemci.mjs <nokta> <etiket>");
else for (const yol of YOL) {
  const zincir = new Map();
  let yanitlanan = 0;
  for (let i = 0; i < ADET; i += 1) {
    const s = await bir(yol);
    if (s.kod === 200) yanitlanan += 1;
    zincir.set(s.durak, (zincir.get(s.durak) ?? 0) + 1);
  }
  const d = [...zincir].sort().map(([a, n]) => `${a} (${n})`).join("  |  ");
  console.log(`${etiket.padEnd(22)} ${yol.padEnd(17)} ${String(yanitlanan)}/${ADET}  ${d}`);
}
```

Düzenek aynı işi iki yerleşimle koşar. **Ayrı** yerleşimde iki aktarıcı süreci vardır: `tv`
içerik yolu ile uygulama yolunu ayırır, `yd` kopyalar arasında dağıtır. **Birleşik** yerleşimde
tek bir `tvyd` süreci ikisini de yapar. Her yerleşimde kopya listesini tutan süreç durdurulur ve
hangi yolun ayakta kaldığı sayılır.

```bash
# olc.sh — ayni is iki yerlesimle: iki ayri aktarici sureci, sonra tek birlesik surec.
# Ikinci asamada kopya listesini tutan surec durduruluyor ve hangi yolun ayakta kaldigi sayiliyor.
node vekil/uc.mjs 8891 statik & S=$!
node vekil/uc.mjs 8892 k1 & K1=$!
node vekil/uc.mjs 8893 k2 & K2=$!
node vekil/uc.mjs 8894 k3 & K3=$!

node vekil/aktarici.mjs 8860 tv "/varlik=8891;*=8850" & TV=$!
node vekil/aktarici.mjs 8850 yd "*=8892,8893,8894" & YD=$!
sleep 1
node vekil/istemci.mjs 8860 "ayri: tv + yd"
kill $YD; sleep 0.5
node vekil/istemci.mjs 8860 "ayri: yd durduruldu"
kill $TV; sleep 0.3

node vekil/aktarici.mjs 8861 tvyd "/varlik=8891;*=8892,8893,8894" & B=$!
sleep 1
node vekil/istemci.mjs 8861 "birlesik: tvyd"
kill $B; sleep 0.5
node vekil/istemci.mjs 8861 "birlesik: durduruldu"

kill $S $K1 $K2 $K3
```

```
ayri: tv + yd          /varlik/stil.css  6/6  tv > statik (6)
ayri: tv + yd          /takip            6/6  tv > yd > k1 (2)  |  tv > yd > k2 (2)  |  tv > yd > k3 (2)
ayri: yd durduruldu    /varlik/stil.css  6/6  tv > statik (6)
ayri: yd durduruldu    /takip            0/6  tv > ulasilamadi (6)
birlesik: tvyd         /varlik/stil.css  6/6  tvyd > statik (6)
birlesik: tvyd         /takip            6/6  tvyd > k1 (2)  |  tvyd > k2 (2)  |  tvyd > k3 (2)
birlesik: durduruldu   /varlik/stil.css  0/6  baglanti yok (6)
birlesik: durduruldu   /takip            0/6  baglanti yok (6)
```

#### İki Sayı, İki Yön

Bu sayılar **ölçüm** sınıfındadır ve belirlenimlidir. İki yerleşim iki ayrı sütunda ters
sıralanıyor.

**Durak sayısı.** Ayrı yerleşimde takip isteği üç durağa dokunuyor: `tv > yd > k1`. Birleşik
yerleşimde iki durağa: `tvyd > k1`. İçerik yolu ikisinde de iki duraktır. Her durak bir ağ
atlaması, bir ayrıştırma ve bir yeniden yazma demektir; ayrı yerleşim aynı isteği bir kez fazla
elden geçiriyor.

**Yalıtım.** Kopya listesini tutan süreç durdurulduğunda ayrı yerleşimde içerik yolu 6/6
yanıtlanmaya devam ediyor, yalnız takip yolu 0/6'ya düşüyor — ve düşüş bile `tv` üzerinden bir 502
olarak dönüyor, yani istemci bir yanıt alıyor. Birleşik yerleşimde ikisi de 0/6 ve istemci hiçbir
yanıt alamıyor, çünkü bağlanacağı bir bağlantı noktası kalmıyor. Kopya listesinin değişmesi bir
yapılandırma değişikliğidir ve sık olur; birleşik süreçte o değişiklik içerik yolunu da
durdurur.

İki sayı aynı kararın iki yüzüdür: **bölmek bir durak ekler, birleştirmek bir arıza yüzeyi
ekler.**

#### Ayrım Nerede

Aynı program iki rolü de üstlenebildiğine göre ayrım programda değildir. İki yerdedir.

**Sorumluluk.** Ters vekil "hangi bileşen" sorusunu yanıtlar: `/varlik` ile başlayan yol içerik
sürecine, geri kalanı uygulamaya. Kural tablosundaki önekler farklı işler yapan bileşenlere
işaret eder ve hedef listeleri tek elemanlıdır. Yük dengeleyici "hangi kopya" sorusunu yanıtlar:
hedef listesi aynı işi yapan süreçlerden oluşur ve içlerinden hangisinin seçildiği isteğin
sonucunu değiştirmez. İlk soruda yanlış seçim **yanlış davranıştır**, ikincisinde yalnız farklı
bir kopyadır.

**Konum.** Ters vekil uygulama sınırında durur: sistemin dış yüzünü tek bir yol uzayı olarak
gösterir ve arkasındaki bileşen bölünmesini gizler. Yük dengeleyici kopya sınırında durur: bir
bileşenin kaç kopyayla çalıştığını gizler. İki gizleme farklı ölçeklerde işler ve bu yüzden ikisi
zincirde farklı yerlerde durabilir — ölçümdeki `tv > yd` sırası bunun ifadesidir, tersi
anlamsızdır.

Bir sürecin ikisini birden üstlenmesi bu ayrımı ortadan kaldırmaz, yalnız aynı yapılandırma
dosyasına yazar. Ayrımı görünür tutan şey kural tablosunun biçimidir: hangi satırın öneki bir
bileşen ayrımı, hangisinin hedef listesi bir kopya kümesidir.

#### Hesaba Geri Dönüş

Bölmenin faturası durak sayısında görünüyordu; o sayının hizmet erişilebilirliğindeki karşılığı
K01'de kurulmuştu. Erişilebilirliğin Sayısal İfadesi dersi takip yolunu dört bileşenli seri bir
zincir olarak almış, bileşen başına yüzde 99,9 ile bileşik erişilebilirliği yüzde 99,6006 ve
aylık kesintiyi 172,5 dakika bulmuştu. Aktarıcı süreçler o zincire eklenen yeni bileşenlerdir.

```js
// vekil/zincir.mjs — durak eklemenin K01 bilesik erisilebilirlik hesabindaki karsiligi
const AY = 30 * 24 * 60;           // dakika
const TABAN = 4;                   // K01 Erisilebilirligin Sayisal Ifadesi: dort bilesenli takip yolu
const BILESEN = 0.999;             // K01 varsayim: bilesen basina hizmet erisilebilirligi

const seri = (a, n) => a ** n;
const kopyali = (a, k) => 1 - (1 - a) ** k;
const dakika = (a) => (1 - a) * AY;

console.log("yerlesim              durak  zincir bileseni  bilesik erisilebilirlik  aylik kesinti  tabana gore");
const taban = seri(BILESEN, TABAN);
for (const [ad, durak, kopya] of [
  ["durak yok (K01)", 0, 1], ["birlesik surec", 1, 1], ["ayri iki surec", 2, 1],
  ["ayri, her biri 2 kopya", 2, 2], ["birlesik, 2 kopya", 1, 2]]) {
  const a = taban * seri(kopyali(BILESEN, kopya), durak);
  console.log(`${ad.padEnd(22)}${String(durak).padStart(6)}${String(TABAN + durak).padStart(17)}  ` +
    `${(a * 100).toFixed(4).padStart(22)}%  ${dakika(a).toFixed(1).padStart(11)} dk  ` +
    `${(dakika(a) - dakika(taban)).toFixed(1).padStart(9)} dk`);
}

const birlesik = taban * seri(BILESEN, 1), ayri = taban * seri(BILESEN, 2);
console.log(`\nrolleri iki surece bolmenin faturasi = ${(dakika(ayri) - dakika(birlesik)).toFixed(1)} dk/ay`);
console.log(`ayni fatura duraklar ikiser kopyali oldugunda = ` +
  `${(dakika(taban * seri(kopyali(BILESEN, 2), 2)) - dakika(taban * seri(kopyali(BILESEN, 2), 1))).toFixed(2)} dk/ay`);
console.log(`K01 aylik kesinti butcesi (%99.9) = ${((1 - 0.999) * AY).toFixed(1)} dk; ` +
  `ayri yerlesimin kesintisi butcenin ${(dakika(ayri) / ((1 - 0.999) * AY)).toFixed(2)} kati`);
```

```
yerlesim              durak  zincir bileseni  bilesik erisilebilirlik  aylik kesinti  tabana gore
durak yok (K01)            0                4                 99.6006%        172.5 dk        0.0 dk
birlesik surec             1                5                 99.5010%        215.6 dk       43.0 dk
ayri iki surec             2                6                 99.4015%        258.6 dk       86.0 dk
ayri, her biri 2 kopya     2                6                 99.6004%        172.6 dk        0.1 dk
birlesik, 2 kopya          1                5                 99.6005%        172.6 dk        0.0 dk

rolleri iki surece bolmenin faturasi = 43.0 dk/ay
ayni fatura duraklar ikiser kopyali oldugunda = 0.04 dk/ay
K01 aylik kesinti butcesi (%99.9) = 43.2 dk; ayri yerlesimin kesintisi butcenin 5.99 kati
```

Bu sayılar **hesap** sınıfındadır. İlk üç satır bölmenin faturasını veriyor: tek kopyalı
duraklarla, rolleri iki sürece ayırmak aylık kesintiyi 215,6 dakikadan 258,6 dakikaya çıkarıyor —
ayda 43,0 dakika. Sayı K01'in yüzde 99,9 hedefi için ayırdığı **bütün aylık bütçeye** (43,2
dakika) neredeyse eşittir. Yani rolleri ayırma kararı, tek başına, bir aylık kesinti bütçesi
kadar tutuyor.

Dördüncü ve beşinci satır faturanın nereden geldiğini gösteriyor. Duraklar ikişer kopyalı
olduğunda aynı bölme 0,04 dakikaya iniyor ve iki yerleşim ayırt edilemez hâle geliyor. K01'in
kopya tablosundaki kural burada da geçerli: koşut kopyalarda kesinti payı üs alır. **Durak
eklemenin faturası durak eklemekten değil, durağı tek kopyalı bırakmaktan geliyor.**

Son satır tabloyu bir ölçütle bitiriyor. Ayrı yerleşimin aylık kesintisi 258,6 dakikadır ve yüzde
99,9 bütçesinin 5,99 katıdır. Bu, yerleşimin kötü olduğunu değil, **yüzde 99,9 hedefinin bileşen
başına yüzde 99,9 ile karşılanamayacağını** söyler; K01 aynı sonucu dört bileşenle bulmuştu, iki
durak eklemek onu keskinleştiriyor. Bir kenar katmanı tasarlanırken durak sayısı bir mimari
tercih değil, doğrudan bir erişilebilirlik kalemidir.

#### Özet

- Yük dengeleyici ile ters vekil aynı programla yazılabilir: kural tablosunda hedef listesi tek
  elemanlıysa yapılan iş yönlendirme, aynı bileşenin kopyalarından oluşuyorsa dağıtımdır.
- Ayrı yerleşimde takip isteği üç durağa dokundu (`tv > yd > k1`), birleşik yerleşimde ikiye
  (`tvyd > k1`); bölmek isteği bir kez fazla elden geçiriyor.
- Kopya listesini tutan süreç durdurulduğunda ayrı yerleşimde içerik yolu 6/6 yanıtlanmaya devam
  etti, birleşik yerleşimde iki yol da 0/6 oldu ve istemci hiç yanıt alamadı.
- Ayrım sorumluluktadır ve konumdadır: ters vekil "hangi bileşen" sorusunu uygulama sınırında,
  yük dengeleyici "hangi kopya" sorusunu kopya sınırında yanıtlar; ilkinde yanlış seçim yanlış
  davranış, ikincisinde yalnız farklı bir kopyadır.
- Tek kopyalı duraklarla rolleri ayırmak aylık kesintiyi 215,6'dan 258,6 dakikaya çıkarıyor: ayda
  43,0 dakika, yüzde 99,9 hedefinin bütün aylık bütçesi kadar.
- Duraklar ikişer kopyalı olduğunda aynı fatura 0,04 dakikaya iniyor; durak eklemenin bedeli
  durağı tek kopyalı bırakmaktan gelir.

#### Sonraki Adım

Buraya kadarki beş ders bir şeyi hiç sorgulamadı: dengeleyicinin seçimi **serbesttir**. Sıralı
kural, en az bağlantı kuralı ve iki yerleşimin hepsi, bir isteğin herhangi bir kopyaya
gönderilebileceğini varsaydı; tutarlı karma bile seçimi kararlı tutmayı isterken zorunlu
kılmıyordu. Kopyaların birbirinin eşi olmaktan çıktığı bir durum vardır: bir istemcinin önceki
isteğinden kalan bir durum belirli bir kopyanın belleğinde durursa, o istemcinin sonraki isteği
artık herhangi bir kopyaya gidemez. Seçim bir tercih olmaktan çıkıp bir kısıt hâline gelir.
Sonraki ders bu kısıtı adlandırır ve ölçer: dağılımın ne kadar bozulduğunu, bir kopya düştüğünde
ne kadar durumun kaybolduğunu ve kopya eklemenin tepe yükü neden düşürmediğini sayar.

### Oturum Yapışkanlığı

Source: https://academia.sh/tr/kurslar/trafik-katmani/oturum-yapiskanligi

Seçimin bir kısıt hâline gelmesi ve bunun ölçekleme faturası: yapışkan bağlamanın dağılımı ne kadar bozduğunun ölçülmesi, bir kopya düştüğünde kaybolan oturumun ve kopya eklendiğinde bağı kopan oturumun sayılması, en yüklü kopyanın kopya eklenmesine rağmen düşmemesi ve bölünemeyen payın giriş kursundaki seri pay bağıntısıyla bir üst sınıra çevrilmesi.

Buraya kadarki beş ders bir şeyi hiç sorgulamadı: dengeleyicinin seçimi serbestti. Bir istek
herhangi bir kopyaya gönderilebiliyordu, çünkü kopyalar birbirinin eşiydi. Tutarlı karma bile
seçimi kararlı tutmayı isterken zorunlu kılmıyordu — anahtar başka bir kopyaya düşse yanıt yine
doğru olurdu, yalnız önbellek soğuk kalırdı.

Bir istemcinin önceki isteğinden kalan durum belirli bir kopyanın belleğinde duruyorsa durum
değişir. O istemcinin sonraki isteği artık herhangi bir kopyaya gidemez; seçim bir tercih olmaktan
çıkıp bir **kısıt** hâline gelir. Bu bağa **oturum yapışkanlığı** (session stickiness) denir.
Eşzamansız İşleme kursunda geçen **yapışkan yönlendirme** aynı şeydir: istemci hep aynı örneğe
yönlendirilir. Oturum durumunun kendisi ve yönetimi Sunucu Tarafı Temelleri kursunun konusudur ve
burada yeniden anlatılmaz; bu dersin işi yapışkanlığın **ölçekleme faturasını** ölçmektir.

#### Bağın Ölçülmesi

Model bir istemci karışımı alır ve üç kuralı aynı karışımda karşılaştırır. **Yapışkansız** kuralda
karar istek başına verilir. **Yapışkan-kalan** kuralda istemci kimliğinin karması kopya sayısına
bölünür. **Yapışkan-tutarlı** kuralda bağ, önceki dersteki tutarlı karma halkasından okunur.

İstemci karışımı gönderi takip servisinin gerçek biçimini taşır: bir büyük satıcı entegrasyonu
tek bir oturumdan çok sayıda sorgu gönderir, dokuz orta satıcı daha az, doksan küçük satıcı çok
az. Sayılar model parametresidir.

```js
// otur/model.mjs — yapiskanligin dagilim, oturum kaybi ve olcek artisi uzerindeki etkisi.
// Bu bir MODELDIR: istemci karisimi ve istek sayilari model parametreleridir.
const ISTEMCI = [                  // [ad oneki, istemci sayisi, istemci basina istek]
  ["buyuk", 1, 2000], ["orta", 9, 400], ["kucuk", 90, 50],
];
const SANAL = 200;                 // tutarli karma sanal dugum sayisi

function karma(metin) {            // FNV-1a + son karistirma adimi; cig etkisi Karma Tablolari
  let h = 2166136261;               // dersinde tanimlandi: benzer anahtarlar uzak degerler vermeli
  for (let i = 0; i < metin.length; i += 1) h = Math.imul(h ^ metin.charCodeAt(i), 16777619) >>> 0;
  h ^= h >>> 15; h = Math.imul(h, 2246822507) >>> 0; h ^= h >>> 13;
  return h >>> 0;
}

const istemciler = ISTEMCI.flatMap(([ad, adet, istek]) =>
  Array.from({ length: adet }, (_, i) => ({ ad: `${ad}-${i}`, istek })));
const TOPLAM = istemciler.reduce((a, c) => a + c.istek, 0);

function halka(kopya) {
  const h = [];
  for (const k of kopya) for (let v = 0; v < SANAL; v += 1) h.push([karma(`${k}#${v}`), k]);
  return h.sort((x, y) => x[0] - y[0]);
}
function halkada(a, h) {
  const c = karma(a);
  if (c > h[h.length - 1][0]) return h[0][1];
  let alt = 0, ust = h.length - 1;
  while (alt < ust) { const o = (alt + ust) >> 1; if (h[o][0] < c) alt = o + 1; else ust = o; }
  return h[alt][1];
}

function baglama(kural, kopya) {   // istemci -> kopya eslemesi (yapiskansizda esleme yok)
  if (kural === "yapiskan-kalan") return new Map(istemciler.map((c) => [c.ad, kopya[karma(c.ad) % kopya.length]]));
  if (kural === "yapiskan-tutarli") { const h = halka(kopya); return new Map(istemciler.map((c) => [c.ad, halkada(c.ad, h)])); }
  return null;
}

function yuk(kural, kopya) {       // kopya basina istek sayisi
  const y = new Map(kopya.map((k) => [k, 0]));
  const b = baglama(kural, kopya);
  if (b === null) {                // istek basina sirali: her istek ayri karar
    let s = 0;
    for (const c of istemciler) for (let i = 0; i < c.istek; i += 1) { const k = kopya[s++ % kopya.length]; y.set(k, y.get(k) + 1); }
  } else for (const c of istemciler) y.set(b.get(c.ad), y.get(b.get(c.ad)) + c.istek);
  return y;
}

const dengesizlik = (y, n) => (Math.max(...y.values()) / TOPLAM) * n;
const UC = ["k1", "k2", "k3"], DORT = [...UC, "k4"];

console.log(`${istemciler.length} istemci, ${TOPLAM} istek; en buyuk istemcinin payi = ` +
  `${(Math.max(...istemciler.map((c) => c.istek)) / TOPLAM).toFixed(4)}\n`);
console.log("kural              3 kopya yuku          dengesizlik   4 kopya yuku               dengesizlik   en yuklu kopya dususu");
for (const kural of ["yapiskansiz", "yapiskan-kalan", "yapiskan-tutarli"]) {
  const u = yuk(kural, UC), d = yuk(kural, DORT);
  const pu = Math.max(...u.values()) / TOPLAM, pd = Math.max(...d.values()) / TOPLAM;
  console.log(`${kural.padEnd(18)} ${[...u.values()].join("/").padEnd(20)} ${dengesizlik(u, 3).toFixed(3).padStart(11)}   ` +
    `${[...d.values()].join("/").padEnd(25)} ${dengesizlik(d, 4).toFixed(3).padStart(11)}   ` +
    `${(1 - pd / pu).toFixed(4).padStart(21)}`);
}

console.log("\nkopya eklendiginde bagi degisen istemci ve onlarin istek payi:");
for (const kural of ["yapiskan-kalan", "yapiskan-tutarli"]) {
  const bu = baglama(kural, UC), bd = baglama(kural, DORT);
  const oynayan = istemciler.filter((c) => bu.get(c.ad) !== bd.get(c.ad));
  console.log(`  ${kural.padEnd(18)} istemci ${String(oynayan.length).padStart(3)}/${istemciler.length}  ` +
    `istek payi ${(oynayan.reduce((a, c) => a + c.istek, 0) / TOPLAM).toFixed(4)}`);
}

console.log("\nbir kopya dustugunde kaybolan oturum ve o kopyaya bagli istek payi (3 kopya):");
for (const kural of ["yapiskansiz", "yapiskan-kalan", "yapiskan-tutarli"]) {
  const b = baglama(kural, UC);
  if (b === null) { console.log(`  ${"yapiskansiz".padEnd(18)} oturum   0/${istemciler.length}  istek payi 0.0000 (durum kopyada durmuyor)`); continue; }
  const dusen = istemciler.filter((c) => b.get(c.ad) === "k1");
  console.log(`  ${kural.padEnd(18)} oturum ${String(dusen.length).padStart(3)}/${istemciler.length}  ` +
    `istek payi ${(dusen.reduce((a, c) => a + c.istek, 0) / TOPLAM).toFixed(4)}`);
}
```

```
100 istemci, 10100 istek; en buyuk istemcinin payi = 0.1980

kural              3 kopya yuku          dengesizlik   4 kopya yuku               dengesizlik   en yuklu kopya dususu
yapiskansiz        3367/3367/3366             1.000   2525/2525/2525/2525             1.000                  0.2501
yapiskan-kalan     2500/2500/5100             1.515   1650/1850/2000/4600             1.822                  0.0980
yapiskan-tutarli   3950/2500/3650             1.173   1450/2100/2750/3800             1.505                  0.0380

kopya eklendiginde bagi degisen istemci ve onlarin istek payi:
  yapiskan-kalan     istemci  77/100  istek payi 0.8515
  yapiskan-tutarli   istemci  30/100  istek payi 0.3762

bir kopya dustugunde kaybolan oturum ve o kopyaya bagli istek payi (3 kopya):
  yapiskansiz        oturum   0/100  istek payi 0.0000 (durum kopyada durmuyor)
  yapiskan-kalan     oturum  36/100  istek payi 0.2475
  yapiskan-tutarli   oturum  33/100  istek payi 0.3911
```

#### Üç Ayrı Fatura

Tablolar yapışkanlığın üç ayrı kalemde ödendiğini gösteriyor.

**Dağılım.** Yapışkansız kuralda dengesizlik 1,000 — istekler sayıya göre bölünüyor ve istemci
kimliği hiç rol oynamıyor. Yapışkan-kalan kuralda 1,515, yapışkan-tutarlı kuralda 1,173. Sapmanın
kaynağı istemcilerin eşit sayıda istek göndermemesidir: büyük satıcının 2000 isteği tek bir
kopyaya düşüyor ve dengeleyicinin bunu düzeltme yetkisi yok. Bu, ikinci dersteki bağlantı
sapmasının aynısıdır, yalnız orada bağ bağlantı ömrüydü, burada oturum.

**Kopya düşmesi.** Yapışkansız kuralda düşen kopyanın taşıdığı hiçbir oturum yoktur; istekler
kalan kopyalara yönlenir ve kaybolan bir şey olmaz. Yapışkan kurallarda düşen kopyaya bağlı
oturumlar da düşer: yapışkan-tutarlı kuralda 100 oturumun 33'ü ve isteklerin yüzde 39,11'i.
Birinci dersteki sağlık denetimi bu kaybı **azaltmaz** — kopyayı havuzdan düşürmek isteklerin
yanıtlanmasını sağlar, ama o kopyanın belleğindeki oturumu geri getirmez. Sağlık denetiminin
34,26 isteklik penceresi burada geçerli değildir; kayıp pencereyle değil, oturumla ölçülür.

**Kopya ekleme.** Üçüncü tablo yapışkanlığın en sinsi kalemidir. Yapışkan-kalan kuralda dördüncü
kopya eklendiğinde 100 istemcinin 77'si başka bir kopyaya bağlanıyor ve bu istemciler toplam
isteğin yüzde 85,15'ini taşıyor; yani ölçek artışı oturumların neredeyse tamamını koparıyor.
Yapışkan-tutarlı kuralda oran 30 istemci ve yüzde 37,62'ye iniyor — önceki dersin taşıma sonucu
burada oturum cinsinden tekrarlanıyor.

Aynı satırın sonundaki sütun asıl sonucu veriyor. Dördüncü kopya eklendiğinde en yüklü kopyanın
yükü yapışkansız kuralda yüzde 25,01 düşüyor; bu, kusursuz bölünmenin verdiği rakamdır. Yapışkan
kurallarda düşüş yüzde 9,80 ve yüzde 3,80. **Kopya eklemek tepe yükü düşürmüyor**, çünkü en yüklü
kopyanın yükünü yaratan büyük oturum yerinde kalıyor. Yapışkan-tutarlı kuralın oturum korumada
daha iyi olması burada aleyhine işliyor: bağı korumak, yükü taşımamak demektir.

#### Hesaba Geri Dönüş

Bu davranışın adı K01'de konmuştu. Yatay ve Dikey Ölçekleme dersi işin bölünemeyen kısmını
**seri pay** olarak adlandırmış ve $n$ birimle en iyi hızlanmayı şöyle yazmıştı:

$$
S(n) = \frac{1}{s + \dfrac{1 - s}{n}}
$$

Yapışkanlıkta seri payın karşılığı doğrudandır: **tek bir oturum bölünemez.** En büyük oturumun
toplam yüke oranı, kaç kopya eklenirse eklensin en yüklü kopyada kalır.

```js
// otur/olcek.mjs — yapiskanligin seri paya cevrilmesi ve K01 tepe hizindaki karsiligi
const ISTEMCI = [["buyuk", 1, 2000], ["orta", 9, 400], ["kucuk", 90, 50]];   // model.mjs ile ayni
const TEPE_UC = 513.89;            // K01 Kabaca Buyukluk Hesabi: tepe ucta istek/s
const DOYUM = 400;                 // 01. ders varsayim Y1
const GUVENLI = 200;               // 01. ders: Y1 x Y2
const OLCUM = { 3: 1.173, 4: 1.505 };   // model.mjs ciktisi: yapiskan-tutarli dengesizlik

const toplam = ISTEMCI.reduce((a, [, adet, istek]) => a + adet * istek, 0);
const s = Math.max(...ISTEMCI.map(([, , istek]) => istek)) / toplam;   // bolunemeyen pay

const amdahl = (n) => 1 / (s + (1 - s) / n);   // K01 Yatay ve Dikey Olcekleme dersinin bagintisi
console.log(`toplam istek = ${toplam}, en buyuk oturumun payi (seri pay s) = ${s.toFixed(4)}`);
console.log(`ust sinir 1/s = ${(1 / s).toFixed(2)}: kopya sayisi ne olursa olsun tepe yuk bu kattan fazla bolunemez\n`);

console.log("kopya  yapiskansiz hizlanma  yapiskan hizlanma  en yuklu kopya alt siniri istek/s  o an doluluk");
for (const n of [3, 4, 8, 16, 64]) {
  const alt = TEPE_UC / amdahl(n);
  console.log(`${String(n).padStart(5)}  ${String(n).padStart(19)}  ${amdahl(n).toFixed(2).padStart(17)}  ` +
    `${alt.toFixed(2).padStart(33)}  ${(alt / DOYUM).toFixed(3).padStart(12)}`);
}
console.log(`${"sonsuz".padStart(5)}  ${"sonsuz".padStart(19)}  ${(1 / s).toFixed(2).padStart(17)}  ` +
  `${(TEPE_UC * s).toFixed(2).padStart(33)}  ${((TEPE_UC * s) / DOYUM).toFixed(3).padStart(12)}\n`);

console.log("kopya  olculen dengesizlik  en yuklu kopya istek/s  doluluk  gereken kopya");
for (const [n, d] of Object.entries(OLCUM)) {
  const hiz = (d * TEPE_UC) / n;
  console.log(`${n.padStart(5)}  ${d.toFixed(3).padStart(18)}  ${hiz.toFixed(2).padStart(22)}  ` +
    `${(hiz / DOYUM).toFixed(3).padStart(7)}  ${String(Math.ceil((d * TEPE_UC) / GUVENLI)).padStart(13)}`);
}
console.log(`\nduyarlilik: en buyuk oturum toplamin %10'u olsa ust sinir ${(1 / 0.10).toFixed(2)}, ` +
  `%30'u olsa ${(1 / 0.30).toFixed(2)} olurdu`);
```

```
toplam istek = 10100, en buyuk oturumun payi (seri pay s) = 0.1980
ust sinir 1/s = 5.05: kopya sayisi ne olursa olsun tepe yuk bu kattan fazla bolunemez

kopya  yapiskansiz hizlanma  yapiskan hizlanma  en yuklu kopya alt siniri istek/s  o an doluluk
    3                    3               2.15                             239.14         0.598
    4                    4               2.51                             204.79         0.512
    8                    8               3.35                             153.28         0.383
   16                   16               4.03                             127.52         0.319
   64                   64               4.75                             108.20         0.270
sonsuz               sonsuz               5.05                             101.76         0.254

kopya  olculen dengesizlik  en yuklu kopya istek/s  doluluk  gereken kopya
    3               1.173                  200.93    0.502              4
    4               1.505                  193.35    0.483              4

duyarlilik: en buyuk oturum toplamin %10'u olsa ust sinir 10.00, %30'u olsa 3.33 olurdu
```

Bu sayılar **hesap** sınıfındadır. Seri pay 0,1980 ve üst sınır 5,05: kopya sayısı sonsuza gitse
bile tepe yük beş kattan fazla bölünemez. Yapışkansız sütunla karşılaştırıldığında fark
büyüyor — 16 kopyada yapışkansız kural 16 kat böler, yapışkan kural 4,03 kat. Fazladan konan
kopyaların çoğu en yüklü kopyaya hiçbir şey yapmıyor.

Doluluk sütunu bunu bir eşiğe bağlıyor. Birinci ders kopya başına hedef doluluğu 0,50 olarak
seçmişti (Y2). Yapışkan düzende üç kopya bu hedefi tutmuyor: en yüklü kopya en az 239,14 istek/s
ve 0,598 doluluk taşır. Dört kopyada 204,79 ve 0,512 — hâlâ hedefin üstünde. Hedefin altına inmek
için sekiz kopya gerekiyor ve o noktada üç kopyanın işini sekiz kopya yapıyor. **Yapışkanlık
kopya sayısını iki kattan fazla artırıyor ve artışın karşılığında kapasite gelmiyor.**

İkinci tablo ölçülen dengesizlikle aynı hesabı yapıyor. Üç kopyada en yüklü kopya 200,93 istek/s
ve 0,502 doluluk; dört kopyada 193,35 ve 0,483. Bir kopya eklemek en yüklü kopyanın yükünü yalnız
yüzde 3,8 düşürüyor ve gereken kopya sayısı iki durumda da 4 çıkıyor. Karşılaştırma noktası
birinci dersin sayısıdır: yapışkanlık olmadan 3 kopya yetiyordu, ikinci dersin bağlantı sapmasıyla
5 çıkmıştı; buradaki 4, oturum bağının kendi payıdır.

Sonuç, K01'in yatay ölçekleme kuralının bu katmandaki karşılığıdır. O ders "yatay ölçekleme birim
sayısını artırmakla olmaz, işin paylaşılan durum gerektirmeyecek biçimde bölünebilmesiyle olur"
demişti ve indis bölümlemesinin seri payını yüzde 28,0 ölçmüştü. Oturum yapışkanlığı aynı cümlenin
trafik katmanındaki hâlidir: durum kopyanın belleğinde kaldığı sürece dengeleyici ne kadar akıllı
olursa olsun yükü bölemez. Yapışkanlığı kaldırmak bir dengeleme kararı değil, durumu süreç dışına
taşıma kararıdır.

#### Özet

- Oturum yapışkanlığı, istemcinin isteklerini belirli bir kopyaya bağlayarak dağıtım seçimini bir
  kısıta çevirir; Eşzamansız İşleme kursundaki yapışkan yönlendirme aynı bağdır.
- Aynı istemci karışımında dengesizlik yapışkansız kuralda 1,000, yapışkan-kalan kuralda 1,515,
  yapışkan-tutarlı kuralda 1,173 çıktı; sapmanın kaynağı istemcilerin eşit sayıda istek
  göndermemesidir.
- Bir kopya düştüğünde yapışkan-tutarlı düzende 100 oturumun 33'ü ve isteklerin yüzde 39,11'i
  kayboluyor; sağlık denetimi isteği kurtarır, oturumu kurtarmaz.
- Dördüncü kopya eklendiğinde en yüklü kopyanın yükü yapışkansız kuralda yüzde 25,01, yapışkan
  kurallarda yüzde 9,80 ve yüzde 3,80 düşüyor; bağı korumak yükü taşımamak demektir.
- En büyük oturumun payı 0,1980 bir seri paydır ve ölçekleme üst sınırını 5,05'te tutar: 16 kopya
  yapışkansız kuralda 16 kat, yapışkan kuralda 4,03 kat böler.
- Y2 ile konan 0,50 doluluk hedefi yapışkan düzende üç kopyada tutmuyor (0,598) ve dört kopyada da
  tutmuyor (0,512); ölçülen dengesizlikle gereken kopya sayısı 4'tür, yapışkanlıksız 3 idi.

#### Sonraki Adım

Bu konu isteğin **hangi kopyaya** düştüğünü çözdü. Dengeleyici bir yönlendirme aygıtıdır: kararını
bağlantı düzeyinde ya da içerik düzeyinde verir, kuralını sıraya, kuyruk uzunluğuna ya da anahtara
göre seçer, düşen kopyayı denetimle havuzdan çıkarır ve durum kopyanın belleğinde kaldığında
seçme yetkisini kaybeder. Kenarda biriken işler bununla bitmiyor. Aynı noktada kimlik doğrulanıyor,
hız sınırı uygulanıyor, istemcinin beklediği biçime çeviri yapılıyor ve tek bir kullanıcı isteğini
karşılamak için birden çok servisten gelen yanıtlar toplanıyor. Bu işlerin dengeleyiciye mi,
uygulamaya mı, yoksa ayrı bir katmana mı ait olduğu açıkta kaldı — üçüncü seçeneğin bir adı vardır
ve sonraki konu onunla başlar: kenar sorumluluklarının toplandığı bir ağ geçidi neyi üstlenir,
neyi üstlenmemelidir.

## Ağ Geçidi Kalıpları

Kenarda toplanan sorumlulukların yerleştirilmesi: API ağ geçidinin ne yaptığı ve ne yapmaması gerektiği, tek istekte çoklu servis çağrısının toplanması, ortak işlerin kenara boşaltılması, istemci türüne özel arayüz kurulması, yardımcı süreçlerle ilgi ayrımı ve doğrulama katmanının yalıtılması.

### API Ağ Geçidi

Source: https://academia.sh/tr/kurslar/trafik-katmani/api-ag-gecidi

Kenarda biriken sorumlulukların yerleştirilmesi: API ağ geçidinin yük dengeleyiciden ve ters vekilden hangi kararla ayrıldığı, beş kenar sorumluluğunun üç yerleşimde tekrarlanan satır ve düzenlenen birim sayısıyla ölçülmesi ve tek giriş noktasının uçtaki tepe istek hızını tek bileşende topladığının hesaplanması.

Önceki konu isteğin **hangi kopyaya** düştüğünü çözdü. Yük dengeleyici bir yönlendirme
aygıtıdır: kararını bağlantı düzeyinde ya da isteğin içeriğine bakarak verir, düşen kopyayı
sağlık denetimiyle havuzdan çıkarır ve durum kopyanın belleğinde kaldığında seçme yetkisini
kaybeder — oturum yapışkanlığı bunun bedelini gereken kopya sayısının 3'ten 4'e çıkmasıyla
ölçtü. Kararın konusu her seferinde aynıydı: eldeki eş kopyalardan hangisi.

Kenarda biriken işler bundan fazlasıdır. Bir takip isteği uygulamaya ulaşmadan önce
kimliğinin doğrulanması, hızının sınırlanması, gövdesinin servisin beklediği biçime
çevrilmesi ve birden çok servisten gelen yanıtın tek gövdede toplanması gerekebilir.
Bunların hiçbiri "hangi kopya" sorusu değildir ve üç yere birden konabilir: dengeleyiciye,
uygulamaya ya da ayrı bir katmana. Bu ders üçüncü seçeneği adlandırır ve soruyu tek bir
yerleşim kararına indirir: her serviste mi, kenarda tek bir bileşende mi, ikisine bölünmüş mü.

#### Ağ Geçidi Hangi Kararı Verir

**API ağ geçidi** (API gateway), bir sistemin dışa açılan tek giriş noktasıdır ve kararını
*işlem* düzeyinde verir: gelen istek hangi servise ait, hangi biçimde iletilecek, hangi
denetimlerden geçmiş olması gerekiyor. Bu kararı verebilmek için ağ geçidi bir **servis
haritası** taşır — yolların servislere eşlenişi.

Yük dengeleyicinin kararı bu değildir. Dengeleyici, aynı işi yapan kopyalar arasından birini
seçer; hangi servisin ne yaptığını bilmesi gerekmez, elindeki havuzun eş olduğunu varsayar.
Ters vekil ise Sunucu Tarafı Temelleri kursunda kurulan biçimiyle isteği alıp arkadaki
sunucuya ileten süreçtir; TLS sonlandırma ve statik dosya sunumu orada ele alındı. Üç adın
aynı süreçte birleşmesi sıktır ve bu bir çelişki değildir: ayrım süreçlerin sayısında değil,
verilen kararda durur. Bir istek için "hangi kopya" sorusu dengeleyicinin, "hangi servis ve
hangi biçim" sorusu ağ geçidinin kararıdır.

Bu ayrım ağ geçidinin **ne yapmaması** gerektiğini de belirler. Ücretlendirme bağlamının
tarife kuralı ya da teslimat operasyonu bağlamının rota kuralı ağ geçidine konduğunda, kenar
iki bağlamın alan kurallarını birden tanımaya başlar ve iki bağlamın her değişikliği kenarı
düzenletir. Kenara ait olan iş, isteğin **üstverisine** bakarak karar verilebilen iştir;
gönderinin kendisine bakmayı gerektiren iş servistedir. Bu ölçüt konunun üçüncü dersinde
mekanik bir kurala çevrilir.

#### Beş Sorumluluk, Üç Yerleşim

Ölçüm için süreç içi bir model kullanılır: gerçek bir ağ geçidi ürünü, ayrı süreç ya da ağ
yoktur. Model üç servisi (takip, olay, ücret — sırasıyla okuma, yazma ve toplu akış) ve beş
kenar sorumluluğunu bir veri yapısı olarak tutar. Belirteç doğrulama Kimlik Doğrulama ve
Yetkilendirme kursunda, hız sınırlama Eşzamansız İşleme kursunda kurulmuştu; burada ikisinin
de algoritması değil **yeri** ele alınır.

```js
// kenar/yerlesim.mjs — uc servis, bes kenar sorumlulugu ve uc yerlesim; surec ici model
export const SERVIS = { takip: "okuma", olay: "yazma", ucret: "toplu" };

// Her sorumlulugun gerceklestirmesi kac satir tutuyor (model degeri, tek yerde yazili)
export const SORUMLULUK = {
  "yol eslesme": 7,
  "belirtec dogrulama": 12,
  "hiz sinirlama": 9,
  "istek gunlugu": 6,
  "bicim cevirisi": 11,
};

export const YERLESIM = {
  "her serviste": { gecit: [], serviste: Object.keys(SORUMLULUK) },
  "ag gecidinde": { gecit: Object.keys(SORUMLULUK), serviste: [] },
  "karma": {
    gecit: ["yol eslesme", "hiz sinirlama", "istek gunlugu", "belirtec dogrulama"],
    serviste: ["belirtec dogrulama", "bicim cevirisi"],
  },
};

export function olc(y) {
  const servisSayisi = Object.keys(SERVIS).length;
  const toplam = (liste) => liste.reduce((t, s) => t + SORUMLULUK[s], 0);
  const gecitVar = y.gecit.length > 0;
  return {
    "istemcinin bildigi adres": gecitVar ? 1 : servisSayisi,
    "kenarda toplanan satir": toplam(y.gecit),
    "servislerde tekrarlanan satir": servisSayisi * toplam(y.serviste),
    "sorumlulugu tasiyan birim (ortalama)":
      Number((Object.keys(SORUMLULUK).reduce((t, s) =>
        t + (y.gecit.includes(s) ? 1 : 0) + (y.serviste.includes(s) ? servisSayisi : 0), 0)
        / Object.keys(SORUMLULUK).length).toFixed(2)),
    "bir istegin doktugu durak": gecitVar ? 2 : 1,
    "ag gecidinin doktugu akis": gecitVar ? servisSayisi : 0,
    "gecit durdugunda yanitlanan akis": `${gecitVar ? 0 : servisSayisi}/${servisSayisi}`,
  };
}
```

Satır sayıları modelin girdisidir ve **varsayım** sınıfındadır: bir gerçekleştirmeden
ölçülmemiştir, yalnız büyüklük sırasını taşır. Okunan şey toplamın kendisi değil, üçe
çarpılmasının ürettiği farktır; beş sayı yarıya inse de tekrarlanan satırın kenarda toplanan
satıra oranı aynı kalır.

Üçüncü yerleşimde `belirtec dogrulama` iki listede birden geçiyor. Bu bir yazım hatası
değil, bilinçli bir seçimdir: ağ geçidi belirteci doğrular, servis de doğrular ve ikinci
doğrulama ağ geçidinin atlandığı durumu karşılar. Sayaç bunu ödenen bir sayı olarak
gösteriyor.

```js
// kenar/olc.mjs — uc yerlesimi ayni sayaclarla olcer ve K01 hesabina baglar
import { YERLESIM, olc } from "./yerlesim.mjs";

const ALAN = ["istemcinin bildigi adres", "kenarda toplanan satir",
  "servislerde tekrarlanan satir", "sorumlulugu tasiyan birim (ortalama)",
  "bir istegin doktugu durak", "ag gecidinin doktugu akis",
  "gecit durdugunda yanitlanan akis"];

const olcum = Object.entries(YERLESIM).map(([ad, y]) => ({ ad, ...olc(y) }));
console.log(`${"olcu".padEnd(37)}${olcum.map((o) => o.ad.padStart(14)).join("")}`);
for (const a of ALAN) {
  console.log(`${a.padEnd(37)}${olcum.map((o) => String(o[a]).padStart(14)).join("")}`);
}

// K01 Kabaca Buyukluk Hesabi dersinin sayilari (hesap sinifi, oradan alindi)
const K01 = { okumaTepe: 416.67, yazmaTepe: 97.22, ucTepe: 513.89 };
const yaz = (ad, deger, not = "") => console.log(`${ad.padEnd(37)}${deger.padStart(10)}  ${not}`);

console.log("");
yaz("K01 — uctaki tepe istek/s", K01.ucTepe.toFixed(2), "okuma 416.67 + yazma 97.22");
yaz("gecit yok — en yuklu bilesen", K01.okumaTepe.toFixed(2), "takip servisi");
yaz("gecit var — en yuklu bilesen", K01.ucTepe.toFixed(2),
  `ag-gecidi, x${(K01.ucTepe / K01.okumaTepe).toFixed(2)}`);
for (const o of olcum) {
  yaz(`durak-istek/s — ${o.ad}`,
    (K01.ucTepe * o["bir istegin doktugu durak"]).toFixed(2),
    `durak ${o["bir istegin doktugu durak"]}`);
}
```

```
olcu                                   her serviste  ag gecidinde         karma
istemcinin bildigi adres                          3             1             1
kenarda toplanan satir                            0            45            34
servislerde tekrarlanan satir                   135             0            69
sorumlulugu tasiyan birim (ortalama)              3             1             2
bir istegin doktugu durak                         1             2             2
ag gecidinin doktugu akis                         0             3             3
gecit durdugunda yanitlanan akis                3/3           0/3           0/3

K01 — uctaki tepe istek/s                513.89  okuma 416.67 + yazma 97.22
gecit yok — en yuklu bilesen             416.67  takip servisi
gecit var — en yuklu bilesen             513.89  ag-gecidi, x1.23
durak-istek/s — her serviste             513.89  durak 1
durak-istek/s — ag gecidinde            1027.78  durak 2
durak-istek/s — karma                   1027.78  durak 2
```

#### Sayıların Okunması

Tablonun ilk üç satırı ağ geçidinin ne için kurulduğunu söylüyor. Geçit yokken istemci üç
adres bilmek zorunda ve beş sorumluluk üç serviste 135 satır tutuyor; geçitle birlikte adres
1'e, o satırlar kenarda 45'e iniyor. Aynı işi taşıyan satır sayısı üçte bire düşmüyor —
sıfırdan 45'e çıkıyor ve 135 sıfırlanıyor. Fark, tekrarın kaldırılmasıdır: bir sorumluluğu
taşıyan birim sayısı ortalama 3'ten 1'e iniyor, yani hız sınırlama kuralı değiştiğinde
düzenlenen birim sayısı 3 yerine 1 oluyor.

Sonraki üç satır bedeli veriyor. Her istek artık iki durağa dokunuyor; uçtaki tepe hız
sabit kalsa bile sistemde saniyede işlenen durak-istek sayısı 513,89'dan 1027,78'e, tam iki
katına çıkıyor. Bu sayı gecikme değildir — bir süre ölçülmedi — ama gecikmenin nereden
büyüyeceğini gösterir: her istek fazladan bir bileşenin kuyruğuna girer.

Son satır en pahalısıdır. Geçit durduğunda yanıtlanan akış 3/3'ten 0/3'e iniyor. Geçitsiz
yerleşimde bir servisin durması yalnız o akışı düşürürken, geçitli yerleşimde tek bir bileşen
üç akışı birden düşürüyor. Karma yerleşim bu satırı düzeltmiyor: belirteci iki yerde doğrulamak
ağ geçidinin atlanabildiği durumu karşılar, ağ geçidinin durduğu durumu karşılamaz. Karma
yerleşimin gerçek kazancı ortada duruyor — tekrarlanan satır 135 yerine 69, kenarda toplanan
satır 45 yerine 34 — ve gerçek bedeli de: bir sorumluluğu taşıyan birim sayısı ortalama 2, yani
belirteç doğrulama hâlâ hem ağ geçidinde hem serviste bakılır.

#### Hesaba Dönüş

Kursun kuralı gereği bu kararın K01 hesabındaki karşılığı yazılır. Kabaca Büyüklük Hesabı
dersinde uçtaki tepe istek hızı saniyede 513,89 çıkmıştı (416,67 okuma + 97,22 yazma) ve o
sayı **üç ayrı uca** dağılmış hâlde duruyordu; o dersin diyagramında en yüklü kenar 416,67
istek/s taşıyan takip kenarıydı. Ağ geçidi kurulduğunda bu dağılım kalkıyor: tek bir bileşen
513,89 istek/s taşıyor, yani eski en yüklü bileşenin 1,23 katı.

Daha önemlisi, ağ geçidinin dokunduğu akış sayısı 3 oluyor. Sistem Tasarımı Nedir dersinde
bu sayı yalnız `gonderi-deposu` için 3'tü ve o ders bir kural bırakmıştı: bir tasarımın en
kırılgan noktası, en çok akışın dokunduğu bileşendir. Ağ geçidi kurulduğunda sistemde böyle
iki bileşen olur — biri veri katmanında, biri kenarda. Kenar bileşeni için bu, `gecit
durdugunda yanitlanan akis` satırının 0/3 olmasıyla aynı olgudur.

Hesabın değişmeyen yanı da yazılmalı: `onbellek arkasi okuma/s` 41,67, `okuma cikis Mbit/s`
1,60 ve günlük veri artışı 976 MB bu kararla oynamıyor. Ağ geçidi bu dersteki hâliyle istek
başına gövdeyi değiştirmiyor, yalnız isteğin geçtiği durak sayısını ve sorumlulukların yerini
değiştiriyor. Gövdeyi değiştiren kararlar sonraki iki derste ölçülür.

#### Özet

- API ağ geçidi kararını işlem düzeyinde verir ve bir servis haritası taşır; yük dengeleyici
  eş kopyalar arasından seçer, ters vekil isteği iletir. Üçü aynı süreçte birleşebilir, ayrım
  verilen karardadır.
- Kenara ait iş, isteğin üstverisine bakarak karar verilebilen iştir; gönderinin kendisine
  bakmayı gerektiren alan kuralı serviste kalır.
- Beş sorumluluk üç serviste 135 satır tekrarlanırken kenarda 45 satıra iniyor ve bir
  sorumluluğu taşıyan birim sayısı ortalama 3'ten 1'e düşüyor.
- Ödenen sayılar: her istek 1 yerine 2 durağa dokunuyor (durak-istek/s 513,89 → 1027,78) ve
  geçit durduğunda yanıtlanan akış 3/3'ten 0/3'e iniyor.
- Karma yerleşim ortada duruyor: tekrarlanan satır 69, kenarda toplanan satır 34, ama
  sorumluluk başına birim sayısı ortalama 2 ve 0/3 satırı düzelmiyor.
- K01'e dönüş: uçtaki 513,89 istek/s üç kenara dağılmış hâlden tek bileşene toplanıyor (eski
  en yüklü bileşenin 1,23 katı) ve ağ geçidinin dokunduğu akış sayısı 3 oluyor.

#### Sonraki Adım

Bu ders ağ geçidinin taşıdığı servis haritasını bir varsayım olarak kullandı: yolların
servislere eşlendiği söylendi, eşlemenin kendisi ölçülmedi. Eşleme ise iki ayrı iş yapabilir.
Birincisi yönlendirmedir — gelen yol tek bir servise çevrilir ve istemci arkadaki bölünmeyi
görmez. İkincisi daha fazlasıdır: takip sayfası hem gönderinin durumunu hem ücretini
istiyorsa, ağ geçidi tek isteği iki servise dağıtıp iki yanıtı tek gövdede birleştirebilir.
Sonraki ders bu ikisini gerçek yerel süreçlerle kurar ve toplamanın istemci istek sayısını
kaç düşürdüğünü, karşılığında uçtaki gövdeyi kaç bayt büyüttüğünü ölçer.

### Ağ Geçidi Yönlendirme ve Toplama

Source: https://academia.sh/tr/kurslar/trafik-katmani/ag-gecidi-yonlendirme-ve-toplama

Servis haritasının iki ayrı işi: yolun tek servise çevrilmesi ve tek isteğin birden çok servise dağıtılıp yanıtların tek gövdede birleştirilmesi; üç erişim biçiminin yerel süreçlerle ölçülmesi ve toplamanın istek sayısını yarıya indirirken uçtaki gövdeyi kaç kat büyüttüğünün hesaplanması.

Önceki ders ağ geçidinin bir servis haritası taşıdığını söyledi ama haritayı bir varsayım
olarak bıraktı. Harita iki ayrı iş yapabilir. Birincisi **ağ geçidi yönlendirme** (gateway
routing): gelen yol tek bir servise çevrilir, istemci arkadaki bölünmeyi görmez. İkincisi
**ağ geçidi toplama** (gateway aggregation): tek istek birden çok servise dağıtılır ve gelen
yanıtlar tek gövdede birleştirilir.

Ayrımın somut hâli takip sayfasıdır. Sayfa bir gönderinin durumunu teslimat operasyonu
bağlamından, ücretini ise ücretlendirme bağlamından alır. İki bağlam iki ayrı servistir, yani
sayfa iki yanıt ister. Bu ders o iki yanıtın kaç istekle, kaç baytla ve kaç turla alındığını
gerçek yerel süreçlerle ölçer; sonra ölçülen oranı Kabaca Büyüklük Hesabı dersinin takip
yanıtı sayısına uygular.

#### Düzenek

İki alan servisi ve bir ağ geçidi ayrı süreçler olarak koşar. Servislerin döndürdüğü alan
kümesi Web API Tasarımı kursundaki kaynak tasarımı kurallarına göre belirlenmiştir ve burada
yeniden tartışılmaz; ölçülen şey kenarda verilen karardır.

```js
// gecit/servis.mjs — iki alan servisi: teslimat operasyonu 8471, ucretlendirme 8472
import { createServer } from "node:http";

const DURUM = {
  "TR-4821": { durum: "dagitimda", bolge: "35", guncellenme: "2026-03-11T08:24:00Z",
    rota: ["34", "41", "35"] },
  "TR-9007": { durum: "kabul", bolge: "34", guncellenme: "2026-03-11T07:02:00Z", rota: ["34"] },
};
const UCRET = {
  "TR-4821": { tarife: 9600, indirim: 1440, net: 8160, sozlesmeNo: "S7" },
};

const sun = (port, ad, tablo) => createServer((istek, yanit) => {
  const no = istek.url.split("/").pop();
  const kayit = tablo[no];
  const govde = JSON.stringify(kayit ? { takipNo: no, ...kayit } : { hata: "bulunamadi" });
  yanit.writeHead(kayit ? 200 : 404, { "Content-Type": "application/json" });
  yanit.end(govde);
}).listen(port, "127.0.0.1", () => console.log(`${ad} 127.0.0.1:${port}`));

sun(8471, "teslimat-op  ", DURUM);
sun(8472, "ucretlendirme", UCRET);
```

Ağ geçidi haritayı bir nesne olarak tutar ve iki yolu ayırır: `/takip/<no>/<alt>` bir servise
çevrilir, `/takip/<no>` ise iki servisi tek turda çağırır. Üçüncü bir yol, `/sayac`, geçit ile
servisler arasındaki sayaçları okuyup sıfırlar; ölçüm ucudur, tasarımın parçası değildir.

```js
// gecit/gecit.mjs — ag gecidi 8473: servis haritasiyla yonlendirme ve tek istekte toplama
import { createServer } from "node:http";

const HARITA = { durum: 8471, ucret: 8472 };      // yol parcasi -> servis
let sayac = { istek: 0, bayt: 0, tur: 0 };        // gecit ile servisler arasindaki sayaclar

async function servis(ad, no) {
  sayac.istek += 1;
  const y = await fetch(`http://127.0.0.1:${HARITA[ad]}/${ad}/${no}`);
  const metin = await y.text();
  sayac.bayt += Buffer.byteLength(metin);
  return y.ok ? JSON.parse(metin) : null;
}

createServer(async (istek, yanit) => {
  const [kok, no, alt] = istek.url.split("/").filter(Boolean);
  let govde;
  if (kok === "sayac") {                           // olcum ucu: sayaclari okur ve sifirlar
    govde = sayac;
    sayac = { istek: 0, bayt: 0, tur: 0 };
  } else if (kok !== "takip") {
    govde = null;
  } else if (alt) {                                // yonlendirme: yol tek servise cevrilir
    sayac.tur += 1;
    govde = await servis(alt, no);
  } else {                                         // toplama: iki servis tek turda cagrilir
    sayac.tur += 1;
    const [durum, ucret] = await Promise.all([servis("durum", no), servis("ucret", no)]);
    govde = durum && { ...durum, ucret: ucret && { tarife: ucret.tarife,
      indirim: ucret.indirim, net: ucret.net, sozlesmeNo: ucret.sozlesmeNo } };
  }
  const metin = JSON.stringify(govde ?? { hata: "bulunamadi" });
  yanit.writeHead(govde ? 200 : 404, { "Content-Type": "application/json" });
  yanit.end(metin);
}).listen(8473, "127.0.0.1", () => console.log("ag-gecidi     127.0.0.1:8473"));
```

İstemci üç erişim biçimini sırayla dener ve her birinde altı sayı toplar. Bayt sayıları yalnız
gövdeyi sayar; başlık ve protokol yükü K01'in hesabında da dışarıda bırakılmıştı.

```js
// gecit/olc.mjs — uc erisim bicimini olcer ve K01'in takip yaniti hesabina baglar
const al = async (url) => {
  const y = await fetch(url);
  const metin = await y.text();
  return { bayt: Buffer.byteLength(metin), veri: y.ok ? JSON.parse(metin) : null };
};
const sayacOku = async () => (await al("http://127.0.0.1:8473/sayac")).veri;
const yaprak = (d) => (typeof d !== "object" || d === null ? 1
  : Object.values(d).reduce((t, v) => t + yaprak(v), 0));

async function olc(ad, adres, istekler) {
  await sayacOku();                                   // onceki senaryonun sayaclarini sifirlar
  let bayt = 0, alan = 0;
  for (const u of istekler) {
    const r = await al(u);
    bayt += r.bayt;
    alan += r.veri ? yaprak(r.veri) : 0;
  }
  const ic = await sayacOku();
  return { ad, "istemci istegi": istekler.length, "istemcinin bildigi adres": adres,
    "istemciye ulasan bayt": bayt, "tasinan alan": alan,
    "gecit-servis istegi": ic.istek, "gecit-servis bayt": ic.bayt,
    "gecit turu": ic.tur };
}

const N = "TR-4821";
const S = [
  await olc("ayri cagri", 2, [`http://127.0.0.1:8471/durum/${N}`, `http://127.0.0.1:8472/ucret/${N}`]),
  await olc("yonlendirme", 1, [`http://127.0.0.1:8473/takip/${N}/durum`,
    `http://127.0.0.1:8473/takip/${N}/ucret`]),
  await olc("toplama", 1, [`http://127.0.0.1:8473/takip/${N}`]),
];
const ALAN = ["istemci istegi", "istemcinin bildigi adres", "istemciye ulasan bayt",
  "tasinan alan", "gecit-servis istegi", "gecit-servis bayt", "gecit turu"];
console.log(`${"olcu".padEnd(26)}${S.map((s) => s.ad.padStart(13)).join("")}`);
for (const a of ALAN) console.log(`${a.padEnd(26)}${S.map((s) => String(s[a]).padStart(13)).join("")}`);

// Eksik parca: ucretlendirme bu takip numarasini tanimiyor
const eksik = await al(`http://127.0.0.1:8473/takip/TR-9007`);
console.log(`\neksik parcali toplama = ${eksik.bayt} bayt, tasinan alan = ${yaprak(eksik.veri)}`);
console.log(`  govde: ${JSON.stringify(eksik.veri)}`);

// K01 Kabaca Buyukluk Hesabi: V5 = 480 bayt (varsayim), okuma tepesi 416.67 istek/s (hesap)
const durumBayt = (await al(`http://127.0.0.1:8471/durum/${N}`)).bayt;
const ucretBayt = (await al(`http://127.0.0.1:8472/ucret/${N}`)).bayt;
const birlesik = (await al(`http://127.0.0.1:8473/takip/${N}`)).bayt;
const V5 = 480, OKUMA_TEPE = 416.67;
const mbit = (istek, bayt) => (istek * bayt * 8) / 1e6;
console.log(`\ndurum ${durumBayt} B, ucret ${ucretBayt} B, birlesik ${birlesik} B`);
console.log(`oran — ucret/durum = ${(ucretBayt / durumBayt).toFixed(3)}, ` +
  `birlesik/durum = ${(birlesik / durumBayt).toFixed(3)}`);
const KURULUM = [
  ["K01 (yalniz durum)", OKUMA_TEPE, V5],
  ["ayri cagri", OKUMA_TEPE * 2, (V5 * (durumBayt + ucretBayt)) / durumBayt / 2],
  ["toplama", OKUMA_TEPE, (V5 * birlesik) / durumBayt],
];
console.log(`${"kurulum".padEnd(20)}${"istek/s".padStart(10)}${"bayt".padStart(9)}${"Mbit/s".padStart(9)}`);
for (const [ad, istek, bayt] of KURULUM) {
  console.log(`${ad.padEnd(20)}${istek.toFixed(2).padStart(10)}${bayt.toFixed(0).padStart(9)}` +
    `${mbit(istek, bayt).toFixed(2).padStart(9)}`);
}
const [, ayri, top] = KURULUM;
console.log(`toplama / ayri cagri — istek x${(top[1] / ayri[1]).toFixed(2)}, ` +
  `cikis x${(mbit(top[1], top[2]) / mbit(ayri[1], ayri[2])).toFixed(2)}`);

// T1 duyarliligi: goruntulemelerin yalniz bir bolumu ucret istiyorsa (T1 = 0.40)
const T1 = 0.4;
const ayriIstek = OKUMA_TEPE * (1 + T1);
const ayriBayt = (V5 * (durumBayt + T1 * ucretBayt)) / durumBayt / (1 + T1);
const topBayt = (V5 * (durumBayt + T1 * (birlesik - durumBayt))) / durumBayt;
console.log(`T1 = ${T1.toFixed(2)} -> ayri cagri ${ayriIstek.toFixed(2)} istek/s ` +
  `${mbit(ayriIstek, ayriBayt).toFixed(2)} Mbit/s | toplama ${OKUMA_TEPE.toFixed(2)} istek/s ` +
  `${mbit(OKUMA_TEPE, topBayt).toFixed(2)} Mbit/s`);
```

```bash
node gecit/servis.mjs & s=$!
curl -s --retry 20 --retry-connrefused --retry-delay 0 -o /dev/null http://127.0.0.1:8472/ucret/TR-4821
node gecit/gecit.mjs & g=$!
curl -s --retry 20 --retry-connrefused --retry-delay 0 -o /dev/null http://127.0.0.1:8473/sayac
node gecit/olc.mjs
kill $s $g
```

```
teslimat-op   127.0.0.1:8471
ucretlendirme 127.0.0.1:8472
ag-gecidi     127.0.0.1:8473
olcu                         ayri cagri  yonlendirme      toplama
istemci istegi                        2            2            1
istemcinin bildigi adres              2            1            1
istemciye ulasan bayt               194          194          183
tasinan alan                         12           12           11
gecit-servis istegi                   0            2            2
gecit-servis bayt                     0          194          194
gecit turu                            0            2            1

eksik parcali toplama = 114 bayt, tasinan alan = 6
  govde: {"takipNo":"TR-9007","durum":"kabul","bolge":"34","guncellenme":"2026-03-11T07:02:00Z","rota":["34"],"ucret":null}

durum 115 B, ucret 79 B, birlesik 183 B
oran — ucret/durum = 0.687, birlesik/durum = 1.591
kurulum                istek/s     bayt   Mbit/s
K01 (yalniz durum)      416.67      480     1.60
ayri cagri              833.34      405     2.70
toplama                 416.67      764     2.55
toplama / ayri cagri — istek x0.50, cikis x0.94
T1 = 0.40 -> ayri cagri 583.34 istek/s 2.04 Mbit/s | toplama 416.67 istek/s 1.98 Mbit/s
```

#### Yönlendirme Tek Başına Ne Kazandırır

Tablonun ilk iki kolonu bunu yanıtlıyor: yönlendirmeye geçildiğinde istemci isteği 2'de,
istemciye ulaşan bayt 194'te, taşınan alan 12'de kalıyor. Değişen tek sayı istemcinin bildiği
adres: 2 yerine 1. Yönlendirme bir başarım kararı değil, bir **bağ** kararıdır. Servis
haritası ağ geçidinde durduğu için ücretlendirme servisi başka bir adrese taşındığında ya da
iki servise bölündüğünde istemci düzenlenmez; harita düzenlenir.

Karşılığında `gecit-servis istegi` 0'dan 2'ye çıkıyor. Aynı iki çağrı hâlâ yapılıyor, yalnız
kenarın arkasına geçmiş durumda. Yönlendirme bir çağrıyı ortadan kaldırmaz; kimin yaptığını
değiştirir.

#### Toplama Neyi Değiştirir

Üçüncü kolon dört sayıyı birden oynatıyor. İstemci isteği 2'den 1'e, taşınan alan 12'den
11'e, istemciye ulaşan bayt 194'ten 183'e ve geçit turu 2'den 1'e iniyor. Alan sayısının
düşmesi `takipNo` alanının iki gövdede birden taşınmaktan tek gövdeye inmesindendir; 11 baytlık
azalma da bundandır. Geçit turunun 1'e inmesi ise iki çağrının tek turda, birbirini beklemeden
yapılmasıdır; iki servisten yanıt gelmesini bekleyen taraf istemci değil ağ geçididir.

Değişmeyen sayı önemli: `gecit-servis istegi` toplamada da 2. Toplama, sistemin yaptığı çağrı
sayısını düşürmez — **kenarın dışında görünen** çağrı sayısını düşürür. Bu ayrım kararın nereye
yazılacağını belirler: kazanç istemci tarafındaki tur sayısında ve istemcinin taşıdığı
bilgide, maliyet ise ağ geçidinin iki yanıtı bekleyen kodunda.

#### Eksik Parça Bir Sözleşme Kararıdır

`TR-9007` numaralı gönderinin ücretlendirme kaydı yok. Toplama bu durumda 114 baytlık bir
gövde ve 6 alan döndürüyor; `ucret` alanı `null`. Bu, kodun bir seçimidir ve seçenekleri
sayılabilir: birleşik yanıt eksik parçayla dönebilir, tümüyle başarısız sayılabilir ya da
eksik parça istemciye ayrı bir alanda bildirilebilir. Toplama yapan bir ağ geçidi bu seçimi
yapmak zorundadır, çünkü artık tek bir yanıtın içinde birden çok kaynağın durumu vardır. Bu
sözleşme kararı yazılmadığında istemci, eksik `ucret` alanını "ücret sıfır" ile
karıştırabilir. Kararın kendisi ağ geçidine değil, iki tarafın anlaştığı yanıt biçimine
aittir.

#### Hesaba Dönüş

K01'in varsayım tablosunda V5 takip yanıtını 480 bayt sayıyordu ve gerekçesi "durum, bölge,
güncellenme zamanı ve son üç rota adımı"ydı — yani yalnız durum parçası. Takip sayfasının
ücreti de göstermesi K01'de yoktu; bu **bu kursun varsayımıdır** (T1 = 1,00: her takip
görüntülemesi ücret bilgisini de ister). Gerekçesi sayfanın tek ekranda iki bilgiyi
göstermesidir; duyarlılığı aşağıda hesaplandı.

Düzenekten ölçülen oranlar belirlenimlidir: gövdeler JSON metnidir, bayt sayıları makineden
bağımsızdır. Ücret gövdesi durum gövdesinin 0,687 katı, birleşik gövde 1,591 katı. Bu oranlar
V5'e uygulandığında üç kurulum çıkıyor. K01'in kendi satırı 416,67 istek/s ve 480 bayt ile
1,60 Mbit/s. Ayrı çağrıda istek hızı ikiye katlanıyor (833,34) ve istek başına ortalama gövde
405 bayta düşüyor; çıkış 2,70 Mbit/s. Toplamada istek hızı 416,67'de kalıyor ama gövde 764
bayta çıkıyor; çıkış 2,55 Mbit/s.

Üç sayı üç ayrı şey söylüyor. Birincisi toplama istek hızını yarıya indiriyor (×0,50) ama
çıkışı yalnız 0,94 katına indiriyor: bant genişliğini belirleyen şey paketleme değil, taşınan
alan kümesidir. İkincisi K01'in 1,60 Mbit/s'i her iki kurulumda da aşılıyor; gereksinim
büyüdüğünde hesap yeniden koşturulur, eski sayı korunmaz. Üçüncüsü T1'in duyarlılığı: yalnız
görüntülemelerin yüzde kırkı ücret istiyorsa ayrı çağrıda 583,34 istek/s ve 2,04 Mbit/s,
toplamada 416,67 istek/s ve 1,98 Mbit/s çıkıyor. Toplamanın istek hızı kazancı T1 küçüldükçe
azalır; gövde büyütme bedeli de azalır.

#### Özet

- Servis haritası iki iş yapar: yönlendirme yolu tek servise çevirir, toplama tek isteği
  birden çok servise dağıtıp yanıtları birleştirir.
- Yönlendirme yalnız bağ kararıdır: istemci isteği 2, bayt 194 ve alan 12 sabit kalırken
  istemcinin bildiği adres 2'den 1'e iniyor, `gecit-servis istegi` 0'dan 2'ye çıkıyor.
- Toplama istemci isteğini 2'den 1'e, taşınan alanı 12'den 11'e, geçit turunu 2'den 1'e
  indiriyor; geçit ile servisler arasındaki istek sayısı 2'de kalıyor.
- Toplamanın döndürdüğü gövdede birden çok kaynağın durumu birleşir; eksik parçanın nasıl
  bildirileceği bir sözleşme kararıdır — örnekte eksik parça `null` ile döndü, gövde 114 bayt
  ve 6 alan.
- Ölçülen oranlar: ücret gövdesi durum gövdesinin 0,687 katı, birleşik gövde 1,591 katı; bayt
  sayıları makineden bağımsızdır.
- K01'e dönüş: 416,67 istek/s ve 480 bayt ile 1,60 Mbit/s olan çıkış, ayrı çağrıda 833,34
  istek/s ve 2,70 Mbit/s, toplamada 416,67 istek/s ve 2,55 Mbit/s oluyor — istek ×0,50, çıkış
  ×0,94.

#### Sonraki Adım

Toplama, ağ geçidinin gövdeye dokunan ilk işiydi ve bir sözleşme kararı gerektirdi. Kenara
taşınabilecek işlerin çoğu ise gövdeye hiç dokunmaz: bir belirtecin doğrulanması, bir hız
sınırının uygulanması, bir erişim kaydının yazılması. Bu işler her serviste tekrarlanabilir
ya da tek bir yerde toplanabilir; ilk ders ikisini satır sayısıyla karşılaştırdı ama hangi
işin taşınabilir olduğunu bir kurala bağlamadı. Sonraki ders o kuralı kurar: bir denetimin
okuduğu girdiler yazıldığında, kenara taşınabilenler ile serviste kalması gerekenler mekanik
olarak ayrılır — ve doğrulamanın tek yerde yapılmasının uygulamaya ne ödettiği ölçülür.

### Ağ Geçidi Yük Boşaltma

Source: https://academia.sh/tr/kurslar/trafik-katmani/ag-gecidi-yuk-bosaltma

Ortak işlerin kenara taşınmasının mekanik bir kurala bağlanması: bir denetimin okuduğu girdiler yazıldığında taşınabilenlerin ayrılması, tekrarlanan satır sayısının ölçülmesi, güven sınırının kaymasının bedeli ve kenara taşınan denetimin hangi hızda koştuğunun K01 hesabından okunması.

Toplama ağ geçidinin gövdeye dokunan işiydi. Kenara taşınabilecek işlerin çoğu gövdeye hiç
dokunmaz: bir belirtecin imzasının doğrulanması, bir hız sınırının uygulanması, bir erişim
kaydının yazılması. **Ağ geçidi yük boşaltma** (gateway offloading) bu işleri servislerden
alıp kenarda tek bir yerde toplamaktır.

İlk ders bu yerleşimi satır sayısıyla karşılaştırdı ama hangi işin taşınabilir olduğunu bir
kurala bağlamadı ve "isteğin üstverisine bakan iş kenara ait" ölçütünü sözle bıraktı. Bu ders
o ölçütü mekanik hâle getirir: her denetimin okuduğu girdiler yazılır, girdilerin sınıfı
denetimi kendiliğinden ayırır. Belirteç doğrulama Kimlik Doğrulama ve Yetkilendirme kursunda,
hız sınırlama Web API Tasarımı kursunda, TLS sonlandırma bu kursun Yük Dengeleyici Rolü
dersinde ele alındı; hiçbiri burada yeniden anlatılmaz.

#### Taşınabilirlik Kuralı

Bir denetim iki tür girdi okuyabilir. **Üstveri** isteğin kendisinden gelir: başlıklar, yol,
kaynak adres, içerik uzunluğu. **Alan girdisi** sistemin verisinden gelir: gönderi kaydı,
sözleşme kaydı, günlük sayaç. Kural tek cümledir: bir denetim yalnız üstveri okuyorsa kenara
taşınabilir, bir alan girdisi okuyorsa serviste kalır.

Kuralın gerekçesi bir bağ sayısıdır. Alan girdisi okuyan bir denetim kenara taşındığında ağ
geçidi o veriye erişmek zorunda kalır; ilk dersin söylediği gibi kenar iki bağlamın alan
kurallarını tanımaya başlar ve iki bağlamın her değişikliği kenarı düzenletir. Kural, o bağı
kurmayı reddetmenin ölçülebilir biçimidir.

```js
// kenar/denetim.mjs — alti denetim, okuduklari girdiler ve tasinabilirlik kurali
export const USTVERI = ["basliklar", "yol", "kaynak adres", "icerik uzunlugu"];

// okur: kararin zorunlu girdileri; secmeli: kayda yazilmasi istenen ama karari degistirmeyen girdi
export const DENETIM = {
  "belirtec imzasi": { okur: ["basliklar"], secmeli: [], satir: 12 },
  "hiz siniri": { okur: ["kaynak adres", "basliklar"], secmeli: [], satir: 9 },
  "govde boyutu": { okur: ["icerik uzunlugu"], secmeli: [], satir: 5 },
  "erisim kaydi": { okur: ["yol", "basliklar"], secmeli: ["gonderi kaydi"], satir: 6 },
  "gonderi sahipligi": { okur: ["basliklar", "gonderi kaydi"], secmeli: [], satir: 14 },
  "sozlesme kotasi": { okur: ["sozlesme kaydi", "gunluk sayac"], secmeli: [], satir: 11 },
};

export const ustveriMi = (g) => USTVERI.includes(g);
export const tasinir = (d) => d.okur.every(ustveriMi);
export const eksikAlan = (d) => (tasinir(d) ? d.secmeli.filter((g) => !ustveriMi(g)).length : 0);
```

Satır sayıları modelin girdisidir ve **varsayım** sınıfındadır; okunan şey tek bir gerçekleştirme
uzunluğu değil, aynı satırların üç serviste tekrarlanmasının ürettiği farktır. Kural ise
girdilerin sınıfından çıkar ve satır sayılarından bağımsızdır.

```js
// kenar/bosalt.mjs — kurali alti denetime uygular, satirlari sayar ve K01 hesabina baglar
import { DENETIM, tasinir, eksikAlan, ustveriMi } from "./denetim.mjs";

const SERVIS = 3;                                  // takip, olay, ucret
const ad = Object.keys(DENETIM);
const kenar = ad.filter((a) => tasinir(DENETIM[a]));
const serviste = ad.filter((a) => !tasinir(DENETIM[a]));

console.log(`${"denetim".padEnd(19)}${"alan girdisi".padStart(13)}  karar`);
for (const a of ad) {
  const alan = DENETIM[a].okur.filter((g) => !ustveriMi(g));
  console.log(`${a.padEnd(19)}${String(alan.length).padStart(13)}  ` +
    `${tasinir(DENETIM[a]) ? "kenara tasinir" : `serviste kalir (${alan.join(", ")})`}`);
}
const eksik = kenar.reduce((t, a) => t + eksikAlan(DENETIM[a]), 0);
console.log(`\nkenara tasinan = ${kenar.length}/${ad.length}, serviste kalan = ${serviste.length}/${ad.length}`);
console.log(`kenarda eksik kalan kayit alani = ${eksik}`);

const satir = (liste) => liste.reduce((t, a) => t + DENETIM[a].satir, 0);
const YERLESIM = [
  ["her serviste", [], ad],
  ["bosaltilmis", kenar, serviste],
];
console.log(`\n${"yerlesim".padEnd(14)}${"kenar satiri".padStart(14)}${"servis satiri".padStart(15)}${"toplam".padStart(9)}`);
for (const [y, k, s] of YERLESIM) {
  console.log(`${y.padEnd(14)}${String(satir(k)).padStart(14)}` +
    `${String(SERVIS * satir(s)).padStart(15)}${String(satir(k) + SERVIS * satir(s)).padStart(9)}`);
}

// K01 Kabaca Buyukluk Hesabi: uctaki tepe 513.89 istek/s (hesap sinifi)
const UC_TEPE = 513.89;
const GUVEN = [
  ["gecit yok", SERVIS, 1, 0],
  ["gecit dogrular, servis guvenir", 1, 1, SERVIS],
  ["gecit ve servis dogrular", 1 + SERVIS, 2, 0],
];
console.log(`\n${"belirtec dogrulama".padEnd(32)}${"birim".padStart(7)}${"dogrulama/s".padStart(13)}${"korumasiz servis".padStart(18)}`);
for (const [y, birim, kez, acik] of GUVEN) {
  console.log(`${y.padEnd(32)}${String(birim).padStart(7)}` +
    `${(UC_TEPE * kez).toFixed(2).padStart(13)}${`${acik}/${SERVIS}`.padStart(18)}`);
}

// Denetimin hangi hizda kostugu: K01'in uc akis hesabi
const HIZ = [
  [`kenar denetimleri (${kenar.length})`, "513.89 istek/s", "uctaki tepe"],
  ["gonderi sahipligi", "416.67 istek/s", "okuma tepesi"],
  ["sozlesme kotasi", "833.33 kayit/s", "toplu is tarama hizi"],
];
console.log("");
for (const [a, h, k] of HIZ) console.log(`${a.padEnd(23)}${h.padStart(15)}  ${k}`);
```

```
denetim             alan girdisi  karar
belirtec imzasi                0  kenara tasinir
hiz siniri                     0  kenara tasinir
govde boyutu                   0  kenara tasinir
erisim kaydi                   0  kenara tasinir
gonderi sahipligi              1  serviste kalir (gonderi kaydi)
sozlesme kotasi                2  serviste kalir (sozlesme kaydi, gunluk sayac)

kenara tasinan = 4/6, serviste kalan = 2/6
kenarda eksik kalan kayit alani = 1

yerlesim        kenar satiri  servis satiri   toplam
her serviste               0            171      171
bosaltilmis               32             75      107

belirtec dogrulama                birim  dogrulama/s  korumasiz servis
gecit yok                             3       513.89               0/3
gecit dogrular, servis guvenir        1       513.89               3/3
gecit ve servis dogrular              4      1027.78               0/3

kenar denetimleri (4)   513.89 istek/s  uctaki tepe
gonderi sahipligi       416.67 istek/s  okuma tepesi
sozlesme kotasi         833.33 kayit/s  toplu is tarama hizi
```

#### Kuralın Verdiği Ayrım

Altı denetimin dördü kenara taşınıyor, ikisi serviste kalıyor ve ayrımı yapan şey bir yargı
değil bir liste. `gonderi sahipligi` bir gönderinin isteği yapan kimliğe ait olup olmadığını
sorar; yanıt için gönderi kaydını okumak zorundadır, dolayısıyla kenarda verilemez. Bu,
Kimlik Doğrulama ve Yetkilendirme kursunda nesne düzeyinde yetki denetimi olarak kurulan
sorunun kenar karşılığıdır: kimliği doğrulamak kenarda yapılabilir, o kimliğin belirli bir
nesneye erişip erişemeyeceğine karar vermek yapılamaz. `sozlesme kotasi` iki alan girdisi
okuduğu için daha da kesin biçimde serviste kalır.

`erisim kaydi` satırı kuralın sınırını gösteriyor. Denetim yalnız üstveri okuduğu için kenara
taşınıyor, ama seçmeli girdisi bir alan girdisidir: kenarda yazılan kayıt hangi yolun
çağrıldığını bilir, o çağrının hangi gönderiyi döndürdüğünü bilmez. Sayaç bunu `kenarda eksik
kalan kayit alani = 1` olarak yazıyor. Boşaltma bu durumda işi taşımaz, işin bir alanını
düşürür; kararın yazılı hâli "erişim kaydı kenara taşındı, kayıt bir alan eksik" olmalıdır.

Satır tablosu kazancı veriyor: altı denetim üç serviste 171 satır tutarken, boşaltılmış
yerleşimde kenarda 32 ve servislerde 75 satır, toplam 107 satır tutuyor. Toplam 0,63 katına
iniyor. Düşüş üçte bire varmıyor çünkü serviste kalan iki denetim hâlâ üç serviste
tekrarlanıyor — ve o iki denetim en uzun ikisidir.

#### Güven Sınırı Nereye Kayıyor

Boşaltmanın gerçek bedeli satırlarda değil, ikinci tabloda. Geçit yokken üç servis de kendi
belirteç doğrulamasını yapar: kod üç birimde, doğrulama saniyede 513,89 kez, korumasız servis
0/3. Doğrulama kenara alınıp servisler ağ geçidine güvendiğinde kod tek birime iner ve
doğrulama sayısı değişmez, ama korumasız servis 3/3 olur: ağ geçidini atlayan bir istek üç
servisin hiçbirinde doğrulanmaz. Kod satırındaki kazanç, bir güven varsayımıyla ödenmiştir ve
o varsayım yazılmadıkça karar eksiktir.

Üçüncü satır varsayımı kaldırıyor: ağ geçidi de servis de doğrularsa korumasız servis 0/3'e
döner, ama kod dört birime çıkar ve doğrulama saniyede 1027,78 kez koşar. Aynı işi iki kez
yapmanın ölçüsü budur. Üç satırın hiçbiri her ölçüde önde değil; seçim, ağ geçidinin
atlanabilir olup olmadığına dair bir kararla birlikte yazılır.

#### Hesaba Dönüş

Son tablo kursun kuralını iki yönde birden kullanıyor. Kenara taşınan dört denetim K01'in
uçtaki tepe hızında koşar: saniyede 513,89 istek, yani sistemin en yüksek istek hızı. Kenarda
tek bir yerde toplanan denetimin toplam maliyeti bu yüzden dört denetimin 513,89 ile çarpımıdır
ve boşaltma bu çarpımı düşürmez — yalnız tek yerde toplar.

Serviste kalan iki denetim ise farklı hızlarda koşuyor. `gonderi sahipligi` okuma akışına
aittir ve K01'in tepe okuma hızında, saniyede 416,67 istek üzerinde koşar. `sozlesme kotasi`
toplu akışa aittir ve K01'in gün sonu tarama hızında, saniyede 833,33 kayıt üzerinde koşar.
Sonuç beklenenin tersidir: kenara taşınmayan bir denetim, kenara taşınanlardan daha yüksek
hızda koşabiliyor. Boşaltma bir başarım kararı değil, bir yerleşim kararıdır; en pahalı iş
kenarda olmak zorunda değildir.

#### Özet

- Bir denetim yalnız üstveri okuyorsa kenara taşınabilir, bir alan girdisi okuyorsa serviste
  kalır; kural girdilerin listesinden mekanik olarak çıkar.
- Altı denetimin dördü taşınıyor, ikisi kalıyor: `gonderi sahipligi` gönderi kaydını,
  `sozlesme kotasi` sözleşme kaydı ile günlük sayacı okuyor.
- Boşaltma işin bir alanını düşürebilir: kenarda yazılan erişim kaydı bir alan eksik kalıyor
  (`kenarda eksik kalan kayit alani = 1`).
- Satır sayısı 171'den 107'ye, 0,63 katına iniyor; düşüşün sınırı serviste kalan iki denetimin
  hâlâ üç serviste tekrarlanmasıdır.
- Güven sınırı kayıyor: doğrulama kenara alındığında kod 3 birimden 1'e iner ama korumasız
  servis 0/3'ten 3/3'e çıkar; iki yerde doğrulamak 0/3'e döner, karşılığında kod 4 birime ve
  doğrulama 513,89'dan 1027,78 kez/s'ye çıkar.
- K01'e dönüş: kenar denetimleri uçtaki tepede (513,89 istek/s) koşarken serviste kalan iki
  denetim 416,67 istek/s ve 833,33 kayıt/s hızlarında koşuyor — kenar, en pahalı işin yeri
  değildir.

#### Sonraki Adım

Buraya kadarki üç ders ağ geçidini tek bir kenar olarak ele aldı: bütün istemciler aynı
adrese gelir, aynı denetimlerden geçer ve toplama yapıldığında aynı birleşik gövdeyi alır.
Oysa takip bilgisini isteyen istemciler aynı değildir. Bir mobil takip kartı durum ve bölgeyi
gösterir, bir web takip sayfası rota adımlarını da açar, bir satıcı paneli ücret kalemlerini
ister. Tek bir birleşik gövde üçünü birden karşıladığında her istemci kullanmadığı alanları
da taşır. Sonraki ders bu alanları sayar ve kenarı istemci türüne göre bölmenin gövdeyi kaç
bayta indirdiğini, karşılığında kaç kenar birimi ekletiğini ölçer.

### Ön Yüz İçin Backend

Source: https://academia.sh/tr/kurslar/trafik-katmani/on-yuz-icin-backend

Kenarın istemci türüne göre bölünmesi: üç istemcinin alan kümelerinin ayrılması, tek birleşik gövdenin taşıdığı kullanılmayan alanların ve istek sayısının ölçülmesi, ayrı kenar birimlerinin ödettiği toplu uç şartı ve istemci karışımının K01 çıkış hesabına etkisi.

Önceki üç ders kenarı tek bir yüzey olarak ele aldı: bütün istemciler aynı adrese gelir, aynı
denetimlerden geçer, toplama yapıldığında aynı birleşik gövdeyi alır. Oysa takip bilgisini
isteyen istemciler aynı şeyi istemez. Bir mobil takip kartı yalnız durumu ve güncellenme
zamanını gösterir; bir web takip sayfası bölgeyi ve rota adımlarını da açar; bir satıcı paneli
gönderi listesini ücret kalemleriyle birlikte ister.

**Ön yüz için backend** (backend for frontend), kenarı istemci türü başına ayrı bir birime
bölmektir: her istemcinin kendi kenar birimi olur ve o birim yalnız o istemcinin istediği
alanları, o istemcinin istediği biçimde döndürür. Bu ders iki yerleşimi karşılaştırır ve
sorunun ölçüsünü kullanılmayan alan sayısı ile istek sayısında arar. Aşırı veri çekme Web API
Tasarımı kursunda kurulmuş ve orada arayüz biçemleri üzerinde ölçülmüştü; burada aynı olgu bir
**kenar yerleşimi** kararı olarak ele alınır.

#### Üç İstemci, Üç Alan Kümesi

Model süreç içidir: gerçek bir istemci, tarayıcı ya da ayrı süreç yoktur. Birleşik gövde
önceki dersin ölçtüğü gövdedir; alan kümeleri istemci türü başına listelenir. `gonderi` alanı
bir görüntülemede kaç kaydın istendiğini, `pay` alanı takip sorgularının ne kadarının o
istemciden geldiğini söyler.

```js
// kenar/istemci.mjs — uc istemci turu, istedikleri alanlar ve alanlarin hangi serviste oldugu
export const KAYIT = {
  takipNo: "TR-4821", durum: "dagitimda", bolge: "35",
  guncellenme: "2026-03-11T08:24:00Z", rota: ["34", "41", "35"],
  ucret: { tarife: 9600, indirim: 1440, net: 8160, sozlesmeNo: "S7" },
};

export const SERVIS_ALANI = {
  "teslimat-op": ["takipNo", "durum", "bolge", "guncellenme", "rota"],
  "ucretlendirme": ["ucret"],
};

// gonderi: bir goruntulemede kac kayit isteniyor; pay: takip sorgularinin ne kadari (T2)
export const ISTEMCI = {
  "mobil kart": { alan: ["takipNo", "durum", "guncellenme"], gonderi: 1, pay: 0.6 },
  "web sayfasi": { alan: ["takipNo", "durum", "bolge", "guncellenme", "rota"], gonderi: 1, pay: 0.3 },
  "satici paneli": { alan: ["takipNo", "durum", "ucret"], gonderi: 5, pay: 0.1 },
};

export const yaprak = (d) => (typeof d !== "object" || d === null ? 1
  : Object.values(d).reduce((t, v) => t + yaprak(v), 0));
export const sec = (kayit, alanlar) => Object.fromEntries(alanlar.map((a) => [a, kayit[a]]));
export const bayt = (d) => Buffer.byteLength(JSON.stringify(d));
export const servisSayisi = (alanlar) => Object.values(SERVIS_ALANI)
  .filter((liste) => alanlar.some((a) => liste.includes(a))).length;
```

`pay` değerleri **bu kursun varsayımıdır** (T2): takip sorgularının yüzde altmışı mobil
karttan, yüzde otuzu web sayfasından, yüzde onu satıcı panelinden gelir. K01'in tablosuna
eklenmez, çünkü K01 istemci türü ayırmıyordu. Gerekçesi takip sorgusunun çoğunun alıcı
tarafından tek gönderi için yapılmasıdır; duyarlılığı aşağıda hesaplanır.

```js
// kenar/olc.mjs — tek kenar ile on yuz icin backend yerlesimini olcer ve K01 cikisina baglar
import { KAYIT, ISTEMCI, yaprak, sec, bayt, servisSayisi } from "./istemci.mjs";

const TAM = yaprak(KAYIT);                    // birlesik govdenin tasidigi yaprak alan sayisi

function tekKenar(i) {                        // her istemci ayni birlesik govdeyi alir
  const kullanilan = yaprak(sec(KAYIT, i.alan));
  return { istek: i.gonderi, bayt: i.gonderi * bayt(KAYIT), tasinan: i.gonderi * TAM,
    kullanilmayan: i.gonderi * (TAM - kullanilan), icIstek: 2 * i.gonderi };
}

function onYuz(i) {                           // her istemci turu icin ayri kenar birimi
  const govde = i.gonderi === 1 ? sec(KAYIT, i.alan)
    : Array.from({ length: i.gonderi }, () => sec(KAYIT, i.alan));
  return { istek: 1, bayt: bayt(govde), tasinan: yaprak(govde), kullanilmayan: 0,
    icIstek: servisSayisi(i.alan) };
}

const ALAN = ["istek", "bayt", "tasinan", "kullanilmayan", "icIstek"];
for (const [ad, olc] of [["tek kenar", tekKenar], ["on yuz icin backend", onYuz]]) {
  console.log(`\n-- ${ad} --`);
  console.log(`${"istemci".padEnd(15)}${ALAN.map((a) => a.padStart(14)).join("")}`);
  let t = Object.fromEntries(ALAN.map((a) => [a, 0]));
  for (const [i, tanim] of Object.entries(ISTEMCI)) {
    const r = olc(tanim);
    ALAN.forEach((a) => { t[a] += r[a]; });
    console.log(`${i.padEnd(15)}${ALAN.map((a) => String(r[a]).padStart(14)).join("")}`);
  }
  console.log(`${"toplam".padEnd(15)}${ALAN.map((a) => String(t[a]).padStart(14)).join("")}`);
  console.log(`kenar birimi = ${ad === "tek kenar" ? 1 : Object.keys(ISTEMCI).length}, ` +
    `bir alan eklendiginde etkilenen istemci = ${ad === "tek kenar" ? Object.keys(ISTEMCI).length : 1}, ` +
    `servisin sunmasi gereken toplu uc = ${ad === "tek kenar" ? 0 : 2}`);
}

// K01 Kabaca Buyukluk Hesabi: V5 = 480 bayt (varsayim), tepe okuma 416.67 istek/s (hesap).
// Olcek: modelin durum govdesi 115 bayt, K01'in takip yaniti 480 bayt.
const V5 = 480, OKUMA_TEPE = 416.67, DURUM_BAYT = bayt(sec(KAYIT, ["takipNo", "durum", "bolge",
  "guncellenme", "rota"]));
const OLCEK = V5 / DURUM_BAYT;
const mbit = (istek, bayt) => (istek * bayt * 8) / 1e6;
console.log(`\ndurum govdesi = ${DURUM_BAYT} bayt, K01 olcegi = ${OLCEK.toFixed(4)} (480 / ${DURUM_BAYT})`);

console.log(`${"yerlesim".padEnd(21)}${"istek/s".padStart(10)}${"bayt/istek".padStart(12)}${"Mbit/s".padStart(9)}`);
for (const [ad, olc] of [["tek kenar", tekKenar], ["on yuz icin backend", onYuz]]) {
  let istek = 0, toplamBayt = 0;
  for (const tanim of Object.values(ISTEMCI)) {
    const r = olc(tanim);
    istek += OKUMA_TEPE * tanim.pay * r.istek;
    toplamBayt += OKUMA_TEPE * tanim.pay * r.bayt * OLCEK;
  }
  console.log(`${ad.padEnd(21)}${istek.toFixed(2).padStart(10)}` +
    `${(toplamBayt / istek).toFixed(0).padStart(12)}${((toplamBayt * 8) / 1e6).toFixed(2).padStart(9)}`);
}
console.log(`K01 (tek istemci turu)${OKUMA_TEPE.toFixed(2).padStart(9)}${String(V5).padStart(12)}` +
  `${mbit(OKUMA_TEPE, V5).toFixed(2).padStart(9)}`);

// T2 duyarliligi: mobil payi 0.60 yerine 0.30, aradaki fark web sayfasina gecerse
const T2 = { "mobil kart": 0.3, "web sayfasi": 0.6, "satici paneli": 0.1 };
for (const [ad, olc] of [["tek kenar", tekKenar], ["on yuz icin backend", onYuz]]) {
  let istek = 0, toplamBayt = 0;
  for (const [i, tanim] of Object.entries(ISTEMCI)) {
    const r = olc(tanim);
    istek += OKUMA_TEPE * T2[i] * r.istek;
    toplamBayt += OKUMA_TEPE * T2[i] * r.bayt * OLCEK;
  }
  console.log(`T2 mobil 0.30 -> ${ad.padEnd(21)}${istek.toFixed(2).padStart(9)} istek/s` +
    `${((toplamBayt * 8) / 1e6).toFixed(2).padStart(7)} Mbit/s`);
}
```

```
-- tek kenar --
istemci                 istek          bayt       tasinan kullanilmayan       icIstek
mobil kart                  1           183            11             8             2
web sayfasi                 1           183            11             4             2
satici paneli               5           915            55            25            10
toplam                      7          1281            77            37            14
kenar birimi = 1, bir alan eklendiginde etkilenen istemci = 3, servisin sunmasi gereken toplu uc = 0

-- on yuz icin backend --
istemci                 istek          bayt       tasinan kullanilmayan       icIstek
mobil kart                  1            78             3             0             1
web sayfasi                 1           115             7             0             1
satici paneli               1           551            30             0             2
toplam                      3           744            40             0             4
kenar birimi = 3, bir alan eklendiginde etkilenen istemci = 1, servisin sunmasi gereken toplu uc = 2

durum govdesi = 115 bayt, K01 olcegi = 4.1739 (480 / 115)
yerlesim                istek/s  bayt/istek   Mbit/s
tek kenar                583.34         764     3.56
on yuz icin backend      416.67         569     1.90
K01 (tek istemci turu)   416.67         480     1.60
T2 mobil 0.30 -> tek kenar               583.34 istek/s   3.56 Mbit/s
T2 mobil 0.30 -> on yuz icin backend     416.67 istek/s   2.05 Mbit/s
```

#### Kullanılmayan Alan ve İstek Sayısı

Tek kenarda üç istemcinin toplam 7 isteği 77 alan taşıyor ve bunun 37'si kullanılmıyor —
taşınan alanın yüzde kırk sekizi. Dağılım eşit değil: mobil kart 11 alanın 8'ini, web sayfası
4'ünü, satıcı paneli beş kayıt boyunca 25'ini kullanmıyor. En küçük istemci en çok fazlalığı
taşıyor, çünkü birleşik gövde en geniş istemcinin ihtiyacına göre biçimlenmiştir.

Ön yüz için backend yerleşiminde bu sayı sıfırlanıyor; ilginç olan yanı istek sayısıdır. Toplam
istek 7'den 3'e iniyor ve düşüşün tamamı satıcı panelinden geliyor: panel beş gönderi için beş
istek yaparken tek istekte liste alıyor. Bu, Web API Tasarımı kursunda ölçülen N+1 örüntüsünün
kenardaki hâlidir — liste getirip her satır için ayrı istek yapan yerleşim. Ön yüz için backend
onu ortadan kaldırmıyor, kenarın arkasına taşıyor: `icIstek` sütunu paneli 10'dan 2'ye indiriyor
ama sıfıra indirmiyor.

Gövde baytı da 1281'den 744'e, 0,58 katına iniyor. Bu sayı taşınan alanın 77'den 40'a inmesiyle
aynı yönde ama aynı oranda değil; alan sayısı 0,52 katına inerken bayt 0,58 katına iniyor,
çünkü kısa alan adları ve zarf karakterleri her gövdede sabit bir pay tutar.

#### Ödenen Sayılar

Üç sayı büyüyor. Birincisi kenar birimi sayısı: 1'den 3'e. Her birim toplama kodunu kendi
içinde tekrarlar, yani ilk dersin ölçtüğü "tekrarlanan satır" sorunu kenarın kendi içinde
yeniden doğar. İkincisi istemci başına düzenleme: tek kenarda bir alan eklendiğinde etkilenen
istemci 3, ön yüz için backend'de 1. Bu ikisi aynı ödünleşimin iki yarısıdır — birim sayısını
artırmak, bir değişikliğin etki alanını daraltmanın bedelidir.

Üçüncüsü daha az görünür ve en bağlayıcısıdır: `servisin sunmasi gereken toplu uc` 0'dan 2'ye
çıkıyor. Panelin listesini tek istekte karşılamak için ağ geçidinin iki servisten de toplu
sorgu yapabilmesi gerekir; bu, kenarda alınan bir kararın servis sözleşmelerine yazdığı bir
şarttır. Ön yüz için backend, yalnız kenarı değiştiren bir karar değildir.

#### Hesaba Dönüş

K01'in `okuma cikis Mbit/s` hesabı tek bir istemci türü varsayıyordu: 416,67 istek/s ve 480
baytlık yanıt, 1,60 Mbit/s. Modelin gövdeleri K01 ölçeğine çevrilir — modelin durum gövdesi 115
bayt, K01'in takip yanıtı 480 bayt, ölçek 4,1739 — ve T2 payları uygulanır.

Tek kenarda uçtaki hız 583,34 istek/s, istek başına gövde 764 bayt, çıkış 3,56 Mbit/s: K01'in
sayısının 2,23 katı. Hızın 416,67'yi aşması satıcı panelinin beş isteğindendir; gövdenin
büyümesi ise birleşik gövdenin herkese gitmesindendir. Ön yüz için backend yerleşiminde hız
416,67'ye, gövde 569 bayta ve çıkış 1,90 Mbit/s'ye iniyor — K01'in 1,60'ının 1,19 katı. Fark
kalıcıdır ve gereksinimden gelir: ücret bilgisi K01'in 480 baytında yoktu.

Duyarlılık iki yerleşimi ayırıyor. Mobil payı 0,60'tan 0,30'a inip fark web sayfasına geçtiğinde
tek kenarın sayıları hiç oynamıyor: 583,34 istek/s ve 3,56 Mbit/s. Ön yüz için backend'de ise
çıkış 1,90'dan 2,05 Mbit/s'ye çıkıyor. Bu, tek kenarın istemci karışımına **duyarsız** olduğunu
söylüyor — herkes aynı gövdeyi aldığı için karışım değişse de bant genişliği değişmez. Duyarsızlık
burada bir üstünlük değil: sayı, en geniş istemcinin ihtiyacına kilitlenmiştir ve mobil istemci
payı ne kadar artarsa artsın küçülmez.

#### Özet

- Ön yüz için backend, kenarı istemci türü başına ayrı bir birime böler; her birim yalnız o
  istemcinin alanlarını döndürür.
- Tek kenarda üç istemcinin 7 isteği 77 alan taşıyor ve 37'si kullanılmıyor (yüzde kırk sekiz);
  en küçük istemci en çok fazlalığı taşıyor.
- Ön yüz için backend kullanılmayan alanı 0'a, isteği 7'den 3'e, gövdeyi 1281'den 744 bayta
  indiriyor; istek düşüşünün tamamı satıcı panelinin liste isteğinden gelir.
- Ödenen sayılar: kenar birimi 1'den 3'e, servisin sunması gereken toplu uç 0'dan 2'ye çıkıyor;
  karşılığında bir alan eklendiğinde etkilenen istemci 3'ten 1'e iniyor.
- K01'e dönüş: 416,67 istek/s ve 480 bayt ile 1,60 Mbit/s olan çıkış, tek kenarda 583,34 istek/s
  ve 3,56 Mbit/s, ön yüz için backend'de 416,67 istek/s ve 1,90 Mbit/s oluyor.
- T2 duyarlılığı iki yerleşimi ayırıyor: mobil payı yarıya indiğinde tek kenar 3,56 Mbit/s'de
  sabit kalıyor, ön yüz için backend 1,90'dan 2,05'e çıkıyor — tek kenarın sayısı en geniş
  istemciye kilitlidir.

#### Sonraki Adım

Buraya kadarki dört ders kenarı bir bileşen olarak ele aldı ve her kararı o bileşenin içine
yazdı: yönlendirme, toplama, boşaltılan denetimler, istemciye özel gövde. Bu dersin ödediği
sayılardan biri bu yaklaşımın sınırını gösteriyor — kenar birimi sayısı arttıkça aynı ortak
kod her birimde tekrarlanıyor. Ortak kodu paylaşmanın bir yolu onu kitaplık olarak gömmektir,
ama o zaman sürümü değiştiğinde bütün birimler yeniden yayınlanır. Sonraki ders başka bir
yolu ele alır: ortak işi aynı dağıtım biriminde koşan ayrı bir sürece vermek. Elçi ve yan
araba kalıpları bu yerleşimi tanımlar ve ölçülen şey yeniden yayınlanan birim sayısı ile
dağıtım birimi başına süreç sayısı olur.

### Elçi ve Yan Araba Kalıpları

Source: https://academia.sh/tr/kurslar/trafik-katmani/elci-ve-yan-araba-kaliplari

Ortak işin ayrı bir yardımcı sürece verilmesi: elçinin dış sözleşmeyi servis kodundan ayırdığının iki taşıyıcı sürümüyle ölçülmesi, yan arabanın çalışma zamanı bağımsızlığı ile yeniden yayınlanan birim sayısına etkisi ve süreç sayısının ödettiği yerel durak.

Önceki ders kenar birimi sayısını 1'den 3'e çıkardı ve bir sorun bıraktı: aynı ortak kod her
birimde tekrarlanıyor. Ortak kodu paylaşmanın bilinen yolu onu bir kitaplığa almaktır, ama
kitaplık iki şey dayatır — her birim aynı çalışma zamanında olmalı ve kitaplığın sürümü
değiştiğinde her birim yeniden yapılıp yayınlanmalıdır.

Başka bir yol, ortak işi **ayrı bir sürece** vermektir. **Yan araba** (sidecar), ana süreçle
aynı dağıtım biriminde koşan ve onun ortak işlerini üstlenen yardımcı süreçtir. **Elçi**
(ambassador), aynı yerleşimin giden çağrılara uygulanmış hâlidir: servis yerel bir adrese
çağrı yapar, elçi dış hedefi bulur ve dış sözleşmeye çevirir. İkisi de kalıp olarak yeni
değildir — Alan Odaklı Tasarım kursundaki bağlantı noktaları ve bağdaştırıcılar dersi aynı
ayrımı kod düzeyinde kurmuştu. Burada ele alınan şey kalıbın kendisi değil, **dağıtım birimi
düzeyindeki** karşılığı ve o karşılığın ödettiği sayılar.

#### Elçi: Dış Sözleşmenin Servis Kodundan Ayrılması

Teslimat operasyonu bağlamı gönderi durumunu dış bir taşıyıcıdan alır. Taşıyıcı aynı bilgiyi
iki ayrı sözleşmeyle sunuyor; düzenek ikisini de gerçek bir süreç olarak koşturur.

```js
// elci/tasiyici.mjs — dis tasiyici servisi 8481: ayni bilgiyi iki ayri sozlesmeyle sunar
import { createServer } from "node:http";

const KAYIT = { "TR-4821": { kod: "OFD", bolge: "35", zaman: "2026-03-11T08:24:00Z" } };

createServer((istek, yanit) => {
  const [surum, , kuyruk] = istek.url.split("/").filter(Boolean);
  const no = surum === "v1" ? new URL(istek.url, "http://y").searchParams.get("no") : kuyruk;
  const k = KAYIT[no];
  const govde = !k ? { error: "not_found" }
    : surum === "v1" ? { code: k.kod, zone: k.bolge, ts: Date.parse(k.zaman) / 1000 }
      : { state: "out_for_delivery", region: { code: k.bolge }, updatedAt: k.zaman };
  yanit.writeHead(k ? 200 : 404, { "Content-Type": "application/json" });
  yanit.end(JSON.stringify(govde));
}).listen(8481, "127.0.0.1", () => console.log("tasiyici 127.0.0.1:8481"));
```

Elçi ayrı bir süreçtir ve hangi sözleşmeye konuşacağını başlatma argümanından alır. Yaptığı
iş üç parçadır: dış yolu kurmak, dış gövdeyi iç biçime çevirmek ve dış çağrıyı ölçmek.

```js
// elci/elci.mjs — elci sureci: yerel adresi dis sozlesmeye cevirir. Kullanim: node elci/elci.mjs v1 8480
import { createServer } from "node:http";

const [surum, port] = [process.argv[2], Number(process.argv[3])];
const DURUM_ADI = { OFD: "dagitimda", out_for_delivery: "dagitimda" };
let son = { yol: "-", bayt: 0 };                   // en son dis cagrinin yolu ve govde bayti

const disYol = (no) => (surum === "v1" ? `/v1/durum?no=${no}` : `/v2/status/${no}`);
const cevir = (d) => (surum === "v1"
  ? { durum: DURUM_ADI[d.code], bolge: d.zone, guncellenme: new Date(d.ts * 1000).toISOString() }
  : { durum: DURUM_ADI[d.state], bolge: d.region.code,
    guncellenme: new Date(d.updatedAt).toISOString() });

createServer(async (istek, yanit) => {
  const [kok, no] = istek.url.split("/").filter(Boolean);
  if (kok === "sayac") {
    yanit.writeHead(200, { "Content-Type": "application/json" });
    return yanit.end(JSON.stringify({ surum, ...son }));
  }
  const yol = disYol(no);
  const y = await fetch(`http://127.0.0.1:8481${yol}`);
  const metin = await y.text();
  son = { yol, bayt: Buffer.byteLength(metin) };
  const govde = y.ok ? cevir(JSON.parse(metin)) : { hata: "bulunamadi" };
  yanit.writeHead(y.ok ? 200 : 404, { "Content-Type": "application/json" });
  yanit.end(JSON.stringify({ takipNo: no, ...govde }));
}).listen(port, "127.0.0.1", () => console.log(`elci-${surum} 127.0.0.1:${port}`));
```

Ölçüm betiği servis kodunun yerine geçer: iki elçiye de aynı yerel adresi, aynı yolu ve aynı
isteği verir. Servis kodunun tamamı tek satırdır ve içinde dış adres, dış yol ya da dış alan
adı geçmez.

```js
// elci/olc.mjs — servis kodu iki elciye ayni istegi yapar; disa cikan sozlesme farkli
const al = async (url) => {
  const y = await fetch(url);
  const metin = await y.text();
  return { bayt: Buffer.byteLength(metin), metin };
};

// Servis kodunun tamami: yerel bir adrese sabit bir yol ile istek yapar.
const servisIstegi = (elciPort) => `http://127.0.0.1:${elciPort}/durum/TR-4821`;

const YERLESIM = [["v1", 8480], ["v2", 8489]];
const sonuc = [];
for (const [surum, port] of YERLESIM) {
  const yanit = await al(servisIstegi(port));
  const sayac = JSON.parse((await al(`http://127.0.0.1:${port}/sayac`)).metin);
  sonuc.push({ surum, istek: "/durum/TR-4821", yanitBayt: yanit.bayt, yanit: yanit.metin,
    disYol: sayac.yol, disBayt: sayac.bayt });
}

console.log(`${"elci".padEnd(6)}${"servis istegi".padEnd(17)}${"yanit B".padStart(8)}` +
  `${"dis bayt".padStart(10)}  dis yol`);
for (const s of sonuc) {
  console.log(`${s.surum.padEnd(6)}${s.istek.padEnd(17)}${String(s.yanitBayt).padStart(8)}` +
    `${String(s.disBayt).padStart(10)}  ${s.disYol}`);
}
const ayni = new Set(sonuc.map((s) => s.yanit));
console.log(`\nservise donen govde (v1): ${sonuc[0].yanit}`);
console.log(`servise donen govde (v2): ${sonuc[1].yanit}`);
console.log(`servisin gordugu sozlesme = ${ayni.size}, dis sozlesme = ${sonuc.length}`);
console.log(`servis kodunda dis adres = 0, dis sozlesme degisince duzenlenen servis dosyasi = 0`);
```

```bash
node elci/tasiyici.mjs & t=$!
curl -s --retry 20 --retry-connrefused --retry-delay 0 -o /dev/null http://127.0.0.1:8481/v1/durum?no=TR-4821
node elci/elci.mjs v1 8480 & a=$!
curl -s --retry 20 --retry-connrefused --retry-delay 0 -o /dev/null http://127.0.0.1:8480/sayac
node elci/elci.mjs v2 8489 & b=$!
curl -s --retry 20 --retry-connrefused --retry-delay 0 -o /dev/null http://127.0.0.1:8489/sayac
node elci/olc.mjs
kill $t $a $b
```

```
tasiyici 127.0.0.1:8481
elci-v1 127.0.0.1:8480
elci-v2 127.0.0.1:8489
elci  servis istegi     yanit B  dis bayt  dis yol
v1    /durum/TR-4821         95        42  /v1/durum?no=TR-4821
v2    /durum/TR-4821         95        86  /v2/status/TR-4821

servise donen govde (v1): {"takipNo":"TR-4821","durum":"dagitimda","bolge":"35","guncellenme":"2026-03-11T08:24:00.000Z"}
servise donen govde (v2): {"takipNo":"TR-4821","durum":"dagitimda","bolge":"35","guncellenme":"2026-03-11T08:24:00.000Z"}
servisin gordugu sozlesme = 1, dis sozlesme = 2
servis kodunda dis adres = 0, dis sozlesme degisince duzenlenen servis dosyasi = 0
```

Ölçümün taşıdığı sayı son satırlardadır: dış sözleşme 2, servisin gördüğü sözleşme 1. İki
elçiye giden istek de aynı yola gitti ve iki elçiden dönen gövde birebir aynı 95 bayt. Dış
tarafta ise yollar da baytlar da farklı: `v1` çağrısı 42 bayt, `v2` çağrısı 86 bayt taşıyor,
yani aynı üç bilgi için ikinci sözleşme 2,05 kat gövde kullanıyor.

Sayaç bir denetim aracı olarak da işe yarıyor. Çevirinin eksik kalması, örneğin zaman
damgasının bir sözleşmede olduğu gibi bırakılması, `servisin gordugu sozlesme` sayısını 1
yerine 2 yapardı. Elçinin işi "isteği iletmek" değil, iç sözleşmeyi **tek** tutmaktır ve bu
sayı onun ölçüsüdür.

#### Yan Araba: Ortak Yeteneğin Dağıtım Birimine Bağlanması

İkinci ölçüm süreç içi bir modeldir: gerçek dağıtım aracı, kapsayıcı ya da yayınlama yoktur.
Model bu kursta oluşan altı dağıtım birimini sayar — üç servis (takip, olay, ücret) ve önceki
dersin eklediği üç kenar birimi — ve ikisinin iki ayrı çalışma zamanında olduğunu varsayar.

```js
// elci/birim.mjs — ortak yetenegin iki yerlesimi; dagitim birimi duzeyinde surec ici model
const BIRIM = {                                  // bu kursta olusan alti dagitim birimi
  takip: "A", olay: "A", ucret: "B",             // A ve B: iki ayri calisma zamani
  "kenar-mobil": "A", "kenar-web": "A", "kenar-panel": "B",
};
const YERLESIM = {
  "kitaplik": { ayriSurec: false, calismaZamani: ["A"] },
  "yan araba": { ayriSurec: true, calismaZamani: ["A", "B"] },
};

const olc = (y) => {
  const birim = Object.entries(BIRIM);
  const kullanabilen = birim.filter(([, z]) => y.calismaZamani.includes(z)).length;
  return {
    "ortak yetenegi kullanabilen birim": `${kullanabilen}/${birim.length}`,
    "surum degisince yeniden yapilan birim": y.ayriSurec ? 1 : kullanabilen,
    "yeniden yayinlanan servis kodu": y.ayriSurec ? 0 : kullanabilen,
    "dagitim birimi basina surec": y.ayriSurec ? 2 : 1,
    "toplam surec": birim.length * (y.ayriSurec ? 2 : 1),
    "kenar birimindeki yerel durak": y.ayriSurec ? 2 : 1,
  };
};

const ALAN = Object.keys(olc(YERLESIM["yan araba"]));
const olcum = Object.entries(YERLESIM).map(([ad, y]) => ({ ad, ...olc(y) }));
console.log(`dagitim birimi = ${Object.keys(BIRIM).length} ` +
  `(calisma zamani A: ${Object.values(BIRIM).filter((z) => z === "A").length}, ` +
  `B: ${Object.values(BIRIM).filter((z) => z === "B").length})`);
console.log(`${"olcu".padEnd(38)}${olcum.map((o) => o.ad.padStart(12)).join("")}`);
for (const a of ALAN) console.log(`${a.padEnd(38)}${olcum.map((o) => String(o[a]).padStart(12)).join("")}`);

// K01 Kabaca Buyukluk Hesabi: uctaki tepe 513.89 istek/s (hesap sinifi)
const UC_TEPE = 513.89;
console.log("");
for (const o of olcum) {
  const durak = 1 + o["kenar birimindeki yerel durak"];      // ag gecidi duragi + kenar duraklari
  console.log(`${o.ad.padEnd(10)} durak ${durak} -> durak-istek/s = ${(UC_TEPE * durak).toFixed(2)}`);
}
```

```
dagitim birimi = 6 (calisma zamani A: 4, B: 2)
olcu                                      kitaplik   yan araba
ortak yetenegi kullanabilen birim              4/6         6/6
surum degisince yeniden yapilan birim            4           1
yeniden yayinlanan servis kodu                   4           0
dagitim birimi basina surec                      1           2
toplam surec                                     6          12
kenar birimindeki yerel durak                    1           2

kitaplik   durak 2 -> durak-istek/s = 1027.78
yan araba  durak 3 -> durak-istek/s = 1541.67
```

#### Sayıların Okunması

İlk satır kitaplık yerleşiminin sessiz kısıtını gösteriyor: ortak yeteneği altı birimin
yalnız dördü kullanabiliyor, çünkü ikisi başka bir çalışma zamanında. Bu birimler ya yeteneği
kendileri yeniden yazar ya da onsuz kalır; iki durumda da "ortak yetenek" sıfatı yanlıştır.
Yan araba yerleşiminde sayı 6/6 olur, çünkü iki süreç arasındaki bağ bir işlev çağrısı değil
bir yerel çağrıdır.

İkinci ve üçüncü satırlar yayınlama maliyetini ayırıyor. Ortak yeteneğin sürümü
değiştiğinde kitaplık yerleşiminde dört birim yeniden yapılıp yayınlanır ve dört servis kodu
yeniden yayınlanmış olur. Yan araba yerleşiminde yeniden yapılan birim 1, yeniden yayınlanan
servis kodu 0'dır: servislerin yapıtı değişmez. Bu, önceki derslerin "tekrarlanan satır"
ölçüsünün dağıtım düzeyindeki karşılığıdır — orada aynı kodun kaç dosyada durduğu, burada aynı
değişikliğin kaç yapıtı yenilettiği sayılıyor.

Son üç satır bedeli veriyor ve bedel ucuz değil. Dağıtım birimi başına süreç 1'den 2'ye,
toplam süreç 6'dan 12'ye çıkıyor. Her kenar birimi içinde bir yerel durak daha oluşuyor ve
bu, ilk dersin `durak-istek/s` ölçüsünü büyütüyor.

#### Hesaba Dönüş

İlk ders K01'in uçtaki tepe hızını (513,89 istek/s) alıp ağ geçidiyle birlikte her isteğin iki
durağa dokunduğunu ve durak-istek hızının 1027,78'e çıktığını hesaplamıştı. Yan araba üçüncü
durağı ekliyor: 513,89 × 3 = 1541,67 durak-istek/s. Sayı K01'in hiçbir varsayımını değiştirmiyor
— günlük sorgu, gövde boyutu ve tepe çarpanı aynı kalıyor — ama aynı istek hızının sistemde kaç
yerde işlendiğini üç katına çıkarıyor.

Bu, süre ölçüsü değildir; bu makinede ölçülmüş bir gecikme yoktur ve yazılmaz. Söylediği şey
şudur: bir yardımcı süreç kararı, hiçbir varsayımı değiştirmeden K01'in tepe hızını sistemin
üç ayrı yerinde birden görünür kılar. Kararın savunması bu yüzden "ilgileri ayırıyor"
cümlesiyle yazılamaz; yanına 6/6, 1, 0, 12 ve 1541,67 sayıları yazılır.

#### Özet

- Yan araba ana süreçle aynı dağıtım biriminde koşan yardımcı süreçtir; elçi aynı yerleşimin
  giden çağrılara uygulanmış hâlidir ve dış hedefi ile dış sözleşmeyi üstlenir.
- Elçi ölçümünde dış sözleşme 2, servisin gördüğü sözleşme 1 çıktı: iki elçi de aynı 95 baytlık
  gövdeyi döndürdü, dışarıda 42 ve 86 bayt taşındı.
- Servis kodunda dış adres 0 ve dış sözleşme değiştiğinde düzenlenen servis dosyası 0; eksik
  bir çeviri `servisin gordugu sozlesme` sayısını 1'den 2'ye çıkararak kendini belli eder.
- Kitaplık yerleşiminde ortak yeteneği altı birimin dördü kullanabiliyor ve sürüm değiştiğinde
  dört servis kodu yeniden yayınlanıyor; yan arabada 6/6 kullanabiliyor, yeniden yapılan birim 1,
  yeniden yayınlanan servis kodu 0.
- Ödenen sayılar: dağıtım birimi başına süreç 1'den 2'ye, toplam süreç 6'dan 12'ye çıkıyor.
- K01'e dönüş: uçtaki 513,89 istek/s üçüncü durakla birlikte 1541,67 durak-istek/s'ye çıkıyor;
  hiçbir varsayım değişmiyor, aynı hız üç yerde işleniyor.

#### Sonraki Adım

Beş ders boyunca kenara yerleştirilen her iş bir kazanç ve bir bedelle yazıldı, ama hepsinin
ortak bir kabulü vardı: kenara ulaşan istek işlenmeye değer bir istektir. Oysa uçtaki tepe
hızın bir bölümü hiçbir zaman yanıtlanmayacak isteklerden oluşur — eksik alanlı gövdeler,
tanınmayan yollar, sınırı aşan boyutlar, biçimsiz belirteçler. Bu istekler uygulamaya
ulaştığında uygulamanın kaynaklarını, ulaşmadan önce durdurulduğunda kenarın kaynaklarını
harcar. Son ders doğrulamayı ayrı bir katmana yalıtan kapı bekçisi kalıbını ele alır ve
geçersiz isteğin uygulamaya ulaşma oranını ölçüp K01'in uçtaki tepe hızına uygular.

### Kapı Bekçisi Kalıbı

Source: https://academia.sh/tr/kurslar/trafik-katmani/kapi-bekcisi-kalibi

Doğrulamanın ayrı bir katmana yalıtılması: kapıda verilebilen denetimlerle uygulamada kalması gerekenlerin ayrılması, geçersiz isteğin uygulamaya ulaşma oranının ve taşıdığı baytın ölçülmesi, güvenilmeyen girdiye dokunan birim sayısının düşürülmesi ve sonucun K01'in uçtaki tepe hızına uygulanması.

Beş ders boyunca kenara yerleştirilen her iş bir kazanç ve bir bedelle yazıldı, ama hepsinin
ortak bir kabulü vardı: kenara ulaşan istek işlenmeye değer bir istektir. Uçtaki tepe hızın bir
bölümü ise hiçbir zaman yanıtlanmayacak isteklerden oluşur — tanınmayan yollar, zorunlu alanı
eksik gövdeler, sınırı aşan boyutlar, biçimsiz belirteçler.

**Kapı bekçisi** (gatekeeper), doğrulamayı ayrı bir katmana yalıtan yerleşimdir: güvenilmeyen
girdiyi yalnız bu katman görür, uygulama yalnız doğrulanmış ve normalleştirilmiş isteği alır.
Ağ geçidinden farkı sorumluluk kapsamıdır; ağ geçidi yönlendirir, toplar ve boşaltılmış işleri
yapar, kapı bekçisi tek bir soru sorar: bu istek uygulamaya ulaşmalı mı. Bu ders o sorunun kaç
istekte "hayır" olduğunu ölçer.

#### Kapıda Verilebilen Doğrulama

Üçüncü dersin taşınabilirlik kuralı burada da geçerlidir: yalnız isteğin kendisine bakan bir
denetim kapıda verilebilir, alan verisine bakan bir denetim veremez. Model bunu iki denetim
kümesiyle ayırır ve altmış istekten oluşan belirlenimli bir küme üzerinde koşturur. Küme
kurgudur: altı kusur türünün her biri beşer kez geçer, çünkü ölçülmek istenen şey gerçekçi bir
hata oranı değil, **kusurların hangisinin kapıda tutulabildiğidir**.

```js
// kapi/istek.mjs — belirlenimli istek kumesi ve iki dogrulama katmani; surec ici model
export const GONDERI = { "TR-4821": { sahip: "M7" }, "TR-9007": { sahip: "M3" } };
const TEMEL = { yol: "/takip", takipNo: "TR-4821", belirtec: "b.M7.imza", govdeBayt: 120 };

// Her on ikinci istekte bir kusur; kume 60 istekten olusur, alti kusur turu beser kez gecer.
export function kume(n = 60) {
  const KUSUR = {
    6: { yol: "/yok" },                    // taninmayan yol
    7: { takipNo: undefined },             // sema: zorunlu alan eksik
    8: { govdeBayt: 9000 },                // govde boyutu asimi
    9: { belirtec: "bozuk" },              // bicimsiz belirtec
    10: { takipNo: "TR-0001" },            // kayitli olmayan gonderi
    11: { belirtec: "b.M3.imza" },         // baskasinin gonderisi
  };
  return Array.from({ length: n }, (_, i) => ({ ...TEMEL, ...(KUSUR[i % 12] ?? {}) }));
}

// Kapi bekcisi: yalnizca istegin kendisine bakar (yol, sema, boyut, belirtec bicimi).
export const KAPI = {
  yol: (r) => r.yol === "/takip",
  sema: (r) => typeof r.takipNo === "string" && /^TR-\d{4}$/.test(r.takipNo),
  boyut: (r) => r.govdeBayt <= 2048,
  belirtec: (r) => /^b\.M\d+\.imza$/.test(r.belirtec),
};

// Uygulama: alan verisine bakan iki dogrulama; kapida verilemez.
export const UYGULAMA = {
  varlik: (r) => GONDERI[r.takipNo] !== undefined,
  yetki: (r) => GONDERI[r.takipNo]?.sahip === r.belirtec.split(".")[1],
};

export const gecer = (denetimler, r) => Object.values(denetimler).every((d) => d(r));
```

Belirteç doğrulama Kimlik Doğrulama ve Yetkilendirme kursunda kuruldu; buradaki `belirtec`
denetimi imzayı sınamaz, yalnız biçimi sınar — kapıda verilebilecek olan budur.

```js
// kapi/olc.mjs — kapi bekcisi olan ve olmayan yerlesimi olcer, sonra K01 hesabina baglar
import { kume, KAPI, UYGULAMA, gecer } from "./istek.mjs";

const istekler = kume();
const gecersiz = istekler.filter((r) => !(gecer(KAPI, r) && gecer(UYGULAMA, r)));
const kapidaTutulan = gecersiz.filter((r) => !gecer(KAPI, r));

const bayt = (liste) => liste.reduce((t, r) => t + r.govdeBayt, 0);
const ulasan = (kapiVar) => (kapiVar ? istekler.filter((r) => gecer(KAPI, r)) : istekler);

const ALAN = ["uygulamaya ulasan istek", "uygulamaya ulasan gecersiz istek",
  "uygulamaya ulasan govde bayti", "guvenilmeyen girdiye dokunan birim",
  "uygulamanin disa acik adresi", "dogrulama kodu tasiyan birim"];
const olc = (kapiVar) => {
  const u = ulasan(kapiVar);
  return {
    "uygulamaya ulasan istek": `${u.length}/${istekler.length}`,
    "uygulamaya ulasan gecersiz istek": u.filter((r) => !gecer(UYGULAMA, r) || !gecer(KAPI, r)).length,
    "uygulamaya ulasan govde bayti": bayt(u),
    "guvenilmeyen girdiye dokunan birim": kapiVar ? 1 : 3,
    "uygulamanin disa acik adresi": kapiVar ? 0 : 1,
    "dogrulama kodu tasiyan birim": kapiVar ? 1 + 3 : 3,
  };
};

const olcum = [["kapi yok", olc(false)], ["kapi bekcisi", olc(true)]];
console.log(`${"olcu".padEnd(36)}${olcum.map(([a]) => a.padStart(14)).join("")}`);
for (const a of ALAN) console.log(`${a.padEnd(36)}${olcum.map(([, o]) => String(o[a]).padStart(14)).join("")}`);

const oran = kapidaTutulan.length / gecersiz.length;
console.log(`\ngecersiz istek = ${gecersiz.length}/${istekler.length}, ` +
  `kapida tutulan = ${kapidaTutulan.length}, kapida tutulamayan = ${gecersiz.length - kapidaTutulan.length}`);
console.log(`kapinin tuttugu gecersiz orani = ${oran.toFixed(3)} (${Object.keys(KAPI).length} kapi ` +
  `denetimi, ${Object.keys(UYGULAMA).length} uygulama denetimi)`);

// K01 Kabaca Buyukluk Hesabi: uctaki tepe 513.89, tepe okuma 416.67 istek/s (hesap sinifi)
const UC_TEPE = 513.89, OKUMA_TEPE = 416.67, ONBELLEK_ARKASI = 41.67;
console.log(`\n${"T3".padEnd(6)}${"kapinin arkasina istek/s".padStart(25)}${"okuma/s".padStart(11)}` +
  `${"onbellek arkasi/s".padStart(19)}`);
for (const T3 of [0.08, 0.16]) {                       // T3: uctaki isteklerin gecersiz orani
  const kalan = 1 - T3 * oran;
  console.log(`${T3.toFixed(2).padEnd(6)}${(UC_TEPE * kalan).toFixed(2).padStart(25)}` +
    `${(OKUMA_TEPE * kalan).toFixed(2).padStart(11)}${(ONBELLEK_ARKASI * kalan).toFixed(2).padStart(19)}`);
}
console.log(`kapi yok (T3 = 0.08 icin bile) -> ${UC_TEPE.toFixed(2)} istek/s, ` +
  `${OKUMA_TEPE.toFixed(2)} okuma/s, ${ONBELLEK_ARKASI.toFixed(2)} onbellek arkasi/s`);
```

```
olcu                                      kapi yok  kapi bekcisi
uygulamaya ulasan istek                      60/60         40/60
uygulamaya ulasan gecersiz istek                30            10
uygulamaya ulasan govde bayti                51600          4800
guvenilmeyen girdiye dokunan birim               3             1
uygulamanin disa acik adresi                     1             0
dogrulama kodu tasiyan birim                     3             4

gecersiz istek = 30/60, kapida tutulan = 20, kapida tutulamayan = 10
kapinin tuttugu gecersiz orani = 0.667 (4 kapi denetimi, 2 uygulama denetimi)

T3     kapinin arkasina istek/s    okuma/s  onbellek arkasi/s
0.08                     486.48     394.45              39.45
0.16                     459.08     372.23              37.23
kapi yok (T3 = 0.08 icin bile) -> 513.89 istek/s, 416.67 okuma/s, 41.67 onbellek arkasi/s
```

#### Sayıların Okunması

Otuz geçersiz isteğin yirmisi kapıda tutuluyor, onu tutulamıyor: oran 0,667. Tutulamayanlar
kayıtlı olmayan gönderiyi soran ve başkasının gönderisini isteyen isteklerdir; ikisi de gönderi
kaydını okumadan ayırt edilemez. Kapı bekçisi bu yüzden doğrulamayı **kaldırmaz**, ikiye böler
ve `dogrulama kodu tasiyan birim` sayısı 3'ten 4'e çıkar. Kalıbın adı yanıltıcı olabilir: kapı,
uygulamanın kendi doğrulamasının yerine geçmez.

Bayt satırı en büyük farkı veriyor: uygulamaya ulaşan gövde 51.600 bayttan 4.800 bayta iniyor,
0,093 katına. Düşüşün neredeyse tamamı boyutu aşan beş istekten geliyor. Uygulamaya ulaşmayan
istek yalnız bir işlem tasarrufu değil, ayrıştırılmayan bir gövdedir.

Son iki satır kalıbın asıl amacını taşıyor. `guvenilmeyen girdiye dokunan birim` 3'ten 1'e,
`uygulamanin disa acik adresi` 1'den 0'a iniyor. Ham gövdeyi ayrıştıran, biçimini sınayan ve
sınırı aşanı reddeden kod tek bir birimde toplanır; uygulama birimleri yalnız kapıdan geçmiş,
biçimi bilinen bir istek görür. Bu, üçüncü dersteki güven sınırı sorusunun aynısıdır ve aynı
bedeli taşır: kapı atlanabiliyorsa 0/3 koruma varsayımı çöker.

#### Hesaba Dönüş

Modelin geçersiz oranı (30/60) gerçekçi değildir ve öyle sunulmaz. Gerçek oran **bu kursun
varsayımıdır** (T3 = 0,08: uçtaki isteklerin yüzde sekizi biçimsel olarak geçersizdir).
Gerekçesi eski istemci sürümlerinin, süresi dolmuş belirteçlerin ve tarayıcı yeniden
denemelerinin sürekli bir taban üretmesidir; K01'in tablosuna eklenmez, çünkü K01 yalnız
yanıtlanan isteği sayıyordu. Modelden gelen 0,667 ise varsayım değil, denetim listelerinden
çıkan bir orandır.

İkisi birleştiğinde K01'in üç sayısı birden oynuyor. Uçtaki tepe 513,89 istek/s, kapının
arkasına 486,48 istek/s olarak geçiyor; tepe okuma 416,67'den 394,45'e, `onbellek arkasi
okuma/s` 41,67'den 39,45'e iniyor. Kapı yokken üçü de değişmiyor. T3 iki katına çıktığında —
yüzde on altı geçersiz — sayılar 459,08, 372,23 ve 37,23 oluyor: kazanç T3 ile doğru orantılı
büyüyor, çünkü kapının tuttuğu pay sabit.

Sayıların büyüklüğü de okunmalı: yüzde sekiz geçersizin üçte ikisi tutulduğunda uçtaki hız
yalnız 0,947 katına iniyor. Kapı bekçisi bir ölçekleme aracı değildir; kazandırdığı asıl sayı
üstteki tablodadır — güvenilmeyen girdiye dokunan birim ve uygulamanın dışa açık adresi.

#### Özet

- Kapı bekçisi doğrulamayı ayrı bir katmana yalıtır: güvenilmeyen girdiyi yalnız o katman görür,
  uygulama doğrulanmış isteği alır.
- Kapıda verilebilen denetim isteğin kendisine bakandır; altmış istekli kümede otuz geçersizin
  yirmisi kapıda tutuldu, onu tutulamadı (oran 0,667).
- Doğrulama kaldırılmaz, bölünür: doğrulama kodu taşıyan birim 3'ten 4'e çıkıyor.
- Uygulamaya ulaşan istek 60/60'tan 40/60'a, gövde 51.600 bayttan 4.800 bayta (0,093 katına)
  iniyor; düşüşün neredeyse tamamı boyutu aşan isteklerden gelir.
- Kalıbın asıl kazancı yalıtımdır: güvenilmeyen girdiye dokunan birim 3'ten 1'e, uygulamanın
  dışa açık adresi 1'den 0'a iniyor.
- K01'e dönüş (T3 = 0,08 varsayımıyla): uçtaki 513,89 istek/s kapının arkasında 486,48'e, tepe
  okuma 416,67'den 394,45'e, önbellek arkası okuma 41,67'den 39,45'e iniyor; T3 = 0,16'da
  sırasıyla 459,08, 372,23 ve 37,23.

#### Kurs Kapanışı

Kurs, isteğin kullanıcıdan uygulamaya kadarki yolunu durak durak tasarladı ve her durakta aynı
üç soruyu sordu: bu durak hangi kararı veriyor, giriş kursunun hesabındaki hangi sayıyı
oynatıyor, karşılığında hangi sayı büyüyor. Derslerin bıraktığı ölçüler aşağıdaki tabloda
toplanıyor.

| Ders | Durağın kararı | Oynadığı K01 sayısı | Karşılığında büyüyen |
|---|---|---|---|
| Alan Adı Sistemi Tasarımı | yönlendirme politikası | gecikmeye göre 1,171 mesafe birimi (coğrafi 1,710, ağırlıklı 2,144) | devralma penceresi 39–905 sn, aylık kesinti bütçesinin %0,50–%14,28'i |
| İçerik Dağıtım Ağları | önbelleğin konumu | uygulamaya ulaşan okuma 416,67 → 41,76 istek/s | 480 baytlık gövde telde 653 bayt (1,360); depoya ulaşan istek 138,89'da kaldı |
| İtme ve Çekme Tabanlı Dağıtım | içeriğin yayma modeli | çekmede kökene 42,34 istek/s — K01'in 41,67'si korunuyor | itmede tepe 1.166,64 itme/s, 4,48 Mbit/s ve kenarlarda 6,91 GB |
| Statik İçerik Barındırma | içerik yolunun ayrılması | uygulama süreci 3.291,67 → 513,89 istek/s, 241,60 → 1,60 Mbit/s | 2.777,78 istek/s ve 240,00 Mbit/s içerik sürecine geçti |
| Yük Dengeleyici Rolü | dağıtım + sağlık denetimi | 513,89 istek/s en az 3 kopya; arıza başına düşen istek 102.778 → 34,26 | denetimin kendi yükü 15 istek/s, uçtaki yükün %2,9'u |
| Katman 4 Dengeleme | bağlantı düzeyinde dağıtım | karar 51,39 karar/s (63 istek için 6) | istek sapması 4,00; hedefi tutmak 3 yerine 5 kopya |
| Katman 7 Dengeleme | içerik farkındalıklı yönlendirme | istek sapması 4,00 → 1,07, akışlar ayrı havuzlarda | karar 51,39 → 513,89 karar/s; 3 yerine 4 kopya |
| Dengeleme Algoritmaları | dağıtım algoritması | yer değiştiren anahtar %74,85 → %26,48 | ısınmada depoya ulaşan 138,89 → 238,18 istek/s (bölme kalanıyla 419,57) |
| Yük Dengeleyici ve Ters Vekil | rollerin ayrılması | kopya listesi düştüğünde içerik yolu 6/6 yanıtlandı | durak 2 → 3; tek kopyalı duraklarla aylık kesinti 215,6 → 258,6 dk |
| Oturum Yapışkanlığı | durumun kopyaya bağlanması | 0,50 doluluk hedefi için gereken kopya 3 → 4 | dengesizlik 1,000 → 1,173; bir kopya düşünce oturumların 33/100'ü ve isteklerin %39,11'i kayboluyor |
| API Ağ Geçidi | kenar sorumluluklarının yeri | tekrarlanan satır 135 → 45, sorumluluk başına birim 3 → 1 | uçtaki 513,89 istek/s tek bileşende; durak-istek/s 513,89 → 1027,78; geçit durunca 0/3 |
| Ağ Geçidi Yönlendirme ve Toplama | tek istekte çoklu çağrı | uçtaki istek 833,34 → 416,67 istek/s (×0,50) | gövde 405 → 764 bayt; çıkış 1,60 → 2,55 Mbit/s |
| Ağ Geçidi Yük Boşaltma | denetimin kenara taşınması | satır 171 → 107; 4/6 denetim kenarda, 513,89 istek/s'de koşuyor | korumasız servis 0/3 → 3/3, ya da doğrulama 513,89 → 1027,78 kez/s |
| Ön Yüz İçin Backend | istemciye özel gövde | kullanılmayan alan 37 → 0; 583,34 → 416,67 istek/s, 3,56 → 1,90 Mbit/s | kenar birimi 1 → 3; servisin sunması gereken toplu uç 0 → 2 |
| Elçi ve Yan Araba Kalıpları | ortak işin ayrı sürece verilmesi | servisin gördüğü sözleşme 1 (dış 2); kullanabilen birim 4/6 → 6/6 | toplam süreç 6 → 12; durak-istek/s 1027,78 → 1541,67 |
| Kapı Bekçisi Kalıbı | doğrulamanın yalıtılması | kapının arkasına 513,89 → 486,48 istek/s; okuma 416,67 → 394,45 | doğrulama kodu taşıyan birim 3 → 4; kapıda tutulamayan geçersiz 10/30 |

Tablonun kuralı adıyla anılmalı: **her durak, giriş kursunun varsayım tablosundan çıkan
hesaplara geri bağlandı.** Kenarda alınan bir kararın ölçüsü üç sayıdan biridir — uygulamaya
ulaşan istek, sınırdan geçen bayt ve bir birim düştüğünde yanıtlanan istek oranı. Bu üçünden
birine bağlanmayan bir kenar kararı, savunulabilir bir karar değildir; sağ kolonun hiçbir satırda
boş olmaması da bunun öteki yarısıdır. Kursun eklediği üç varsayım (takip sayfasının ücreti de
istemesi, istemci karışımı, geçersiz istek oranı) K01'in tablosuna karışmadı; kendi adlarıyla,
gerekçeleriyle ve duyarlılıklarıyla yazıldı.

Kursun bıraktığı soru bir katman ileridedir. İstek artık uygulamaya ulaştı: adı çözüldü, kenar
önbelleğinden geçti, bir kopyaya düştü, ağ geçidinden ve kapıdan geçti. Ama uygulamanın kendi
içindeki servis etkileşimi tasarlanmadı — servislerin durumsuz olup olmadığı, birbirlerinin
adresini nasıl buldukları, bir çağrı yanıt vermediğinde ne kadar bekleyip kaç kez deneyecekleri
ve birden çok servise yayılan bir iş akışının koreografiyle mi orkestrasyonla mı kurulacağı.
Bu kursun ağ geçidi, iki servisi paralel çağırıp yanıtlarını birleştirirken bu soruların
hepsine sessizce bir yanıt varsaydı. Sonraki kurs **Uygulama Katmanı ve Servis Etkileşimi** o
varsayımları açar.

