İçeriğe geç
academia.sh

Ders 02 / 11

Barındırıcı, İstemci ve Sunucu

Üç rolün sorumluluk dağılımının mesajla sayılması: on kalem üç role dağıtılır, doğru dağılım hiçbir uzlaşma mesajı gerektirmez ve rol sınırını geçen her kalem kapsamı ile uzaklığının çarpımı kadar mesaj ekler. Barındırıcı ile sunucu hiç doğrudan konuşmadığı için aralarındaki uzaklık iki, istemciyle olan uzaklık birdir; araç tanımı barındırıcıya taşınınca 12, istemciye taşınınca 6 mesaj eklenir, izin listesi sunucuya taşınınca 12, bağlam ve durum sunucuya taşınınca 2 mesaj eklenir. On kalemin tamamı tek rolde toplandığında barındırıcıda 51, sunucuda 45, istemcide 33 mesaj birikir, doğru dağılımda ise sıfır. Aynı üç araçlık zincir doğru dağılımda 6 istek, 6 yanıt, 179 zarf belirteci ve 9 gidiş-dönüş tutarken oturum sunucuya kaydığında 9, 9, 254 ve 12 olur, izin listesi sunucuya kaydığında 12, 12, 341 ve 15 olur; iki farklı abonenin koşumu aynı sayımı verir.

İçindekiler

Önceki derste üç rol adlandırıldı ve aralarındaki mesajlar sayıldı: aynı üç araçlık zincir protokolsüz tabanda sıfır mesajla, protokollü kurulumda 6 istek, 6 yanıt, 179 zarf belirteci ve 9 gidiş-dönüşle 844 sonucunu verdi. Adlandırma yapıldı, dağılım yapılmadı. İzin listesi barındırıcıda mı istemcide mi durur, araç tanımının tek doğru yeri neresidir, oturumu kim tutar, onayı kim ister?

Bu soruların yanıtı bir üslup tercihi değildir. Bir kalem yanlış rolde durduğunda o kalemi kullanan taraf onu elinde tutmaz, karşı tarafa sormak zorunda kalır; her sorma bir istek, her yanıt bir mesajdır. Sorumluluk dağılımı bu yüzden sayılabilir bir şeydir: doğru dağılım, hiçbir kalemin uzlaşma mesajı gerektirmediği dağılımdır ve yanlış dağılımın bedeli mesaj cinsinden yazılır. Bu ders on kalemi üç role dağıtır, her kalemin sınırı geçtiğinde kaç mesaj eklediğini sayar ve aynı zinciri dört yerleşimde koşturur.

  • PY10. Ortam, üç kurgu sunucu ve protokol benzeticisi kurgudur; gerçek bir sunucu ya da çalışma zamanı çağrılmaz. Tohum 20260218. Zarfın sabit bedeli sekiz belirteçtir.
  • PY11. On kalem üç role dağıtılır. Doğru dağılım, hiçbir kalemin uzlaşma mesajı gerektirmediği dağılımdır ve taban çizgisi budur.
  • PY12. Barındırıcı ile sunucu hiç doğrudan konuşmaz; arada istemci vardır. Bu yüzden barındırıcı ile sunucu arasındaki uzaklık iki, istemciyle olan uzaklık birdir.
  • PY13. Kalemin kapsamı, kaç kez uzlaşılması gerektiğidir: sunucu başına ya da çağrı başına olan kalemlerde üç, oturum başına olanlarda bir.
  • PY14. Kalemin biçimi iki değer alır: çift bir istek ile bir yanıt, tek ise yanıtsız bir bildirim üretir.
  • PY15. Eklenen mesajlar yerel aktarım fiyatıyla sayılır; uzak aktarımda gidiş-dönüş iki katıdır ve bu ders yalnız alt sınırı basar.
  • PY16. Sayımlar koşumdan bağımsızdır; ikinci koşum aynı dört yerleşimi başka bir abone için çalıştırır. Bu ders oran basmaz, sayım basar; bildirilen beş araçlık kümenin çözünürlüğü burada bağlayıcı değildir.
  • PY17. İzin listesinin ve onay noktasının kendi ölçümü Yapay Zekâ Ajanları kursunda yapıldı ve tekrarlanmaz: izin listesi tam yetkiye göre başarımı 0,9583’ten 0,8333’e indirmiş, 20 çağrıyı durdurmuştu. Burada ölçülen şey o kalemin yerinin bedelidir.

Kalemin Doğru Rolü

Sunucuda duran üç kalem araç tanımı, araç yürütmesi ve yetenek bildirimidir. Ortak yanları şudur: üçü de aracın kendisine aittir ve araç değiştiğinde birlikte değişirler. Bir aracın alan adları değiştiğinde tanım, işleyici ve bildirim aynı anda güncellenir; üçü ayrı yerlerde dururlarsa değişiklik üç yerde eşzamanlı yapılmak zorundadır.

İstemcide duran üç kalem oturum, zarflama ile sayım ve aktarım seçimidir. Ortak yanları şudur: üçü de bağlantıya aittir, araca değil. Bir sunucunun yerel mi uzak mı olduğu ne barındırıcıyı ne aracı ilgilendirir; ikisi de aynı sonucu bekler. Aktarım seçimi barındırıcıya taşınırsa barındırıcı her sunucunun bağlantı biçimini bilmek zorunda kalır ve sunucu sayısı değiştikçe barındırıcı değişir.

Barındırıcıda duran dört kalem izin listesi, onay noktası, bağlam ile durum ve model çağrısıdır. Ortak yanları şudur: dördü de kullanıcıya ve karara aittir. Bu grubun en kritik üyesi izin listesidir: bir sunucuya “hangi araçlara izniniz var” diye sorulamaz, çünkü sunucu kendi yetki yüzeyini kendisi belirlerse izin listesi diye bir şey kalmaz. Yetki kararı, o kararın sonucuna katlanacak tarafta durur.

Aşağıdaki kod önceki dersin kurgu ortamını ve benzeticisini kurar, sonra on kalemi bir tabloya yazar. tasi, bir kalemi başka bir role koyduğunda iki tarafın onu birbirine anlatması için gereken mesajları gerçekten üretir; sayı mesafe ile kapsam çarpımından gelir.

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


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


# ---- KURGU ortam: olcum aginin abone kayitlari
BOLGE = ["dogu", "bati", "kuzey", "guney", "merkez"]
TIP = ["mesken", "isyeri"]
ABONE = {}
for i in range(60):
    r = uretec(TOHUM + 31 * i)
    onceki = 10000 + int(r() * 80000)
    ABONE[f"A{i + 1:03d}"] = {"bolge": BOLGE[int(r() * 5)], "tip": TIP[int(r() * 2)],
                              "onceki": onceki, "simdiki": onceki + int(r() * 70)}
BASAMAK, USTU, ISYERI_KAT = ((10, 4), (25, 7), (40, 11)), 16, 2


def _bedel(m3, tip):
    kalan, alt, top = m3, 0, 0
    for ust, birim in BASAMAK:
        dilim = min(kalan, ust - alt)
        if dilim <= 0:
            break
        top += dilim * birim
        kalan -= dilim
        alt = ust
    return (top + kalan * USTU) * (ISYERI_KAT if tip == "isyeri" else 1)


def t_sayac(abone=None, **_):
    a = ABONE.get(abone)
    return {"hata": "abone yok"} if a is None else {
        "onceki": a["onceki"], "simdiki": a["simdiki"], "tip": a["tip"]}


def t_tuketim(onceki=None, simdiki=None, **_):
    if onceki is None or simdiki is None:
        return {"hata": "eksik alan"}
    f = simdiki - onceki
    return {"m3": f + 100000 if f < 0 else f}


def t_tarife(m3=None, tip="mesken", **_):
    return {"hata": "eksik alan"} if m3 is None else {"tutar": _bedel(m3, tip)}


def t_bolge(bolge=None, **_):
    if bolge not in BOLGE:
        return {"hata": "bolge yok"}
    n = sum(1 for a in ABONE.values() if a["bolge"] == bolge)
    return {"bolge": bolge, "abone": n}


def t_kayit(abone=None, sutun=None, deger=None, **_):
    if not (abone and sutun and deger is not None):
        return {"hata": "eksik alan"}
    return {"yazildi": True}


# ---- KURGU sunucular: her biri yetenek bildirir
SUNUCU = {
    "olcum": {"surum": 2, "aktarim": "yerel",
              "arac": {"sayac_oku": {"islev": t_sayac, "alan": ("abone",), "yan_etki": False},
                       "tuketim": {"islev": t_tuketim, "alan": ("onceki", "simdiki"),
                                   "yan_etki": False}},
              "kaynak": ("abone_listesi",), "istem": ()},
    "tarife": {"surum": 1, "aktarim": "uzak",
               "arac": {"tarife": {"islev": t_tarife, "alan": ("m3", "tip"), "yan_etki": False}},
               "kaynak": ("basamak_tablosu",), "istem": ("bedel_aciklamasi",)},
    "kayit": {"surum": 3, "aktarim": "uzak",
              "arac": {"bolge_ozet": {"islev": t_bolge, "alan": ("bolge",), "yan_etki": False},
                       "kayit_yaz": {"islev": t_kayit, "alan": ("abone", "sutun", "deger"),
                                     "yan_etki": True}},
              "kaynak": (), "istem": ()},
}
ISTEMCI_SURUM = {"olcum": 2, "tarife": 1, "kayit": 2}      # kayit sunucusu ileride
IZIN = ("sayac_oku", "tuketim", "tarife", "bolge_ozet")     # kayit_yaz izin listesinde yok

SAYIM = {"istek": 0, "yanit": 0, "bildirim": 0, "belirtec": 0, "gidis_donus": 0}


def mesaj(tur, govde, aktarim="yerel"):
    """KURGU zarf. Gercek bir protokol uygulanmaz; sayilan sey zarfin bedelidir."""
    SAYIM[tur] += 1
    b = len(belirtecle(govde)) + 8                       # zarf sabiti
    SAYIM["belirtec"] += b
    if tur == "istek":
        SAYIM["gidis_donus"] += 2 if aktarim == "uzak" else 1
    return b


def elsikismasi(istemci_surum=None, izin=None):
    """Yetenek uzlasmasi: surum uyusmazligi ve izin listesi arac kumesini daraltir."""
    istemci_surum = ISTEMCI_SURUM if istemci_surum is None else istemci_surum
    izin = IZIN if izin is None else izin
    anlasilan, dusen = {}, []
    for ad, s in SUNUCU.items():
        mesaj("istek", f"yetenek sor {ad}", s["aktarim"])
        mesaj("yanit", f"yetenek bildir {ad} surum {s['surum']} "
                       + " ".join(s["arac"]) + " " + " ".join(s["kaynak"]))
        if istemci_surum.get(ad, 0) < s["surum"]:
            dusen.append((ad, "surum", s["surum"], istemci_surum.get(ad, 0)))
            continue
        for t, tan in s["arac"].items():
            if t not in izin:
                dusen.append((ad, "izin", t, None))
                continue
            anlasilan[t] = dict(tan, sunucu=ad, aktarim=s["aktarim"])
    return anlasilan, dusen


def cagir(anlasilan, ad, durum):
    if ad not in anlasilan:
        return {"hata": "arac bildirilmedi"}
    t = anlasilan[ad]
    kw = {a: durum[a] for a in t["alan"] if a in durum}
    mesaj("istek", f"{ad} " + " ".join(f"{k} {v}" for k, v in kw.items()), t["aktarim"])
    s = t["islev"](**kw)
    mesaj("yanit", " ".join(f"{k} {v}" for k, v in s.items()))
    return s


# ---- KURGU sorumluluk dagilimi: kalem -> (dogru rol , kapsam , mesaj bicimi)
ROL = ("barindirici", "istemci", "sunucu")
KALEM = {
    "arac tanimi":       ("sunucu", 3, 2), "arac yurutmesi":  ("sunucu", 3, 2),
    "yetenek bildirimi": ("sunucu", 3, 2), "oturum":          ("istemci", 3, 2),
    "zarflama ve sayim": ("istemci", 3, 1), "aktarim secimi":  ("istemci", 3, 2),
    "izin listesi":      ("barindirici", 3, 2), "onay noktasi": ("barindirici", 3, 2),
    "baglam ve durum":   ("barindirici", 1, 1), "model cagrisi": ("barindirici", 1, 2),
}


def mesafe(a, b):
    """Barindirici ile sunucu hic dogrudan konusmaz; arada istemci vardir."""
    return 0 if a == b else (1 if "istemci" in (a, b) else 2)


def tasi(kalem, yeni_rol):
    """Kalem dogru rolunun disinda durursa iki taraf onu her kapsam biriminde
    birbirine anlatir; ciftte istek ve yanit, tekte tek yonlu bildirim."""
    dogru, kapsam, bicim = KALEM[kalem]
    n = mesafe(dogru, yeni_rol) * kapsam
    for i in range(n):
        if bicim == 2:
            mesaj("istek", f"{kalem} uzlas {i}")
            mesaj("yanit", f"{kalem} uzlasildi {i}")
        else:
            mesaj("bildirim", f"{kalem} bildir {i}")
    return n * bicim


print(f"{'kalem':<19}{'dogru rol':<14}" + "".join(f"{r + 'de':>15}" for r in ROL))
toplam = dict.fromkeys(ROL, 0)
for k, (dogru, kapsam, bicim) in KALEM.items():
    ek = []
    for r in ROL:
        for j in SAYIM:
            SAYIM[j] = 0
        ek.append(tasi(k, r))
        toplam[r] += ek[-1]
    print(f"{k:<19}{dogru:<14}" + "".join(f"{e:>15}" for e in ek))
print(f"{'rol basina kalem':<19}{'':<14}"
      + "".join(f"{sum(1 for v in KALEM.values() if v[0] == r):>15}" for r in ROL))
print(f"{'tumu tek rolde':<19}{'':<14}" + "".join(f"{toplam[r]:>15}" for r in ROL))
kalem              dogru rol       barindiricide      istemcide       sunucude
arac tanimi        sunucu                     12              6              0
arac yurutmesi     sunucu                     12              6              0
yetenek bildirimi  sunucu                     12              6              0
oturum             istemci                     6              0              6
zarflama ve sayim  istemci                     3              0              3
aktarim secimi     istemci                     6              0              6
izin listesi       barindirici                 0              6             12
onay noktasi       barindirici                 0              6             12
baglam ve durum    barindirici                 0              1              2
model cagrisi      barindirici                 0              2              4
rol basina kalem                               4              3              3
tumu tek rolde                                51             33             45

Rol Sınırını Geçmenin Bedeli

Tablonun köşegeni sıfırdır: her kalem kendi doğru rolünde durduğunda hiçbir uzlaşma mesajı gerekmez. Dağılım dört kalemi barındırıcıya, üçünü istemciye, üçünü sunucuya veriyor. Bu dağılım bir zevk meselesi değil, sıfır sütununun tanımıdır.

Sayılar iki çarpandan gelir. Birincisi uzaklıktır: araç tanımı istemciye kaydığında 6, ta barındırıcıya kaydığında 12 mesaj ekliyor. Aradaki iki kat, barındırıcı ile sunucunun hiç doğrudan konuşmamasından gelir; barındırıcıya giden her bilgi istemciden bir kez daha geçer. İkincisi kapsamdır: izin listesi çağrı başına uzlaşılması gereken bir kalemdir ve sunucuya kaydığında 12 mesaj ekler, oysa bağlam ile durum oturum başına bir kez uzlaşılır ve aynı sınırı geçtiğinde yalnız 2 bildirim ekler. Aynı yanlışlık, kapsamı büyük kalemde altı kat pahalıdır.

Son satır dağılımın toplam sayısıdır. On kalemin tamamı barındırıcıya toplanırsa 51 mesaj, sunucuya toplanırsa 45, istemciye toplanırsa 33 mesaj birikiyor; doğru dağılımda sıfır. İstemcinin en ucuz toplanma yeri olması rastlantı değildir: istemci ikisinin ortasındadır ve hiçbir kaleme iki adım uzakta değildir. Bu, her şeyi istemciye yığmanın doğru olduğu anlamına gelmez — üçüncü satırdaki 33 mesaj hâlâ ödenmiş bir bedeldir ve bu ders yalnız mesajı sayar, izin listesi sunucuya kaydığında kimin karar verdiğinin değiştiğini saymaz.

Aynı Zincir, Dört Yerleşim

Tablo kalemleri tek tek ölçtü. Aşağıdaki kod aynı üç araçlık zinciri dört farklı yerleşimle baştan sona koşturur ve toplam sayımı basar. İkinci koşum aynı dört yerleşimi başka bir abone için tekrarlar.

DOGRU = {k: v[0] for k, v in KALEM.items()}
SENARYO = [("dogru dagilim", DOGRU),
           ("oturum sunucuda", dict(DOGRU, **{"oturum": "sunucu"})),
           ("izin listesi sunucuda", dict(DOGRU, **{"izin listesi": "sunucu"})),
           ("arac tanimi barindiricida", dict(DOGRU, **{"arac tanimi": "barindirici"}))]


def kurulum(yerlesim, abone):
    """Ayni ucluk zincir; tek fark kalemlerin hangi rolde durdugu."""
    for k in SAYIM:
        SAYIM[k] = 0
    for kalem, rol in yerlesim.items():
        tasi(kalem, rol)
    anlasilan, _ = elsikismasi()
    durum = {"abone": abone}
    for ad in ("sayac_oku", "tuketim", "tarife"):
        durum.update(cagir(anlasilan, ad, durum))
    return durum["tutar"], dict(SAYIM)


print("abone  yerlesim                    sonuc  istek  yanit  bildirim"
      "  zarf belirteci  gidis-donus")
for abone in ("A017", "A031"):
    for ad, y in SENARYO:
        t, s = kurulum(y, abone)
        print(f"{abone}   {ad:<26} {t:>5} {s['istek']:>6} {s['yanit']:>6}"
              f" {s['bildirim']:>9} {s['belirtec']:>15} {s['gidis_donus']:>12}")
abone  yerlesim                    sonuc  istek  yanit  bildirim  zarf belirteci  gidis-donus
A017   dogru dagilim                844      6      6         0             179            9
A017   oturum sunucuda              844      9      9         0             254           12
A017   izin listesi sunucuda        844     12     12         0             341           15
A017   arac tanimi barindiricida    844     12     12         0             341           15
A031   dogru dagilim                 89      6      6         0             179            9
A031   oturum sunucuda               89      9      9         0             254           12
A031   izin listesi sunucuda         89     12     12         0             341           15
A031   arac tanimi barindiricida     89     12     12         0             341           15

Dört yerleşim aynı sonucu veriyor: A017 için 844, A031 için 89. Yerleşim hesabı değiştirmez, yalnız fiyatını değiştirir. Doğru dağılımda zincir 179 zarf belirteci tutuyor; tek bir kalem bir sınır kaydığında 254’e, iki adım kaydığında 341’e çıkıyor. Bir kalemin yanlış rolde durması, işin kendisini iki katına yakın pahalılaştırıyor ve zincirin gidiş-dönüşü dokuzdan on beşe yükseliyor.

Üçüncü ve dördüncü satırların aynı olması öğreticidir. İzin listesi barındırıcıdan sunucuya, araç tanımı sunucudan barındırıcıya kayıyor; yönler zıt, sayılar birebir aynı. Bedeli belirleyen şey kalemin ne olduğu değil, kaç sınır geçtiği ve kaç kez uzlaşıldığıdır. İki yerleşim mesaj cinsinden ayırt edilemez; ayırt eden şey mesaj değil, yetki kararının kimde durduğudur ve o bu tabloda görünmez.

İki abonenin dört satırı da birebir aynı. Yerleşimin bedeli veriye bağlı değildir; sözleşmenin biçimine bağlıdır. Bir araç bağlantısının sayısı aracın sayısı değil sözleşmenin sayısıdır.

Özet

  • Üç rolün doğru dağılımı, hiçbir kalemin uzlaşma mesajı gerektirmediği dağılımdır: dört kalem barındırıcıda, üçü istemcide, üçü sunucuda durur.
  • Sunucudaki kalemler araca, istemcidekiler bağlantıya, barındırıcıdakiler kullanıcıya ve karara aittir; izin listesi sunucuya sorulamaz, çünkü kararın sonucuna katlanan taraf barındırıcıdır.
  • Rol sınırını geçen bir kalem, uzaklık ile kapsamın çarpımı kadar mesaj ekler: araç tanımı istemciye kayınca 6, barındırıcıya kayınca 12 mesaj; bağlam ile durum sunucuya kayınca 2 bildirim.
  • Barındırıcı ile sunucu hiç doğrudan konuşmadığı için aradaki uzaklık ikidir ve bu, iki uçtaki kalemlerin yanlış yerleşimini iki kat pahalı yapar.
  • On kalemin tamamı tek rolde toplanırsa barındırıcıda 51, sunucuda 45, istemcide 33 mesaj birikir; doğru dağılımda sıfır.
  • Aynı zincir doğru dağılımda 179 zarf belirteci ve 9 gidiş-dönüş, izin listesi sunucuya kayınca 341 zarf belirteci ve 15 gidiş-dönüş tutar; iki abone için sayım birebir aynıdır.

Sonraki Adım

Bu derste yerleşim değişti, aktarım değişmedi: olcum yerelde, tarife ile kayit uzakta duruyordu ve eklenen bütün mesajlar yerel fiyatla sayıldı. Oysa gidiş-dönüş sütunu istek sütunundan bağımsız hareket ediyor; doğru dağılımda 6 istek 9 gidiş-dönüş üretti. Bu farkın kaynağı aktarımdır ve tek başına ölçülmeyi hak eder. Sonraki ders aynı iş yükünü üç aktarım kurulumunda koşturur: hepsi yerel, hepsi uzak ve ikisinin karışımı. İstek sayısı sabit kalırken gidiş-dönüşün ne yaptığı orada görünecek.

İ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