---
title: 'Bağlayıcılar ve API Tüketimi'
source: 'https://academia.sh/tr/kurslar/veri-hatlari/baglayicilar-ve-api-tuketimi'
course: 'Veri Hatları ve Orkestrasyon'
language: tr
updated: '2026-08-17T18:08:49+00:00'
license: 'CC BY-SA 4.0'
---

# Bağlayıcılar ve API Tüketimi

Sayfalama ve hız sınırı altında bağlayıcının tamamladığı çağrı ile aldığı satırın sayılması: pencere başına sekiz çağrı kotasıyla 25 satırlık sayfada 96 çağrının 83'ü tamamlanıyor ve 2075 satır alınıyor, 100 satırlık sayfada 24 çağrının 20'si tamamlanıyor ve 2000 satır alınıyor, yani düşen çağrı başına kaçan satır sayfa boyuyla birlikte 25'ten 100'e çıkıyor. Yeniden deneme küçük sayfada kotayı yiyor ve alınan satırı 2075'ten 2025'e düşürüyor, 112 sayfa bir pencere geciktiriyor, 2026-12 dönemi hiç alınmıyor; buna karşılık sunum sapması −374'ten −125'e iniyor, çünkü kayıp dağınık olmaktan çıkıp kuyruğun sonunda toplanıyor. Bağlayıcının kendi çağrı defteri eksiği gecikmesiz bildiriyor: beklenen 96, tamamlanan 83.

Önceki ders `al` görevini tek bir hamle olarak ele aldı: kaynağın o anki hâli çağrıldı ve satırlar
elde oldu. Kaynak sistemler böyle okunmaz. Veriyi bir uçnokta üzerinden veren bir kaynak onu
**sayfa sayfa** teslim eder, belirli bir pencerede kaç çağrı yapılabileceğini **sınırlar** ve
çağrılardan bir kısmı geçici olarak düşer. `al` görevinin bir kez koşması artık tek bir işlem
değil, onlarca çağrıdan oluşan bir dizidir.

Bu dersin ölçüsü iki sayıdır: **kısıt altında tamamlanan çağrı** ve **alınan satır**. Sayfalama ve
hız sınırının kendisi Web API Tasarımı, SQL Temelleri ve Model API'leri ile Uygulama Geliştirme
kurslarında ölçüldü; yordam burada tekrarlanmaz. Burada sorulan tek şey şudur: bir **bağlayıcı**
(connector) bu kısıtların altında hattın istediği satırların kaçını getirebiliyor, ve getiremediği
satırın hangi izi kalıyor.

- **VA9.** Kod **kurgudur**; gerçek bir uçnokta, bağlayıcı ürünü ya da orkestratör çağrılmaz.
  Kaynak yine 200 abone, 12 dönem, 2400 satır, tohum 20260218.
- **VA10.** Uçnokta bir dönemin satırlarını **sayfa boyu** kadar parça hâlinde verir ve dönem
  başına kaç satır bulunduğunu bildirir; bağlayıcı bu yüzden kaç sayfa isteyeceğini önceden bilir.
- **VA11.** Hız sınırı **pencere başına kota** olarak modellenir: her dönemin bir penceresi vardır
  ve o pencerede en çok `kota` çağrı tamamlanabilir. Sığmayan sayfa bir sonraki pencereye kalır;
  bu bir **dönem** gecikmedir. Süre ham olarak yazılmaz.
- **VA12.** Geçici hata payı 0,15'tir ve tohumdan türetilir; aynı sayfanın aynı denemesi her
  koşumda aynı sonucu verir. Hat belirlenimcidir.
- **VA13.** Yeniden deneme hakkı **kotadan yenir**: başarısız bir çağrının tekrarı da bir çağrıdır.
  Geri çekilme yordamı Önbellekleme, Kuyruklar ve Eşzamansız İşleme kursunda ölçüldü, burada
  tekrarlanmaz.
- **VA14.** Hakkı tükenen sayfa **bırakılır** ve bağlayıcı yoluna devam eder; o sayfanın satırları
  hiç alınmaz.
- **VA15.** Taban çizgisi orkestrasyonsuz koşumdur: yeniden deneme yok, kuyruk yok, tek elle
  tetikleme. Yeniden deneme bu dersin eklediği tek düzenektir.
- **VA16.** Satır oranının adımı 1/2400, yani 0,0004; sunum üzerinde oran basılmaz.

## Kısıt Altında Bir Bağlayıcı

Aşağıdaki blok ortak tanımı kurar ve üzerine sayfalı bir uçnokta ile onu tüketen bir bağlayıcı
ekler. Bağlayıcının tek bir kuyruğu vardır: her dönem o dönemin sayfaları kuyruğa girer, pencere
kotası bitene kadar sayfalar çekilir, kalanlar bir sonraki pencereye devrolur.

```python
# KURGUDUR. Gercek bir ucnokta, baglayici urunu ya da orkestrator cagrilmaz;
# olcum aginin sayac okumalari kurgudur, tohum 20260218.
TOHUM, M32 = 20260218, 0xFFFFFFFF


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


BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
DONEM = [f"2026-{a:02d}" for a in range(1, 13)]
ABONE = {}
for i in range(200):
    r = uretec(TOHUM + 37 * i)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "baslangic": 10000 + int(r() * 60000)}


def kaynak_uret():                                  # her donem her abone icin bir okuma
    kayit = []
    for i, (ab, a) in enumerate(ABONE.items()):
        e = a["baslangic"]
        for d in DONEM:
            r = uretec(TOHUM + 101 * i + 7 * DONEM.index(d))
            e += 4 + int(r() * 46)
            kayit.append({"abone": ab, "donem": d, "bolge": a["bolge"], "tip": a["tip"],
                          "endeks": e, "birim": "m3"})
    return kayit


# ---- HAT: bes asama, her asama kendi dusurdugu satiri sayar.
def a1_ayikla(kayit):
    ZOR = ("abone", "donem", "bolge", "endeks", "birim")
    tut = [k for k in kayit if all(a in k for a in ZOR)]
    return tut, len(kayit) - len(tut)


def a2_tekille(kayit):
    gor, tut = set(), []
    for k in kayit:
        ad = (k["abone"], k["donem"])
        if ad in gor:
            continue
        gor.add(ad)
        tut.append(k)
    return tut, len(kayit) - len(tut)


def a3_tuketim(kayit):
    tablo = {(k["abone"], k["donem"]): k for k in kayit}
    cikti, dusen = [], 0
    for k in kayit:
        i = DONEM.index(k["donem"])
        if i == 0:
            continue
        onceki = tablo.get((k["abone"], DONEM[i - 1]))
        if onceki is None:
            dusen += 1
            continue
        try:
            f = int(k["endeks"]) - int(onceki["endeks"])
        except (TypeError, ValueError):
            dusen += 1
            continue
        cikti.append(dict(k, m3=f))
    return cikti, dusen


def a4_ozet(kayit):
    top = {}
    for k in kayit:
        ad = (k["bolge"], k["donem"])
        top[ad] = top.get(ad, 0) + k["m3"]
    return top, 0


def a5_sun(ozet):                                   # bolge basina donem ortalamasi
    bolge = {}
    for (b, d), v in ozet.items():
        bolge.setdefault(b, []).append(v)
    return {b: round(sum(v) / len(v), 2) for b, v in bolge.items()}, 0


def okuma_sonucu(kayitlar):
    v, _ = a1_ayikla(kayitlar)
    v, _ = a2_tekille(v)
    v, _ = a3_tuketim(v)
    oz, _ = a4_ozet(v)
    sun, _ = a5_sun(oz)
    return sun, len(v)


# ---- KURGU ucnokta: sayfali okuma , pencere basina kota , gecici hata.
def sayfa(kayitlar, donem, no, boyu):
    h = [k for k in kayitlar if k["donem"] == donem]
    return h[no * boyu:(no + 1) * boyu]


def cagri_duser(donem, no, hak, pay):
    """Gecici hata tohumdan turetilir , kosumdan bagimsizdir."""
    r = uretec(TOHUM + 13 * DONEM.index(donem) + 3 * no + 101 * hak)
    return r() < pay


def baglayici(kayitlar, boyu, kota, pay=0.15, deneme=0):
    """Her donemin bir penceresi var ; pencerede en cok `kota` cagri tamamlanir.
    Sigmayan sayfa bir sonraki pencereye kalir , bu bir donem gecikmedir."""
    adet = (200 + boyu - 1) // boyu
    alinan, tamam, basarisiz, geciken, kuyruk = [], 0, 0, 0, []
    for d in DONEM:
        kuyruk += [(d, n) for n in range(adet)]
        kalan = kota
        while kuyruk and kalan > 0:
            gd, n = kuyruk[0]
            gecti, hak = False, 0
            while hak <= deneme and kalan > 0:
                kalan -= 1
                if cagri_duser(gd, n, hak, pay):
                    basarisiz += 1
                    hak += 1
                    continue
                tamam += 1
                gecti = True
                break
            if gecti or hak > deneme:               # ya alindi ya da hak bitti
                kuyruk.pop(0)
                if gecti:
                    alinan.extend(sayfa(kayitlar, gd, n, boyu))
        geciken += len(kuyruk)                      # bir pencere daha bekleyen sayfa
    return alinan, tamam, basarisiz, geciken, len(kuyruk)


ham = kaynak_uret()
dogru_sun, dogru_n = okuma_sonucu(ham)
print("kota 8 cagri/pencere , gecici hata payi 0.15")
print("boyu  sayfa  deneme  beklenen  tamam  basarisiz  geciken  alinmayan  alinan  tuketim")
for boyu in (25, 50, 100):
    for deneme in (0, 2):
        al, tm, bs, gc, kal = baglayici(ham, boyu, 8, 0.15, deneme)
        s, t = okuma_sonucu(al)
        adet = (200 + boyu - 1) // boyu
        print(f"{boyu:>4} {adet:>6} {deneme:>7} {12 * adet:>9} {tm:>6} {bs:>10} "
              f"{gc:>8} {kal:>10} {len(al):>7} {t:>8}")
```

```
kota 8 cagri/pencere , gecici hata payi 0.15
boyu  sayfa  deneme  beklenen  tamam  basarisiz  geciken  alinmayan  alinan  tuketim
  25      8       0        96     83         13        0          0    2075     1575
  25      8       2        96     81         15      112         15    2025     1825
  50      4       0        48     39          9        0          0    1950     1300
  50      4       2        48     48         12        0          0    2400     2200
 100      2       0        24     20          4        0          0    2000     1400
 100      2       2        24     24          6        0          0    2400     2200
```

## Sayfa Boyu ile Çağrı Başına Kaçan Satır

Yeniden denemesiz üç satır ilk takası veriyor. Sayfa boyu 25 iken bir dönem sekiz sayfa eder,
on iki dönem **96 çağrı** ister; boyu 100'e çıkınca aynı iş **24 çağrıya** iner. Çağrı sayısı
sayfa boyuyla ters orantılı düşer ve bu, hız sınırı olan bir kaynakta doğrudan kazançtır.

Kazancın karşılığı aynı satırlarda yazılı. Boyu 25'te 13 çağrı düşüyor ve 325 satır kaçıyor; boyu
50'de 9 çağrı düşüyor ama 450 satır kaçıyor; boyu 100'de yalnız 4 çağrı düşüyor ve yine 400 satır
kaçıyor. Çarpım her satırda birebir tutuyor: kaçan satır **düşen çağrı sayısı ile sayfa boyunun
çarpımıdır**. Sayfa boyunu dörde katlamak çağrı sayısını dörtte bire indirir ve **tek bir
başarısızlığın bedelini dört katına çıkarır**. Bağlayıcı ayarı bu iki eğrinin kesiştiği yerde
seçilir, ve hangisinin ağır bastığı kaynağın hata payına bağlıdır.

Tüketim sütunu bedelin hattın içinde nasıl büyüdüğünü gösteriyor. Boyu 50'de 450 satır kaçıyor ama
tüketim satırı 2200'den **1300**'e düşüyor: kaçan her satır kendi dönemindeki tüketimi düşürmekle
kalmıyor, **bir sonraki dönemin** tüketimini de hesaplanamaz kılıyor, çünkü tüketim bir fark
hesabıdır. 450 satırlık bir eksik, 900 satırlık bir kayba dönüşüyor.

## Yeniden Denemenin Kotayı Yemesi

Bir pencerenin taşıyabileceği en fazla satır, kota ile sayfa boyunun çarpımıdır. Kota sekiz iken
boyu 25 pencere başına **200 satır**, boyu 50 **400 satır**, boyu 100 **800 satır** tavanı verir.
Bir dönemin talebi ise tam 200 satırdır. Boyu 25'te tavan ile talep **birebir eşittir** ve
bağlayıcının hiçbir boşluğu yoktur; boyu 50'de tavan talebin iki katı, boyu 100'de dört katıdır.
Yeniden denemenin kendine yer bulup bulamayacağını belirleyen şey, hata payı değil bu boşluktur.

Yeniden deneme boyu 50 ve boyu 100 satırlarında **bedavaya yakındır**: 48 ve 24 çağrı kotanın
altında kaldığı için başarısız çağrılar tekrarlanabiliyor ve alınan satır 2400'e, tüketim 2200'e
çıkıyor. Sapma sıfırlanıyor.

Boyu 25 satırında aynı düzenek tersine dönüyor. Beklenen 96 çağrı zaten kotanın tam sınırındadır;
yeniden denemeler kotadan yediği için her pencerede birkaç sayfa yetişemiyor ve kuyruk büyüyor.
Sonuç, yeniden deneme **olmadan** alınan 2075 satıra karşılık yeniden deneme **ile** alınan
**2025 satırdır**. Düzeneği eklemek alınan satırı düşürmüştür. Yanına iki sayı daha yazılıyor:
**112 sayfa** en az bir pencere gecikmiş ve **15 sayfa** on iki pencere bittiğinde hâlâ kuyrukta
beklemektedir. Bu kursun ikinci iddiası tam olarak budur: orkestrasyon düzeneği de bozar, ve
bozduğunu ancak kendi sayacına bakan görür.

## Bağlayıcının Kendi Çağrı Defteri

Sıradaki blok üç kurulumu yan yana koyup kaybın **nereye** düştüğünü soruyor.

```python
TAM_KUME = set((b, d) for b in BOLGE for d in DONEM)
print("boyu kota deneme  alinan  satir orani  bolum_donem  donem basina alinan satir")
for boyu, kota, deneme in ((25, 8, 0), (25, 8, 2), (25, 12, 2)):
    al, tm, bs, gc, kal = baglayici(ham, boyu, kota, 0.15, deneme)
    say = [sum(1 for k in al if k["donem"] == d) for d in DONEM]
    gor = set((k["bolge"], k["donem"]) for k in al)
    print(f"{boyu:>4} {kota:>4} {deneme:>6} {len(al):>7} {(2400 - len(al)) / 2400:>12.4f} "
          f"{str(gor != TAM_KUME):>12}  {say}")
print()
for boyu, kota, deneme in ((25, 8, 0), (25, 8, 2), (25, 12, 2)):
    s, t = okuma_sonucu(baglayici(ham, boyu, kota, 0.15, deneme)[0])
    print(f"boyu {boyu} kota {kota} deneme {deneme}",
          {b: round(s.get(b, 0) - dogru_sun[b], 2) for b in dogru_sun})
```

```
boyu kota deneme  alinan  satir orani  bolum_donem  donem basina alinan satir
  25    8      0    2075       0.1354        False  [175, 175, 175, 150, 175, 125, 200, 175, 200, 175, 150, 200]
  25    8      2    2025       0.1562         True  [200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 25, 0]
  25   12      2    2400       0.0000        False  [200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200]

boyu 25 kota 8 deneme 0 {'merkez': -373.72, 'kuzey': -302.19, 'dogu': -278.0, 'bati': -190.91, 'guney': -367.28}
boyu 25 kota 8 deneme 2 {'merkez': -124.85, 'kuzey': -118.25, 'dogu': -82.06, 'bati': -78.39, 'guney': -105.05}
boyu 25 kota 12 deneme 2 {'merkez': 0.0, 'kuzey': 0.0, 'dogu': 0.0, 'bati': 0.0, 'guney': 0.0}
```

İkinci satırın dönem dizisi dersin en ters sonucudur. Yeniden denemeli kurulum **daha az satır
alıyor** ama sunum sapması **daha küçük**: −374 … −191 yerine −125 … −78. Sebep kaybın miktarında
değil **yerindedir**. Yeniden denemesiz kurulumda kayıp on iki döneme dağılmıştır ve her dönemin
toplamını aşağı çeker; yeniden denemeli kurulumda ilk on dönem **eksiksiz** alınmış, kuyruk
büyüdüğü için 2026-11 yalnız 25 satır almış ve 2026-12 **hiç alınmamıştır**. Bölge ortalaması var
olan dönemler üzerinden hesaplandığı için sunum düzelmiş görünür. Sunulan sayının iyileşmesi
verinin iyileştiği anlamına gelmez.

Kaybı kim bildiriyor sorusunun cevabı da iki satırda ayrılıyor. Dağınık kayıpta dönem duyarlı
bütünlük denetimi **yeşil kalıyor**, çünkü her bölge her dönemde hâlâ görünüyor; yakalayan tek
şey 0,1354 oranıyla satır sayısı denetimidir. Kuyruk kaybında ise aynı denetim **ateşliyor**, çünkü
bir dönemin hiçbir satırı yoktur. İkisinden de ucuzu hattın içinde değil bağlayıcının kendi
defterindedir: beklenen 96 çağrıya karşılık 83 tamamlanmıştır ve bu fark **hiçbir aşama
beklemeden**, çağrı biter bitmez bilinir. Kotayı sekizden on ikiye çıkarmak son satırı üretir —
96 çağrının hepsi tamamlanır, 2400 satır alınır, sapma boşalır ve geciken sayfa kalmaz.

## Özet

- Bir bağlayıcının işi kısıt altında sayılır: sayfa boyu 25 iken 96 çağrı gerekir, 100 iken 24;
  çağrı sayısı sayfa boyuyla ters orantılıdır ve hız sınırı olan bir kaynakta doğrudan kazançtır.
- Kaçan satır, düşen çağrı sayısı ile sayfa boyunun çarpımıdır: 13 çağrı 325 satır, 9 çağrı 450
  satır, 4 çağrı 400 satır. Sayfa boyunu büyütmek tek bir başarısızlığın bedelini aynı oranda
  büyütür.
- Kaçan satır hattın içinde büyür: 450 satırlık eksik, tüketim bir fark hesabı olduğu için 900
  satırlık kayba dönüşür.
- Yeniden deneme kotanın altında bedavadır ve 2400 satırın hepsini geri getirir; kotanın sınırında
  kotayı yer, 112 sayfayı geciktirir ve alınan satırı 2075'ten 2025'e düşürür.
- Kayıp kuyruğun sonunda toplandığında sunum sapması küçülür (−125 … −78) ama iki dönem tamamen
  yok olur; bunu satır sayısı değil dönem duyarlı bütünlük denetimi görür, en ucuzunu ise
  bağlayıcının çağrı defteri gecikmesiz bildirir.

## Sonraki Adım

Bu dersteki bağlayıcı kaynağı **çekti**: ne zaman okuyacağına kendi karar verdi, kotasını kendi
harcadı ve kaçırdığını kendi defterinden bildi. Kaynağın veriyi kendiliğinden **ittiği** bir
düzenek bu dengeyi tersine çevirir. Kayıtlar bir **konuya** yazılır, konu **bölümlere** ayrılır ve
bölümleri bir **tüketici grubu** okur. Sonraki ders bu düzeneği iki sayı üzerinden ölçer: bölüm
sayısının tüketicilere dağıttığı iş, ve bölüm başına sıra korunumu. Ölçülecek takas şudur: bölüm
sayısı arttıkça paralellik artar, ama aynı abonenin kayıtları farklı bölümlere düştüğünde tüketim
hesabının dayandığı sıra kırılır.
