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.