İçeriğe geç
academia.sh

Ders 01 / 21

Neden Konteyner

Ortam farkının çıktının içine alınıp alınamayacağı sayılır: önceki kursun 18 farkı üç kovaya ayrılır, içeri alınanın bayt bedeli ölçülür ve ortamda kalmak zorunda olanın payı yazılır.

İçindekiler

Önceki kurs farkın nerede saklandığını saydı ve bir yerde durdu: üç ortam ile üretim arasında on boyut üzerinde 18 fark vardı, bunların 12’si ortam künyesinde yazıyordu, 6’sı yalnız süreç koşarken görünüyordu. Sayımın söylediği asıl şey farkın büyüklüğü değil, nerede durduğuydu: kurulu paket sürümleri, kaynak sınırları, dosya yolları, saat dilimi. Fark yazılımın içinde değil, yazılımın koştuğu yerdeydi.

Bu, farkı kapatmanın iki ayrı yolu olduğu anlamına gelir. Birincisi ortamları birbirine yaklaştırmaktır: her halkanın künyesini üretiminkine çekmek, sonra çekilmiş hâlde tutmak. İkincisi farkı ortamdan alıp yapı çıktısının içine koymaktır. Çıktı koştuğu yerden ne kadar az şey isterse, koştuğu yerin ne kadar farklı olduğu o kadar az önem taşır.

İkinci yolun adı konteynerdir: uygulamanın yanına, uygulamanın ihtiyaç duyduğu ortam parçalarını da koyup hepsini tek bir çıktı olarak taşımak. Bu ders o yolun ne kadarını gerçekten kapatabildiğini sorar ve soru üç parçalıdır — 18 farkın kaçı çıktının içine alınabilir, alınanın bedeli kaç bayttır, alınamayan ne kalır.

Kurs boyunca aynı kurgu sürer: bir belediyenin bölgesel ölçüm ağı. Yazılım su sayaçlarından okuma toplar, doğrular, faturaya çevirir ve saha ekiplerine iş emri açar; gecelik bir toplu iş bütün günün okumalarını işler. Kurgudur; aşağıdaki sayılar da bu kurgunun modelinden gelir.

KK1. Önceki kursun fark listesi bu dersin girdisidir; on boyut ve ortam başına fark sayısı oradan devralınır, yeniden sayılmaz. KK2. Ölçülen çıktı tek bir dosya değil, dosyalardan oluşan bir kümedir; kümenin nasıl paketlendiği sonraki konunun sorusudur.

Farkı Üç Kovaya Ayırmak

Bir farkın çıktının içine alınabilmesinin tek koşulu vardır: o boyutun değeri bir dosya olarak yazılabilmelidir. Paket sürümü yazılabilir; paketin kendisi çıktının içine konur ve ortamda kurulu olan sürüm önemsizleşir. Ağ gecikmesi yazılamaz; gecikme bir dosyanın içeriği değil, iki makine arasındaki yolun özelliğidir. Aradaki boyutlar da vardır ve onların ayrı bir adı olmalıdır.

KK3. Kova kuralı tektir: boyutun değeri bir dosya olarak çıktının içine yazılabiliyorsa içeri; çekirdek, donanım ya da işlenen verinin kendisi belirliyorsa ortam; ikisi de doğruysa sınır. KK4. Bir boyutun kovası bütün ortamlar için aynıdır; kova boyuta bağlıdır, ortama değil.

// olcum-agi/kova.mjs — onceki kursun 18 farkini uc kovaya ayirir (model, kurgu veri)

// Girdi: bolgesel olcum agi kurgusunda uc ortamin uretimden ayrildigi boyutlar.
// Liste onceki kurstan devralindi; burada yeniden sayilmiyor.
const FARK = {
  gelistirme: ["cozumleyiciSurumu", "bellekMB", "esZamanliIsci", "sayacSayisi",
    "faturaKapisi", "isEmriKuyrugu", "saatDilimi", "harfDuyarliDosyaSistemi", "agGecikmeMs"],
  sinama: ["cozumleyiciSurumu", "bellekMB", "esZamanliIsci", "sayacSayisi",
    "faturaKapisi", "saatDilimi", "agGecikmeMs"],
  hazirlik: ["sayacSayisi", "agGecikmeMs"],
};

// Kova kurali: boyutun degeri bir dosya olarak ciktinin icine yazilabiliyorsa ICERI;
// cekirdek, donanim ya da isleyen verinin kendisi belirliyorsa ORTAM; ikisi de
// dogruysa SINIR.
const KOVA = {
  cozumleyiciSurumu: ["iceri", "cozumleyici ikilisi ciktinin icinde tasinir"],
  kuralPaketiSurumu: ["iceri", "kural paketi ciktinin icinde tasinir"],
  esZamanliIsci: ["iceri", "isci sayisi cikti icindeki yapilandirmada sabitlenir"],
  saatDilimi: ["iceri", "saat dilimi tablosu ve ayari ciktinin icinde tasinir"],
  bellekMB: ["ortam", "siniri uygulayan denetim grubu ciktinin disindadir"],
  sayacSayisi: ["ortam", "veri hacmi ciktinin degil isleyen sistemin ozelligidir"],
  agGecikmeMs: ["ortam", "gecikme fiziksel yolun ozelligidir"],
  faturaKapisi: ["sinir", "istemci iceri girer, kapinin kendisi disarida kalir"],
  isEmriKuyrugu: ["sinir", "istemci iceri girer, kuyruk disarida kalir"],
  harfDuyarliDosyaSistemi: ["sinir", "dosyalar iceri girer, ad eslestirme kurali alttan gelir"],
};

const ORTAMLAR = Object.keys(FARK);
const BOYUTLAR = Object.keys(KOVA);
const kovasi = (b) => KOVA[b][0];

console.log("boyut".padEnd(26) + "kova".padEnd(8) + "fark".padEnd(6) + "gerekce");
for (const b of BOYUTLAR) {
  const kac = ORTAMLAR.filter((o) => FARK[o].includes(b)).length;
  console.log(b.padEnd(26) + kovasi(b).padEnd(8) + String(kac).padEnd(6) + KOVA[b][1]);
}

const tumFarklar = ORTAMLAR.flatMap((o) => FARK[o]);
const kovaSay = (k) => tumFarklar.filter((b) => kovasi(b) === k).length;
const boyutSay = (k) => BOYUTLAR.filter((b) => kovasi(b) === k).length;

console.log("\ntoplam fark: " + tumFarklar.length + " (on boyut uzerinde)");
for (const k of ["iceri", "ortam", "sinir"]) {
  console.log(`${k.padEnd(8)}boyut ${boyutSay(k)}/10   fark ${kovaSay(k)}/18   ` +
    BOYUTLAR.filter((b) => kovasi(b) === k).join(", "));
}

console.log("\nciktinin icine alindiginda ortam basina kalan fark:");
for (const o of ORTAMLAR) {
  const kalan = FARK[o].filter((b) => kovasi(b) !== "iceri");
  console.log(`${o.padEnd(12)}${FARK[o].length} -> ${kalan.length}   kalan: ${kalan.join(", ")}`);
}
const kalanToplam = ORTAMLAR.reduce((t, o) =>
  t + FARK[o].filter((b) => kovasi(b) !== "iceri").length, 0);
console.log(`toplam 18 -> ${kalanToplam}; sinir kovasi da kapatilirsa ${kalanToplam - kovaSay("sinir")}`);
boyut                     kova    fark  gerekce
cozumleyiciSurumu         iceri   2     cozumleyici ikilisi ciktinin icinde tasinir
kuralPaketiSurumu         iceri   0     kural paketi ciktinin icinde tasinir
esZamanliIsci             iceri   2     isci sayisi cikti icindeki yapilandirmada sabitlenir
saatDilimi                iceri   2     saat dilimi tablosu ve ayari ciktinin icinde tasinir
bellekMB                  ortam   2     siniri uygulayan denetim grubu ciktinin disindadir
sayacSayisi               ortam   3     veri hacmi ciktinin degil isleyen sistemin ozelligidir
agGecikmeMs               ortam   3     gecikme fiziksel yolun ozelligidir
faturaKapisi              sinir   2     istemci iceri girer, kapinin kendisi disarida kalir
isEmriKuyrugu             sinir   1     istemci iceri girer, kuyruk disarida kalir
harfDuyarliDosyaSistemi   sinir   1     dosyalar iceri girer, ad eslestirme kurali alttan gelir

toplam fark: 18 (on boyut uzerinde)
iceri   boyut 4/10   fark 6/18   cozumleyiciSurumu, kuralPaketiSurumu, esZamanliIsci, saatDilimi
ortam   boyut 3/10   fark 8/18   bellekMB, sayacSayisi, agGecikmeMs
sinir   boyut 3/10   fark 4/18   faturaKapisi, isEmriKuyrugu, harfDuyarliDosyaSistemi

ciktinin icine alindiginda ortam basina kalan fark:
gelistirme  9 -> 6   kalan: bellekMB, sayacSayisi, faturaKapisi, isEmriKuyrugu, harfDuyarliDosyaSistemi, agGecikmeMs
sinama      7 -> 4   kalan: bellekMB, sayacSayisi, faturaKapisi, agGecikmeMs
hazirlik    2 -> 2   kalan: sayacSayisi, agGecikmeMs
toplam 18 -> 12; sinir kovasi da kapatilirsa 8

Kovalar boyut sayısı ile fark sayısı arasında ayrışıyor. İçeri kovasında dört boyut var ama yalnız 6 fark duruyor; çünkü kural paketi sürümü zaten dört ortamda da aynıydı — kapatılacak bir farkı yoktu. Ortam kovasında üç boyut var ama 8 fark duruyor; veri hacmi ve ağ gecikmesi üç ortamın üçünde de üretimden ayrılıyordu. Yani içeri alınabilirlik ile farkın büyüklüğü ters yönde dizilmiş: en çok fark üreten iki boyut, çıktının içine hiç alınamayan iki boyut. Kova sayımı bu yüzden boyut üzerinden değil fark üzerinden okunur; boyut sayısı neyin ele alınabildiğini, fark sayısı ise ne kadarının gerçekten kapandığını söyler.

Ortam başına okuma daha keskin. Geliştirme ortamı 9 farktan 6’sına iniyor, sınama 7’den 4’e, hazırlık 2’den 2’ye — yani hiç değişmiyor. Üretime en yakın halkanın kazancı sıfır, çünkü hazırlığın ayrıldığı iki boyutun ikisi de ortam kovasında. Bu sonuç, “konteyner ortam farkını ortadan kaldırır” cümlesinin tam olarak nerede yanlış olduğunu verir: kazanç, üretimden en uzak halkada en büyük, en yakın halkada sıfırdır. Toplamda 18 fark 12’ye iner; sınır kovasındaki dördü de kapatılırsa 8’e.

İçeri Almanın Bayt Bedeli

Altı farkın kapanması bedava değil. İçeri alınan her parça çıktının içine gerçekten yazılan bir dosya kümesidir ve çıktının boyutu, taşınan her yere taşınır: depolanan bayt, ağdan geçen bayt, diske açılan bayt.

KK5. Ölçümün kaynak ağacı gerçektir — servis dosyaları belirlenimci bir üreteçle diske yazılır (tohum 20260801) ve node:fs ile gerçekten ölçülür. KK6. İçeri alınan parçaların boyutları ise modeldir — bildirilen değerlerdir, ölçülmüş bir kurulumdan gelmez — ve içeri alınan parça ortamda kurulu olanın yerine geçer; iki kopya sayılmaz.

// olcum-agi/bedel.mjs — iceri alinanin bayt bedeli
// Kaynak agaci gercekten diske yazilir ve gercekten olculur; ortamdan iceri
// alinan parcalarin boyutlari MODEL degeridir, olculmus bir kurulumdan degil.
import { mkdirSync, writeFileSync, readdirSync, statSync, rmSync } from "node:fs";
import { join } from "node:path";

const KOK = "/tmp/olcum-agi-kaynak";
let tohum = 20260801;                       // uretec tohumu; ayni tohum ayni agaci verir
const sonraki = () => (tohum = (tohum * 1103515245 + 12345) % 2147483648);

// Kurgu servislerin kaynak agaci: her servis icin belirlenimci satirlar uretilir.
const SERVIS = { toplayici: 210, dogrulayici: 340, faturalama: 480, isEmri: 160, gecelikIs: 260 };
rmSync(KOK, { recursive: true, force: true });
mkdirSync(join(KOK, "src"), { recursive: true });
for (const [ad, satir] of Object.entries(SERVIS)) {
  const govde = Array.from({ length: satir }, (_, i) =>
    `export const ${ad}${i} = ${sonraki() % 100000};`).join("\n");
  writeFileSync(join(KOK, "src", `${ad}.mjs`), govde + "\n");
}
writeFileSync(join(KOK, "yapilandirma.json"),
  JSON.stringify({ esZamanliIsci: 8, saatDilimi: "+00:00", kuralPaketi: "9.1.0" }, null, 2));

const bayt = (yol) => statSync(yol).isDirectory()
  ? readdirSync(yol).reduce((t, a) => t + bayt(join(yol, a)), 0) : statSync(yol).size;
const kaynak = bayt(KOK);

// MODEL: ortamdan cikarilip ciktinin icine alinan parcalarin bildirilen boyutlari.
const ICERI = {
  "cozumleyici calisma zamani": 44_800_000,
  "kural paketi ve bagimliliklari": 31_200_000,
  "saat dilimi tablosu": 460_000,
};
const TABAN = { "kucuk": 7_600_000, "orta": 31_500_000, "genel amacli": 118_000_000 };
const mb = (n) => (n / 1_000_000).toFixed(2).padStart(8) + " MB";

console.log("olculen kaynak agaci (gercek dosyalar, tohum " + 20260801 + ")");
for (const a of readdirSync(join(KOK, "src")).sort())
  console.log("  src/" + a.padEnd(20) + String(bayt(join(KOK, "src", a))).padStart(8) + " bayt");
console.log("  yapilandirma.json".padEnd(24) +
  String(bayt(join(KOK, "yapilandirma.json"))).padStart(8) + " bayt");
console.log("  kaynak toplami".padEnd(24) + String(kaynak).padStart(8) + " bayt = " + mb(kaynak));

console.log("\nMODEL: ciktinin icine alinan parcalar");
let iceriToplam = 0;
for (const [ad, b] of Object.entries(ICERI)) {
  iceriToplam += b;
  console.log("  " + ad.padEnd(32) + mb(b));
}
console.log("  " + "toplam (taban haric)".padEnd(32) + mb(iceriToplam));

console.log("\ntaban kok dosya sistemi turu tarandi (kapatilan fark sayisi degismez: 6/18)");
for (const [tur, t] of Object.entries(TABAN)) {
  const cikti = kaynak + iceriToplam + t;
  console.log(`  ${tur.padEnd(14)}taban ${mb(t)}   cikti ${mb(cikti)}   ` +
    `kaynagin ${Math.round(cikti / kaynak)} kati   fark basina ${mb((cikti - kaynak) / 6)}`);
}
rmSync(KOK, { recursive: true, force: true });
olculen kaynak agaci (gercek dosyalar, tohum 20260801)
  src/dogrulayici.mjs        12429 bayt
  src/faturalama.mjs         17114 bayt
  src/gecelikIs.mjs           8959 bayt
  src/isEmri.mjs              4992 bayt
  src/toplayici.mjs           7217 bayt
  yapilandirma.json           76 bayt
  kaynak toplami           50787 bayt =     0.05 MB

MODEL: ciktinin icine alinan parcalar
  cozumleyici calisma zamani         44.80 MB
  kural paketi ve bagimliliklari     31.20 MB
  saat dilimi tablosu                 0.46 MB
  toplam (taban haric)               76.46 MB

taban kok dosya sistemi turu tarandi (kapatilan fark sayisi degismez: 6/18)
  kucuk         taban     7.60 MB   cikti    84.11 MB   kaynagin 1656 kati   fark basina    14.01 MB
  orta          taban    31.50 MB   cikti   108.01 MB   kaynagin 2127 kati   fark basina    17.99 MB
  genel amacli  taban   118.00 MB   cikti   194.51 MB   kaynagin 3830 kati   fark basina    32.41 MB

Yazılan kod 50.787 bayttır. Ortamdan çıkarılıp içeri alınan üç parça 76,46 MB tutar; buna altındaki kök dosya sistemi eklenir ve çıktı en küçük tabanla 84,11 MB‘a çıkar. Oran kaynağın 1.656 katıdır. Kapatılan altı fark başına düşen bedel 14,01 MB’dır ve bu, yalıtım bütçesinin ilk kalemidir: bir fark, on dört megabayt karşılığında ortamdan çıkarılmıştır.

Taban türünün taranması ikinci kalemi verir. Kapatılan fark sayısı üç türde de aynıdır — 6 — ama çıktı 84,11 MB ile 194,51 MB arasında değişir. Aynı kazanç için ödenen bedel 2,3 kat farklıdır ve farkı yaratan tek şey, çıktının altına hangi kök dosya sisteminin konduğudur. “Konteyner hafiftir” cümlesinin karar taşımamasının nedeni budur: hafiflik bir ölçüm sonucu değil, bir seçimin sonucudur ve seçim çıktının içinde durur.

Bedelin yalnız bayt kalemi de yoktur. İçeri alınan çözümleyici çalışma zamanı, ortamda yükseltildiğinde kendiliğinden yükselen bir bileşendi; içeri alındığı andan itibaren onu yükseltmek çıktının yeniden üretilmesini gerektirir. Fark ortamdan çıkarılırken, o farkı kapatma sorumluluğu da ortamı işletenden çıktıyı üretene geçer.

Bu devir bütçenin görünmeyen kalemidir. Ortamı işleten ekip için bir sürüm yükseltmesi tek bir kurulum işiydi ve o makinede koşan bütün uygulamaları birden ilgilendiriyordu. Çıktının içine alındıktan sonra aynı yükseltme, o parçayı taşıyan her çıktı için ayrı ayrı yapılan bir yapı işidir. Kurgudaki ağda beş servis vardır; çözümleyici sürümünün yükseltilmesi bir kurulum yerine beş yeniden üretim demektir. Bayt kalemi ölçülebildiği için görünürdür, bu kalem ölçülmediği sürece görünmez — ve yalıtım bütçesinin gerçek toplamı ikisinin toplamıdır.

Ortamda Kalan ve Sınırda Duran

Ortam kovasındaki üç boyut, çıktının içine alınamamalarının nedenleriyle birlikte ayrılır. Kaynak sınırını uygulayan şey çıktının dışındaki bir denetim grubudur; çıktı ne kadar bellek isteyeceğini bildirebilir ama sınırı kendisi koyamaz. Veri hacmi işlenen sayaç sayısıdır ve çalışan sistemin özelliğidir, çıktının değil. Ağ gecikmesi fiziksel yolun özelliğidir. Üçünün ortak yanı şudur: hiçbiri bir dosyanın içeriği olarak yazılamaz.

Sınır kovasındaki üç boyut ise farkın bir parçasını içeri alır. Fatura kapısı ve iş emri kuyruğu için istemci kitaplığı, sözleşme tanımı ve zaman aşımı ayarı çıktının içine girer; karşı taraftaki gerçek kapı dışarıda kalır. Fark küçülür ama sıfırlanmaz — “sözleşme sapması” hata sınıfı, istemci içeri alındıktan sonra da açık kalır.

Üçüncü sınır boyutu yalıtımın delindiği yeri en açık gösteren boyuttur. Dosyaların hepsi çıktının içindedir; ama iki dosya adının aynı ad sayılıp sayılmayacağına karar veren kural çıktının içinde değil, çıktının açıldığı dosya sisteminden gelir. Aynı çıktı, harf duyarlı bir dosya sisteminde tarife dosyasını bulamaz, harf duyarsız birinde bulur. Aynı olgu saat için de geçerlidir: saat dilimi tablosu içeri alınabilir, saatin değeri alınamaz — o çekirdekten okunur. Konteyner yalıtımının tek cümlelik özeti buradan çıkar: çıktı dosyaları taşır, davranışı değil. Davranışın bir bölümü hep alttaki çekirdeğe ve dosya sistemine bağlı kalır.

Özet

  • Ortam farkını kapatmanın iki yolu vardır; bu kurs ikincisini ölçer: farkı ortamdan alıp yapı çıktısının içine koymak. Yolun adı konteynerdir.
  • Önceki kursun 18 farkı üç kovaya ayrıldı: içeri alınabilen 6, ortamda kalmak zorunda olan 8, sınırda duran 4. İçeri alınabilirlik ile fark üretme sıklığı ters yönde dizilidir.
  • Ortam başına kazanç eşit değildir: geliştirme 9 farktan 6’ya, sınama 7’den 4’e iner, hazırlık 2’de kalır. Üretime en yakın halkanın kazancı sıfırdır.
  • İçeri almanın bedeli ölçüldü: 50.787 baytlık kaynak, en küçük tabanla 84,11 MB’lık bir çıktıya dönüşür — kaynağın 1.656 katı, kapatılan fark başına 14,01 MB. Taban türü değişince kazanç aynı kalır, bedel 2,3 kat artar.
  • Yalıtım delinir: kaynak sınırını çıktının dışındaki denetim grubu uygular, saatin değeri ve dosya adı eşleştirme kuralı alttaki çekirdekten gelir. Çıktı dosyaları taşır, davranışı değil.

Sonraki Adım

Bu ders farkın çıktının içine alınabileceğini gösterdi ama bir şeyi hiç sormadı: içeri alınan bu 76 megabaytlık ortam parçası nerede ve neyin yanında koşacak? Aynı makinede ikinci bir uygulama da kendi çözümleyicisini, kendi kural paketini ve kendi saat dilimi tablosunu getirirse ne olur — ikisi birbirinin dosyalarını görür mü, birbirinin belleğini tüketebilir mi, biri diğerinin süreçlerini durdurabilir mi? Ortam farkını kapatmak ile ortamı paylaşan iki uygulamayı birbirinden ayırmak ayrı işlerdir ve ikincisinin adı yalıtımdır. Sonraki ders yalıtımı düzeylerine ayırır ve her düzeyin neyi ayırdığını, neyi yinelediğini ve karşılığında ne kadar bellek ile ne kadar başlangıç gecikmesi istediğini aynı ölçütlerle karşılaştırır.

İ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