---
title: 'Kopya Kümeleri ve Sürüm Nesneleri'
source: 'https://academia.sh/tr/kurslar/orkestrasyon/kopya-kumeleri-ve-dagitimlar'
course: 'Konteyner Orkestrasyonu'
language: tr
updated: '2026-08-17T18:09:08+00:00'
license: 'CC BY-SA 4.0'
---

# Kopya Kümeleri ve Sürüm Nesneleri

Bildirimsel sürüm yönetiminin iki ölçüsü: istenen kopya sayısı ile gerçek kopya sayısını uzlaştıran denetleyicinin tur başına işi, ve geçiş ayarlarının — kaç fazla, kaç eksik kopya — geçiş turu, kapasite altı tur ve geri alma penceresi üzerindeki etkisi.

Önceki ders kapsülün sınırını çizdi ve altı kopya gerektiğini bir varsayım olarak aldı. O varsayım
tek başına hiçbir şey yapmaz: bir kapsül düşerse yerine yenisi gelmez, bir düğüm kaybolursa
üzerindeki kapsüller de kaybolur. Altı sayısının bir etkisi olması için bir yere **bildirilmesi** ve
bir denetleyicinin o bildirimi sürekli gerçekle karşılaştırması gerekir. Bu bildirimi taşıyan nesne
**kopya kümesi**dir: tek bir kapsül şablonu ve tek bir sayı.

Sayı yeterli değildir. Şablonun kendisi de değişir — yeni bir sürüm çıkar ve altı kapsülün içeriği
değişmesi gerekir. Bunu yöneten nesne **sürüm nesnesi**dir; iki kopya kümesi tutar ve istenen sayıyı
ikisi arasında adım adım kaydırır. Bu ders iki nesneyi de `node` ile yazar ve geçişi tur tur sayar.
Ölçülen şey bir modeldir; gerçek bir küme koşturulmaz.

**TN7 — okuma toplayıcı için istenen kopya sayısı altıdır.** **TN8 — denetleyicinin bildiği tek şey
istenen sayı ile gerçek sayıdır**; kapsüllerin içi ona görünmez. **TN9 — yeni oluşturulan kapsül iki
tur sonunda hazır olur**, silme aynı turda biter. **TN10 — sürüm nesnesi iki kopya kümesi tutar** ve
istenen sayıyı ikisi arasında paylaştırır. **TN11 — geçiş ayarı iki sayıdır:** en çok kaç fazla
kapsül, en çok kaç eksik hazır kopya. **TN12 — yeni sürümün bozukluğu dördüncü turun sonunda
anlaşılır**; geri alma aynı ayarlarla ters yönde yürür.

## İstenen Sayı ile Gerçek Sayı

Denetleyicinin yaptığı iş tek satırdır: farkı al, işareti neyse o yöne bir eylem üret. Aşağıdaki
koşum bu tek satırı dört olayın üzerinden geçiriyor — soğuk başlangıç, iki kapsülün çökmesi,
istenen sayının değişmesi ve dışarıdan elle iki kapsül eklenmesi.

```js
// kopya.mjs — kopya kumesi denetleyicisi: istenen ile gercek kopya sayisini uzlastirir (MODEL).
export const HAZIR_TUR = 2;                              // TN9: yeni kapsul 2 turda hazir olur

export const kume = (ad, istenen) => ({ ad, istenen, hazir: 0, bekleyen: [] });
export const toplam = (k) => k.hazir + k.bekleyen.length;

export function ilerle(k) {                              // bekleyen kapsuller hazir olur
  k.bekleyen = k.bekleyen.map((x) => x - 1);
  const olan = k.bekleyen.filter((x) => x <= 0).length;
  k.hazir += olan;
  k.bekleyen = k.bekleyen.filter((x) => x > 0);
  return olan;
}
export const olustur = (k, n) => { for (let i = 0; i < n; i++) k.bekleyen.push(HAZIR_TUR); };
export function sil(k, n) {                              // once bekleyen, sonra hazir silinir
  let kalan = n;
  while (kalan > 0 && k.bekleyen.length) { k.bekleyen.pop(); kalan--; }
  const d = Math.min(kalan, k.hazir); k.hazir -= d;
  return n - (kalan - d);
}

// Denetleyici: farki bir eyleme cevirir. Bildigi tek sey istenen ve gercek sayidir. TN8.
export function uzlas(k) {
  const fark = k.istenen - toplam(k);
  if (fark > 0) { olustur(k, fark); return `+${fark} olustur`; }
  if (fark < 0) { sil(k, -fark); return `${fark} sil`; }
  return 'fark yok';
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const K = kume('okuma-toplayici', 6);                  // TN7
  const OLAY = { 4: ['iki kapsul cokti', (k) => (k.hazir -= 2)],
    8: ['istenen 8 oldu', (k) => (k.istenen = 8)],
    11: ['elle iki kapsul eklendi', (k) => olustur(k, 2)] };
  const s = (x, n) => String(x).padStart(n);
  let olusan = 0, silinen = 0, eksikTur = 0;
  console.log(`${'tur'.padEnd(4)}${'olay'.padEnd(25)}${s('istenen', 8)}${s('hazir', 6)}`
    + `${s('bekleyen', 9)}   eylem`);
  for (let t = 1; t <= 14; t++) {
    const o = OLAY[t]; if (o) o[1](K);
    ilerle(K);
    const once = toplam(K);
    const eylem = uzlas(K);
    const d = toplam(K) - once;
    if (d > 0) olusan += d; else silinen += -d;
    if (K.hazir < K.istenen) eksikTur++;
    console.log(`${String(t).padEnd(4)}${(o ? o[0] : '').padEnd(25)}${s(K.istenen, 8)}`
      + `${s(K.hazir, 6)}${s(K.bekleyen.length, 9)}   ${eylem}`);
  }
  console.log(`\n14 turda ${olusan} olusturma, ${silinen} silme, ${eksikTur} turda hazir sayisi`
    + ` istenenin altinda`);
}
```

```
tur olay                      istenen hazir bekleyen   eylem
1                                   6     0        6   +6 olustur
2                                   6     0        6   fark yok
3                                   6     6        0   fark yok
4   iki kapsul cokti                6     4        2   +2 olustur
5                                   6     4        2   fark yok
6                                   6     6        0   fark yok
7                                   6     6        0   fark yok
8   istenen 8 oldu                  8     6        2   +2 olustur
9                                   8     6        2   fark yok
10                                  8     8        0   fark yok
11  elle iki kapsul eklendi         8     8        0   -2 sil
12                                  8     8        0   fark yok
13                                  8     8        0   fark yok
14                                  8     8        0   fark yok

14 turda 10 olusturma, 2 silme, 6 turda hazir sayisi istenenin altinda
```

Dört olay dört ayrı gerekçeden geliyor, denetleyicinin verdiği yanıt ise tek biçimdir. Soğuk
başlangıçta altı, çöküşte iki, istenen sayı arttığında iki kapsül oluşturulur; hepsinde uygulanan
kural aynıdır ve hiçbirinde **neden** düşüldüğü sorulmaz. Denetleyici çöküşle elle silmeyi ayırt
etmez, çünkü **TN8** gereği ikisi de aynı sayıya iner. Bu, devretmenin en somut kazancıdır: dört
farklı senaryo için dört ayrı yordam yazılmaz.

On birinci tur bunun ters yüzüdür. Dışarıdan eklenen iki kapsül aynı turda silinir; bildirimin
dışında yapılan bir değişiklik, bir sonraki uzlaşma turundan uzun yaşamaz. Kümede elle yapılan iş
kalıcı değildir ve bunu gösteren tek kanıt tablodaki `-2 sil` satırıdır.

Sayıların bedeli ise ikinci ve beşinci turlarda görünüyor: `fark yok` yazan iki turda gerçekten hiç
iş yapılmaz, ama hazır kopya sayısı hâlâ istenenin altındadır. Toplam ölçü altı turdur — on dört
turun altısında küme eksik kapasiteyle çalıştı. Bunun tamamı **TN9**'dan, yani hazır olmanın iki
tur sürmesinden gelir; denetleyici farkı gördüğü turda kapatamaz, yalnız kapatma emrini verir.
Kapasite açığı, kararın verilmesiyle etkisinin görünmesi arasındaki gecikmedir.

Tablonun on turunda yazan `fark yok` da bir sonuçtur. Aynı kural her turda yeniden koşar ve fark
kapalıysa hiçbir şey yapmaz; bu, uzlaşma döngüsünün küme ölçeğinde de değişmeyen özelliğidir.
Denetleyici bir kez tetiklenip biten bir yordam değil, sürekli koşan ve çoğu turda hiçbir iş
üretmeyen bir karşılaştırmadır. Tur başına iş, on dört turun dördünde sıfırdan farklıdır.

## Geçişin Ayarları

Kopya sayısı sabit kalırken şablon değişirse iş uzlaşma olmaktan çıkar, bir **geçişe** dönüşür.
Sürüm nesnesi iki kopya kümesini aynı anda yönetir ve iki sayıya uyar: aynı anda en çok kaç fazla
kapsül olabilir, aynı anda en çok kaç kopya eksik olabilir.

```js
// gecis.mjs — surum nesnesi: iki kopya kumesi arasinda asamali gecis ve geri alma (MODEL).
import { kume, toplam, ilerle, olustur, sil } from './kopya.mjs';

const N = 6;                                             // TN7: istenen kopya sayisi

// fazla: en cok kac fazla kapsul; eksik: en cok kac eksik hazir kopya. TN11.
function gecis(fazla, eksik, bozukTur = null) {
  const eski = kume('surum-1', N), yeni = kume('surum-2', 0);
  eski.hazir = N;
  const olusan = { 'surum-1': 0, 'surum-2': 0 };
  let t = 0, altTur = 0, tepe = N, silinen = 0, geriTur = null, durgun = 0, yon = 'ileri';
  while (t < 80) {
    t++;
    ilerle(eski); ilerle(yeni);
    if (bozukTur && t === bozukTur && yon === 'ileri') { yon = 'geri'; geriTur = t - 1; }
    const hedef = yon === 'ileri' ? yeni : eski, kaynak = yon === 'ileri' ? eski : yeni;
    const yer = Math.min(N + fazla - (toplam(eski) + toplam(yeni)), N - toplam(hedef));
    if (yer > 0) { olustur(hedef, yer); olusan[hedef.ad] += yer; }
    const dus = Math.min(eski.hazir + yeni.hazir - (N - eksik), toplam(kaynak));
    if (dus > 0) { sil(kaynak, dus); silinen += dus; }
    tepe = Math.max(tepe, toplam(eski) + toplam(yeni));
    if (eski.hazir + yeni.hazir < N) altTur++;
    durgun = yer <= 0 && dus <= 0 && !eski.bekleyen.length && !yeni.bekleyen.length
      ? durgun + 1 : 0;
    if (durgun >= 2) return { tur: null, altTur, tepe, olusan, silinen, geriTur };
    if (toplam(kaynak) === 0 && hedef.hazir >= N) break;
  }
  return { tur: t, altTur, tepe, olusan, silinen, geriTur };
}

const AYAR = [[0, 0], [0, 1], [1, 0], [1, 1], [2, 2], [6, 0]];
const s = (x, n) => String(x).padStart(n);
console.log(`istenen kopya ${N}, hazir olma 2 tur`);
console.log(`${s('fazla', 6)}${s('eksik', 6)}${s('tur', 11)}${s('kapasite alti', 15)}`
  + `${s('tepe kapsul', 13)}${s('olusan', 8)}${s('silinen', 9)}`);
for (const [f, e] of AYAR) {
  const r = gecis(f, e), o = r.olusan['surum-1'] + r.olusan['surum-2'];
  console.log(`${s(f, 6)}${s(e, 6)}${s(r.tur ?? 'ilerlemez', 11)}${s(`${r.altTur} tur`, 15)}`
    + `${s(r.tepe, 13)}${s(o, 8)}${s(r.silinen, 9)}`);
}

console.log(`\nyeni surum 4. turun sonunda bozuk cikarsa (TN12):`);
console.log(`${s('fazla', 6)}${s('eksik', 6)}${s('ileri tur', 11)}${s('geri tur', 10)}`
  + `${s('toplam', 8)}${s('kapasite alti', 15)}${s('bosa olusan', 13)}`);
for (const [f, e] of AYAR.slice(1)) {
  const r = gecis(f, e, 5);
  if (r.geriTur === null) {
    console.log(`${s(f, 6)}${s(e, 6)}   gecis 4. turdan once bitti: geri alinacak eski kopya yok`);
    continue;
  }
  console.log(`${s(f, 6)}${s(e, 6)}${s(r.geriTur, 11)}${s(r.tur - r.geriTur, 10)}`
    + `${s(r.tur, 8)}${s(`${r.altTur} tur`, 15)}${s(r.olusan['surum-2'], 13)}`);
}
```

```
istenen kopya 6, hazir olma 2 tur
 fazla eksik        tur  kapasite alti  tepe kapsul  olusan  silinen
     0     0  ilerlemez          0 tur            6       0        0
     0     1         19         18 tur            6       6        6
     1     0         18          0 tur            7       6        6
     1     1         10          9 tur            7       6        6
     2     2          6          5 tur            8       6        6
     6     0          3          0 tur           12       6        6

yeni surum 4. turun sonunda bozuk cikarsa (TN12):
 fazla eksik  ileri tur  geri tur  toplam  kapasite alti  bosa olusan
     0     1          4         6      10          9 tur            1
     1     0          4         5       9          0 tur            2
     1     1          4         6      10          9 tur            3
     2     2          4         6      10          9 tur            6
     6     0   gecis 4. turdan once bitti: geri alinacak eski kopya yok
```

İlk satır iki sayının anlamını en keskin biçimde veriyor: ikisi de sıfırsa geçiş **başlamaz**. Ne
fazladan bir kapsüle yer vardır ne de bir kopyayı eksiltmeye izin; sürüm nesnesi kuralları ihlal
etmeden hiçbir adım atamaz ve model durgunluğu görüp çıkar. Bildirimsel bir nesnenin ilerlemek için
en az bir yönde esneklik istemesi, bu tablonun ilk sonucudur.

Sonraki iki satır aynı sayıda kapsül oluşturup silmelerine rağmen taban tabana zıt maliyet
üretiyor. Bir eksiğe izin verip fazlaya izin vermemek geçişi on dokuz tura yayar ve bunların on
sekizinde küme eksik kapasiteyle çalışır; tepe kapsül sayısı altıda kalır, yani hiç ek kaynak
harcanmaz. Bir fazlaya izin verip eksiğe izin vermemek on sekiz tur sürer, kapasitenin altına
**hiç** düşmez ve karşılığında yalnız bir kapsüllük ek kaynak ister. İki ayar arasındaki tur farkı
birdir; kapasite farkı on sekiz turdur. Ek kaynak vermeye razı olmak, aynı süreyi kesintisiz
geçirmenin bedelidir.

Alttaki iki satır hızın nereden geldiğini gösteriyor. Bir fazla ve bir eksik birlikte tanındığında
tur sayısı on sekizden ona iner; iki ve iki tanındığında altıya. Hız her iki ayardan da beslenir,
ama kapasite altı turlar da onunla birlikte gelir. Son satır bu eğrinin ucudur: altı fazla kapsüle
izin verildiğinde geçiş üç turda biter, kapasite hiç düşmez — tepe kapsül sayısı on ikidir, yani
kaynak bir süreliğine iki katına çıkar. Bu ayar, iki ortamlı geçişin sayısal karşılığıdır.

İkinci tablo o üç turluk hızın gizli bedelini ödetiyor. Dördüncü turun sonunda yeni sürümün bozuk
olduğu anlaşıldığında, bir fazla ve sıfır eksik ayarında geri alma beş tur sürer, kapasite hiç
düşmez ve boşa giden kapsül sayısı ikidir. İki-iki ayarında geri alma altı tur alır ve altı kapsül
boşa gitmiştir — dört tur içinde yeni sürümün tamamı kurulmuştur. Altı fazlalı ayarda ise geri alma
diye bir şey yoktur: geçiş dördüncü turdan önce bitmiş, eski kopya kümesi sıfırlanmıştır. **Geri
alma penceresi, geçişin süresiyle aynı şeydir.** Geçişi hızlandıran her ayar bu pencereyi kısaltır
ve bir noktadan sonra kapatır.

## Devredilen Karar ve Bilmediği Şey

Bu derste devredilen karar iki tanedir: **kaç kopya koşacağı** ve **yeni şablona hangi hızla
geçileceği.** Birincisi için sistemin bilmesi gereken tek bilgi kalemi istenen sayıdır — bu yüzden
ucuzdur ve dört farklı olaya tek kuralla yanıt verir. İkincisi için iki kalem gerekir: fazla ve
eksik. Bu iki sayı bir tercih değil, iki kaynağın karşılıklı fiyatıdır; biri geçici kapasite, öteki
geçici kesinti.

İki kalemin maliyeti de eşit değildir. İstenen sayı bir kez yazılır ve nadiren değişir; ölçüm
gerektirmez, eskimez, yanlış olduğunda sonucu doğrudan görünür. Geçiş ayarları ise her yayında
yeniden değerlendirilmesi gereken bir tahmine dayanır: yeni sürümün ne kadar sürede ayağa kalkacağı
ve arızalıysa ne kadar sürede belli olacağı. İkinci tahmin ölçülemez olduğu için ayarlar çoğu
zaman bir kez yazılır ve her yayında aynı kalır — oysa tablonun gösterdiği gibi aynı ayar, hızlı
ayağa kalkan bir sürümde geri alma penceresini tümüyle kapatabilir.

Sistemin **bilmediği** şey de aynı tabloda duruyor. Sürüm nesnesi yeni kopyaların hazır olduğunu
görür, doğru çalıştığını görmez; **TN8** gereği kapsülün içi ona kapalıdır. Bozukluk dördüncü turun
sonunda bir yerden gelir ve modelde bu bir varsayımdır. Sistemin ölçemediği bu bilgi kalemi
yüzünden iki-iki ayarında altı kapsül boşa kurulur, altı fazlalı ayarda ise eski sürüm hiç
kalmadığı için geri dönülecek yer kalmaz. Yanlış karar burada bir hesap hatası değildir: hız,
sistemin göremediği bir bilginin gelmesini beklemeden ilerlemektir.

## Özet

- Kopya kümesi denetleyicisi tek kural uygular: fark artıysa oluştur, eksiyse sil. Soğuk başlangıç,
  çöküş, istenen sayının değişmesi ve elle ekleme aynı yordamla karşılanır.
- Bildirimin dışında elle eklenen iki kapsül aynı turda silindi; kümede elle yapılan iş bir sonraki
  uzlaşma turundan uzun yaşamaz.
- On dört turun altısında hazır kopya sayısı istenenin altında kaldı; bunun kaynağı hazır olmanın
  iki tur sürmesi, yani kararla etkisi arasındaki gecikmedir.
- Geçiş ayarının iki sayısı da sıfırsa geçiş hiç başlamaz; bir eksiğe izin vermek on dokuz turun on
  sekizini kapasite altında geçirtir, bir fazlaya izin vermek aynı işi on sekiz turda ve hiç kapasite
  düşürmeden yapar.
- İki fazla ve iki eksik geçişi altı tura, altı fazla üç tura indirir; ikincisinde tepe kapsül sayısı
  on ikiye, yani iki katına çıkar.
- Geri alma penceresi geçişin süresiyle aynıdır: dördüncü turda fark edilen bozukluk bir-sıfır
  ayarında iki kapsülü, iki-iki ayarında altı kapsülü boşa çıkarır; üç turda biten geçişte geri
  dönülecek eski kopya kalmaz.

## Sonraki Adım

Bu ders altı kapsülü ayakta tutmayı ve içeriğini değiştirmeyi ölçtü. İki koşumda da kapsüller
sürekli oluşturulup silindi: on dört turda on oluşturma iki silme, geçişte altı oluşturma altı
silme. Her yeni kapsül yeni bir kapsüldür ve öncekinin adresi onunla gitmiştir. Bu durumda ona
istek gönderen bir başka bileşen kime bağlanacaktır? Kopya kümesi altı kapsülü garanti eder ama
**hangi altı** olduğunu garanti etmez. Sonraki ders bu boşluğu dolduran nesneyi ölçer: kopya
kümesi altında değişirken üstte sabit kalan bir ad, o adın çözümlenmesinin isteğe eklediği tur ve
hazır olmayan bir kopyaya giden istek sayısı.
