İçeriğe geç
academia.sh

Ders 02 / 16

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.

İçindekiler

Ö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.

# 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.

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.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat