İçeriğe geç
academia.sh

Ders 12 / 27

Planlama ve Uygulama Akışı

Kayıt ile durumu karşılaştırıp kalem kalem ekle, değiştir, yeniden oluştur ve sil kararı üreten bir planlayıcı yazılır, sonra planın kendisi ölçülür: kaç kalem planda yok ama uygulamada oluyor, kaç kalem planda olup gerçekleşmiyor, yeniden oluşturulacak denilen kalemlerin kaçı gerçekten yeniden oluşturuluyor ve planı gözden geçirmek kaç satır kaç dakika tutuyor.

İçindekiler

Bir önceki ders plan kalemlerini kayıt biçimine göre saydı, ama planın kendisini hep hazır kabul etti: kalemler bir yerden geliyordu. Bu ders o yeri kurar. Planlayıcı, bildirimsel sağlamanın en somut vaadidir — değişiklik uygulanmadan önce ne olacağını gösteren bir liste. Vaadi ölçmenin yolu da bellidir: listeyi üret, sonra uygula, sonra ikisini karşılaştır.

Daha önce sürekli koşan bir uzlaşma döngüsü ölçülmüştü: istenen durumla gerçek durumu her turda karşılaştırıp farkı kendiliğinden kapatan bir denetleyici. Buradaki akış onun tersidir. Uygulama tetiklenir; iki tetikleme arasında geçen sürede gerçek, kimseye sormadan kendi başına değişir. Plan da işte o arada üretilir ve bu dersin bütün sapmaları o boşluktan çıkar.

Ölçüm bölgesel ölçüm ağının kaydı üzerindedir ve kurgudur; koşan şey node ile yazılmış bir planlayıcı modelidir, hiçbir sağlayıcıya çağrı gitmez.

BS37. Planlayıcı kaydı durumla karşılaştırır, gerçekle değil. Durum geçen uygulamanın yazdığı defterdir; gerçek sağlayıcıda o an durandır. İkisi ayrı kaynaktır. BS38. Durum on üç kaynak taşır ve geçen uygulamadan kalmıştır. BS39. Kayıt durumdan on bir noktada ayrılır: bir yeni kaynak, bir silinen kaynak, üç imaj yükseltmesi ve altı alan değişikliği. BS40. Gerçek durumdan üç noktada sapmıştır; üçü de kayıt dışı, elle yapılmış değişikliktir. BS41. Planlayıcının şeması ile koşan sağlayıcının davranışı üç noktada ayrılır: planlayıcı boyut değişikliğini yeniden oluşturma sayar ama sağlayıcı o alanı yerinde günceller; sağlayıcı dizeleri büyük-küçük harf ayırmadan saklar; yeni yaratılan makineye kayıtta olmayan bir alan ekler. Hesaplanan alanın değeri uygulamadan önce bilinmez, yalnız baktığı kaynağın yeniden oluşturulup oluşturulmayacağından tahmin edilir. BS42. Plan kalemi bir başlık satırı yazar; ekle, sil ve yeniden oluştur kalemlerinde kaynağın bütün alanları, değiştir kaleminde yalnız değişen alanlar listelenir. Dikkatli okuma hızı dakikada 25 satırdır.

Planlayıcı

// plan.mjs — kayit ile durumu karsilastirip plan ureten planlayici, ve plani gercek
// uygulamayla karsilastiran olcum. Model; hicbir saglayiciya cagri gitmez.

const REF = (kaynak) => ({ ref: kaynak });      // hesaplanan alan: degeri uygulamadan once bilinmez

// BS38: durum — gecen uygulamanin yazdigi kayit. On uc kaynak.
const DURUM = {
  "ag.olcum": { blok: "10.20.0.0/16", bolge: "kuzey" },
  "altag.toplayici": { ag: "ag-01", blok: "10.20.1.0/24" },
  "guvenlik_kumesi.toplayici": { ag: "ag-01", giris: "10.20.1.0/24" },
  "veri_deposu.sayac": { altag: "altag-01", boyut: "orta", surum: "4.2" },
  "kuyruk.parti": { altag: "altag-01", saklama: 3 },
  "kuyruk.eski_parti": { altag: "altag-01", saklama: 3 },
  "makine.toplayici_kuzey_1": { altag: "altag-01", imaj: "temel-7", boyut: "orta" },
  "makine.toplayici_kuzey_2": { altag: "altag-01", imaj: "temel-7", boyut: "orta" },
  "makine.toplayici_dogu_1": { altag: "altag-01", imaj: "temel-7", boyut: "orta" },
  "nesne.toplayici_ayari": { depo: "olcum-yapilandirma", veri_adresi: "sayac-01.veri" },
  "dengeleyici.toplayici": { altag: "altag-01", algoritma: "sirayla" },
  "saglik_denetimi.toplayici": { hedef: "dengeleyici-01", aralik: 30 },
  "dns_kaydi.toplayici": { adres: "dengeleyici-01.adres", ttl: 300 },
};

// BS39: kayit — istenen. Durumdan on bir noktada ayriliyor.
const KAYIT = {
  ...DURUM,
  "veri_deposu.sayac": { altag: "altag-01", boyut: "buyuk", surum: "4.2" },
  "kuyruk.parti": { altag: "altag-01", saklama: 7 },
  "makine.toplayici_kuzey_1": { altag: "altag-01", imaj: "temel-9", boyut: "orta" },
  "makine.toplayici_kuzey_2": { altag: "altag-01", imaj: "temel-9", boyut: "orta" },
  "makine.toplayici_dogu_1": { altag: "altag-01", imaj: "temel-9", boyut: "orta" },
  "makine.toplayici_dogu_2": { altag: "altag-01", imaj: "temel-9", boyut: "orta" },
  "nesne.toplayici_ayari": { depo: "olcum-yapilandirma", veri_adresi: REF("veri_deposu.sayac") },
  "dengeleyici.toplayici": { altag: "altag-01", algoritma: "SIRAYLA" },
  "saglik_denetimi.toplayici": { hedef: "dengeleyici-01", aralik: 10 },
  "dns_kaydi.toplayici": { adres: "dengeleyici-01.adres", ttl: 60 },
};
delete KAYIT["kuyruk.eski_parti"];

// BS40: gercek — saglayicida gercekten duran. Durumdan uc noktada sapmis; plan bunlari gormez.
const GERCEK = {
  ...DURUM,
  "ag.olcum": { blok: "10.20.0.0/17", bolge: "kuzey" },          // elle daraltilmis
  "guvenlik_kumesi.toplayici": { ag: "ag-01", giris: "0.0.0.0/0" },  // elle acilmis
  "saglik_denetimi.toplayici": { hedef: "dengeleyici-01", aralik: 5 },  // elle dusurulmus
};

const YENIDEN_PLAN = ["imaj", "boyut", "altag"];   // BS41: planlayicinin elindeki sema
const YENIDEN_GERCEK = ["imaj", "altag"];          // saglayici boyutu yerinde guncelliyor
const NORM = (v) => (typeof v === "string" ? v.toLowerCase() : v);
const VARSAYILAN = { makine: { izleme: "acik" } };  // saglayici yeni kaynaga kendi ekliyor
const K = (v) => JSON.stringify(v);

// Ortak karsilastirici. gercekMi=false ise planlayici, true ise uygulama gozuyle bakar.
function karsilastir(kayit, taban, { gercekMi }) {
  const yeniden = gercekMi ? YENIDEN_GERCEK : YENIDEN_PLAN;
  const esit = gercekMi ? (a, b) => K(NORM(a)) === K(NORM(b)) : (a, b) => K(a) === K(b);
  const kalem = new Map();
  for (const [ad, y] of Object.entries(kayit)) {
    const e = taban[ad];
    const tum = Object.keys(y).length;
    if (!e) { kalem.set(ad, { karar: "ekle", alan: Object.keys(y), tum }); continue; }
    const alan = Object.keys(y).filter((k) => !y[k]?.ref && !esit(y[k], e[k]));
    const karar = alan.length
      ? (alan.some((k) => yeniden.includes(k)) ? "yeniden olustur" : "degistir") : null;
    kalem.set(ad, { karar, alan, tum });
  }
  for (const ad of Object.keys(taban))
    if (!kayit[ad]) kalem.set(ad, { karar: "sil", alan: [], tum: Object.keys(taban[ad]).length });
  // Hesaplanan alan: baktigi kaynak yeniden olusturuluyorsa deger degisir.
  for (const [ad, y] of Object.entries(kayit))
    for (const [k, v] of Object.entries(y))
      if (v?.ref && kalem.get(v.ref)?.karar === "yeniden olustur") {
        const kl = kalem.get(ad);
        kl.alan.push(k);
        kl.karar = kl.alan.some((a) => yeniden.includes(a)) ? "yeniden olustur" : "degistir";
      }
  for (const [ad, kl] of kalem) if (!kl.karar) kalem.delete(ad);
  return kalem;
}

const PLAN = karsilastir(KAYIT, DURUM, { gercekMi: false });
const UYGULAMA = karsilastir(KAYIT, GERCEK, { gercekMi: true });
// Saglayici varsayilani: yeni kaynak yaratilinca plan disi alan eklenir.
let varsayilanAlan = 0;
for (const [ad, kl] of UYGULAMA)
  if (kl.karar === "ekle") varsayilanAlan += Object.keys(VARSAYILAN[ad.split(".")[0]] ?? {}).length;

const say = (m, k) => [...m.values()].filter((v) => v.karar === k).length;
console.log("karar          plan  uygulama");
const kutuk = (ad, a, b) =>
  console.log(`${ad.padEnd(15)}${String(a).padStart(4)}${String(b).padStart(10)}`);
for (const k of ["ekle", "degistir", "yeniden olustur", "sil"])
  kutuk(k, say(PLAN, k), say(UYGULAMA, k));
kutuk("toplam", PLAN.size, UYGULAMA.size);

const planDisi = [...UYGULAMA.keys()].filter((a) => !PLAN.has(a));
const olmayan = [...PLAN.keys()].filter((a) => !UYGULAMA.has(a));
const ortak = [...PLAN.keys()].filter((a) => UYGULAMA.has(a));
const kararUyusmaz = ortak.filter((a) => PLAN.get(a).karar !== UYGULAMA.get(a).karar);
const planYeniden = [...PLAN].filter(([, v]) => v.karar === "yeniden olustur").map(([a]) => a);
const gercekYeniden = planYeniden.filter((a) => UYGULAMA.get(a)?.karar === "yeniden olustur");
const eskiYanlis = ortak.filter((a) => DURUM[a] && GERCEK[a] && K(DURUM[a]) !== K(GERCEK[a]));

console.log("\nplanin uygulamayi ongorme orani");
console.log(`  planda yok, uygulamada oldu : ${planDisi.length}  (${planDisi.join(", ")})`);
console.log(`  planda var, uygulamada yok  : ${olmayan.length}  (${olmayan.join(", ")})`);
console.log(`  ikisinde de var             : ${ortak.length}, karari uyusmayan ` +
  `${kararUyusmaz.length} (${kararUyusmaz.join(", ")})`);
console.log(`  yeniden olusturma orani     : ${gercekYeniden.length}/${planYeniden.length}`);
console.log(`  planin gosterdigi eski deger yanlis: ${eskiYanlis.length} kalem ` +
  `(${eskiYanlis.join(", ")})`);
console.log(`  planda hic gorunmeyen alan  : ${varsayilanAlan} (saglayici varsayilani)`);
const kesisim = ortak.length - kararUyusmaz.length;
const birlesim = new Set([...PLAN.keys(), ...UYGULAMA.keys()]).size;
console.log(`  tam isabet ${kesisim}/${birlesim} = %${Math.round((kesisim / birlesim) * 100)}`);

// BS42: plan kalemi 1 baslik satiri yazar; ekle/sil/yeniden olustur kaleminde kaynagin butun
// alanlari, degistir kaleminde yalniz degisen alanlar listelenir. Dikkatli okuma 25 satir/dakika.
const TUMU = ["ekle", "sil", "yeniden olustur"];
const satirSay = (m) => [...m.values()].reduce((s, v) =>
  s + 1 + (TUMU.includes(v.karar) ? v.tum : v.alan.length), 0);
const kararSatiri = (m) => [...m.values()]
  .filter((v) => v.karar === "yeniden olustur" || v.karar === "sil")
  .reduce((s, v) => s + 1 + v.tum, 0);

// Ayni kaydin N bolgede yinelenmis hali: adresler ve hesaplanan alan atiflari onekleniyor.
const olcekle = (obj, n) => Object.fromEntries(Array.from({ length: n }, (_, i) =>
  Object.entries(obj).map(([ad, y]) => [`b${i}_${ad}`, Object.fromEntries(
    Object.entries(y).map(([k, v]) => [k, v?.ref ? REF(`b${i}_${v.ref}`) : v]))])).flat());

console.log("\nplani okumanin bedeli");
console.log("bolge  kalem  satir  dakika  karar isteyen satir   %");
for (const n of [1, 3, 10, 30]) {
  const pl = karsilastir(olcekle(KAYIT, n), olcekle(DURUM, n), { gercekMi: false });
  const t = satirSay(pl), kr = kararSatiri(pl);
  console.log(`${String(n).padStart(5)}${String(pl.size).padStart(7)}${String(t).padStart(7)}` +
    `${(t / 25).toFixed(1).padStart(8)}${String(kr).padStart(21)}` +
    `${String(Math.round((kr / t) * 100)).padStart(4)}`);
}
karar          plan  uygulama
ekle              1         1
degistir          5         6
yeniden olustur   4         3
sil               1         1
toplam           11        11

planin uygulamayi ongorme orani
  planda yok, uygulamada oldu : 2  (ag.olcum, guvenlik_kumesi.toplayici)
  planda var, uygulamada yok  : 2  (nesne.toplayici_ayari, dengeleyici.toplayici)
  ikisinde de var             : 9, karari uyusmayan 1 (veri_deposu.sayac)
  yeniden olusturma orani     : 3/4
  planin gosterdigi eski deger yanlis: 1 kalem (saglik_denetimi.toplayici)
  planda hic gorunmeyen alan  : 1 (saglayici varsayilani)
  tam isabet 8/13 = %62

plani okumanin bedeli
bolge  kalem  satir  dakika  karar isteyen satir   %
    1     11     33     1.3                   19  58
    3     33     99     4.0                   57  58
   10    110    330    13.2                  190  58
   30    330    990    39.6                  570  58

Üst tablo ilk bakışta rahatlatıcıdır: plan on bir kalem, uygulama on bir kalem. Sayı tutuyor. Alt bölüm o rahatlığı kaldırır — aynı sayıdaki iki liste aynı liste değildir. On üç ayrı adresin sekizinde plan ile uygulama hem kalemde hem kararda birleşiyor. Tam isabet oranı yüzde 62.

Sapmanın kaynağı tek bir yapısal seçimdir: planlayıcı kaydı durumla karşılaştırır, uygulama ise gerçeğe dokunur. Durum ile gerçek arasındaki her fark, plana tanım gereği giremez. Ölçüm ağında üç kalem böyle: ağ bloğu biri tarafından daraltılmış, güvenlik kümesinin giriş kuralı sonuna kadar açılmış, sağlık denetiminin aralığı elle düşürülmüş. Plan hiçbirini yazmaz. Uygulama ilk ikisini sessizce geri alır — planda görünmeyen iki kalem — üçüncüsünde ise kalemi doğru gösterir ama eski değeri yanlış gösterir: plan “30’dan 10’a” der, gerçekte 5’ten 10’a çıkılır.

Bu üçüncü tür özellikle sinsi olandır, çünkü kalem sayısını bozmaz. Planı okuyan kişi doğru sayıda kalem görür, doğru kararları görür, yalnız her kalemin nereden başladığı konusunda yanıltılır. Güvenlik kümesinin sonuna kadar açılmış olması da böyle geri alınır: kimse istemeden düzeltilir, kimse fark etmeden kapanır ve o kuralın ne kadar süre açık kaldığı hiçbir yere yazılmaz.

Planda Olup Gerçekleşmeyen Kalemler

Ters yöndeki iki kalem başka bir mekanizmadan gelir. dengeleyici.toplayici kalemi plandadır çünkü kayıt algoritma değerini büyük harfle yazmıştır ve planlayıcı dizeleri birebir karşılaştırır. Sağlayıcı aynı değeri harf ayrımı gözetmeden sakladığı için uygulamada hiçbir şey olmaz. Plan bir değişiklik vaat etti, uygulama sıfır iş yaptı.

Bu kalem zararsız görünür ama bedeli vardır: her plan koşumunda yeniden çıkar. Kayıt ile durum arasında kapanmayan bir fark, uzlaşmayan bir kalem olarak kalıcı hâle gelir ve planı okuyan kişi onu her seferinde gözden geçirmek zorunda kalır. Zamanla böyle kalemler “her zaman çıkar, boş ver” diye öğrenilir — ve o alışkanlık plandaki gerçek bir kalemi de aynı refleksle geçiştirir.

İkinci kalem daha derindir. nesne.toplayici_ayari kaydında veri deposunun adresi vardır ve bu adres hesaplanan bir alandır: değeri ancak uygulamadan sonra bilinir. Planlayıcı bu alanı tahmin edemez, yalnız şunu bilir — baktığı kaynak yeniden oluşturulacaksa adres de değişecektir. Veri deposu planda yeniden oluşturma kalemidir, dolayısıyla ayar nesnesi de plana girer. Uygulamada veri deposu yeniden oluşturulmaz, adresi değişmez ve ayar nesnesine dokunulmaz. Planlayıcı burada yanlış bir veri değil, yanlış bir varsayımın sonucunu yazdı.

Yeniden Oluşturulacak Denilen Kalemler

Yeniden oluşturma satırı bu kursun en pahalı kararıdır: yok etmek ve yeniden yaratmak geri alınamaz ve önceki derste ölçüldüğü gibi kesinti üretir. Planın bu kalemdeki isabeti dörtte üçtür.

Kaçırılan kalem veri deposudur ve sebebi bir kayıt hatası değildir. Planlayıcının elindeki şema boyut alanının yeniden oluşturma gerektirdiğini söylüyor; koşan sağlayıcı ise o alanı yerinde güncelleyebiliyor. Şema ile davranış arasındaki bu tek satırlık fark, plana bakan kişiye kırk bir günlük sayaç verisinin silineceğini gösterdi. Yanılma yönü şanslıdır — plan gerçekten olandan daha kötüsünü vaat etti — ama yön bir güvence değildir; ters yöndeki bir şema farkı, planda “yerinde değişecek” yazan bir kalemi uygulamada yeniden oluşturmaya çevirir.

Bu tek kalemin dalga etkisi de sayıya girer: ayar nesnesinin plana girmesinin tek sebebi veri deposunun yeniden oluşturulacak sanılmasıydı. Yanlış bir yeniden oluşturma kararı, kendisi dışında en az bir kalem daha üretti. Hesaplanan alana bakan kaynak sayısı arttıkça bu çarpan büyür.

Bir de hiç görünmeyen bir kalem var. Yeni yaratılan makineye sağlayıcı, kayıtta yazmayan bir alan ekliyor. Plan üç alanlı bir kaynak yaratacağını söylüyor, ortaya dört alanlı bir kaynak çıkıyor. Dördüncü alan bir sonraki uygulamada da plana girmez, çünkü kayıt o alanı hiç bilmez. Kaydın kapsamadığı altyapı burada tam olarak bir alan genişliğindedir, ve o alanı kimse yönetmez.

Planı Okumanın Bedeli

Alt tablo planın kendi maliyetini verir. Tek bölge için plan 33 satır ve dikkatli okumayla 1,3 dakika. Bu, gözden geçirilebilir bir metindir. Ölçüm ağı otuz bölgeye çıktığında aynı plan 990 satıra ve 39,6 dakikaya çıkar — ve bu, tek bir imaj yükseltmesinin planıdır.

Oranın sabit kalması dikkate değer: karar isteyen satırlar, yani yeniden oluşturma ve silme kalemleri, her ölçekte planın yüzde 58’idir. Plan büyüdükçe sinyal oranı düşmez, ama mutlak gözden geçirme yükü doğrusal büyür. Otuz bölgelik bir planda 570 satır geri alınamaz bir karar taşır ve bunların hepsi aynı ekranda, aynı biçimde, aynı renkte akar.

Buradan çıkan işletim kuralı sayıya dayanır. Kırk dakikalık bir planı satır satır okuyan kimse yoktur; okunmayan plan ise vaadini yerine getirmez. Planın gözden geçirilebilir kalması için ya kaydın uygulama birimi küçültülür — otuz bölge tek seferde değil, bölge bölge uygulanır — ya da plandan yalnız yeniden oluşturma ve silme kalemleri süzülüp önce onlar okunur. İkisi de kaydın bölünmesiyle ilgilidir, ve o konu bu dersin sınırının dışındadır.

Son olarak planın öngörme oranı ile okuma bedeli birlikte okunmalıdır. Yüzde 62 isabetli bir liste, otuz dakika okunduğunda bile uygulamanın tamamını anlatmaz. Planın değeri kesinlik değil, karar verilebilirliktir: geri alınamaz kalemleri uygulamadan önce göstermesi. O işi dörtte üç isabetle yapıyor, ve kaçırdığı çeyreğin sebebi kayıtta değil, planlayıcının şeması ile sağlayıcının davranışı arasındaki farktadır.

Özet

  • Planlayıcı kaydı durumla karşılaştırır, uygulama gerçeğe dokunur; durum ile gerçek arasındaki her fark plana tanım gereği giremez. Sapmaların çoğunun kaynağı bu tek yapısal seçimdir.
  • Plan 11 kalem, uygulama 11 kalem, ama 13 adresin yalnız 8’inde hem kalem hem karar uyuşuyor: tam isabet yüzde 62.
  • Planda yok, uygulamada oldu: 2 kalem (elle daraltılmış ağ bloğu, sonuna kadar açılmış giriş kuralı). 1 kalem daha doğru göründü ama eski değeri yanlış gösterdi: plan 30’dan der, gerçek 5’tir.
  • Planda var, uygulamada yok: 2 kalem — biri harf normalizasyonundan (her koşumda yeniden çıkar), biri hesaplanan alandan (yanlış yeniden oluşturma varsayımının dalga etkisi).
  • Yeniden oluşturma isabeti 3/4. Kaçırılan kalem, planlayıcının şeması ile sağlayıcının davranışı arasındaki bir alanlık farktan geldi ve tek başına bir kalem daha üretti.
  • Plan 1 bölgede 33 satır ve 1,3 dakika, 30 bölgede 990 satır ve 39,6 dakika; karar isteyen satır oranı her ölçekte yüzde 58 kalıyor, yani gözden geçirme yükü doğrusal büyüyor.

Sonraki Adım

Bu ders planı, kayıtta yazılı olan kaynaklar için ölçtü. Ölçüm ağında ise kayıtta hiç yazmayan kaynaklar da var: ilk kurulumda elle açılmış bir nesne deposu, bir DNS bölgesi, iki eski makine. Onlar plana hiç girmez, çünkü planlayıcı yalnız kaydın ve durumun bildiğini karşılaştırır. Sonraki ders bu kaynakları yönetime alır — içe aktarma — ve bedelini sayar: kalem başına kaç alan elle eşleştiriliyor, içe aktarma sonrası ilk planda kaç kalem gereksiz değişiklik gösteriyor, kaynağı kayıt dışı bırakmakla yönetime almak arasındaki fark ne.

İ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