Ders 10 / 26
İstem Önbellekleme
Aynı 240 kurgu isteğin yedi önbellek kurulumunda ölçülmesi: istemin 186 belirtecinin 175'i bütün isteklerde ortaktır. İçeriğe göre anahtarlanan önek önbelleği 0,9792 isabetle giriş belirtecini 44367'den 7472'ye indiriyor ve doğru yanıt payını hiç değiştirmiyor. Soruya göre anahtarlanan yanıt önbelleğinde ömür uzadıkça isabet 0,4708'den 0,8792'ye çıkıyor, çağrı 240'tan 29'a düşüyor, ama bayat yanıt payı 0,0208'den 0,4417'ye tırmanıyor ve doğru yanıt payı 0,9333'ten 0,5542'ye iniyor. İki önbellek birlikte girişi 2946'ya indiriyor, yani on beş kat, ve yanıt önbelleği açıldığında önek isabeti 0,9792'den 0,9359'a düşüyor.
İçindekiler
Önceki derste ağır yükte 295 çağrı yapıldı ve bu çağrıların hepsi aynı yönergeyle başlıyordu. Yeniden deneme o tekrarı bir kat daha büyüttü: düzeltmek için gönderilen her çağrı, ortak metni bir kez daha belirteçledi ve bir kez daha ödedi. Tekrarın kendisi ölçülmemişti.
Bir destek yardımcısında bu tekrar iki katmanlıdır. Birincisi istemin öneki: yönerge ve saha ekibinin kurgu belge dağarcığı her istekte aynıdır ve istemin büyük bölümünü kaplar. İkincisi sorunun kendisi: birkaç soru bütün trafiğin yarısını üretir ve aynı soru gün boyunca onlarca kez sorulur. İki tekrarın da bir çaresi vardır ve iki çare aynı şey değildir. Bu ders ikisini ayrı ayrı kurar ve yan yana ölçer: önbellek isabeti yükseldikçe belirteç düşer, ama saklanan yanıtın bir yaşı olur ve dayandığı belge değiştiğinde yanıt hâlâ hızlı, hâlâ ucuz ve artık yanlıştır.
- UK9. Kod bir benzeticidir; gerçek bir uç nokta çağrılmaz. Dağarcık, sorular ve güncelleme takvimi kurgudur, tohum 20260218.
- UK10. Dağarcık on kurgu belgedir; her belgenin bir sürümü vardır ve dört ayrı adımda ikişer belge güncellenir.
- UK11. İstem iki parçalıdır: bütün isteklerde aynı olan önek (yönerge ile dağarcık) ve sorunun kendisi.
- UK12. Önek önbelleği içeriğe göre anahtarlanır. Önek bir önceki çağrıdakiyle birebir aynıysa isabet sayılır ve önek belirteçlerinin yüzde onu ödenir. Dağarcık değişirse önek de değişir.
- UK13. Yanıt önbelleği soruya göre anahtarlanır ve bir ömrü vardır. Ömür içindeki isabet çağrı yapmaz, hiç belirteç harcamaz.
- UK14. Bayat yanıt, önbellekten dönen ve dayandığı belgenin sürümü artık geçerli olmayan yanıttır.
- UK15. Doğru yanıt, etiketi doğru olan ve bayat olmayan yanıttır; bu dersin ürün ölçütü budur.
- UK16. İş yükü 120 adımda 240 istektir, adım başına iki; soru dağılımı çarpıktır.
İki Ayrı Önbellek, İki Ayrı Anahtar
Önce dağarcık ve sorular kurulur, sonra bir belge güncellenip aynı sorunun yanıtının ne olduğuna bakılır. Ayrım burada görünür hâle gelir: önek, dağarcık değişince kendiliğinden değişir; saklanmış bir yanıt ise değişmez.
# BENZETICI -- KURGUDUR. Gercek bir uc nokta cagrilmaz. Belge dagarcigi, sorular # ve guncelleme takvimi kurgudur, tohum 20260218. TOHUM, M32 = 20260218, 0xFFFFFFFF ADIM, ONEK_INDIRIM = 120, 0.10 # kosum uzunlugu, isabetli onegin odenen payi 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 ayrik(u, w): t = 0.0 for i, x in enumerate(w): t += x if u < t: return i return len(w) - 1 def belirtecle(m): b = [] for s in m.lower().replace(",", " , ").split(): while len(s) > 5: b.append(s[:5]) s = s[5:] b.append(s) return b def izno(m): h = 2166136261 for c in m: h = ((h ^ ord(c)) * 16777619) & M32 return h KONU = ["fatura", "ariza", "sayac", "tarife", "kesinti"] BELGE = [{"kod": "FT1", "konu": "fatura", "anahtar": "fatura tutari", "metin": "fatura tutari hesap donemi ve gecikme farki kurallari"}, {"kod": "FT2", "konu": "fatura", "anahtar": "fatura odemesi", "metin": "fatura odemesi yontemleri ve borc gorunumu kurallari"}, {"kod": "AR1", "konu": "ariza", "anahtar": "ariza kaydi", "metin": "ariza kaydi acma ve ekip yonlendirme yordami"}, {"kod": "AR2", "konu": "ariza", "anahtar": "baglanti bozuklugu", "metin": "baglanti bozuk oldugunda uygulanan denetim adimlari"}, {"kod": "SY1", "konu": "sayac", "anahtar": "sayac endeksi", "metin": "sayac endeks okumasi ve duzeltme yordami"}, {"kod": "SY2", "konu": "sayac", "anahtar": "sayac degisimi", "metin": "sayac degisimi randevu kurallari ve sure taahhudu"}, {"kod": "TA1", "konu": "tarife", "anahtar": "tarife basamagi", "metin": "tarife basamaklari ve abone tipine gore birim ucret"}, {"kod": "TA2", "konu": "tarife", "anahtar": "tarife degisikligi", "metin": "tarife degisikligi basvurusu ve gecerlilik kosullari"}, {"kod": "KS1", "konu": "kesinti", "anahtar": "planli kesinti", "metin": "planli kesinti duyurusu yayimlama ve takip kurallari"}, {"kod": "KS2", "konu": "kesinti", "anahtar": "mahalle kesintisi", "metin": "mahallede kesinti bildirimi ve tahmini donus suresi"}] for b in BELGE: b["surum"] = 1 SORU = [{"b": i, "konu": b["konu"], "metin": k.format(a=b["anahtar"])} for i, b in enumerate(BELGE) for k in ("{a} konusunda ne yapmam gerekiyor", "{a} icin gecerli kural nedir", "{a} ile ilgili son durum ne")] AGIRLIK = [1.0 / (i + 1) ** 1.0 for i in range(len(SORU))] AGIRLIK = [w / sum(AGIRLIK) for w in AGIRLIK] GUNCELLEME = {24: [6, 1], 48: [0, 8], 72: [2, 6], 96: [4, 7]} # adim -> belge IZ = {"fatur": "fatura", "tutar": "fatura", "borc": "fatura", "odeme": "fatura", "ariza": "ariza", "bozuk": "ariza", "bagla": "ariza", "kayit": "ariza", "sayac": "sayac", "endek": "sayac", "okuma": "sayac", "tarif": "tarife", "birim": "tarife", "abone": "tarife", "basam": "tarife", "kesin": "kesinti", "duyur": "kesinti", "mahal": "kesinti"} YONERGE = ("Asagidaki dagarcigi kullanarak soruyu yanitla . Yanitta once etiket , " "sonra dayandigin belge kodu ve surumu yaz . Dagarcik: ") SAYAC = [0] def onek(): return YONERGE + " ; ".join(f"{b['kod']} s{b['surum']} {b['metin']}" for b in BELGE) + " . Soru: " def cagir(soru, tohum=TOHUM): """KURGU uc nokta. Dagarcigin o andaki surumunu okur.""" SAYAC[0] += 1 istem = onek() + soru["metin"] bel = belirtecle(istem) p = {k: 0.15 for k in KONU} for t in belirtecle(soru["metin"]): if IZ.get(t) in p: p[IZ[t]] += 1.0 r = uretec((tohum ^ izno(soru["metin"])) + 7919 * SAYAC[0]) e = max(sorted(p), key=lambda a: p[a]) if r() > 0.10 else KONU[int(r() * 5)] b = BELGE[soru["b"]] return {"etiket": e, "kod": b["kod"], "surum": b["surum"], "giris": len(bel), "onek": len(belirtecle(onek())), "cikis": len(belirtecle(f"{e} {b['kod']} s{b['surum']}"))} def akis(tohum=TOHUM): """Her adimda iki istek; soru dagilimi carpiktir (birkac soru baskin).""" r = uretec(tohum + 991) return [(a, SORU[ayrik(r(), AGIRLIK)]) for a in range(ADIM) for _ in range(2)] for b in BELGE: b["surum"] = 1 ilk = cagir(SORU[0]) print("ilk cagri :", {k: ilk[k] for k in ("etiket", "kod", "surum", "giris", "onek")}) BELGE[0]["surum"] += 1 # dagarcik guncellendi ikinci = cagir(SORU[0]) print("guncelleme sonrasi:", {k: ikinci[k] for k in ("kod", "surum", "giris")}) print("saklanan yanit :", ilk["kod"], "s" + str(ilk["surum"]), "-> bayat" if ilk["surum"] != BELGE[0]["surum"] else "-> taze") BELGE[0]["surum"] = 1 ist = akis() sik = {} for _, s in ist: sik[s["metin"][:26]] = sik.get(s["metin"][:26], 0) + 1 print(f"\nistek {len(ist)} , benzersiz soru {len(sik)} , onek {ilk['onek']} belirtec") print("en sik uc soru:", [(a, n) for a, n in sorted(sik.items(), key=lambda x: -x[1])[:3]])
ilk cagri : {'etiket': 'fatura', 'kod': 'FT1', 'surum': 1, 'giris': 186, 'onek': 175}
guncelleme sonrasi: {'kod': 'FT1', 'surum': 2, 'giris': 186}
saklanan yanit : FT1 s1 -> bayat
istek 240 , benzersiz soru 29 , onek 175 belirtec
en sik uc soru: [('fatura tutari konusunda ne', 56), ('fatura tutari icin gecerli', 41), ('fatura tutari ile ilgili s', 23)]
İlk satır tekrarın büyüklüğünü veriyor: istem 186 belirteç, bunun 175’i önek. Yani her isteğin ödediği belirtecin 0,9409’u bir önceki istekle birebir aynıdır. İkinci satır güncellemeden sonraki çağrının aynı belgeyi ikinci sürümüyle okuduğunu gösteriyor. Üçüncü satır ise ayrımın kendisidir: saklanmış yanıt hâlâ birinci sürüme dayanıyor ve bayat olmuş.
Soru dağılımı da önemlidir. 240 istek yalnız 29 farklı soruya karşılık geliyor ve en sık üç soru tek başına 120 isteği kaplıyor. Bir yanıt önbelleğinin işe yaraması bu çarpıklığa bağlıdır; her isteğin farklı olduğu bir yükte yanıt önbelleğinin isabeti sıfır kalır.
İsabet Yükselirken Bayat Yanıt Payı
Yedi kurulum aynı akışta koşturulur: önbelleksiz taban, yalnız önek önbelleği, dört farklı ömürle yanıt önbelleği, ve ikisi birlikte.
def kosum(onek_ac, omur=0, tohum=TOHUM): """onek_ac: onek onbellegi acik mi . omur: yanit onbelleginin adim omru.""" for b in BELGE: b["surum"] = 1 SAYAC[0] = 0 onbellek, izi, gecen = {}, [None], [-1] s = dict.fromkeys(("oi", "yi", "giris", "cikis", "bayat", "dogru", "istek"), 0) for adim, soru in akis(tohum): if adim != gecen[0]: gecen[0] = adim for i in GUNCELLEME.get(adim, []): BELGE[i]["surum"] += 1 s["istek"] += 1 kayit = onbellek.get(soru["metin"]) if omur and kayit and adim - kayit["adim"] <= omur: s["yi"] += 1 bayat = kayit["surum"] != BELGE[soru["b"]]["surum"] s["bayat"] += bayat s["dogru"] += kayit["etiket"] == soru["konu"] and not bayat continue y = cagir(soru, tohum) s["cikis"] += y["cikis"] if onek_ac and izi[0] == onek(): # onek icerige gore anahtarlanir s["oi"] += 1 s["giris"] += round(y["onek"] * ONEK_INDIRIM) + y["giris"] - y["onek"] else: s["giris"] += y["giris"] izi[0] = onek() onbellek[soru["metin"]] = {"etiket": y["etiket"], "surum": y["surum"], "adim": adim} s["dogru"] += y["etiket"] == soru["konu"] n, c = s["istek"], max(SAYAC[0], 1) return (s["yi"] / n, s["oi"] / c, s["giris"], s["giris"] + s["cikis"], SAYAC[0], s["bayat"] / n, s["dogru"] / n) DUZEN = [("onbelleksiz", 0, 0), ("onek onbellegi", 1, 0), ("yanit omur 8", 0, 8), ("yanit omur 24", 0, 24), ("yanit omur 64", 0, 64), ("yanit omur sinirsiz", 0, 10 ** 6), ("onek + yanit omur 24", 1, 24)] print("duzenek yanit isb onek isb giris toplam cagri bayat" " dogru") for ad, o, m in DUZEN: a = kosum(o, m) print(f"{ad:<21} {a[0]:>8.4f} {a[1]:>8.4f} {a[2]:>6} {a[3]:>6} {a[4]:>5}" f" {a[5]:>6.4f} {a[6]:>6.4f}") print("\nikinci kosum (tohum 20260219), yanit isb / bayat / dogru:") for ad, o, m in DUZEN: a = kosum(o, m, TOHUM + 1) print(f" {ad:<21} {a[0]:.4f} / {a[5]:.4f} / {a[6]:.4f}")
duzenek yanit isb onek isb giris toplam cagri bayat dogru onbelleksiz 0.0000 0.0000 44367 45263 240 0.0000 0.9333 onek onbellegi 0.0000 0.9792 7472 8368 240 0.0000 0.9333 yanit omur 8 0.4708 0.0000 23456 23917 127 0.0208 0.9208 yanit omur 24 0.6750 0.0000 14407 14686 78 0.0500 0.9292 yanit omur 64 0.8000 0.0000 8870 9042 48 0.1333 0.8625 yanit omur sinirsiz 0.8792 0.0000 5357 5461 29 0.4417 0.5542 onek + yanit omur 24 0.6750 0.9359 2946 3225 78 0.0500 0.9292 ikinci kosum (tohum 20260219), yanit isb / bayat / dogru: onbelleksiz 0.0000 / 0.0000 / 0.9083 onek onbellegi 0.0000 / 0.0000 / 0.9083 yanit omur 8 0.5292 / 0.0292 / 0.8667 yanit omur 24 0.6958 / 0.0833 / 0.8250 yanit omur 64 0.8208 / 0.2167 / 0.6833 yanit omur sinirsiz 0.9000 / 0.5000 / 0.4042 onek + yanit omur 24 0.6958 / 0.0833 / 0.8250
İkinci satır bu dersin en ucuz kazancıdır ve tuzağı yoktur. Önek önbelleği 0,9792 isabetle giriş belirtecini 44367’den 7472’ye indiriyor, yani 5,94 kat. Bayat yanıt payı 0,0000, doğru yanıt payı değişmiyor. Nedeni anahtardadır: önek içeriğe göre anahtarlanır. Dağarcık güncellendiği anda önek metni de değişir, eşleşme kırılır ve bir sonraki çağrı tam ödenir. Bir önbelleğin bayatlaması, anahtarının içerikten kopmasıyla başlar.
Yanıt önbelleği satırları bunun tersidir. Anahtar soru metnidir ve soru değişmez; değişen şey, sorunun dayandığı belgedir. Ömür sekiz adımken isabet 0,4708 ve bayat pay 0,0208; ömür sınırsız olduğunda isabet 0,8792’ye çıkıyor ve bayat pay 0,4417’ye tırmanıyor. Çağrı sayısı 240’tan 29’a düşüyor, giriş belirteci 5357’ye iniyor. Sayfanın maliyet tarafından bakıldığında son satır en iyi satırdır. Ürün tarafından bakıldığında ise doğru yanıt payı 0,9333’ten 0,5542’ye düşmüştür: her iki isteğin yaklaşık birinde kullanıcıya artık geçerli olmayan bir kural anlatılıyor.
Ömrün Seçimi Bir Doğruluk Kararıdır
Kaybın hangi ömürde ölçülebilir hâle geldiği, iki koşum farkına bakılarak söylenir. Önbelleksiz taban ikinci tohumda 0,9083 veriyor, yani koşum farkı 0,0250. Ömür sekizde kayıp 0,0125, ömür yirmi dörtte 0,0041 — ikisi de koşum farkının altında ve ölçülmemiş sayılır. Ömür altmış dörtte kayıp 0,0708, sınırsızda 0,3791; bunlar sırasıyla koşum farkının yaklaşık üç ve on beş katı, yani ölçülmüştür. Karar buradan okunur: bu güncelleme takviminde ömrü yirmi dörde kadar uzatmak bedelsizdir, altmış dörde çıkarmak değildir.
Bu okumanın bir uyarısı var. İkinci koşumda ömür yirmi dördün kaybı 0,0833’e çıkıyor, yani kendi tabanına göre koşum farkının üç katı. Aynı ayar bir koşumda gürültünün altında, ötekinde ölçülür durumda. Bu, yirmi dört adımın güncelleme aralığına yakın olmasından gelir: dağarcık her yirmi dört adımda bir değiştiği için, ömrü tam o aralığa oturtmak kararı belge güncellemesinin zamanlama şansına bırakır. Önbellek ömrü, verinin değişme sıklığından bağımsız seçilemez.
Son satır iki önbelleğin birlikte çalıştığı kurulumdur ve tek başına hiçbirinin vermediği bir sayı üretiyor: giriş belirteci 2946, yani tabana göre 15,06 kat düşüş, bayat pay ise ömür yirmi dördünkiyle aynı, 0,0500. Aynı satırda daha ince bir etki de var: önek isabeti 0,9792’den 0,9359’a düşüyor. Yanıt önbelleği çağrı sayısını 240’tan 78’e indirdiği için, dört güncellemenin kırdığı eşleşme artık çok daha küçük bir bölene bölünüyor. Bir önbellek, öbürünün isabet oranını düşürerek iyileştirir; iki düzeneğin sayısı ayrı ayrı ölçülüp toplanamaz.
Özet
- İstemin 186 belirtecinin 175’i bütün isteklerde ortaktır; tekrarın büyüklüğü ölçülmeden hangi önbelleğin işe yarayacağı bilinemez.
- Önek önbelleği içeriğe göre anahtarlandığı için bayatlamaz: 0,9792 isabetle girişi 44367’den 7472’ye indiriyor ve doğru yanıt payını hiç değiştirmiyor.
- Yanıt önbelleğinde ömür uzadıkça isabet 0,4708’den 0,8792’ye çıkarken bayat yanıt payı 0,0208’den 0,4417’ye tırmanıyor ve doğru yanıt payı 0,9333’ten 0,5542’ye iniyor.
- İki koşum farkı 0,0250’dir: ömür sekiz ve yirmi dördün kaybı bu farkın altında kalıp ölçülmemiş sayılırken, altmış dört ve sınırsız ömrün kaybı ölçülmüştür.
- Ömür, güncelleme aralığına yakın seçildiğinde karar kararsızlaşır; aynı ayar bir koşumda gürültünün altında, ötekinde onun üç katı kayıp veriyor.
- İki önbellek birlikte girişi 2946’ya indiriyor, ama yanıt önbelleği önek isabetini 0,9792’den 0,9359’a düşürüyor: düzeneklerin sayıları ayrı ölçülüp toplanamaz.
Sonraki Adım
Bu derste kazanılan şey belirteçtir. Önbellekten dönen bir yanıt hiç çağrı yapmadığı için kullanıcının beklemesini de kısaltır, ama bu ders o tarafı hiç saymadı: tablo yalnız belirteç, çağrı ve doğruluk sütunları taşıyor. Oysa bir destek yardımcısında en görünür ölçüt bekleme süresidir ve onu belirleyen şey yalnız önbellek değildir. Bağlamın büyüklüğü, çağrının tek başına mı yoksa bir zincirin parçası olarak mı yapıldığı, ve pahalı adımın her istekte mi yoksa yalnız gerekli olduğunda mı çalıştırıldığı beklemeyi ayrı ayrı değiştirir. Sonraki ders bu üç kurulumu karşılaştırır: küçük bağlam, büyük bağlam ve iki aşamalı çağrı hangi gecikme sınıfında duruyor ve her birinin isabeti ne.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.