---
title: 'Önbellek Yerleşimi'
source: 'https://academia.sh/tr/kurslar/veri-olcekleme/onbellek-yerlesimi'
course: 'Veri Katmanı Ölçekleme'
language: tr
updated: '2026-08-17T18:11:01+00:00'
license: 'CC BY-SA 4.0'
---

# Önbellek Yerleşimi

Kopyanın hangi katmanda duracağının bir tasarım kararı olarak ele alınması: istemci, kenar, web, uygulama ve veritabanı katmanlarının kapsam ve kapasiteyle ayrılması, dört katmanlı bir zincirin katman başına isabetinin ve ıskalama cezasının ölçülmesi, giriş kursundaki 0,90 önbellek isabeti varsayımının tasarımın sonucu hâline getirilmesi ve tek bir doğru boyutlu önbelleğin aynı oranı daha az dokunuşla verdiğinin gösterilmesi.

Önceki konu verinin nerede ve hangi biçimde durduğunu tasarladı: depo türü erişim örüntüsüne
göre seçildi, veri çoğaltıldı, parçalandı ve okuma yolu denormalizasyonla kısaltıldı. Bütün
bunların sonunda okuma yolu gerçekten kısaldı, ama bir şey değişmedi: her okuma hâlâ bir depoya
gidiyor. Sıradaki soru okumanın deponun **önünde** karşılanmasıdır ve ilki şudur: kopya hangi
katmanda durmalı.

Bu ders o soruyu bir yerleşim kararına çevirir. Önbellekleme, Kuyruklar ve Eşzamansız İşleme
kursu önbellek katmanlarını, stratejileri ve geçersizleştirmeyi kurdu ve ölçtü; burada hiçbiri
yeniden anlatılmaz. Değişen şey ölçeğin kendisidir. Sistem Tasarımına Giriş kursunun kabaca
büyüklük hesabında önbellek bir strateji değil tek bir sayıydı: V9, takip sorgusunun
önbellekten karşılanma oranı, 0,90 alınmıştı ve `onbellek arkasi okuma/s` satırını 41,67'ye,
`depoya ulasan istek/s` satırını 138,89'a indiriyordu. O sayı bir **varsayım**dı. Bu dersin işi
onu bir **sonuç** hâline getirmektir: hangi yerleşim 0,90'ı üretir, üretirken ne öder.

## Katmanı Ne Ayırır

Bir önbellek katmanını üç şey tanımlar.

**Kapsam**, aynı kopyanın kaç isteği karşılayabileceğidir. İstemci önbelleği tek bir kullanıcıya
hizmet eder; kenar önbelleği bir bölgedeki bütün kullanıcılara; web katmanındaki paylaşılan yanıt
önbelleği bütün isteklere; uygulama içindeki süreç içi önbellek yalnız kendi örneğine düşen
isteklere. Kapsam büyüdükçe bir kopyanın ısıtılması daha çok isteğe yarar.

**Kapasite**, katmanın kaç girdi tutabildiğidir. Kapasite çalışma kümesinin altındaysa katman
kendi girdilerini tahliye eder ve artığı bir sonraki katmana sızdırır.

**Geri alınabilirlik**, konan bir kopyanın kaldırılıp kaldırılamayacağıdır ve kapsamla ters
gider. Uygulama içindeki girdi kodla anında silinir. Kenar katmanındaki için ayrı bir işlem
gerekir. İstemcideki kopya için hiçbir yol yoktur: konarken verilen süre dolana kadar orada
kalır. Bu üçüncü ölçüt bu dersin sayılarında görünmez ama son bölümde kararı belirler.

Beşinci bir katman daha vardır ve ötekilerden farklıdır: **veritabanı önbelleği**, kaynağın
kendi içindedir. Bir sorgunun maliyetini düşürür, sorgu **sayısını** düşürmez; hesabın hiçbir
satırı ona bağlı değildir. Bu ayrım Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda
ölçülerek kuruldu ve burada tekrarlanmaz. Aşağıdaki modelde bu yüzden dört katman vardır.

## Zincir Modeli

Model süreç içidir: katmanlar birer nesnedir, sayaçlar açıktır, kapasite ile erişim örüntüsü
parametredir. Gerçek bir önbellek ürünü ya da bulut ortamı kurulmaz; ölçülen şey süre değil,
**sayım**dır ve bu yüzden koşumdan koşuma değişmez.

Erişim örüntüsü kursun takip sorgusudur: takip numarasına göre tekil okuma. Bir gönderinin
sorguları bir arada gelir — kullanıcı sayfayı açar, yeniler, bir süre sonra tekrar bakar. Bu
öbeklenme bu dersin varsayımıdır ve K01'in tablosuna eklenmez.

**B1 (bu dersin varsayımı): bir gönderinin sorguları 10 uzunluğunda öbekler hâlinde gelir ve
aynı anda 1000 gönderi sorgulanmaktadır.** Gerekçe: Trafik Katmanı kursunun İçerik Dağıtım
Ağları dersi aynı öbek uzunluğunu kullanmış ve kenar isabetini 0,8998 ölçmüştü; buradaki ek,
eşzamanlı gönderi sayısının bir **çalışma kümesi** tanımlaması ve kapasiteyi anlamlı
kılmasıdır. Duyarlılık: öbek 5'e inerse tekil anahtar sayısı iki katına çıkar ve bütün
katmanların isabeti düşer; çalışma kümesi 2000'e çıkarsa kapasitesi sabit kalan katmanlar
artıklarını bir sonrakine sızdırır.

```js
// onbellek/katman.mjs — katman zincirinin surec ici modeli. Katmanlar birer nesnedir,
// sayaclar aciktir. Kapasite, obek uzunlugu ve calisma kumesi model parametreleridir.
export function onbellek(kapasite) {
  const kutu = new Map();
  const o = {
    tahliye: 0,
    al(a) { const d = kutu.get(a); if (d !== undefined) { kutu.delete(a); kutu.set(a, d); } return d; },
    koy(a, d) {
      kutu.delete(a); kutu.set(a, d);
      if (kutu.size > kapasite) { kutu.delete(kutu.keys().next().value); o.tahliye += 1; }
    },
  };
  return o;
}

// Erisim oruntusu: takip numarasina gore tekil okuma. Bir gonderinin sorgulari `obek`
// uzunlugunda gelir; ayni anda `calismaKumesi` kadar gonderi sorgulanir. Sorgularin
// `sahipPayi` kadari gonderiyi baslatan kullanicidan, kalani baska bir kullanicidan gelir.
export function akis({ istek, calismaKumesi, obek, kullanici, sahipPayi = 0.7 }) {
  let tohum = 20260730;
  const rast = () => ((tohum = (tohum * 1103515245 + 12345) % 2147483648) / 2147483648);
  const yeni = (no) => ({ no, kalan: obek, sahip: Math.floor(rast() * kullanici) + 1 });
  let sonraki = 1;
  const etkin = Array.from({ length: calismaKumesi }, () => yeni(sonraki++));
  const cikti = [];
  for (let i = 0; i < istek; i++) {
    const j = Math.floor(rast() * etkin.length);
    const g = etkin[j];
    const k = rast() < sahipPayi ? g.sahip : Math.floor(rast() * kullanici) + 1;
    cikti.push([k, `takip:${g.no}`]);
    if ((g.kalan -= 1) === 0) etkin[j] = yeni(sonraki++);
  }
  return cikti;
}

// Zincir: her istek katmanlari sirayla yoklar. Iska her katmanda bir yoklama, depoda bir
// erisim, geri donuste her katmana bir yazma dokunusu sayar.
export function zincir(istekler, katmanlar) {
  const kutular = katmanlar.map(() => new Map());
  const sayac = katmanlar.map(() => ({ isabet: 0, tahliye: 0 }));
  const s = { depo: 0, dokunus: 0, iska: 0 };
  const kutuAl = (i, kullanici, anahtar) => {
    const kapsam = katmanlar[i].kapsam;
    const kimlik = kapsam === "kullanici" ? kullanici
      : kapsam === "ornek" ? (anahtar.length + Number(anahtar.slice(6))) % katmanlar[i].ornek : 0;
    let c = kutular[i].get(kimlik);
    if (c === undefined) { c = onbellek(katmanlar[i].kapasite); kutular[i].set(kimlik, c); }
    return c;
  };
  for (const [kullanici, anahtar] of istekler) {
    let bulundu = -1;
    for (let i = 0; i < katmanlar.length; i++) {
      s.dokunus += 1;
      if (kutuAl(i, kullanici, anahtar).al(anahtar) !== undefined) { bulundu = i; break; }
    }
    if (bulundu === -1) { s.depo += 1; s.iska += 1; s.dokunus += 1; }
    else sayac[bulundu].isabet += 1;
    const son = bulundu === -1 ? katmanlar.length - 1 : bulundu - 1;
    for (let i = 0; i <= son; i++) { s.dokunus += 1; kutuAl(i, kullanici, anahtar).koy(anahtar, anahtar); }
  }
  for (let i = 0; i < katmanlar.length; i++)
    for (const c of kutular[i].values()) sayac[i].tahliye += c.tahliye;
  return { sayac, ...s };
}

// M19/K01 kabaca buyukluk hesabinin girdileri (V1-V4, V8): tepe okuma ve tepe yazma.
export const K01 = {
  tepeOkuma: (2_000_000 * 6 / 86_400) * 3,
  tepeYazma: (400_000 * 7 / 86_400) * 3,
};
```

Pencere 480 saniyedir; K01'in tepe okuma hızı 416,67 istek/s olduğuna göre bu pencereye 200.000
takip sorgusu düşer. **Dokunuş**, modelin tek maliyet birimidir: bir katman yoklaması, bir depo
erişimi ya da bir geri yazma. Dokunuşlar ağırlıklandırılmaz — bir depo erişimiyle bir bellek
yoklaması aynı sayılır. Ağırlığı veren şey zaten yerleşim kararının kendisidir; sayım yalnız
kaç iş yapıldığını söyler.

## Ölçüm

```js
// onbellek/yerlesim.mjs — dort katmanli zincirin olculmesi ve K01 hesabina donus
import { akis, zincir, K01 } from "./katman.mjs";

const ISTEK = 200_000, OBEK = 10, CALISMA = 1000, KULLANICI = 40_000;
const istekler = akis({ istek: ISTEK, calismaKumesi: CALISMA, obek: OBEK, kullanici: KULLANICI });
const KATMAN = [
  { ad: "istemci", kapsam: "kullanici", kapasite: 4 },
  { ad: "kenar", kapsam: "paylasilan", kapasite: 250 },
  { ad: "web", kapsam: "paylasilan", kapasite: 600 },
  { ad: "uygulama", kapsam: "ornek", kapasite: 400, ornek: 4 },
];

const tekil = new Set(istekler.map(([, a]) => a)).size;
const r = zincir(istekler, KATMAN);
console.log(`istek ${ISTEK} (480 s pencere), tekil takip numarasi ${tekil}, obek ${OBEK}, es zamanli gonderi ${CALISMA}`);
console.log();
console.log("katman     kapsam       kapasite   isabet  isabet payi  tahliye");
console.log("---------- ----------- --------- -------- ------------ --------");
for (let i = 0; i < KATMAN.length; i++) {
  const k = KATMAN[i], c = r.sayac[i];
  const kap = k.kapsam === "ornek" ? `${k.kapasite}x${k.ornek}` : String(k.kapasite);
  console.log(`${k.ad.padEnd(10)} ${k.kapsam.padEnd(11)} ${kap.padStart(9)} ` +
    `${String(c.isabet).padStart(8)} ${(c.isabet / ISTEK).toFixed(4).padStart(12)} ${String(c.tahliye).padStart(8)}`);
}
console.log(`${"depo".padEnd(10)} ${"-".padEnd(11)} ${"-".padStart(9)} ${String(r.depo).padStart(8)} ` +
  `${(r.depo / ISTEK).toFixed(4).padStart(12)} ${"-".padStart(8)}`);

const h = 1 - r.depo / ISTEK;
const arka = K01.tepeOkuma * (1 - h);
console.log();
console.log(`birlesik isabet      = ${h.toFixed(4)}  (V9 varsayimi 0,90)`);
console.log(`bir iskanin dokunusu = ${2 * KATMAN.length + 1} (${KATMAN.length} yoklama + 1 depo + ${KATMAN.length} geri yazma)`);
console.log(`dokunus / istek      = ${(r.dokunus / ISTEK).toFixed(3)}`);
console.log();
console.log(`K01'e donus (tepe okuma ${K01.tepeOkuma.toFixed(2)}, tepe yazma ${K01.tepeYazma.toFixed(2)} istek/s)`);
console.log(`aga hic cikmayan okuma/s = ${(K01.tepeOkuma * r.sayac[0].isabet / ISTEK).toFixed(2)}`);
console.log(`uygulamaya varan okuma/s = ${(K01.tepeOkuma * (r.sayac[3].isabet + r.depo) / ISTEK).toFixed(2)}`);
console.log(`onbellek arkasi okuma/s  = ${arka.toFixed(2)}  (V9 ile 41,67)`);
console.log(`depoya ulasan istek/s    = ${(arka + K01.tepeYazma).toFixed(2)}  (V9 ile 138,89)`);
console.log(`depoda yazma/okuma orani = ${(K01.tepeYazma / arka).toFixed(2)}  (V9 ile 2,33)`);
```

```
istek 200000 (480 s pencere), tekil takip numarasi 20454, obek 10, es zamanli gonderi 1000

katman     kapsam       kapasite   isabet  isabet payi  tahliye
---------- ----------- --------- -------- ------------ --------
istemci    kullanici           4   140045       0.7002    34810
kenar      paylasilan        250    16520       0.0826    43185
web        paylasilan        600    14390       0.0720    28445
uygulama   ornek           400x4     8394       0.0420    19051
depo       -                   -    20651       0.1033        -

birlesik isabet      = 0.8967  (V9 varsayimi 0,90)
bir iskanin dokunusu = 9 (4 yoklama + 1 depo + 4 geri yazma)
dokunus / istek      = 2.531

K01'e donus (tepe okuma 416.67, tepe yazma 97.22 istek/s)
aga hic cikmayan okuma/s = 291.76
uygulamaya varan okuma/s = 60.51
onbellek arkasi okuma/s  = 43.02  (V9 ile 41,67)
depoya ulasan istek/s    = 140.25  (V9 ile 138,89)
depoda yazma/okuma orani = 2.26  (V9 ile 2,33)
```

Bu sayıların hepsi **hesap** sınıfındadır: belirlenimli bir akış üzerinde sayılmışlardır, süre
ölçülmemiştir, koşumdan koşuma değişmezler.

Birinci sonuç V9 hakkındadır. Dört katmanın birleşik isabeti 0,8967 çıktı; varsayılan 0,90'ın
biraz altında. Fark küçük görünüyor ama hesapta görünür: `onbellek arkasi okuma/s` 41,67 yerine
43,02, `depoya ulasan istek/s` 138,89 yerine 140,25, `depoda yazma/okuma orani` 2,33 yerine
2,26. Varsayım artık savunulabilir bir sayıdır çünkü onu üreten yerleşim yazılmıştır. Kapasite
ya da çalışma kümesi değiştiğinde bu satırlar yeniden hesaplanır.

İkinci sonuç isabetin **dağılımı** hakkındadır. İsteklerin 0,7002'si istemci katmanında,
yalnız dört girdilik bir önbellekte durdu — çünkü öbek içindeki sorguların çoğu aynı
kullanıcıdan geliyor. Bu, saniyede 291,76 okumanın ağa hiç çıkmaması demektir. Kalan üç katman
toplam 0,1966 durdurdu ve uygulamaya varan okuma 416,67'den 60,51 istek/s'ye indi. Trafik
Katmanı kursunun İçerik Dağıtım Ağları dersi aynı satırı 41,76 olarak ölçmüştü; oradaki
uygulama önbelleği pencerenin bütün anahtarlarını tutabiliyordu, buradaki katmanların kapasitesi
çalışma kümesinin altındadır ve tahliye sütunu bunu gösteriyor.

Üçüncü sonuç bedelin nerede olduğudur. Bir ıska dokuz dokunuş yapar: dört yoklama, bir depo
erişimi ve dönüşte dört geri yazma. Ortalama 2,531 dokunuş/istek. Zincir uzadıkça isabet artar
ama **her** ıska daha uzun bir yol yürür.

## Katman Eklemenin Sınırı

Bir katmanın değeri, durdurduğu istek sayısı ile eklediği dokunuşun oranıdır. Aşağıdaki koşum
zinciri baştan kurarak her katmanın kendi payını ayırır ve aynı isabeti tek bir önbellekle
elde etmenin ne istediğini gösterir.

```js
// onbellek/kac-katman.mjs — zincire katman eklendikce ne kazanilir, ne odenir
import { akis, zincir, K01 } from "./katman.mjs";

const ISTEK = 200_000;
const istekler = akis({ istek: ISTEK, calismaKumesi: 1000, obek: 10, kullanici: 40_000 });
const TAM = [
  { ad: "istemci", kapsam: "kullanici", kapasite: 4 },
  { ad: "kenar", kapsam: "paylasilan", kapasite: 250 },
  { ad: "web", kapsam: "paylasilan", kapasite: 600 },
  { ad: "uygulama", kapsam: "ornek", kapasite: 400, ornek: 4 },
];

console.log("zincir                       isabet  depo/s  dokunus/istek  durdurulan  eklenen dokunus  dokunus/durdurulan");
console.log("---------------------------- ------ ------- -------------- ----------- ---------------- ------------------");
let onceki = { dokunus: ISTEK, depo: ISTEK };   // onbelleksiz: istek basina bir depo erisimi
for (let n = 0; n <= TAM.length; n++) {
  const r = n === 0 ? { depo: ISTEK, dokunus: ISTEK } : zincir(istekler, TAM.slice(0, n));
  const h = 1 - r.depo / ISTEK;
  const depoS = K01.tepeOkuma * (1 - h) + K01.tepeYazma;
  const durdurulan = onceki.depo - r.depo;
  const eklenen = r.dokunus - onceki.dokunus;
  const ad = n === 0 ? "(onbelleksiz)" : "+" + TAM[n - 1].ad;
  console.log(`${ad.padEnd(28)} ${h.toFixed(4).padStart(6)} ${depoS.toFixed(2).padStart(7)} ` +
    `${(r.dokunus / ISTEK).toFixed(3).padStart(14)} ${(n === 0 ? "-" : String(durdurulan)).padStart(11)} ` +
    `${(n === 0 ? "-" : String(eklenen)).padStart(16)} ${(n === 0 ? "-" : (eklenen / durdurulan).toFixed(2)).padStart(18)}`);
  onceki = r;
}

const tam = zincir(istekler, TAM);
const h = 1 - tam.depo / ISTEK;
console.log();
console.log(`dort katmanin birlesik isabeti = ${h.toFixed(4)}`);
console.log(`ayni isabet tek katmanla istenirse gereken kapasite:`);
for (const kap of [250, 600, 1000, 1200, 2000]) {
  const t = zincir(istekler, [{ ad: "tek", kapsam: "paylasilan", kapasite: kap }]);
  const th = 1 - t.depo / ISTEK;
  console.log(`  kapasite ${String(kap).padStart(4)} -> isabet ${th.toFixed(4)}  depo/s ${(K01.tepeOkuma * (1 - th) + K01.tepeYazma).toFixed(2).padStart(6)}  dokunus/istek ${(t.dokunus / ISTEK).toFixed(3)}`);
}
```

```
zincir                       isabet  depo/s  dokunus/istek  durdurulan  eklenen dokunus  dokunus/durdurulan
---------------------------- ------ ------- -------------- ----------- ---------------- ------------------
(onbelleksiz)                0.0000  513.89          1.000           -                -                  -
+istemci                     0.7002  222.13          1.600      140045           119910               0.86
+kenar                       0.7828  187.71          2.034       16520            86870               5.26
+web                         0.8548  157.73          2.324       14390            58090               4.04
+uygulama                    0.8967  140.25          2.531        8394            41302               4.92

dort katmanin birlesik isabeti = 0.8967
ayni isabet tek katmanla istenirse gereken kapasite:
  kapasite  250 -> isabet 0.2321  depo/s 417.20  dokunus/istek 2.536
  kapasite  600 -> isabet 0.5236  depo/s 295.71  dokunus/istek 1.953
  kapasite 1000 -> isabet 0.7915  depo/s 184.11  dokunus/istek 1.417
  kapasite 1200 -> isabet 0.8646  depo/s 153.63  dokunus/istek 1.271
  kapasite 2000 -> isabet 0.8975  depo/s 139.95  dokunus/istek 1.205
```

Birinci tablo azalan getiriyi sayıyla veriyor. Önbelleksiz tasarımda depoya ulaşan istek 513,89
istek/s'dir — K01'in uçtaki tepe yükünün tamamı. İlk katman bunu 222,13'e indiriyor ve
durdurduğu her istek başına yalnız 0,86 dokunuş ekliyor, çünkü durdurduğu istek zaten bir depo
erişimini iptal ediyor. Sonraki üç katmanın oranı 5,26, 4,04 ve 4,92: her biri, kurtardığı her
istek için beşe yakın ek dokunuş ödetiyor. Dördüncü katman 8394 isteği durdurup 41.302 dokunuş
ekliyor ve depoya ulaşan yükü yalnız 17,49 istek/s düşürüyor.

İkinci tablo daha rahatsız edici. Kapasitesi 2000 olan **tek** bir paylaşılan önbellek 0,8975
isabet veriyor — dört katmanlı zincirin 0,8967'sinin üstünde — ve bunu istek başına 1,205
dokunuşla yapıyor, 2,531 yerine. Zincirin gerekçesi birleşik isabet oranı değildir: doğru
boyutlandırılmış tek bir katman aynı oranı daha ucuza verir.

Zincirin gerekçesi isabetin **nerede** karşılandığıdır. Tek paylaşılan önbellekte isabetlerin
tamamı bir ağ turuna mal olur ve hepsi tek bir bileşenden geçer; dört katmanlı yerleşimde
saniyede 291,76 okuma hiç ağa çıkmaz. Buna karşılık o 291,76 okuma, geri alınabilirliği en
düşük katmanda karşılanır: istemcideki kopya konduktan sonra silinemez. Yerleşim kararı bu iki
cümlenin arasında verilir ve ikisi de aynı isabet oranıyla uyumludur.

## Özet

- Bir önbellek katmanını kapsam, kapasite ve geri alınabilirlik tanımlar; veritabanı önbelleği
  bu sıralamanın dışındadır çünkü sorgunun maliyetini düşürür, sayısını düşürmez.
- Dört katmanlı zincirin birleşik isabeti 0,8967 ölçüldü. K01'in V9 = 0,90 varsayımı böylece
  tasarımın sonucu oldu: `onbellek arkasi okuma/s` 41,67 yerine 43,02, `depoya ulasan istek/s`
  138,89 yerine 140,25, `depoda yazma/okuma orani` 2,33 yerine 2,26.
- İsabetin 0,7002'si dört girdilik istemci önbelleğinde durdu; saniyede 291,76 okuma ağa hiç
  çıkmadı ve uygulamaya varan okuma 416,67'den 60,51 istek/s'ye indi.
- Zincir uzadıkça her ıska daha uzun yol yürür: dört katmanda bir ıska dokuz dokunuş, ortalama
  2,531 dokunuş/istek. Katmanların durdurdukları istek başına ek dokunuşu sırasıyla 0,86, 5,26,
  4,04 ve 4,92.
- Kapasitesi 2000 olan tek bir paylaşılan önbellek 0,8975 isabeti 1,205 dokunuşla veriyor;
  zincirin gerekçesi isabet oranı değil, isabetin hangi katmanda karşılandığıdır.

## Sonraki Adım

Bu derste her katman aynı biçimde çalıştı: bak, yoksa bir alttakine sor, dönüşte koy. Bu davranış
kodda tek bir döngüdür ve bir adı vardır; üstelik tek seçenek de değildir. Katmanın isabeti
yalnız kapasiteye değil, girdinin **ne zaman düştüğüne** de bağlıdır ve girdiyi düşüren şey
çoğunlukla bir yazmadır. K01'in hesabı deponun gördüğü yerde yazma ağırlıklı bir sistem
tarif ediyordu: yazma/okuma oranı 2,33. Sıradaki ders uygulamanın kendi denetlediği bu
yerleştirmeyi adlandırır ve isabet oranını sabit bir sayı olmaktan çıkarıp yazma sıklığının bir
işlevi hâline getirir; o işlev 0,90'ın nerede tutulabildiğini ve nerede tutulamadığını söyler.
