İçeriğe geç
academia.sh

Ders 05 / 11

Sunucu Yetenekleri

Bildirilen yetenek ile anlaşılan yetenek arasındaki farkın sayılması: üç kurgu sunucu 5 araç, 2 kaynak ve 1 istem bildiriyor, istemcinin izin listesi 4 araç taşıyor ve el sıkışmasından yalnız 3 araç çıkıyor. İki koşum aynı bedeli ödüyor — 3 istek, 3 yanıt, 99 belirteç, 5 gidiş-dönüş ve 0 hata — ama sonuçları ayrışıyor: sürümler hizalıyken 4 araç anlaşılıyor ve izin listesi kayit_yaz aracını kasten düşürüyor, sürüm sapmalıyken kayit sunucusunun tamamı düşüyor ve izin listesinde bulunan bolge_ozet aracı hiçbir hata üretmeden kayboluyor. Bir sunucunun düşmesi araçlarıyla birlikte kaynak ve istem bildirimlerini de götürüyor; olcum düşerse anlaşılan araç 2'ye iniyor. İki kayıp aynı hata metnini veriyor, biri kasıt biri kazadır.

İçindekiler

Önceki derste veri katmanının üç mesaj türü sayıldı: istek, yanıt ve bildirim. Sekiz abonelik toplu iş 48 mesaja bölündü, 640 belirteç etti ve bunun 384’ü yalnız zarftı. Ama o mesajların hepsi anlaşılmış bir araç kümesi üzerinde çalıştı ve o kümenin nasıl oluştuğu sorulmadı.

Bu ders o kümeyi kurar. Bir sunucu bağlandığında ne yapabildiğini kendisi bildirir; bu bildirim üç kalem taşır: araç, kaynak (resource) ve istem. İstemci bildirilenin tamamını almaz. Ölçülecek olan bildirilen ile anlaşılan arasındaki farktır ve bu farkın kaç mesajda, hangi hatayla oluştuğudur. Ders bir de ters yönde okunur: protokolsüz kurulumda beş aracın hepsi elin altındaydı; protokol bu kümeyi daraltıyor ve daraltmanın bir kısmı kasıt, bir kısmı kazadır.

  • PY38. Ortam, üç sunucu, araçlar ve zarf sayımı kurgudur; gerçek bir sunucu, istemci kitaplığı ya da çalışma zamanı çağrılmaz. Tohum 20260218. El sıkışmasında rastgelelik yoktur: bu dersin bütün sayıları koşumdan bağımsızdır ve iki koşum, aynı sunucu kümesine bağlanan iki istemci yapılandırmasıdır.
  • PY39. Yetenek bildirimi (capability declaration) üç kalem taşır: çağrılabilir araç, okunabilir kaynak ve hazır istem. Bu kursta yalnız araç çağrılır; kaynak ile istem bildirim olarak sayılır ve erişim hattı kurulmaz.
  • PY40. Yetenek uzlaşması (capability negotiation) el sıkışmasında geçer: istemci her sunucuya yetenek sorar, sunucu bildirir, istemci iki süzgeçten geçirir.
  • PY41. Birinci süzgeç sürüm sapmasıdır (version skew): istemcinin bildiği sürüm sunucunun sürümünden küçükse o sunucunun tamamı düşer.
  • PY42. İkinci süzgeç izin listesidir: listede olmayan araç, sunucusu geçse bile alınmaz.
  • PY43. İki süzgeç de el sıkışmasının yanıtından sonra çalışır; bedel ödendikten sonra daralma olur ve daralma hata üretmez.
  • PY44. Protokolsüz taban budur: beş aracın beşi de ders içinde tanımlıdır, el sıkışması yoktur, hiçbir araç düşmez.
  • PY45. Küme küçüktür: üç sunucu, beş bildirilen araç, dört izinli araç. Bu kümede bir oranın en küçük adımı 1/5 = 0,2000’dir; bundan küçük fark ölçülemez, bu yüzden oran yerine sayım basılır.
  • PY46. Yetenek uzlaşması iki yönlüdür ve istemci de kendi yeteneklerini bildirir. Bu kurgu yalnız sunucu tarafını modeller, çünkü ölçülen şey sunucunun bildirdiğinin ne kadarının alındığıdır.

Sunucunun Bildirdiği

Bir sunucunun bildirimi bir araç listesinden ibaret değildir. Üç kalem taşır ve üçü de aynı yanıtın içinde gelir. Araç çağrılabilir bir işlevdir; bir adı, alanları ve yan etki bilgisi vardır. Kaynak okunabilir bir içeriktir; sunucunun istemciye açtığı bir belge, tablo ya da listedir. İstem hazır bir istem şablonudur; sunucu kendi alanını bilen bir metni istemciye verir. Gömme Vektörleri ve Erişim Artırılmış Üretim kursunda erişim hattının kendisi ölçülmüştü; burada o hat kurulmaz. Kaynak ile istem bu derste birer bildirim kalemi olarak sayılır, çünkü sunucu düştüğünde onlar da düşer ve bu düşüş araçla aynı sessizlikte olur.

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 ve araclar (M28/K05 ile ayni kurgu, burada sunucuya tasiniyor)
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


print("sunucu  surum aktarim  arac  kaynak  istem")
for ad, s in SUNUCU.items():
    print(f"{ad:<7} {s['surum']:>5} {s['aktarim']:<8} {len(s['arac']):>5}"
          f" {len(s['kaynak']):>7} {len(s['istem']):>6}")
print(f"bildirilen: {sum(len(s['arac']) for s in SUNUCU.values())} arac,"
      f" {sum(len(s['kaynak']) for s in SUNUCU.values())} kaynak,"
      f" {sum(len(s['istem']) for s in SUNUCU.values())} istem;"
      f" izin listesi {len(IZIN)} arac")
sunucu  surum aktarim  arac  kaynak  istem
olcum       2 yerel        2       1      0
tarife      1 uzak         1       1      1
kayit       3 uzak         2       0      0
bildirilen: 5 arac, 2 kaynak, 1 istem; izin listesi 4 arac

Protokolsüz taban bu tablonun tamamıdır: araçlar ders içinde tanımlı olsaydı beşinin de elin altında olurdu. İzin listesi dördünü onaylıyor. Aradaki tek araç kayit_yaz, tek yan etkili araçtır ve dışarıda bırakılması bir karardır — Yapay Zekâ Ajanları kursunda aynı liste 20 çağrıyı durdurmuştu ve o yordam burada tekrarlanmaz.

Bildirilen ile Anlaşılan

El sıkışması her sunucuya bir istek gönderir, bir yetenek yanıtı alır ve iki süzgeci yanıttan sonra çalıştırır. Aşağıdaki iki koşumda tek fark istemcinin kayit sunucusu için bildiği sürümdür. Web API Tasarımı kursunda sürümleme ve geriye uyum yordamı ölçülmüştü; burada tekrarlanmaz, yalnız sapmanın araç kümesine ne yaptığı sayılır.

def sifirla():
    for k in SAYIM:
        SAYIM[k] = 0


HIZALI = {"olcum": 2, "tarife": 1, "kayit": 3}     # istemci ucuncu sunucunun surumunu de biliyor

for etiket, sur in (("hizali", HIZALI), ("sapmali", ISTEMCI_SURUM)):
    sifirla()
    anlasilan, dusen = elsikismasi(sur)
    print(f"istemci kayit sunucusunu surum {sur['kayit']} biliyor  ({etiket})")
    print(f"  el sikismasi : {SAYIM['istek']} istek, {SAYIM['yanit']} yanit,"
          f" {SAYIM['belirtec']} belirtec, {SAYIM['gidis_donus']} gidis-donus, 0 hata")
    print(f"  anlasilan {len(anlasilan)} : {' '.join(sorted(anlasilan))}")
    for s_ad, tur, a, b in dusen:
        neden = f"arac {a} izin listesinde yok" if tur == "izin" else \
            f"sunucu surum {a}, istemci surum {b}"
        print(f"  dusen        : {s_ad} sunucusu, {neden}")
istemci kayit sunucusunu surum 3 biliyor  (hizali)
  el sikismasi : 3 istek, 3 yanit, 99 belirtec, 5 gidis-donus, 0 hata
  anlasilan 4 : bolge_ozet sayac_oku tarife tuketim
  dusen        : kayit sunucusu, arac kayit_yaz izin listesinde yok
istemci kayit sunucusunu surum 2 biliyor  (sapmali)
  el sikismasi : 3 istek, 3 yanit, 99 belirtec, 5 gidis-donus, 0 hata
  anlasilan 3 : sayac_oku tarife tuketim
  dusen        : kayit sunucusu, sunucu surum 3, istemci surum 2

İki koşumun bedeli birebir aynıdır: 3 istek, 3 yanıt, 99 belirteç, 5 gidiş-dönüş ve iki koşumda da sıfır hata. Sonuçları ayrışıyor. Sürümler hizalıyken anlaşılan araç dört, sapmalıyken üç. Kaybolan araç bolge_ozet, ve o araç izin listesindedir — istemci onu kullanmayı açıkça onaylamıştır. Sunucusunun sürümü uymadığı için alınmadı.

İki düşüş satırı aynı kümede duruyor ama aynı şey değiller. kayit_yaz düşüşü kasıttır: yan etkili araç izin listesine konmadı ve protokol bu kararı uyguladı. bolge_ozet düşüşü kazadır: kimse bu aracı dışarıda bırakmaya karar vermedi, istemcinin bildiği sürüm numarası eskiydi. İkisi de aynı sessizlikte oldu; el sıkışması ikisi için de sıfır hata bildirdi. Kursun ikinci iddiasının ikinci örneği budur: standartlaştırmak da bozar. Protokolsüz kurulumda beş araç elin altındaydı, protokollü kurulumda üç kaldı ve düşen ikisinden biri istenmeyen bir kayıptır.

Sunucu Düştüğünde Ne Gider

Sapma bir aracı değil bir sunucuyu düşürüyor. Bunun ölçüsü, her sunucunun sürümü bir eksik bilindiğinde nelerin gittiğidir. Aynı çağrı iki yapılandırmada da denenir; hata metni aynıdır.

print("dusen sunucu  kaybolan arac  kaynak  istem   kalan anlasilan arac")
for ad, s in SUNUCU.items():
    anlasilan, _ = elsikismasi(dict(HIZALI, **{ad: s["surum"] - 1}))
    print(f"{ad:<13} {len(s['arac']):>13} {len(s['kaynak']):>7} {len(s['istem']):>6}"
          f" {len(anlasilan):>22}")

print("\nayni hata metni, iki ayri neden:")
for etiket, sur in (("hizali ", HIZALI), ("sapmali", ISTEMCI_SURUM)):
    anlasilan, _ = elsikismasi(sur)
    print(f"  {etiket}  bolge_ozet -> {cagir(anlasilan, 'bolge_ozet', {'bolge': 'dogu'})}")
    print(f"  {etiket}  kayit_yaz  -> "
          f"{cagir(anlasilan, 'kayit_yaz', {'abone': 'A017', 'sutun': 'bedel', 'deger': 844})}")
dusen sunucu  kaybolan arac  kaynak  istem   kalan anlasilan arac
olcum                     2       1      0                      2
tarife                    1       1      1                      3
kayit                     2       0      0                      3

ayni hata metni, iki ayri neden:
  hizali   bolge_ozet -> {'bolge': 'dogu', 'abone': 11}
  hizali   kayit_yaz  -> {'hata': 'arac bildirilmedi'}
  sapmali  bolge_ozet -> {'hata': 'arac bildirilmedi'}
  sapmali  kayit_yaz  -> {'hata': 'arac bildirilmedi'}

Tablo düşüşün birimini gösteriyor. Bir sunucunun sürümü uymadığında yalnız bir araç değil, o sunucunun bütün bildirimi gider: olcum düşerse iki araç ve bir kaynak, tarife düşerse bir araç, bir kaynak ve bir istem. Kaynak ile istem bu kursta çağrılmıyor, ama sayıda duruyorlar çünkü kaybolan yetenek yalnız çağrılabilir olan değildir. En sert satır ilk satırdır: olcum yerel aktarımda çalışan ve en çok kullanılan sunucudur, düştüğünde anlaşılan araç dörtten ikiye iner.

Son dört satır sessizliğin nasıl göründüğünü veriyor. Sürümler hizalıyken bolge_ozet çağrısı doğu bölgesinde 11 abone döndürüyor. Sapmalı yapılandırmada aynı çağrı, aynı kod ve aynı istemle {'hata': 'arac bildirilmedi'} veriyor — kayit_yaz çağrısının verdiği metnin aynısı. Kasıtlı düşüş ile kazayla düşüş çağrı anında ayırt edilemez; ayırt eden tek şey el sıkışmasının düşen listesidir, ve o liste ancak sayılırsa görünür.

Sayının biçimi de bir karardır. Anlaşılan üç araç bildirilen beşin 0,6000’idir, ama bu kümede bir oranın en küçük adımı 1/5 = 0,2000’dir: tek bir aracın gidip gelmesi oranı iki yüz birimlik adımlarla oynatır ve bundan küçük hiçbir fark ölçülemez. Bu yüzden bu derste oran değil sayım basılır — beş bildirilen, dört izinli, üç anlaşılan, bir kasıtlı düşüş, bir kazara düşüş.

Bu sayımın kime düştüğü de bir karardır. Sunucu bildirdiğini bilir, istemci aldığını bilir; ikisini yan yana koyan bir taraf yoksa fark hiçbir yerde durmaz. Kursun kuralı burada okunur: bir araç bağlantısının sayısı aracın sayısı değil sözleşmenin sayısıdır ve değiştiğinde kimin kırılacağı yazılmayan arayüz ölçülmemiş sayılır. Bu derste kırılan taraf istemcidir, kıran şey sunucunun sürüm numarasıdır ve arada hiçbir hata mesajı yoktur. İstemcinin elindeki tek çare el sıkışmasının iki ucunu saymaktır: kaç araç bildirildi, kaçı anlaşıldı, düşenlerin hangisi izin kararı hangisi sürüm sapması.

Özet

  • Bir yetenek bildirimi üç kalem taşır: çağrılabilir araç, okunabilir kaynak ve hazır istem; üçü de aynı yanıtta gelir ve sunucu düştüğünde üçü birden gider.
  • Üç kurgu sunucu 5 araç, 2 kaynak ve 1 istem bildiriyor; izin listesi 4 aracı onaylıyor ve el sıkışmasından 3 araç çıkıyor.
  • İki yapılandırma aynı bedeli ödüyor — 3 istek, 3 yanıt, 99 belirteç, 5 gidiş-dönüş ve 0 hata — ama sürümler hizalıyken 4, sapmalıyken 3 araç anlaşılıyor.
  • Sürüm sapması bir aracı değil bir sunucuyu düşürür: izin listesinde bulunan bolge_ozet hiçbir hata üretmeden kayboluyor; olcum düşseydi anlaşılan araç 2’ye inerdi.
  • Düşen iki araçtan biri kasıt biri kazadır ve çağrı anında ikisi de aynı hata metnini verir; ayrımı yalnız el sıkışmasının düşen listesi gösterir.
  • Beş araçlık kümede bir oranın en küçük adımı 0,2000’dir; bu yüzden oran değil sayım basılır.

Sonraki Adım

Beş derste model bağlam protokolü dışarıdan anlatıldı. Standartlaşmanın ne kazandırdığı, üç rolün sorumlulukları, aktarım katmanının gidiş-dönüş farkı, veri katmanının üç mesaj türü ve sunucunun bildirdiği yetenekler ölçüldü; her ölçünün yanına protokolsüz taban ile bedeli yazıldı. Ama bütün bu sayılar hazır kurulmuş bir kurgunun üzerinde okundu: hiçbir sunucu ve hiçbir istemci yazılmadı. Bir sunucunun yeteneğini gerçekten bildirmesi için hangi işleyicilerin yazılması gerektiği, bir istemcinin sunucuyu nasıl keşfedip oturum açtığı ve bu derste sayılan sessiz düşüşün istemci kodunda hangi satırda oluştuğu hiç sorulmadı. Sonraki konu protokolü kurmaktan gerçekleştirmeye geçer ve önce sunucu tarafını yazar.

İ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