---
title: 'Sağlayıcılar ve Kaynaklar'
source: 'https://academia.sh/tr/kurslar/kod-olarak-altyapi/saglayicilar-ve-kaynaklar'
course: 'Kod Olarak Altyapı'
language: tr
updated: '2026-08-17T18:09:06+00:00'
license: 'CC BY-SA 4.0'
---

# Sağlayıcılar ve Kaynaklar

Sağlayıcı, yarat-oku-güncelle-sil arayüzü olarak modellenir ve beş kaynak tipi bu arayüzü uygular; kaydın yazdığı alanla hedefte gerçekten duran alan sayılır. Bir değişiklik kümesinde planın kaç kalemi öngördüğü, hangi alanların kaynağı yeniden oluşturmaya zorladığı ve sağlayıcı sürümü değiştiğinde kayıt hiç değişmeden kaç alanın kaydığı ölçülür.

Bir önceki ders kaydı bir dile bağladı, ama kaydın karşısındaki hedef sistem beş satırlık bir
işlevdi: değeri alan, yazan ya da reddeden. Gerçekte bir kaynak yaratılır, okunur, güncellenir ve
silinir; bu dört işlemi bilen, kayıttaki alan adlarını hedef sistemin karşılıklarına çeviren ve
hangi alanın yerinde değiştirilebileceğini bilen katmanın adı **sağlayıcı**dır. Bu ders sağlayıcıyı
bir arayüz olarak modeller ve üç şeyi sayar: kaydın yazdığı alanla hedefte gerçekten duran alan
arasındaki fark, bir değişikliğin planının uygulamayı ne oranda öngördüğü, ve sağlayıcı sürümü
değiştiğinde kayıt hiç değişmeden ne kadarının kaydığı.

Ölçüm **bölgesel ölçüm ağının** batı ortamı üzerindedir ve **kurgudur**; sağlayıcı, kaynak tipi
kataloğu ve hedef depo `node` ile kurulmuş bir **modeldir**. Hiçbir gerçek ürün ya da hedef sistem
çağrılmaz.

**BS7.** Sağlayıcı beş kaynak tipi tanır: makine, kuyruk, veri deposu, ağ, nesne deposu.
**BS8.** Her alanın üç özelliği vardır: türü, yerinde güncellenip güncellenemediği, varsayılanı.
Varsayılanı olmayan alan zorunludur.
**BS9.** Bir alan yerinde güncellenemiyorsa, o alan değiştiğinde kaynak silinip yeniden yaratılır ve
bunun tip başına sabit bir kesinti dakikası vardır.
**BS10.** Plan aşaması yalnız katalogdaki yerinde güncellenebilirlik bayrağını bilir.
**BS11.** Hedef sistem, sayısal bir alan iki katından fazla büyütülürse yerinde büyütmeyi reddeder;
bu kural katalogda yazılı değildir.
**BS12.** Kayıtta yazılmayan alanları sağlayıcı kendi varsayılanıyla doldurur ve doldurduğu değer
kayıtta hiçbir yerde görünmez.

## Sağlayıcı Arayüzü ve Kaynak Tipleri

```js
// saglayici.mjs — kurgu saglayici: kaynak tipi katalogu, yarat/oku/guncelle/sil arayuzu (model).
const A = (tur, yerinde, varsayilan) => ({ tur, yerinde, varsayilan });
export const KATALOG = {                            // saglayici surum 1
  makine: { bolge: A("dize", false), sayi: A("sayi", true), cekirdek: A("sayi", false),
    bellek_gb: A("sayi", true), disk_gb: A("sayi", true, 100), imaj: A("dize", false, "temel-2"),
    izleme: A("dize", true, "acik") },
  kuyruk: { bolge: A("dize", false), bolme: A("sayi", false), saklama_gn: A("sayi", true, 7),
    bicim: A("dize", false, "ikili"), sifreleme: A("dize", true, "kapali") },
  veri_deposu: { bolge: A("dize", false), boyut_gb: A("sayi", true), surum: A("dize", false, "3"),
    yedek_gn: A("sayi", true, 1), sifreleme: A("dize", false, "kapali") },
  ag: { bolge: A("dize", false), alt_ag: A("sayi", false), gecis: A("sayi", true, 1) },
  nesne_deposu: { bolge: A("dize", false), sinif: A("dize", true, "sicak"),
    surum_tut: A("dize", false, "kapali"), saklama_gn: A("sayi", true, 365) },
};
export const KESINTI = { makine: 4, kuyruk: 9, veri_deposu: 25, ag: 12, nesne_deposu: 30 };

export const KAYIT = {                              // batı ortaminin kurgu kaydi
  "makine.toplayici": { bolge: "bati", sayi: 6, cekirdek: 4, bellek_gb: 8 },
  "makine.dogrulayici": { bolge: "bati", sayi: 2, cekirdek: 8, bellek_gb: 16, disk_gb: 200, imaj: "temel-2" },
  "kuyruk.sayac": { bolge: "bati", bolme: 12 },
  "kuyruk.uyari": { bolge: "bati", bolme: 3, bicim: "metin" },
  "veri_deposu.olcum": { bolge: "bati", boyut_gb: 300 },
  "ag.omurga": { bolge: "bati", alt_ag: 3 },
  "nesne_deposu.arsiv": { bolge: "bati" },
};

export const varsayilanlar = (t) => Object.fromEntries(Object.entries(t)
  .filter(([, a]) => a.varsayilan !== undefined).map(([f, a]) => [f, a.varsayilan]));

export function saglayiciYap(katalog) {             // arayuz: yarat / oku / guncelle / sil
  const depo = new Map(), cagri = { oku: 0, yarat: 0, guncelle: 0, sil: 0 };
  return { katalog, cagri, depo,
    oku: (t, a) => (cagri.oku++, depo.get(`${t}.${a}`) ?? null),
    yarat: (t, a, alan) => (cagri.yarat++, depo.set(`${t}.${a}`, { ...varsayilanlar(katalog[t]), ...alan })),
    guncelle: (t, a, alan) => (cagri.guncelle++, Object.assign(depo.get(`${t}.${a}`), alan)),
    sil: (t, a) => (cagri.sil++, depo.delete(`${t}.${a}`)) };
}

const ASIRI = (a, eski, yeni) => a.tur === "sayi" && yeni > eski * 2;   // yerinde buyutulemeyen artis
export function karar(s, anahtar, istenen, plan) {  // plan asamasi ASIRI kuralini bilmez
  const [t, a] = anahtar.split(".");
  const gercek = s.oku(t, a);
  if (!gercek) return ["yaratilacak", []];
  const fark = Object.keys(istenen).filter((f) => gercek[f] !== istenen[f]);
  const zorlayan = fark.filter((f) => !s.katalog[t][f].yerinde ||
    (!plan && ASIRI(s.katalog[t][f], gercek[f], istenen[f])));
  return zorlayan.length ? ["yeniden olusturulacak", zorlayan]
    : fark.length ? ["guncellenecek", fark] : ["degismeyecek", []];
}

export const GECMIS = { yaratilacak: "yaratildi", "yeniden olusturulacak": "yeniden olusturuldu",
  guncellenecek: "guncellendi", degismeyecek: "degismedi", silinecek: "silindi" };

export function uygula(s, kayit) {
  const sonuc = [];
  for (const [k, istenen] of Object.entries(kayit)) {
    const [t, a] = k.split("."), [ne, alan] = karar(s, k, istenen, false);
    if (ne === "yaratilacak") s.yarat(t, a, istenen);
    else if (ne === "yeniden olusturulacak") { s.sil(t, a); s.yarat(t, a, istenen); }
    else if (ne === "guncellenecek") s.guncelle(t, a, Object.fromEntries(alan.map((f) => [f, istenen[f]])));
    sonuc.push([k, GECMIS[ne], alan]);
  }
  for (const k of [...s.depo.keys()]) if (!(k in kayit)) { const [t, a] = k.split("."); s.sil(t, a);
    sonuc.push([k, "silindi", []]); }
  return sonuc;
}
```

Sağlayıcı dört işlemden ibarettir ve hepsi sayılır; kaydın hedef sisteme dokunuşu bu dört çağrının
toplamıdır. Kaynak tipi ise bir alan tablosudur: her alanın türü, yerinde güncellenip
güncellenemediği ve varsayılanı yazılıdır. Bu üç özellikten ikincisi kaydın bedelini, üçüncüsü
kaydın sessizliğini belirler. Karar işlevi ikisini de kullanır: değişen alanlardan biri bile yerinde
güncellenemiyorsa kaynak silinip yeniden yaratılır, aksi hâlde tek bir güncelleme çağrısı yeter.

## Plan ile Uygulamanın Farkı

```js
// degisim.mjs — katalog sayilir, kayit uygulanir, sonra bir degisiklik kumesi planlanip uygulanir.
import { KATALOG, KESINTI, KAYIT, saglayiciYap, karar, uygula, GECMIS } from "./saglayici.mjs";

const alanlar = Object.values(KATALOG).flatMap(Object.values);
const yaz = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 22 : 20)).join("").trimEnd());

console.log(`saglayici v1: ${Object.keys(KATALOG).length} kaynak tipi, ${alanlar.length} alan ` +
  `(tip basina ${(alanlar.length / Object.keys(KATALOG).length).toFixed(1)}); ` +
  `${alanlar.filter((a) => a.varsayilan === undefined).length} zorunlu, ` +
  `${alanlar.filter((a) => !a.yerinde).length} alan yerinde guncellenemez`);

const dar = (...s) => console.log(s.map((x) => String(x).padEnd(14)).join("").trimEnd());
dar("tip", "alan", "zorunlu", "yerinde disi", "kesinti");
for (const [t, alan] of Object.entries(KATALOG)) { const v = Object.values(alan);
  dar(t, v.length, v.filter((a) => a.varsayilan === undefined).length,
    v.filter((a) => !a.yerinde).length, `${KESINTI[t]} dk`); }
console.log();

const s = saglayiciYap(KATALOG);
uygula(s, KAYIT);
const yazili = Object.values(KAYIT).reduce((t, r) => t + Object.keys(r).length, 0);
const gercekAlan = [...s.depo.values()].reduce((t, r) => t + Object.keys(r).length, 0);
console.log(`kayit ${Object.keys(KAYIT).length} kaynak icin ${yazili} alan yaziyor; ` +
  `hedefte ${gercekAlan} alan var, ${gercekAlan - yazili} tanesini saglayici varsayilani doldurdu`);
console.log(`ilk uygulama cagrilari: ${JSON.stringify(s.cagri)}\n`);

const KAYIT2 = structuredClone(KAYIT);              // degisiklik kumesi
KAYIT2["makine.toplayici"].sayi = 10;
KAYIT2["makine.toplayici"].cekirdek = 8;
KAYIT2["makine.dogrulayici"].bellek_gb = 48;
KAYIT2["kuyruk.sayac"].bolme = 16;
KAYIT2["veri_deposu.olcum"].boyut_gb = 600;
delete KAYIT2["kuyruk.uyari"];
KAYIT2["makine.arsivci"] = { bolge: "bati", sayi: 1, cekirdek: 2, bellek_gb: 4 };

Object.assign(s.cagri, { oku: 0, yarat: 0, guncelle: 0, sil: 0 });
const plan = Object.entries(KAYIT2).map(([k, r]) => [k, ...karar(s, k, r, true)])
  .concat([...s.depo.keys()].filter((k) => !(k in KAYIT2)).map((k) => [k, "silinecek", []]));
const planOkuma = s.cagri.oku;
const sonuc = uygula(s, KAYIT2);

yaz("kaynak", "plan", "uygulama", "zorlayan alan");
let sapma = 0;
for (const [k, ne, alan] of plan) {
  const g = sonuc.find((x) => x[0] === k);
  if (GECMIS[ne] !== g[1]) sapma++;
  yaz(k, ne, g[1], (g[2].length ? g[2] : alan).join(", "));
}
const yeniden = (l, e) => l.filter((x) => x[1].startsWith("yeniden")).map((x) => KESINTI[x[0].split(".")[0]]);
const p = yeniden(plan), u = yeniden(sonuc);
console.log(`\nplan ${p.length} yeniden olusturma ongordu, uygulama ${u.length} yapti; ` +
  `${plan.length - sapma}/${plan.length} kalem tuttu`);
console.log(`kesinti: planda ${p.reduce((a, b) => a + b, 0)} dk, uygulamada ${u.reduce((a, b) => a + b, 0)} dk`);
console.log(`plan ${planOkuma} okuma yapti; degisiklik cagrilari ${JSON.stringify(s.cagri)}`);
```

```
saglayici v1: 5 kaynak tipi, 24 alan (tip basina 4.8); 11 zorunlu, 13 alan yerinde guncellenemez
tip           alan          zorunlu       yerinde disi  kesinti
makine        7             4             3             4 dk
kuyruk        5             2             3             9 dk
veri_deposu   5             2             3             25 dk
ag            3             2             2             12 dk
nesne_deposu  4             1             2             30 dk

kayit 7 kaynak icin 20 alan yaziyor; hedefte 36 alan var, 16 tanesini saglayici varsayilani doldurdu
ilk uygulama cagrilari: {"oku":7,"yarat":7,"guncelle":0,"sil":0}

kaynak              plan                  uygulama              zorlayan alan
makine.toplayici    yeniden olusturulacak yeniden olusturuldu   cekirdek
makine.dogrulayici  guncellenecek         yeniden olusturuldu   bellek_gb
kuyruk.sayac        yeniden olusturulacak yeniden olusturuldu   bolme
veri_deposu.olcum   guncellenecek         guncellendi           boyut_gb
ag.omurga           degismeyecek          degismedi
nesne_deposu.arsiv  degismeyecek          degismedi
makine.arsivci      yaratilacak           yaratildi
kuyruk.uyari        silinecek             silindi

plan 2 yeniden olusturma ongordu, uygulama 3 yapti; 7/8 kalem tuttu
kesinti: planda 13 dk, uygulamada 17 dk
plan 7 okuma yapti; degisiklik cagrilari {"oku":14,"yarat":4,"guncelle":1,"sil":4}
```

İlk tablo kaydın kapsamını verir. Beş tip toplam yirmi dört alan tanır; on biri zorunludur, on üçü
yerinde güncellenemez. Dağılım tipe göre değişir ve bedeli de öyle: makinenin yedi alanının üçü,
ağın üç alanının ikisi yerinde güncellenemez, ama makinenin yeniden oluşturulması dört dakika,
nesne deposununki otuz dakika sürer. **Yerinde güncellenemeyen alan oranı ile kesinti dakikası ayrı
iki ölçüdür ve birlikte okunmaları gerekir:** ağın oranı yüksektir ama kaynağı ucuzdur; nesne
deposunun oranı düşüktür, kaynağı pahalıdır.

İkinci satır kayıt ile gerçek arasındaki farkı verir. Kayıt yedi kaynak için **yirmi alan yazar**,
ama uygulamadan sonra hedefte **otuz altı alan** durur. Aradaki **on altı alanı sağlayıcı kendi
varsayılanıyla doldurmuştur** ve bu değerler kayıtta hiçbir yerde yazılı değildir. Kaydı okuyan
biri makinelerin hangi imajla kurulduğunu, kuyruğun şifreli olup olmadığını ya da veri deposunun
kaç gün yedeklendiğini kayıttan öğrenemez. Kaydın kapsamadığı altyapı burada başlar: aynı kaydın
kurduğu kaynakların alanlarının **neredeyse yarısı** kayıt dışı değerlerle koşar.

Üçüncü ölçü planın öngörme oranıdır. Sekiz kalemlik değişiklik kümesinde plan yedi kalemi doğru
söyler, biri tutmaz. Kaçırdığı kalem şudur: doğrulayıcı makinelerin belleği on altıdan kırk sekize
çıkarılır ve katalog bu alanı yerinde güncellenebilir işaretlemiştir, dolayısıyla plan
"güncellenecek" der. Hedef sistem ise iki katından fazla büyümeyi yerinde kabul etmez, kaynağı
siler ve yeniden yaratır. Sonuç: plan iki yeniden oluşturma öngörür, uygulama üç yapar; öngörülen
kesinti on üç dakika, gerçekleşen on yedi dakika. **Planın yanıldığı yer, kataloğun eksik olduğu
yerdir** — ve katalog kaydın değil sağlayıcının malıdır.

Son satır çağrı yüküdür. Sekiz kalem için sağlayıcı on dört okuma, dört yaratma, bir güncelleme ve
dört silme alır. Okumaların yarısı planın kendisine aittir: plan üretmek, hedef sistemi baştan sona
bir kez okumak demektir; kaynak sayısı arttıkça planın maliyeti kaynak sayısıyla birlikte artar.
Yeniden oluşturulan üç kaynak ise dört silmenin üçünü ve dört yaratmanın üçünü tek başına açıklar.
**Yerinde güncellenemeyen üç alan, altı çağrıya ve on yedi dakika kesintiye dönüşür.**

## Sağlayıcı Sürümü Değişince

```js
// surum.mjs — saglayici surumu degisince: kayan varsayilan, korunan alan, degisen karar.
import { KATALOG, KESINTI, KAYIT, saglayiciYap, karar, uygula } from "./saglayici.mjs";

const KATALOG2 = structuredClone(KATALOG);          // saglayici surum 2
KATALOG2.makine.imaj.varsayilan = "temel-3";
KATALOG2.kuyruk.sifreleme.varsayilan = "acik";
KATALOG2.veri_deposu.yedek_gn.varsayilan = 7;
KATALOG2.nesne_deposu.sinif.varsayilan = "soguk";
KATALOG2.kuyruk.saklama_gn.yerinde = false;         // yerinde guncellenebilirlik de degisti
KATALOG2.nesne_deposu.erisim = { tur: "dize", yerinde: true, varsayilan: "ozel" };

const kur = (k) => { const s = saglayiciYap(k); uygula(s, KAYIT); return s; };
const a = kur(KATALOG), b = kur(KATALOG2), fark = [];
for (const [k, r] of a.depo) for (const f of new Set([...Object.keys(r), ...Object.keys(b.depo.get(k))]))
  if (r[f] !== b.depo.get(k)[f]) fark.push([k, f, r[f], b.depo.get(k)[f]]);
console.log(`ayni kayit v1 ve v2 ile kuruldu: ${fark.length} alan farkli, ` +
  `${new Set(fark.map((x) => x[0])).size}/${a.depo.size} kaynak etkilendi`);
for (const [k, f, x, y] of fark) console.log(`  ${k.padEnd(20)}${f.padEnd(11)}${x} -> ${y}`);

const korunan = Object.entries(KAYIT).flatMap(([k, r]) => Object.keys(r)
  .filter((f) => KATALOG[k.split(".")[0]][f].varsayilan !== KATALOG2[k.split(".")[0]][f].varsayilan)
  .map((f) => `${k}.${f}`));
console.log(`kayitta yazili oldugu icin kaymayan alan: ${korunan.length} (${korunan.join(", ")})\n`);

const DEG = structuredClone(KAYIT);                 // kayittaki tek satirlik degisiklik
DEG["kuyruk.sayac"].saklama_gn = 30;
for (const [ad, kat] of [["v1", KATALOG], ["v2", KATALOG2]]) {
  const s = kur(kat), p = Object.entries(DEG).map(([k, r]) => [k, ...karar(s, k, r, true)]);
  const y = p.filter((x) => x[1].startsWith("yeniden"));
  console.log(`${ad}: ayni degisiklik -> ${p.filter((x) => x[1] === "guncellenecek").length} guncelleme, ` +
    `${y.length} yeniden olusturma, ${y.reduce((t, x) => t + KESINTI[x[0].split(".")[0]], 0)} dk kesinti`);
}
```

```
ayni kayit v1 ve v2 ile kuruldu: 6 alan farkli, 5/7 kaynak etkilendi
  makine.toplayici    imaj       temel-2 -> temel-3
  kuyruk.sayac        sifreleme  kapali -> acik
  kuyruk.uyari        sifreleme  kapali -> acik
  veri_deposu.olcum   yedek_gn   1 -> 7
  nesne_deposu.arsiv  sinif      sicak -> soguk
  nesne_deposu.arsiv  erisim     undefined -> ozel
kayitta yazili oldugu icin kaymayan alan: 1 (makine.dogrulayici.imaj)

v1: ayni degisiklik -> 1 guncelleme, 0 yeniden olusturma, 0 dk kesinti
v2: ayni degisiklik -> 0 guncelleme, 1 yeniden olusturma, 9 dk kesinti
```

Sürüm değişimi kaydın en sessiz riskidir, çünkü kayıtta değişen hiçbir şey yoktur. Aynı yedi
kaynaklı kayıt sağlayıcının iki sürümüyle kurulduğunda hedefteki durum **altı alanda** ayrılır ve
**yedi kaynağın beşi** etkilenir: makinenin imajı, iki kuyruğun şifrelemesi, veri deposunun yedek
sıklığı, nesne deposunun saklama sınıfı, ve ikinci sürümün eklediği yepyeni bir erişim alanı.
Sonuncusu ayrıca gösterir ki sürüm yalnız var olan varsayılanları değiştirmez, kayıtta karşılığı
hiç bulunmayan yeni alanlar da ekleyebilir.

Kaymayan tek alan, kayıtta açıkça yazılmış olandır: doğrulayıcı makineler imajını kendi yazdığı için
sürüm değişiminden etkilenmez. Kural buradan çıkar: **kayıt bir alanı yazıyorsa o alan korunur,
yazmıyorsa sağlayıcının sürümüne emanettir.** On altı alanı varsayılana bırakan bir kayıt, on altı
alanı sağlayıcının sürüm notlarına bırakmış demektir. Bu, ilk bölümdeki on altı sayısının ikinci
yüzüdür: aynı sayı bir yerde okunabilirlik kazancı, başka yerde sapma yüzeyidir.

Sürüm ayrıca kararı da değiştirir. Kuyruğun saklama süresini yedi günden otuz güne çıkaran tek
satırlık değişiklik, birinci sürümde bir güncelleme çağrısı ve sıfır dakika kesintiyle biter; ikinci
sürümde aynı satır kaynağı yeniden oluşturur ve dokuz dakika kesinti üretir. Kayıt aynı, değişiklik
aynı, sonuç başka. Bir alanın yerinde güncellenip güncellenemeyeceği kaydın değil sağlayıcının
bilgisidir, o bilgi sürümle değişir, ve değiştiğini haber veren tek yer plan çıktısıdır — plan
okunmadan uygulanan bir değişiklik bu farkı ancak kesinti sırasında öğrenir.

## Özet

- Sağlayıcı v1'in 5 kaynak tipi 24 alan tanıdı; 11'i zorunlu, 13'ü yerinde güncellenemez alandı.
  Yeniden oluşturma bedeli tipe göre 4 ile 30 dakika arasında değişti.
- Kayıt 7 kaynak için 20 alan yazdı, hedefte 36 alan oluştu: **16 alanı sağlayıcı varsayılanı
  doldurdu** ve bu değerler kayıtta hiç görünmedi.
- 8 kalemlik değişiklikte plan 7 kalemi tutturdu; yeniden oluşturma 2 öngörüldü, 3 oldu, kesinti 13
  dakika yerine 17 dakika çıktı. Plan yalnız katalogda yazılı olanı bilir.
- Çağrı yükü 14 okuma, 4 yaratma, 1 güncelleme, 4 silme oldu; okumaların 7'si planın kendisine aitti.
- Sağlayıcı sürümü değişince kayıt hiç değişmeden 6 alan kaydı ve 7 kaynağın 5'i etkilendi; kayıtta
  açıkça yazılı olan 1 alan korundu.
- Aynı tek satırlık değişiklik v1'de 1 güncelleme ve 0 dakika, v2'de 1 yeniden oluşturma ve 9 dakika
  kesinti üretti.

## Sonraki Adım

Buraya kadar hedefteki her kaynağı kayıt kurdu. Gerçek ortamlarda böyle olmaz: ağın bir bölümü, bir
kimlik tanımı ya da başka bir ekibin kurduğu bir depo kaydın dışında durur ve kayıt onlara yalnız
**okuyarak** bağlanabilir. Bir sonraki ders bu bağı ölçer: var olan altyapıyı okuyan **veri
kaynakları** kaç okuma yapıyor, ne sıklıkta, okunan bir değer değiştiğinde kaç kaynak yeniden
hesaplanıyor, ve kaydın kapsamadığı kalemler sapma tespitinde neden hiç görünmüyor.
