Ders 15 / 20
İstek İşleme ve Yönlendirme
Aynı istek kümesi üç yerde işlenir — uçta, bölgede ve kaynakta — ve her yerleşimin kaç ağ turu, kaç milisaniye eklediği sayılır. Uçta yapılabilen dört iş türü için kaynağa hiç gitmeyen istek oranı çıkarılır, uçta yapılamayan iş adıyla yazılır.
İçindekiler
Önceki ders uçta neyin koşabileceğini yazdı: on üç arayüz kaleminden altısı, kurgudaki sekiz iş yükünden dördü. Ama koşabilmek bir yerleşim kararı değildir. Aynı dört iş bölgede de koşar, kaynakta da. Kurgudaki bölgesel ölçüm ağında şube uçlarından gelen her istek bugün bölgeye gidiyor; bir kısmının uçta karara bağlanabileceğini bilmek, hangisinin bağlanması gerektiğini söylemez.
Bu dersin ölçüsü tek bir şeydir: bir kararın nerede verildiği, o isteğe kaç ağ turu ve kaç milisaniye ekler. Turlar sayılınca yerleşim sorusu tercih olmaktan çıkar ve aritmetiğe döner.
KE7. Turlar tam tur (gidiş–dönüş) olarak sayılır; tek yönlü gecikme modellenmez. KE8. Tur ve işlem süreleri model girdisidir; kurgudaki ağın uç, bölge ve kaynak üçlüsüne karşılık gelir. KE9. Bir istek en fazla bir yerde işlenir; aynı iş iki yerde birden yapılmaz.
Üç Yer, Üç Tur
Yol üç bacaktan oluşur. İstemci ile uç arasındaki bacak kısadır, çünkü uç şubeye yakındır. Uç ile bölge arasındaki bacak uzundur. Bölge ile kaynak arasındaki bacak yine kısadır, çünkü ikisi aynı bölgededir. İstek nerede işlenirse, o noktaya kadar olan bütün bacaklar ödenir.
// olcum-agi/yerlesim.mjs — ayni istegin uc yerde islenmesi: tur ve gecikme // MODEL: tur sureleri bildirilen model girdisidir; tek yonlu degil, tam tur sayilir. export const BACAK = { "istemci-kenar": 8, "kenar-bolge": 60, "bolge-kaynak": 20 }; export const YER = { "kenar": { bacak: ["istemci-kenar"], islemMs: 2 }, "bolge": { bacak: ["istemci-kenar", "kenar-bolge"], islemMs: 6 }, "kaynak": { bacak: ["istemci-kenar", "kenar-bolge", "bolge-kaynak"], islemMs: 15 }, }; export const YERLER = Object.keys(YER); export const tur = (y) => YER[y].bacak.length; export const gecikme = (y) => YER[y].bacak.reduce((t, b) => t + BACAK[b], 0) + YER[y].islemMs; // Dort is turu ve her birinin hangi yerde yapilabildigi. export const IS = { "yonlendirme": { yer: ["kenar", "bolge", "kaynak"], sonlandirir: true }, "baslik duzenleme": { yer: ["kenar", "bolge", "kaynak"], sonlandirir: false }, "kimlik dogrulama": { yer: ["kenar", "bolge", "kaynak"], sonlandirir: true }, "a/b ayrimi": { yer: ["kenar", "bolge", "kaynak"], sonlandirir: true }, "iliskisel sorgu": { yer: ["kaynak"], sonlandirir: false }, "islemli yazma": { yer: ["kaynak"], sonlandirir: false }, "veri kumesi taramasi": { yer: ["bolge", "kaynak"], sonlandirir: false }, }; if (import.meta.main) { console.log("bir istegin uc yerde islenmesi (model girdisi)"); console.log("yer".padEnd(10) + "ag turu".padEnd(10) + "ag suresi".padEnd(12) + "islem".padEnd(9) + "toplam".padEnd(10) + "kenara gore"); for (const y of YERLER) { const ag = YER[y].bacak.reduce((t, b) => t + BACAK[b], 0); console.log(y.padEnd(10) + String(tur(y)).padEnd(10) + `${ag} ms`.padEnd(12) + `${YER[y].islemMs} ms`.padEnd(9) + `${gecikme(y)} ms`.padEnd(10) + `+${gecikme(y) - gecikme("kenar")} ms`); } console.log("bacak basina eklenen tur: " + Object.entries(BACAK).map(([b, v]) => `${b} ${v} ms`).join(", ")); console.log("\nis turu nerede yapilabilir (+ yapilir, - yapilmaz)"); console.log("is turu".padEnd(24) + YERLER.map((y) => y.padEnd(10)).join("") + "uc sonlandirir"); for (const [ad, v] of Object.entries(IS)) console.log(ad.padEnd(24) + YERLER.map((y) => (v.yer.includes(y) ? "+" : "-").padEnd(10)).join("") + (v.yer.includes("kenar") ? (v.sonlandirir ? "evet" : "hayir") : "-")); const kenarda = Object.values(IS).filter((v) => v.yer.includes("kenar")).length; console.log(`kenarda yapilabilen: ${kenarda}/${Object.keys(IS).length}`); }
bir istegin uc yerde islenmesi (model girdisi) yer ag turu ag suresi islem toplam kenara gore kenar 1 8 ms 2 ms 10 ms +0 ms bolge 2 68 ms 6 ms 74 ms +64 ms kaynak 3 88 ms 15 ms 103 ms +93 ms bacak basina eklenen tur: istemci-kenar 8 ms, kenar-bolge 60 ms, bolge-kaynak 20 ms is turu nerede yapilabilir (+ yapilir, - yapilmaz) is turu kenar bolge kaynak uc sonlandirir yonlendirme + + + evet baslik duzenleme + + + hayir kimlik dogrulama + + + evet a/b ayrimi + + + evet iliskisel sorgu - - + - islemli yazma - - + - veri kumesi taramasi - + + - kenarda yapilabilen: 4/7
Tur sayısı 1, 2 ve 3’tür; gecikme 10, 74 ve 103 ms. Uçtan bölgeye geçmek +64 ms, bölgeden kaynağa geçmek +29 ms ekler. İki adım eşit değildir ve nedeni bacak süreleridir: uzun bacak uç ile bölge arasındadır. Yerleşim kararının ağırlığı bu yüzden ilk adımda toplanır — bir işi bölgeden kaynağa taşımak yerinde bir ayrıntı, uçtan bölgeye taşımak ise gecikmenin yaklaşık üçte ikisidir.
İşlem süreleri ters yönde çalışır ve kararı yumuşatmaz. Uçta 2 ms, bölgede 6 ms, kaynakta 15 ms’dir; en uzak yer aynı zamanda en yavaş işleyen yerdir, çünkü orada yapılan iş daha ağırdır. Üç kalemin toplamında ağ süresi işlem süresini bastırır: kaynakta 88 ms ağ, 15 ms işlem.
Turların tam tur sayılması (KE7) sayının nasıl okunacağını da belirler. Bir yerleşimin maliyeti tek yönlü mesafe değil, yanıtın geri dönmesi dahil edilmiş süredir; uçta verilen bir karar kaynağa bir soru sorup beklemek zorunda kalırsa o bekleme aynı tabloya bir satır daha ekler. Modelin dışarıda bıraktığı şey de burada görünür: art arda iki bağımsız veri isteği yapan bir iş, tabloda tek satırla temsil edilemez, iki tur öder. Bu yüzden uçta tutulmaya en uygun iş türü, karar için gereken her şeyi isteğin kendisinde taşıyan iştir.
İkinci tablo yedi iş türünü yerleştirir. Dördü üç yerde de yapılabilir. Bunların üçü isteği uçta sonlandırabilir: yönlendirme bir yanıt üretir, kimlik doğrulama bir reddetme üretir, A/B ayrımı hazır bir kopyayı döndürür. Başlık düzenleme uçta yapılır ama isteği sonlandırmaz — başlık yazılır ve istek yoluna devam eder. Bu ayrım sonraki sayımın tamamını belirler: bir işin uçta yapılabilmesi ile o işin kaynağı ziyaret etmekten kurtarması aynı şey değildir.
Uçta Sonlanan İstek
Şimdi bir istek kümesi bu dört işten sırayla geçirilir. Sıralı olması önemlidir: yönlendirme aşamasında kapanan bir istek kimlik doğrulamaya hiç girmez, dolayısıyla aynı istek iki kez sayılmaz.
KE10. Küme 10.000 istektir ve aşama başına uçta sonlanan istek sayısı model girdisidir. KE11. A/B ayrımında uçta hazır bulunan kopya bir girdidir; önbellek isabeti bu derste yeniden ölçülmez. KE12. Uçta işlenip geçen istek kaynak yoluna uç işlem süresini de ekler.
// olcum-agi/suzgec.mjs — istek kumesi ucta sirali suzgecten gecirilir // MODEL: asama basina ucta sonlanan istek sayisi bildirilen model girdisidir. import { YER, YERLER, IS, tur, gecikme } from "./yerlesim.mjs"; const KUME = 10_000; const ASAMA = [ ["yonlendirme", 1_240, "eski adres ucta kalici yanitla kapanir"], ["kimlik dogrulama", 860, "gecersiz belirtec ucta reddedilir"], ["a/b ayrimi", 2_100, "varyant ucta secilir ve ucta hazir kopya doner"], ["baslik duzenleme", 0, "baslik yazilir, istek yoluna devam eder"], ]; console.log(`${KUME} istek, ucta sirali suzgec (model girdisi)`); console.log("asama".padEnd(20) + "dokunulan".padEnd(12) + "ucta sonlanan".padEnd(16) + "kalan".padEnd(9) + "kume orani"); let kalan = KUME, sonlanan = 0; for (const [ad, biten, _] of ASAMA) { const dokunulan = kalan; kalan -= biten; sonlanan += biten; console.log(ad.padEnd(20) + String(dokunulan).padEnd(12) + String(biten).padEnd(16) + String(kalan).padEnd(9) + `%${((biten / KUME) * 100).toFixed(1)}`); } console.log("kaynaga hic gitmeyen: " + sonlanan + `/${KUME} ` + `%${((sonlanan / KUME) * 100).toFixed(1)} kaynaga giden: ${kalan}`); // Iki senaryonun agirlikli gecikmesi ve toplam ag turu. const KENAR_EK = YER["kenar"].islemMs; const senaryo = { "hepsi kaynakta": [[KUME, gecikme("kaynak"), tur("kaynak")]], "dort is ucta": [[sonlanan, gecikme("kenar"), tur("kenar")], [kalan, gecikme("kaynak") + KENAR_EK, tur("kaynak")]], }; console.log("\nagirlikli gecikme ve toplam ag turu"); const ort = {}; for (const [ad, satir] of Object.entries(senaryo)) { const ms = satir.reduce((t, [n, g]) => t + n * g, 0) / KUME; const turlar = satir.reduce((t, [n, , k]) => t + n * k, 0); ort[ad] = ms; console.log(" " + ad.padEnd(18) + `${ms.toFixed(1)} ms/istek ` + `${turlar} tur istek basina ${(turlar / KUME).toFixed(2)} tur`); } const fark = ort["hepsi kaynakta"] - ort["dort is ucta"]; console.log(` ${"kazanc".padEnd(18)}${fark.toFixed(1)} ms/istek ` + `%${((fark / ort["hepsi kaynakta"]) * 100).toFixed(1)}`); // Bir kararin ucta degil daha uzakta verilmesinin marjinal bedeli. console.log("\nayni karari bir basamak uzaga tasimanin bedeli"); for (let i = 1; i < YERLER.length; i++) { const [o, y] = [YERLER[i - 1], YERLER[i]]; console.log(" " + `${o} -> ${y}`.padEnd(20) + `+${tur(y) - tur(o)} tur +${gecikme(y) - gecikme(o)} ms/istek ` + `kume basina +${(((gecikme(y) - gecikme(o)) * KUME) / 1000).toFixed(1)} sn`); } const NEDEN = { "iliskisel sorgu": "cok tabloyu birlestirir; veri kenarda yok", "islemli yazma": "kesin siralama ve geri alma ister; kenarda islem sinir yok", "veri kumesi taramasi": "girdi bellek tabanindan buyuk; kenarda disk yok", }; console.log("\nkenarda yapilamayan is"); for (const [ad, v] of Object.entries(IS)) { if (v.yer.includes("kenar")) continue; console.log(" " + ad.padEnd(24) + `en yakin yer: ${v.yer[0].padEnd(8)}` + NEDEN[ad]); }
10000 istek, ucta sirali suzgec (model girdisi) asama dokunulan ucta sonlanan kalan kume orani yonlendirme 10000 1240 8760 %12.4 kimlik dogrulama 8760 860 7900 %8.6 a/b ayrimi 7900 2100 5800 %21.0 baslik duzenleme 5800 0 5800 %0.0 kaynaga hic gitmeyen: 4200/10000 %42.0 kaynaga giden: 5800 agirlikli gecikme ve toplam ag turu hepsi kaynakta 103.0 ms/istek 30000 tur istek basina 3.00 tur dort is ucta 65.1 ms/istek 21600 tur istek basina 2.16 tur kazanc 37.9 ms/istek %36.8 ayni karari bir basamak uzaga tasimanin bedeli kenar -> bolge +1 tur +64 ms/istek kume basina +640.0 sn bolge -> kaynak +1 tur +29 ms/istek kume basina +290.0 sn kenarda yapilamayan is iliskisel sorgu en yakin yer: kaynak cok tabloyu birlestirir; veri kenarda yok islemli yazma en yakin yer: kaynak kesin siralama ve geri alma ister; kenarda islem sinir yok veri kumesi taramasi en yakin yer: bolge girdi bellek tabanindan buyuk; kenarda disk yok
Dört iş türünün kaynağa hiç gitmeyen istek oranları ayrı ayrı okunur: yönlendirme %12,4, kimlik doğrulama %8,6, A/B ayrımı %21,0, başlık düzenleme %0,0. Toplamda 4.200 istek kaynağı hiç görmez — kümenin %42,0’si. Başlık düzenlemenin sıfır üretmesi onu değersiz kılmaz; yaptığı iş kaynağın yükünü değil, kaynağın kodunu hafifletir. Ama tur sayımında karşılığı yoktur ve tabloda öyle görünür.
İstek başına ağ turu 3,00’ten 2,16‘ya, ağırlıklı gecikme 103,0 ms’den 65,1 ms‘ye iner; kazanç 37,9 ms, yani %36,8. Bu sayı doğrudan %42,0’nin karşılığıdır: kaynağa gitmeyen her istek üç turluk yoldan tek turluk yola geçer. Kaynağa giden 5.800 istek ise 105 ms öder, 103 değil; uçta işlenip geçmenin 2 ms’lik bir bedeli vardır ve ortalamada görünür.
Süzgecin sırası da bir karardır ve “dokunulan” sütununda görünür. Kimlik doğrulama yönlendirmenin ardında durduğu için 10.000 yerine 8.760 isteğe bakar; A/B ayrımı ikisinin ardında olduğu için 7.900’e bakar. Sıra tersine çevrilseydi uçta sonlanan toplam değişmezdi — 4.200 yine 4.200 olurdu — ama A/B ayrımı, sonunda reddedilecek 860 istek için de varyant hesaplardı. Sıralı süzgeçte kazanılan şey tur değil, uçta harcanan işlem süresidir; ucuz ve çok eleyen aşama öne alınır.
Marjinal tablo aynı kararı ters yönden okur. Uçta verilebilen bir kararı bölgeye taşımak istek başına +64 ms, on bin istekte 640 saniye eder. Bölgeden kaynağa taşımak +29 ms ve 290 saniyedir. Kurgudaki ağda bu, kimlik doğrulamasını uçta değil bölgede yapma kararının on bin istekte on dakikadan fazla toplam bekleme yarattığı anlamına gelir — ve bu isteklerin 860’ı zaten reddedilecektir.
Uçta Yapılamayan İş
Devredilen karar bu derste yerleştirmedir: isteğin hangi düğümde karşılandığını uygulama seçmez. Karşılığında gelen kısıt yine bir sayıdır — yedi iş türünden 3’ü uçta yapılamaz ve üçü de adıyla yazılır. İlişkisel sorgu birden çok tabloyu birleştirir; birleştirilecek veri uçta yoktur. İşlemli yazma kesin sıralama ve geri alma ister; uçta işlem sınırı kurulamaz. Veri kümesi taraması girdisi bellek tabanından büyüktür ve uçta disk yoktur. Son ikisi önceki dersin eksik kalem listesinden doğrudan türer: yerel disk kalıcılığı yoktu, işlemli yazmanın dayandığı kalıcı günlük de yoktu.
Bu üçünün en yakın yeri farklıdır ve fark bir tasarım kaldıracıdır. Veri kümesi taraması bölgede yapılabilir, ilişkisel sorgu ve işlemli yazma yalnız kaynakta. Yani uçta yapılamayan her iş aynı uzaklığa sürülmez: bir işi bölgede tutabilmek, kaynağa taşımaya göre istek başına 29 ms geri kazandırır. Kurgudaki ağda gecelik uzlaştırma bu yüzden bölgede kalır, fatura kesinleştirme ise kaynağa iner; ikisi de uçtan çıkar ama aynı uzaklığa değil.
Kısıtın etrafından dolaşmanın yolu bu dersin ölçüsünde nettir ve bedeli de öyle. İlişkisel sorgunun uca taşınabilmesi için sonucun önceden hesaplanıp uçta bir yerde durması gerekir; o zaman soru sorgu olmaktan çıkar, okuma olur. İşlemli yazmanın uca taşınabilmesi için sıralamayı garanti eden tek bir yazarın uçta durması gerekir. İki dolaşma yolu da aynı şeyi ister: uçta duran, okunabilen ve yazılabilen bir durum. Bu dersin modeli o durumu hiç varsaymadı — dört işin dördü de durumsuzdu.
Özet
- Üç yerleşim üç tur eder: uç 1 tur / 10 ms, bölge 2 tur / 74 ms, kaynak 3 tur / 103 ms. Uzun bacak uç ile bölge arasındadır, bu yüzden ilk adım +64 ms, ikinci adım +29 ms’dir.
- Yedi iş türünün 4’ü uçta yapılabilir; bunların 3’ü isteği uçta sonlandırır. Uçta yapılabilmek ile kaynağı ziyaret etmekten kurtarmak aynı şey değildir — başlık düzenleme bunun örneğidir.
- Kaynağa hiç gitmeyen istek oranları: yönlendirme %12,4, kimlik doğrulama %8,6, A/B ayrımı %21,0, başlık düzenleme %0,0. Toplamı 4.200/10.000, yani %42,0.
- İstek başına ağ turu 3,00’ten 2,16’ya, ağırlıklı gecikme 103,0 ms’den 65,1 ms’ye iner; kazanç %36,8. Uçta işlenip geçen istek kaynak yolunda 2 ms’lik ek öder.
- Uçta yapılamayan üç iş adıyla yazılır: ilişkisel sorgu, işlemli yazma, veri kümesi taraması. İkisinin en yakın yeri kaynak, birininki bölgedir; aradaki fark istek başına 29 ms’dir.
Sonraki Adım
Bu dersin dört işi de durumsuzdu: yönlendirme bir tabloya, kimlik doğrulama bir imzaya, A/B ayrımı bir bölme kuralına bakıyordu. Uçta yapılamayan üç iş ise durum istiyor. O zaman soru şu olur: uçta bir değer okunabilir mi, yazılabilir mi? Okuma uca yakınsa hızlıdır — peki yazma nereye gider ve yazılan değer öbür uçlarda ne zaman görünür? İki uç aynı anahtarı okuduğunda ne kadar süre farklı yanıt verirler ve bu süre içinde kaç okuma bayat çıkar? Uçtan büyük bir nesneye erişmek kaç tur eder ve çıkış ücretini hangi yöne çevirir? Sonraki ders uçtaki depolamayı okuma ve yazma eksenlerinde ayrı ayrı ölçer, yayılma penceresini tarar ve depoya konulabilecek değerin sınırını bir kısıt olarak sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.