Ders 04 / 16
Statik İçerik Barındırma
İçerik yolunun uygulama yolundan ayrılması: birleşik ve ayrık düzenlemenin yerel süreçlerle ölçülmesi, bir sayfa yüklemesinin uygulama sürecine düşürdüğü istek ve baytın sayılması ve varlık trafiğinin giriş kursundaki uçtaki tepe istek hızı ile okuma çıkışı hesabına eklenmesi.
İçindekiler
Önceki iki ders içeriği kenarda tuttu ama içeriğin nereden geldiği hep aynı yerdi: uygulamanın kendisi. Ortak sınıftaki yirmi nesne — kabuk, biçem, betik ve simge dosyaları — uygulamanın hiçbir mantığına dokunmuyor; sabit bayt dizileri olarak duruyorlar ve yine de uygulama süreçlerinin adresinden isteniyorlar.
Bu ders o yolu ayırır. İçerik yolu, değişmeyen dosyaların isteğe kadar izlediği yoldur; uygulama yolu, bir isteğin kod çalıştırılarak yanıtlandığı yoldur. Statik dosya sunumu Sunucu Tarafı Temelleri kursunda, varlık adlandırma ve sürümleme Oluşturma Stratejileri ve Altyapı kursunda kuruldu; burada ne derleme ne paketleme anlatılır. Sorulan tek şey şudur: iki yol ayrıldığında uygulama sürecine kaç istek ve kaç bayt ulaşır, ve bu sayı giriş kursunun hesabında neyi değiştirir.
İki Düzenleme
Birleşik düzenleme, aynı sürecin hem /takip yolunu hem /varlik yolunu taşımasıdır. Tek
bir dağıtım birimi vardır, yapılandırma azdır; karşılığında uygulama süreci her sayfa yüklemesinde
yirmi dosya okuması yapar.
Ayrık düzenleme, varlık yolunu ayrı bir sürece vermektir. Uygulama süreci yalnız kod çalıştırılan istekleri görür. İki düzenleme arasındaki fark bir yetenek farkı değildir — ikisi de aynı baytları döndürür — bir yerleşim farkıdır ve sonucu sayılabilir.
// statik/sunucu.mjs — iki duzenlemeyi ayni anda ayaga kaldirir: uygulama sureci 8473'te hem // /takip hem /varlik yollarini tasiyabilir, icerik sureci 8474'te yalniz /varlik tasir. // Varlik dosyalari baslangicta uretilir. /sayac cagrildiginda sayaci dondurur ve sifirlar. import http from "node:http"; import fs from "node:fs"; const V5 = 480; // K01 V5: takip yaniti govdesi const VARLIK = [["kabuk.html", 6_000], ["bicem.css", 40_000], ["uygulama.js", 120_000], ["yazitipi.woff2", 28_000], ["logo.svg", 4_000]]; for (let i = 1; i <= 15; i += 1) VARLIK.push([`simge-${i}.svg`, 1_200]); // T13 fs.mkdirSync("varlik", { recursive: true }); for (const [ad, bayt] of VARLIK) fs.writeFileSync(`varlik/${ad}`, "x".repeat(bayt)); const yeni = () => ({ takip: 0, varlik: 0, bayt: 0 }); const sayacYaz = (s, yanit) => { // kabuktan okunsun diye duz metin yanit.writeHead(200, { "content-type": "text/plain" }); yanit.end(`${s.takip} ${s.varlik} ${s.bayt}`); Object.assign(s, yeni()); // okundu, sifirlandi }; function surec(bagNoktasi, varligiTasi) { const s = yeni(); http.createServer((istek, yanit) => { if (istek.url === "/sayac") return sayacYaz(s, yanit); if (istek.url.startsWith("/varlik/")) { if (!varligiTasi) { yanit.writeHead(404); return yanit.end(); } const g = fs.readFileSync(`varlik/${istek.url.slice("/varlik/".length)}`); s.varlik += 1; s.bayt += g.length; yanit.writeHead(200, { "content-length": g.length }); return yanit.end(g); } const g = JSON.stringify({ takip: istek.url.slice("/takip/".length), durum: "aktarma" }); const govde = g + " ".repeat(V5 - g.length); s.takip += 1; s.bayt += V5; yanit.writeHead(200, { "content-type": "application/json", "content-length": V5 }); yanit.end(govde); }).listen(bagNoktasi); return s; } surec(8473, true); // birlesik duzenleme: uygulama sureci varligi da tasir surec(8474, true); // ayrik duzenlemede icerik sureci
# statik-olc.sh — bir sayfa yuklemesi iki duzenlemede: once uygulama sureci varligi da tasir, # sonra varlik yolu ayri bir surece verilir. Sayac okundugunda sifirlanir. node statik/sunucu.mjs & SUNUCU=$! until curl -sf http://127.0.0.1:8473/sayac >/dev/null; do sleep 0.2; done VARLIK=$(ls varlik) yukle() { # $1 = varlik surecinin bag noktasi curl -s -o /dev/null "http://127.0.0.1:8473/takip/TR900011" for v in $VARLIK; do curl -s -o /dev/null "http://127.0.0.1:$1/varlik/$v"; done } curl -s -o /dev/null http://127.0.0.1:8473/sayac; curl -s -o /dev/null http://127.0.0.1:8474/sayac printf '%s varlik, toplam %s bayt\n\n' "$(ls varlik | wc -l | tr -d ' ')" "$(cat varlik/* | wc -c | tr -d ' ')" printf '%-10s %-10s %7s %8s %9s\n' duzenleme surec takip varlik bayt yukle 8473 printf '%-10s %-10s %7s %8s %9s\n' birlesik uygulama $(curl -s http://127.0.0.1:8473/sayac) printf '%-10s %-10s %7s %8s %9s\n' birlesik icerik $(curl -s http://127.0.0.1:8474/sayac) yukle 8474 printf '%-10s %-10s %7s %8s %9s\n' ayrik uygulama $(curl -s http://127.0.0.1:8473/sayac) printf '%-10s %-10s %7s %8s %9s\n' ayrik icerik $(curl -s http://127.0.0.1:8474/sayac) kill $SUNUCU
20 varlik, toplam 216000 bayt duzenleme surec takip varlik bayt birlesik uygulama 1 20 216480 birlesik icerik 0 0 0 ayrik uygulama 1 0 480 ayrik icerik 0 20 216000
Sayılar ölçüm sınıfındadır; varlık kümesi bu kursun varsayımıdır — T13: sayfa başına 20 varlık, toplam 216.000 bayt, gerekçesi bir takip sayfasının kabuk, biçem, betik, yazı tipi ve simge dosyalarından oluşmasıdır.
Ölçüm bir sayfa yüklemesinin iki düzenlemede uygulama sürecine ne düşürdüğünü veriyor. Birleşik düzenlemede uygulama süreci 21 istek ele aldı ve 216.480 bayt gönderdi. Ayrık düzenlemede aynı sayfa yüklemesi için uygulama süreci 1 istek ele aldı ve 480 bayt gönderdi; kalan 20 istek ve 216.000 bayt içerik sürecine geçti. Uygulama sürecine düşen istek 21’den 1’e, bayt 216.480’den 480’e indi ve bunu sağlayan tek şey yolun ayrılmasıdır — hiçbir önbellek, hiçbir sıkıştırma eklenmedi.
Ayrımın ikinci sonucu ölçekleme birimidir. Birleşik düzenlemede uygulama süreçlerinin sayısı iki ayrı ihtiyacın toplamına göre belirlenir: kod çalıştıran istekler ve dosya okuyan istekler. İki ihtiyaç aynı yönde büyümez — bir sayfa varlığı arttığında kod yükü değişmez. Ayrık düzenlemede iki sayı bağımsız ayarlanır.
İki Ad, İki Yaşam Süresi
Yolun ayrılmasının doğrudan bir sonucu, içerik yolunun kendi adını almasıdır ve bu, konunun ilk dersindeki karara geri döner. Orada yaşam süresi tek bir sayıydı ve iki işi birden yapıyordu: sorgu yükünü azaltmak ve devralma penceresini belirlemek. Ölçüm ödünleşimi vermişti — 900 saniyelik yaşam süresi yukarı sorguyu 64’e indiriyor ama tek bir bölge devralması aylık kesinti bütçesinin yüzde 14,28’ini harcıyordu; 30 saniyelik süre bütçe payını yüzde 0,50’ye indiriyor ama yukarı sorguyu 1.600’e çıkarıyordu.
Tek ad varken bu ödünleşimin tek bir noktası seçilir. İki ad varken iki ayrı nokta seçilebilir, çünkü iki adın devralma ihtiyacı aynı değildir. Uygulama adı bir bölge düştüğünde hızlı devralmak zorundadır; kısa yaşam süresi ve onun getirdiği sorgu yükü ödenir. İçerik adı ise on iki kenarda tutulan değişmeyen dosyaları gösterir: bir kenar düştüğünde ötekiler aynı baytları taşır ve devralma penceresi bir kesintiye dönüşmez. O adın uzun yaşam süresi taşımasında bir sakınca yoktur.
Sonuç, ilk dersteki tablonun iki ayrı satırının aynı anda seçilebilmesidir: kısa süre yalnız uygulamayı çözen ad için, uzun süre içerik adı için. Bir ödünleşimin iki ucunun birden alınması, ödünleşimi doğuran sorumluluğun bölünmesiyle olur.
Hesaba Dönüş
Ölçülen yirmi bir isteğin giriş kursunda bir karşılığı yoktur. Kursun uçtaki tepe istek hızı 513,89, yalnız takip sorgusu ve durum olayını sayıyordu; sayfanın kendisi ve varlıkları hesaba hiç girmemişti. Bu boşluğu doldurmak için bir varsayım daha gerekir — T14: kullanıcı başına günlük 2 sayfa yüklemesi, gerekçesi altı takip sorgusunun ikisinin yeni bir sayfa açılışı, dördünün aynı sayfadaki yenileme olmasıdır.
// statik/hesap.mjs — icerik yolunun ayrilmasinin K01 hesaplarina etkisi. Sayfa basina varlik // sayisi ve bayti onceki bloktaki olcumden alinmistir. const V1 = 2_000_000, TEPE = 3, GUN = 86_400; // K01 V1, V8 const TEPE_UC = 513.89, K01_CIKIS = 1.60; // K01 hesabi const T14 = 2; // kullanici basina gunluk sayfa yuklemesi const VARLIK = 20, VARLIK_BAYT = 216_000; // olcum: onceki blok const KENAR = 12; // T10: onceki dersin kenar sayisi const sayfaTepe = ((V1 * T14) / GUN) * TEPE; const varlikTepe = sayfaTepe * VARLIK; const mbit = (hiz, bayt) => (hiz * bayt * 8) / 1e6; const sat = (ad, istek, bayt) => console.log(`${ad.padEnd(30)}${istek.toFixed(2).padStart(10)}${bayt.toFixed(2).padStart(12)}`); console.log(`gunluk sayfa yuklemesi = ${V1 * T14}, tepe = ${sayfaTepe.toFixed(2)} sayfa/s`); console.log(`sayfa basina ${VARLIK} varlik, ${VARLIK_BAYT} bayt -> ` + `tepe varlik istegi = ${varlikTepe.toFixed(2)} istek/s`); console.log(); console.log(`${"duzenleme".padEnd(30)}${"istek/s".padStart(10)}${"Mbit/s".padStart(12)}`); sat("K01 hesabi (varlik sayilmadi)", TEPE_UC, K01_CIKIS); sat("birlesik yol, uygulama sureci", TEPE_UC + varlikTepe, K01_CIKIS + mbit(sayfaTepe, VARLIK_BAYT)); sat("ayrik yol, uygulama sureci", TEPE_UC, K01_CIKIS); sat("ayrik yol, icerik sureci", varlikTepe, mbit(sayfaTepe, VARLIK_BAYT)); console.log(); console.log(`ayrik yol + kenar: varlik ${KENAR} kenarda tutulunca koken gunde ` + `${VARLIK * KENAR} varlik istegi gorur, ${((VARLIK_BAYT * KENAR) / 1e6).toFixed(2)} MB`); console.log(`birlesik yolda uygulama sureci K01'in ${((TEPE_UC + varlikTepe) / TEPE_UC).toFixed(2)} ` + `kati istek, ${((K01_CIKIS + mbit(sayfaTepe, VARLIK_BAYT)) / K01_CIKIS).toFixed(1)} kati bayt goruyor`); console.log(`bir sayfa yuklemesinde uygulamanin gordugu istek: birlesik ${1 + VARLIK}, ayrik 1`); console.log(`T14 duyarliligi: kullanici basina 1 sayfa yuklemesi olsa varlik istegi ` + `${(varlikTepe / 2).toFixed(2)} istek/s, uctaki toplam ` + `${(TEPE_UC + varlikTepe / 2).toFixed(2)} istek/s`);
gunluk sayfa yuklemesi = 4000000, tepe = 138.89 sayfa/s sayfa basina 20 varlik, 216000 bayt -> tepe varlik istegi = 2777.78 istek/s duzenleme istek/s Mbit/s K01 hesabi (varlik sayilmadi) 513.89 1.60 birlesik yol, uygulama sureci 3291.67 241.60 ayrik yol, uygulama sureci 513.89 1.60 ayrik yol, icerik sureci 2777.78 240.00 ayrik yol + kenar: varlik 12 kenarda tutulunca koken gunde 240 varlik istegi gorur, 2.59 MB birlesik yolda uygulama sureci K01'in 6.41 kati istek, 151.0 kati bayt goruyor bir sayfa yuklemesinde uygulamanin gordugu istek: birlesik 21, ayrik 1 T14 duyarliligi: kullanici basina 1 sayfa yuklemesi olsa varlik istegi 1388.89 istek/s, uctaki toplam 1902.78 istek/s
Tablonun ilk satırı giriş kursunun eksiğini adlandırıyor: 513,89 istek/s ve 1,60 Mbit/s, varlık yolu hiç sayılmadan hesaplanmıştı. İkinci satır varlık trafiği eklendiğinde ne olduğunu gösteriyor. Birleşik düzenlemede uygulama süreci saniyede 3.291,67 istek görür — kursun sayısının 6,41 katı — ve 241,60 Mbit/s gönderir, kursun okuma çıkışının 151,0 katı. Bir tasarımın en büyük kaynak kalemi, hiç hesaplanmamış olan kalem çıkabilir. Giriş kursu aynı sonuca gün sonu işiyle varmıştı: seyrek koşan iş, sürekli koşan akışın 3,75 katı bant genişliği istiyordu. Buradaki oran 151,0’dır ve kalem hesaba hiç girmemiştir.
Üçüncü ve dördüncü satırlar ayrımın ne yaptığını söylüyor: toplam iş azalmıyor, bölünüyor. Uygulama süreci kursun hesapladığı 513,89 istek/s ve 1,60 Mbit/s’e geri dönüyor; 2.777,78 istek/s ve 240,00 Mbit/s içerik sürecine geçiyor. İçerik yolunun ayrılması giriş kursunun hesabını düzeltmiyor — hesabın geçerli kaldığı düzenlemeyi adlandırıyor. Kursun 513,89 sayısı, ancak varlık yolu uygulamadan ayrıldığında uygulama sürecinin gördüğü sayıdır.
Beşinci satır önceki iki dersle birleşiyor. Yirmi varlık, önceki dersin ölçümünde her kenardan istenen ortak sınıftı ve itme tabanlı dağıtımda boşa giden payı sıfırdı. On iki kenara itildiğinde köken günde yalnız 240 varlık isteği görür ve 2,59 MB gönderir. Kullanıcı tarafında akan 240,00 Mbit/s’in kökene ulaşan kısmı bu kadardır. Üç kararın birleşimi — ayrık içerik yolu, kenar önbelleği ve ortak sınıfta itme — 240,00 Mbit/s’lik bir kalemi kökende günlük 2,59 MB’a indiriyor.
Son satır varsayımın duyarlılığıdır. T14 yarıya inseydi varlık isteği 1.388,89 istek/s, uçtaki toplam 1.902,78 istek/s olurdu: hâlâ kursun sayısının üç katından fazla. Varsayım iki katına ya da yarısına çekilse de sonuç değişmiyor — varlık yolu sayılmadığında hesap yanlıştır.
Özet
- İçerik yolu ile uygulama yolunun ayrılması bir yerleşim kararıdır; ikisi de aynı baytları döndürür, değişen isteğin hangi sürece düştüğüdür.
- Ölçüm: bir sayfa yüklemesinde uygulama süreci birleşik düzenlemede 21 istek ve 216.480 bayt, ayrık düzenlemede 1 istek ve 480 bayt gördü.
- Ayrık düzenlemede ölçekleme birimleri bağımsızlaşır ve içerik yolu kendi adını alır; ilk dersteki yaşam süresi ödünleşiminin iki ucu — uygulama adı için kısa, içerik adı için uzun — aynı anda seçilebilir.
- Giriş kursunun uçtaki 513,89 istek/s sayısı varlık yolunu hiç saymamıştı; varlık trafiği eklendiğinde birleşik düzenlemede uygulama süreci 3.291,67 istek/s ve 241,60 Mbit/s görür — 6,41 kat istek, 151,0 kat bayt.
- Ayrım toplamı azaltmaz, böler: uygulama süreci 513,89 istek/s ve 1,60 Mbit/s’e döner, 2.777,78 istek/s ve 240,00 Mbit/s içerik sürecine geçer. Kursun sayısı ancak bu düzenlemede geçerlidir.
- Ayrık yol, kenar önbelleği ve ortak sınıfta itme birleştiğinde köken günde 240 varlık isteği ve 2,59 MB görür; T14 yarıya inse bile varlık yolu sayılmadan hesap yanlıştır.
Sonraki Adım
Bu konu isteklerin bir kısmını uygulamaya hiç ulaştırmamayı başardı: kenar önbelleği takip yanıtlarının onda dokuzunu sınırda karşıladı, ayrılan içerik yolu bir sayfa yüklemesinin yirmi bir isteğinden yirmisini uygulamadan uzaklaştırdı ve alan adı katmanı isteğin hangi bölgeye gideceğini seçti. Geriye uygulamaya gerçekten ulaşması gereken istekler kaldı — ölçülen düzenlemede saniyede 513,89 tanesi. Bunlar için hâlâ tek bir soru yanıtsızdır: bölge seçildikten sonra, aynı işi yapan birden çok kopya varken istek hangisine düşer, ve o kopya ayakta değilse bunu kim fark eder. Sonraki ders bu iki soruyu tek bir bileşene bağlar ve o bileşenin sorumluluklarını sayar.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.