---
title: 'İçerik Dağıtım Ağları'
source: 'https://academia.sh/tr/kurslar/trafik-katmani/icerik-dagitim-aglari'
course: 'Trafik Katmanı'
language: tr
updated: '2026-08-17T18:11:02+00:00'
license: 'CC BY-SA 4.0'
---

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

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.
