---
title: 'İstem Önbellekleme'
source: 'https://academia.sh/tr/kurslar/model-apileri/istem-onbellekleme'
course: "Model API'leri ile Uygulama Geliştirme"
language: tr
updated: '2026-08-17T18:06:37+00:00'
license: 'CC BY-SA 4.0'
---

# İstem Önbellekleme

Aynı 240 kurgu isteğin yedi önbellek kurulumunda ölçülmesi: istemin 186 belirtecinin 175'i bütün isteklerde ortaktır. İçeriğe göre anahtarlanan önek önbelleği 0,9792 isabetle giriş belirtecini 44367'den 7472'ye indiriyor ve doğru yanıt payını hiç değiştirmiyor. Soruya göre anahtarlanan yanıt önbelleğinde ömür uzadıkça isabet 0,4708'den 0,8792'ye çıkıyor, çağrı 240'tan 29'a düşüyor, ama bayat yanıt payı 0,0208'den 0,4417'ye tırmanıyor ve doğru yanıt payı 0,9333'ten 0,5542'ye iniyor. İki önbellek birlikte girişi 2946'ya indiriyor, yani on beş kat, ve yanıt önbelleği açıldığında önek isabeti 0,9792'den 0,9359'a düşüyor.

Önceki derste ağır yükte 295 çağrı yapıldı ve bu çağrıların hepsi aynı yönergeyle başlıyordu.
Yeniden deneme o tekrarı bir kat daha büyüttü: düzeltmek için gönderilen her çağrı, ortak metni
bir kez daha belirteçledi ve bir kez daha ödedi. Tekrarın kendisi ölçülmemişti.

Bir destek yardımcısında bu tekrar iki katmanlıdır. Birincisi **istemin öneki**: yönerge ve saha
ekibinin kurgu belge dağarcığı her istekte aynıdır ve istemin büyük bölümünü kaplar. İkincisi
**sorunun kendisi**: birkaç soru bütün trafiğin yarısını üretir ve aynı soru gün boyunca onlarca
kez sorulur. İki tekrarın da bir çaresi vardır ve **iki çare aynı şey değildir**. Bu ders ikisini
ayrı ayrı kurar ve yan yana ölçer: önbellek isabeti yükseldikçe belirteç düşer, ama saklanan
yanıtın bir **yaşı** olur ve dayandığı belge değiştiğinde yanıt hâlâ hızlı, hâlâ ucuz ve artık
yanlıştır.

- **UK9.** Kod bir **benzeticidir**; gerçek bir uç nokta çağrılmaz. Dağarcık, sorular ve
  güncelleme takvimi **kurgudur**, tohum **20260218**.
- **UK10.** Dağarcık **on kurgu belgedir**; her belgenin bir **sürümü** vardır ve dört ayrı adımda
  ikişer belge güncellenir.
- **UK11.** İstem iki parçalıdır: bütün isteklerde aynı olan **önek** (yönerge ile dağarcık) ve
  sorunun kendisi.
- **UK12. Önek önbelleği içeriğe göre anahtarlanır.** Önek bir önceki çağrıdakiyle birebir aynıysa
  isabet sayılır ve önek belirteçlerinin **yüzde onu** ödenir. Dağarcık değişirse önek de değişir.
- **UK13. Yanıt önbelleği soruya göre anahtarlanır** ve bir **ömrü** vardır. Ömür içindeki isabet
  çağrı yapmaz, hiç belirteç harcamaz.
- **UK14. Bayat yanıt**, önbellekten dönen ve dayandığı belgenin sürümü artık geçerli olmayan
  yanıttır.
- **UK15. Doğru yanıt**, etiketi doğru olan **ve** bayat olmayan yanıttır; bu dersin ürün ölçütü
  budur.
- **UK16.** İş yükü 120 adımda 240 istektir, adım başına iki; soru dağılımı çarpıktır.

## İki Ayrı Önbellek, İki Ayrı Anahtar

Önce dağarcık ve sorular kurulur, sonra bir belge güncellenip aynı sorunun yanıtının ne olduğuna
bakılır. Ayrım burada görünür hâle gelir: önek, dağarcık değişince **kendiliğinden** değişir;
saklanmış bir yanıt ise değişmez.

```python
# BENZETICI -- KURGUDUR. Gercek bir uc nokta cagrilmaz. Belge dagarcigi, sorular
# ve guncelleme takvimi kurgudur, tohum 20260218.
TOHUM, M32 = 20260218, 0xFFFFFFFF
ADIM, ONEK_INDIRIM = 120, 0.10     # kosum uzunlugu, isabetli onegin odenen payi


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def belirtecle(m):
    b = []
    for s in m.lower().replace(",", " , ").split():
        while len(s) > 5:
            b.append(s[:5])
            s = s[5:]
        b.append(s)
    return b


def izno(m):
    h = 2166136261
    for c in m:
        h = ((h ^ ord(c)) * 16777619) & M32
    return h


KONU = ["fatura", "ariza", "sayac", "tarife", "kesinti"]
BELGE = [{"kod": "FT1", "konu": "fatura", "anahtar": "fatura tutari",
          "metin": "fatura tutari hesap donemi ve gecikme farki kurallari"},
         {"kod": "FT2", "konu": "fatura", "anahtar": "fatura odemesi",
          "metin": "fatura odemesi yontemleri ve borc gorunumu kurallari"},
         {"kod": "AR1", "konu": "ariza", "anahtar": "ariza kaydi",
          "metin": "ariza kaydi acma ve ekip yonlendirme yordami"},
         {"kod": "AR2", "konu": "ariza", "anahtar": "baglanti bozuklugu",
          "metin": "baglanti bozuk oldugunda uygulanan denetim adimlari"},
         {"kod": "SY1", "konu": "sayac", "anahtar": "sayac endeksi",
          "metin": "sayac endeks okumasi ve duzeltme yordami"},
         {"kod": "SY2", "konu": "sayac", "anahtar": "sayac degisimi",
          "metin": "sayac degisimi randevu kurallari ve sure taahhudu"},
         {"kod": "TA1", "konu": "tarife", "anahtar": "tarife basamagi",
          "metin": "tarife basamaklari ve abone tipine gore birim ucret"},
         {"kod": "TA2", "konu": "tarife", "anahtar": "tarife degisikligi",
          "metin": "tarife degisikligi basvurusu ve gecerlilik kosullari"},
         {"kod": "KS1", "konu": "kesinti", "anahtar": "planli kesinti",
          "metin": "planli kesinti duyurusu yayimlama ve takip kurallari"},
         {"kod": "KS2", "konu": "kesinti", "anahtar": "mahalle kesintisi",
          "metin": "mahallede kesinti bildirimi ve tahmini donus suresi"}]
for b in BELGE:
    b["surum"] = 1
SORU = [{"b": i, "konu": b["konu"], "metin": k.format(a=b["anahtar"])}
        for i, b in enumerate(BELGE)
        for k in ("{a} konusunda ne yapmam gerekiyor",
                  "{a} icin gecerli kural nedir",
                  "{a} ile ilgili son durum ne")]
AGIRLIK = [1.0 / (i + 1) ** 1.0 for i in range(len(SORU))]
AGIRLIK = [w / sum(AGIRLIK) for w in AGIRLIK]
GUNCELLEME = {24: [6, 1], 48: [0, 8], 72: [2, 6], 96: [4, 7]}   # adim -> belge
IZ = {"fatur": "fatura", "tutar": "fatura", "borc": "fatura", "odeme": "fatura",
      "ariza": "ariza", "bozuk": "ariza", "bagla": "ariza", "kayit": "ariza",
      "sayac": "sayac", "endek": "sayac", "okuma": "sayac", "tarif": "tarife",
      "birim": "tarife", "abone": "tarife", "basam": "tarife", "kesin": "kesinti",
      "duyur": "kesinti", "mahal": "kesinti"}
YONERGE = ("Asagidaki dagarcigi kullanarak soruyu yanitla . Yanitta once etiket , "
           "sonra dayandigin belge kodu ve surumu yaz . Dagarcik: ")
SAYAC = [0]


def onek():
    return YONERGE + " ; ".join(f"{b['kod']} s{b['surum']} {b['metin']}"
                                for b in BELGE) + " . Soru: "


def cagir(soru, tohum=TOHUM):
    """KURGU uc nokta. Dagarcigin o andaki surumunu okur."""
    SAYAC[0] += 1
    istem = onek() + soru["metin"]
    bel = belirtecle(istem)
    p = {k: 0.15 for k in KONU}
    for t in belirtecle(soru["metin"]):
        if IZ.get(t) in p:
            p[IZ[t]] += 1.0
    r = uretec((tohum ^ izno(soru["metin"])) + 7919 * SAYAC[0])
    e = max(sorted(p), key=lambda a: p[a]) if r() > 0.10 else KONU[int(r() * 5)]
    b = BELGE[soru["b"]]
    return {"etiket": e, "kod": b["kod"], "surum": b["surum"],
            "giris": len(bel), "onek": len(belirtecle(onek())),
            "cikis": len(belirtecle(f"{e} {b['kod']} s{b['surum']}"))}


def akis(tohum=TOHUM):
    """Her adimda iki istek; soru dagilimi carpiktir (birkac soru baskin)."""
    r = uretec(tohum + 991)
    return [(a, SORU[ayrik(r(), AGIRLIK)]) for a in range(ADIM) for _ in range(2)]


for b in BELGE:
    b["surum"] = 1
ilk = cagir(SORU[0])
print("ilk cagri  :", {k: ilk[k] for k in ("etiket", "kod", "surum", "giris", "onek")})
BELGE[0]["surum"] += 1                      # dagarcik guncellendi
ikinci = cagir(SORU[0])
print("guncelleme sonrasi:", {k: ikinci[k] for k in ("kod", "surum", "giris")})
print("saklanan yanit    :", ilk["kod"], "s" + str(ilk["surum"]),
      "-> bayat" if ilk["surum"] != BELGE[0]["surum"] else "-> taze")
BELGE[0]["surum"] = 1
ist = akis()
sik = {}
for _, s in ist:
    sik[s["metin"][:26]] = sik.get(s["metin"][:26], 0) + 1
print(f"\nistek {len(ist)} , benzersiz soru {len(sik)} , onek {ilk['onek']} belirtec")
print("en sik uc soru:", [(a, n) for a, n in sorted(sik.items(), key=lambda x: -x[1])[:3]])
```

```
ilk cagri  : {'etiket': 'fatura', 'kod': 'FT1', 'surum': 1, 'giris': 186, 'onek': 175}
guncelleme sonrasi: {'kod': 'FT1', 'surum': 2, 'giris': 186}
saklanan yanit    : FT1 s1 -> bayat

istek 240 , benzersiz soru 29 , onek 175 belirtec
en sik uc soru: [('fatura tutari konusunda ne', 56), ('fatura tutari icin gecerli', 41), ('fatura tutari ile ilgili s', 23)]
```

İlk satır tekrarın büyüklüğünü veriyor: istem 186 belirteç, bunun **175'i önek**. Yani her
isteğin ödediği belirtecin **0,9409'u** bir önceki istekle birebir aynıdır. İkinci satır
güncellemeden sonraki çağrının aynı belgeyi ikinci sürümüyle okuduğunu gösteriyor. Üçüncü satır
ise ayrımın kendisidir: saklanmış yanıt hâlâ birinci sürüme dayanıyor ve **bayat** olmuş.

Soru dağılımı da önemlidir. 240 istek yalnız 29 farklı soruya karşılık geliyor ve en sık üç soru
tek başına 120 isteği kaplıyor. Bir yanıt önbelleğinin işe yaraması bu çarpıklığa bağlıdır;
her isteğin farklı olduğu bir yükte yanıt önbelleğinin isabeti sıfır kalır.

## İsabet Yükselirken Bayat Yanıt Payı

Yedi kurulum aynı akışta koşturulur: önbelleksiz taban, yalnız önek önbelleği, dört farklı ömürle
yanıt önbelleği, ve ikisi birlikte.

```python
def kosum(onek_ac, omur=0, tohum=TOHUM):
    """onek_ac: onek onbellegi acik mi . omur: yanit onbelleginin adim omru."""
    for b in BELGE:
        b["surum"] = 1
    SAYAC[0] = 0
    onbellek, izi, gecen = {}, [None], [-1]
    s = dict.fromkeys(("oi", "yi", "giris", "cikis", "bayat", "dogru", "istek"), 0)
    for adim, soru in akis(tohum):
        if adim != gecen[0]:
            gecen[0] = adim
            for i in GUNCELLEME.get(adim, []):
                BELGE[i]["surum"] += 1
        s["istek"] += 1
        kayit = onbellek.get(soru["metin"])
        if omur and kayit and adim - kayit["adim"] <= omur:
            s["yi"] += 1
            bayat = kayit["surum"] != BELGE[soru["b"]]["surum"]
            s["bayat"] += bayat
            s["dogru"] += kayit["etiket"] == soru["konu"] and not bayat
            continue
        y = cagir(soru, tohum)
        s["cikis"] += y["cikis"]
        if onek_ac and izi[0] == onek():           # onek icerige gore anahtarlanir
            s["oi"] += 1
            s["giris"] += round(y["onek"] * ONEK_INDIRIM) + y["giris"] - y["onek"]
        else:
            s["giris"] += y["giris"]
        izi[0] = onek()
        onbellek[soru["metin"]] = {"etiket": y["etiket"], "surum": y["surum"],
                                   "adim": adim}
        s["dogru"] += y["etiket"] == soru["konu"]
    n, c = s["istek"], max(SAYAC[0], 1)
    return (s["yi"] / n, s["oi"] / c, s["giris"], s["giris"] + s["cikis"],
            SAYAC[0], s["bayat"] / n, s["dogru"] / n)


DUZEN = [("onbelleksiz", 0, 0), ("onek onbellegi", 1, 0), ("yanit omur 8", 0, 8),
         ("yanit omur 24", 0, 24), ("yanit omur 64", 0, 64),
         ("yanit omur sinirsiz", 0, 10 ** 6), ("onek + yanit omur 24", 1, 24)]
print("duzenek               yanit isb  onek isb   giris  toplam  cagri   bayat"
      "   dogru")
for ad, o, m in DUZEN:
    a = kosum(o, m)
    print(f"{ad:<21} {a[0]:>8.4f}  {a[1]:>8.4f}  {a[2]:>6}  {a[3]:>6}  {a[4]:>5}"
          f"  {a[5]:>6.4f}  {a[6]:>6.4f}")
print("\nikinci kosum (tohum 20260219), yanit isb / bayat / dogru:")
for ad, o, m in DUZEN:
    a = kosum(o, m, TOHUM + 1)
    print(f"  {ad:<21} {a[0]:.4f} / {a[5]:.4f} / {a[6]:.4f}")
```

```
duzenek               yanit isb  onek isb   giris  toplam  cagri   bayat   dogru
onbelleksiz             0.0000    0.0000   44367   45263    240  0.0000  0.9333
onek onbellegi          0.0000    0.9792    7472    8368    240  0.0000  0.9333
yanit omur 8            0.4708    0.0000   23456   23917    127  0.0208  0.9208
yanit omur 24           0.6750    0.0000   14407   14686     78  0.0500  0.9292
yanit omur 64           0.8000    0.0000    8870    9042     48  0.1333  0.8625
yanit omur sinirsiz     0.8792    0.0000    5357    5461     29  0.4417  0.5542
onek + yanit omur 24    0.6750    0.9359    2946    3225     78  0.0500  0.9292

ikinci kosum (tohum 20260219), yanit isb / bayat / dogru:
  onbelleksiz           0.0000 / 0.0000 / 0.9083
  onek onbellegi        0.0000 / 0.0000 / 0.9083
  yanit omur 8          0.5292 / 0.0292 / 0.8667
  yanit omur 24         0.6958 / 0.0833 / 0.8250
  yanit omur 64         0.8208 / 0.2167 / 0.6833
  yanit omur sinirsiz   0.9000 / 0.5000 / 0.4042
  onek + yanit omur 24  0.6958 / 0.0833 / 0.8250
```

İkinci satır bu dersin en ucuz kazancıdır ve tuzağı yoktur. Önek önbelleği 0,9792 isabetle giriş
belirtecini **44367'den 7472'ye** indiriyor, yani **5,94 kat**. Bayat yanıt payı **0,0000**,
doğru yanıt payı **değişmiyor**. Nedeni anahtardadır: önek **içeriğe göre** anahtarlanır.
Dağarcık güncellendiği anda önek metni de değişir, eşleşme kırılır ve bir sonraki çağrı tam
ödenir. Bir önbelleğin bayatlaması, anahtarının içerikten kopmasıyla başlar.

Yanıt önbelleği satırları bunun tersidir. Anahtar **soru** metnidir ve soru değişmez; değişen
şey, sorunun dayandığı belgedir. Ömür sekiz adımken isabet 0,4708 ve bayat pay 0,0208; ömür
sınırsız olduğunda isabet 0,8792'ye çıkıyor ve bayat pay **0,4417'ye** tırmanıyor. Çağrı sayısı
240'tan 29'a düşüyor, giriş belirteci 5357'ye iniyor. Sayfanın maliyet tarafından bakıldığında
son satır en iyi satırdır. Ürün tarafından bakıldığında ise doğru yanıt payı **0,9333'ten
0,5542'ye** düşmüştür: her iki isteğin yaklaşık birinde kullanıcıya artık geçerli olmayan bir
kural anlatılıyor.

## Ömrün Seçimi Bir Doğruluk Kararıdır

Kaybın hangi ömürde ölçülebilir hâle geldiği, iki koşum farkına bakılarak söylenir. Önbelleksiz
taban ikinci tohumda 0,9083 veriyor, yani koşum farkı **0,0250**. Ömür sekizde kayıp 0,0125,
ömür yirmi dörtte 0,0041 — ikisi de koşum farkının altında ve **ölçülmemiş sayılır**. Ömür
altmış dörtte kayıp 0,0708, sınırsızda 0,3791; bunlar sırasıyla koşum farkının yaklaşık üç ve on
beş katı, yani **ölçülmüştür**. Karar buradan okunur: bu güncelleme takviminde ömrü yirmi dörde
kadar uzatmak bedelsizdir, altmış dörde çıkarmak değildir.

Bu okumanın bir uyarısı var. İkinci koşumda ömür yirmi dördün kaybı 0,0833'e çıkıyor, yani kendi
tabanına göre koşum farkının üç katı. Aynı ayar bir koşumda gürültünün altında, ötekinde ölçülür
durumda. Bu, yirmi dört adımın **güncelleme aralığına yakın** olmasından gelir: dağarcık her yirmi
dört adımda bir değiştiği için, ömrü tam o aralığa oturtmak kararı belge güncellemesinin zamanlama
şansına bırakır. Önbellek ömrü, verinin değişme sıklığından **bağımsız** seçilemez.

Son satır iki önbelleğin birlikte çalıştığı kurulumdur ve tek başına hiçbirinin vermediği bir sayı
üretiyor: giriş belirteci **2946**, yani tabana göre **15,06 kat** düşüş, bayat pay ise ömür yirmi
dördünkiyle aynı, 0,0500. Aynı satırda daha ince bir etki de var: önek isabeti 0,9792'den
**0,9359'a** düşüyor. Yanıt önbelleği çağrı sayısını 240'tan 78'e indirdiği için, dört
güncellemenin kırdığı eşleşme artık çok daha küçük bir bölene bölünüyor. Bir önbellek, öbürünün
isabet oranını **düşürerek** iyileştirir; iki düzeneğin sayısı ayrı ayrı ölçülüp toplanamaz.

## Özet

- İstemin 186 belirtecinin 175'i bütün isteklerde ortaktır; tekrarın büyüklüğü ölçülmeden hangi
  önbelleğin işe yarayacağı bilinemez.
- Önek önbelleği içeriğe göre anahtarlandığı için bayatlamaz: 0,9792 isabetle girişi 44367'den
  7472'ye indiriyor ve doğru yanıt payını hiç değiştirmiyor.
- Yanıt önbelleğinde ömür uzadıkça isabet 0,4708'den 0,8792'ye çıkarken bayat yanıt payı
  0,0208'den 0,4417'ye tırmanıyor ve doğru yanıt payı 0,9333'ten 0,5542'ye iniyor.
- İki koşum farkı 0,0250'dir: ömür sekiz ve yirmi dördün kaybı bu farkın altında kalıp ölçülmemiş
  sayılırken, altmış dört ve sınırsız ömrün kaybı ölçülmüştür.
- Ömür, güncelleme aralığına yakın seçildiğinde karar kararsızlaşır; aynı ayar bir koşumda
  gürültünün altında, ötekinde onun üç katı kayıp veriyor.
- İki önbellek birlikte girişi 2946'ya indiriyor, ama yanıt önbelleği önek isabetini 0,9792'den
  0,9359'a düşürüyor: düzeneklerin sayıları ayrı ölçülüp toplanamaz.

## Sonraki Adım

Bu derste kazanılan şey belirteçtir. Önbellekten dönen bir yanıt hiç çağrı yapmadığı için
kullanıcının beklemesini de kısaltır, ama bu ders o tarafı hiç saymadı: tablo yalnız belirteç,
çağrı ve doğruluk sütunları taşıyor. Oysa bir destek yardımcısında en görünür ölçüt bekleme
süresidir ve onu belirleyen şey yalnız önbellek değildir. Bağlamın büyüklüğü, çağrının tek başına
mı yoksa bir zincirin parçası olarak mı yapıldığı, ve pahalı adımın her istekte mi yoksa yalnız
gerekli olduğunda mı çalıştırıldığı beklemeyi ayrı ayrı değiştirir. Sonraki ders bu üç kurulumu
karşılaştırır: küçük bağlam, büyük bağlam ve iki aşamalı çağrı hangi **gecikme sınıfında** duruyor
ve her birinin isabeti ne.
