---
title: 'Dayanıklı Durum Nesneleri'
source: 'https://academia.sh/tr/kurslar/sunucusuz/dayanikli-durum-nesneleri'
course: 'Sunucusuz ve Kenar Bilişim'
language: tr
updated: '2026-08-17T18:06:57+00:00'
license: 'CC BY-SA 4.0'
---

# Dayanıklı Durum Nesneleri

Aynı anahtar için tek yazarlı bir nesne modeli koşturulur: eşzamanlı isteklerde kayıp güncelleme sıfıra iner. Karşılığında gelen iki kısıt sayılır — tek örneğin istek başına sıraya girmesi ve nesnenin coğrafi olarak sabitlenmesi — ve sayaç, oda, kilit senaryolarında hangisinin uyduğu yazılır.

Önceki dersin deposu bir şeyi çözmeden bıraktı. Yayılma penceresi okumaları eski değere
bağlıyordu; iki uç aynı anahtarı aynı anda değiştirmek isterse ne olur? Kurgudaki **bölgesel
ölçüm ağında** bunun karşılığı somuttur: bir şubenin doğrulanmış okuma sayacı, aynı anda iki
farklı uçtan gelen kayıtla artırılmak isteniyor.

"Oku, değiştir, yaz" üç ayrı adımdır ve aralarına başkası girebilir. Bu dersin ölçtüğü şey bu
araya girmenin kaç güncelleme düşürdüğü, ve onu sıfıra indiren modelin karşılığında ne istediğidir.
İki model aynı iş yüküyle koşar.

**KE19.** Paylaşılan depo modelinde okuma 20 ms, hesap 1 ms, yazma 64 ms sürer; üçü ayrı
adımdır. **KE20.** Varışlar deterministiktir; rastgelelik yoktur. **KE21.** Tek yazarlı nesnede
aynı anahtar tek bir örneğe yönlendirilir, istekler varış sırasına göre kuyruğa girer, durum
örneğin belleğinde tutulur ve istek başına işleme 6 ms'dir; koşut yürütme yoktur.

## Aynı Anahtara İki Model

İlk model tanıdıktır: değer uzak bir depoda durur, her istemci okur, artırır, geri yazar. İkinci
modelde anahtar bir örneğe bağlanır — aynı anahtar için ağda tek bir örnek vardır ve bütün
istekler oraya sıraya girer. Adım artık üç değil, birdir.

```js
// olcum-agi/tekyazar.mjs — ayni anahtar iki modelde: paylasilan depo (oku-degistir-yaz)
// ve tek yazarli nesne (sirali isleme). MODEL: varislar ve sureler deterministiktir.

const ISTEMCI = 8, ADIM = 50, TOPLAM = ISTEMCI * ADIM;
const OKU_MS = 20, HESAP_MS = 1, YAZ_MS = 64;      // paylasilan depo yolu
const ISLEM_MS = 6;                                 // tek ornekte istek basina isleme

// --- 1. Paylasilan depo: her istemci sirayla oku-degistir-yaz yapar.
const islem = [];
for (let c = 0; c < ISTEMCI; c++) {
  let t = c * 3;
  for (let i = 0; i < ADIM; i++) {
    islem.push({ okuT: t, yazT: t + OKU_MS + HESAP_MS + YAZ_MS, okunan: 0 });
    t = t + OKU_MS + HESAP_MS + YAZ_MS;
  }
}
const olay = [];
for (const o of islem) { olay.push({ t: o.okuT, oku: true, o }); olay.push({ t: o.yazT, oku: false, o }); }
olay.sort((a, b) => a.t - b.t || (a.oku ? -1 : 1));
let deger = 0, ustuneYazilan = 0;
for (const e of olay) {
  if (e.oku) { e.o.okunan = deger; continue; }
  if (deger !== e.o.okunan) ustuneYazilan++;
  deger = e.o.okunan + 1;
}
console.log(`${ISTEMCI} istemci x ${ADIM} artirma = ${TOPLAM} istek, ayni anahtar (model)`);
console.log("paylasilan depo (oku-degistir-yaz)");
console.log(`  beklenen ${TOPLAM}   sayacin son degeri ${deger}   ` +
  `kayip guncelleme ${TOPLAM - deger}   %${(((TOPLAM - deger) / TOPLAM) * 100).toFixed(1)}`);
console.log(`  ustune yazilan yazma ${ustuneYazilan}   islem suresi ${OKU_MS + HESAP_MS + YAZ_MS} ms`);

// --- 2. Tek yazarli nesne: ayni anahtar tek ornege gider, istekler sirayla islenir.
function kuyruk(istemci, araMs) {
  const varis = [];
  for (let c = 0; c < istemci; c++)
    for (let i = 0; i < ADIM; i++) varis.push(c * 3 + i * araMs);
  varis.sort((a, b) => a - b);
  let bos = 0, sayac = 0, bekleme = [];
  for (const v of varis) {
    const basla = Math.max(v, bos);
    bekleme.push(basla - v);
    bos = basla + ISLEM_MS;
    sayac++;                                        // durum bellekte, adim atomik
  }
  bekleme.sort((a, b) => a - b);
  const p95 = bekleme[Math.ceil(0.95 * bekleme.length) - 1];
  const ort = bekleme.reduce((t, v) => t + v, 0) / bekleme.length;
  return { istek: varis.length, sayac, hiz: (istemci * 1000) / araMs, ort, p95,
           sure: (bos - varis[0]) / 1000 };
}
const TAVAN = 1000 / ISLEM_MS;
console.log(`\ntek yazarli nesne (istek basina ${ISLEM_MS} ms, tavan ${TAVAN.toFixed(1)} istek/sn)`);
console.log("yuk".padEnd(22) + "varis hizi".padEnd(14) + "kayip".padEnd(9) +
  "ort. bekleme".padEnd(15) + "p95 bekleme".padEnd(14) + "kuyruk");
for (const [istemci, ara] of [[4, 40], [6, 40], [8, 40]]) {
  const r = kuyruk(istemci, ara);
  console.log(`${istemci} istemci / ${ara} ms`.padEnd(22) +
    `${r.hiz.toFixed(0)}/sn`.padEnd(14) + String(r.istek - r.sayac).padEnd(9) +
    `${r.ort.toFixed(1)} ms`.padEnd(15) + `${r.p95} ms`.padEnd(14) +
    (r.hiz > TAVAN ? "doygun" : "akiyor"));
}
```

```
8 istemci x 50 artirma = 400 istek, ayni anahtar (model)
paylasilan depo (oku-degistir-yaz)
  beklenen 400   sayacin son degeri 45   kayip guncelleme 355   %88.8
  ustune yazilan yazma 355   islem suresi 85 ms

tek yazarli nesne (istek basina 6 ms, tavan 166.7 istek/sn)
yuk                   varis hizi    kayip    ort. bekleme   p95 bekleme   kuyruk
4 istemci / 40 ms     100/sn        0        4.5 ms         9 ms          akiyor
6 istemci / 40 ms     150/sn        0        7.5 ms         15 ms         akiyor
8 istemci / 40 ms     200/sn        0        206.5 ms       386 ms        doygun
```

Paylaşılan depoda 400 artırma isteği sayacı **45**'e taşır. Kayıp güncelleme **355**, yani
%88,8. Sayı bu kadar büyüktür çünkü işlem süresi 85 ms'dir ve sekiz istemci o 85 ms boyunca aynı
eski değeri okur; sekizinin yazması da aynı sonucu üretir, yedisi boşa gider. Bu, deponun bir
kusuru değildir — depo yazılan şeyi doğru yazmıştır. Kaybolan şey **araya girmenin görülmemiş
olmasıdır**.

Tek yazarlı nesnede aynı iş yükünde kayıp güncelleme üç yük düzeyinde de **0**'dır. Nedeni
modelin kendisidir: okuma, hesap ve yazma tek bir örneğin belleğinde art arda olur ve o örnek
aynı anda başka bir isteği işlemez. Sıfırın bir garanti olarak yazılabilmesi, adımın bölünemez
hâle gelmesinden gelir.

## Karşılığında Gelen İki Kısıt

Sıfır bedava değildir. İlk bedel kuyruğa girmedir ve tabloda üç düzeyde okunur. Örnek başına
tavan **166,7 istek/sn**'dir. 100/sn varışta ortalama bekleme 4,5 ms, p95 9 ms. 150/sn varışta
7,5 ms ve 15 ms. 200/sn varışta ise ortalama bekleme **206,5 ms**, p95 **386 ms**'dir ve kuyruk
doygundur — varış tavanı aştığı için bekleme koşum boyunca büyümeye devam eder.

İki yük düzeyi arasındaki fark burada dikkat çeker: 150/sn ile 200/sn arasında varış %33 artarken
ortalama bekleme 7,5 ms'den 206,5 ms'ye, yani yaklaşık 28 kat çıkar. Tek örnek bir ölçekleme
birimidir ve tavanı aştığında yanıt vermeyi kesmez, **biriktirir**. Devredilen karar eşzamanlılığın
yönetimidir; karşılığında gelen kısıt tek bir sayıdır: istek başına 6 ms, saniyede 166,7 istek.

Kısıtın etrafından dolaşmanın yolu örneği çoğaltmak değildir — çoğaltmak tek yazarlığı, dolayısıyla
sıfırı iptal eder. Yol **anahtarı bölmektir**: bir sayaç yerine şube başına bir sayaç tutmak,
toplam yükü örnek sayısına böler. Bedeli, artık küresel bir toplamın tek bir yerde durmamasıdır;
toplam istendiğinde bütün örnekler okunur ve okuma sayısı örnek sayısı kadar artar.

## Nesne Nerede Durur

İkinci bedel coğrafyadır. Nesne bir yerde durur; oradan uzaktaki istemci ona **uzaktan** erişir.
Uçta koşmanın bütün kazancı yakınlıktan geliyordu ve eşgüdümlü durum o yakınlığı tek bir noktaya
indirger.

**KE22.** Uzaklıklar tam turdur ve model girdisidir. **KE23.** Nesne koşum boyunca taşınmaz;
konum değişimi modellenmez. **KE24.** Senaryo hızları toplam istek hızıdır; örnek başına düşen
hız, anahtarın kaç örneğe bölündüğüne göre hesaplanır.

```js
// olcum-agi/senaryo.mjs — nesnenin cografi olarak sabitlenmesi ve senaryo uyumu
// MODEL: uzakliklar tam tur, model girdisidir; nesne kosum boyunca tasinmaz.

const ISLEM_MS = 6, TAVAN = 1000 / ISLEM_MS;
const UC = {
  "uc-1": { yuk: 2600, "en yogun ucta": 4,  "bolgede": 62, "sube basina": 4 },
  "uc-2": { yuk: 2100, "en yogun ucta": 40, "bolgede": 58, "sube basina": 4 },
  "uc-3": { yuk: 1800, "en yogun ucta": 55, "bolgede": 66, "sube basina": 4 },
  "uc-4": { yuk: 1500, "en yogun ucta": 70, "bolgede": 60, "sube basina": 4 },
  "uc-5": { yuk: 1200, "en yogun ucta": 88, "bolgede": 64, "sube basina": 4 },
  "uc-6": { yuk:  800, "en yogun ucta": 96, "bolgede": 70, "sube basina": 4 },
};
const YERLESIM = ["en yogun ucta", "bolgede", "sube basina"];
const TOPLAM = Object.values(UC).reduce((t, u) => t + u.yuk, 0);

console.log(`nesneye erisim turu, ${TOPLAM} istek uc uca dagilmis (model girdisi)`);
console.log("uc".padEnd(8) + "yuk".padEnd(9) + YERLESIM.map((y) => y.padEnd(16)).join(""));
for (const [ad, u] of Object.entries(UC))
  console.log(ad.padEnd(8) + String(u.yuk).padEnd(9) + YERLESIM.map((y) => `${u[y]} ms`.padEnd(16)).join(""));
console.log("agirlikli".padEnd(8) + "".padEnd(9) + YERLESIM.map((y) => {
  const ms = Object.values(UC).reduce((t, u) => t + u.yuk * u[y], 0) / TOPLAM;
  return `${ms.toFixed(1)} ms`.padEnd(16);
}).join(""));
console.log("en kotu uc".padEnd(8) + "".padEnd(9) +
  YERLESIM.map((y) => `${Math.max(...Object.values(UC).map((u) => u[y]))} ms`.padEnd(16)).join(""));
console.log("  esgudum istemeyen is ayni uctan 2 ms'de biter; fark sabitlenmenin bedelidir");

const SENARYO = {
  "sube sayaci":        { anahtar: "sube",    ornek: 6,   hiz: 480, uzunIsMs: 0 },
  "sube odasi":         { anahtar: "sube",    ornek: 6,   hiz: 600, uzunIsMs: 0 },
  "is emri kilidi":     { anahtar: "is emri", ornek: 120, hiz: 240, uzunIsMs: 0 },
  "kuresel sira sayaci":{ anahtar: "tek",     ornek: 1,   hiz: 900, uzunIsMs: 0 },
  "gecelik uzlastirma": { anahtar: "tek",     ornek: 1,   hiz: 5,   uzunIsMs: 40_000 },
};
console.log(`\nsenaryo uyumu (ornek basina tavan ${TAVAN.toFixed(1)} istek/sn)`);
console.log("senaryo".padEnd(22) + "anahtar".padEnd(10) + "ornek".padEnd(8) +
  "toplam hiz".padEnd(13) + "ornek basina".padEnd(14) + "sonuc");
for (const [ad, s] of Object.entries(SENARYO)) {
  const basina = s.hiz / s.ornek;
  const neden = s.uzunIsMs > 0
    ? `uymaz: ${s.uzunIsMs / 1000} sn'lik is ornegi kilitler, ` +
      `arkada ${Math.round((s.uzunIsMs / 1000) * s.hiz)} istek bekler`
    : basina > TAVAN
      ? `uymaz: ornek basina ${basina.toFixed(0)}/sn, tavanin ${(basina / TAVAN).toFixed(1)} kati`
      : `uyar: tavanin %${((basina / TAVAN) * 100).toFixed(0)}'i`;
  console.log(ad.padEnd(22) + s.anahtar.padEnd(10) + String(s.ornek).padEnd(8) +
    `${s.hiz}/sn`.padEnd(13) + `${basina.toFixed(0)}/sn`.padEnd(14) + neden);
}
const uyan = Object.values(SENARYO).filter((s) => s.uzunIsMs === 0 && s.hiz / s.ornek <= TAVAN).length;
console.log(`  ${uyan}/${Object.keys(SENARYO).length} senaryo tek yazarli nesneye uyar`);
```

```
nesneye erisim turu, 10000 istek uc uca dagilmis (model girdisi)
uc      yuk      en yogun ucta   bolgede         sube basina     
uc-1    2600     4 ms            62 ms           4 ms            
uc-2    2100     40 ms           58 ms           4 ms            
uc-3    1800     55 ms           66 ms           4 ms            
uc-4    1500     70 ms           60 ms           4 ms            
uc-5    1200     88 ms           64 ms           4 ms            
uc-6    800      96 ms           70 ms           4 ms            
agirlikli         48.1 ms         62.5 ms         4.0 ms          
en kotu uc         96 ms           70 ms           4 ms            
  esgudum istemeyen is ayni uctan 2 ms'de biter; fark sabitlenmenin bedelidir

senaryo uyumu (ornek basina tavan 166.7 istek/sn)
senaryo               anahtar   ornek   toplam hiz   ornek basina  sonuc
sube sayaci           sube      6       480/sn       80/sn         uyar: tavanin %48'i
sube odasi            sube      6       600/sn       100/sn        uyar: tavanin %60'i
is emri kilidi        is emri   120     240/sn       2/sn          uyar: tavanin %1'i
kuresel sira sayaci   tek       1       900/sn       900/sn        uymaz: ornek basina 900/sn, tavanin 5.4 kati
gecelik uzlastirma    tek       1       5/sn         5/sn          uymaz: 40 sn'lik is ornegi kilitler, arkada 200 istek bekler
  3/5 senaryo tek yazarli nesneye uyar
```

Nesne en yoğun ucun yanına konduğunda ağırlıklı erişim turu **48,1 ms**, bölgeye konduğunda
**62,5 ms**'dir. İlk seçenek ikinciyi ortalamada geçer ama en kötü ucu kötüleştirir: 96 ms'ye
karşı 70 ms. Yani nesneyi en yoğun ucun yanına almak, yükün %26'sını taşıyan uca 4 ms verirken
%8'ini taşıyan uca 96 ms yazar. Bölgeye koymak bu dağılımı düzleştirir; kimseye çok iyi, kimseye
çok kötü davranmaz.

Üçüncü sütun asıl kararı gösterir. Anahtar şube başına bölündüğünde her nesne kendi ucunda durur
ve ağırlıklı erişim turu **4,0 ms**'ye iner — en kötü uç da 4 ms'dir. Eşgüdüm istemeyen bir işin
aynı uçtan 2 ms'de bitmesiyle karşılaştırıldığında fark yalnız 2 ms'dir. Coğrafi sabitlenme
burada bir bedel olmaktan çıkar, çünkü nesne zaten kullanıldığı yerdedir. Sabitlenme, anahtar
coğrafyayla örtüşmediğinde bedel olur.

## Hangi Kullanım Uyar

Son tablo beş senaryoyu aynı iki ölçütle tartar: örnek başına düşen hız ve işin süresi.
**Şube sayacı** 480/sn toplam yük taşır, altı örneğe bölünür, örnek başına 80/sn eder — tavanın
%48'i. **Şube odası** 600/sn ile örnek başına 100/sn ve tavanın %60'ı. **İş emri kilidi** 120
örneğe bölündüğü için örnek başına 2/sn, tavanın %1'i; kilit senaryosu tek yazarlı nesneye en
rahat oturan kullanımdır, çünkü anahtar doğal olarak çok sayıda ve her biri seyrektir.

İki senaryo uymaz ve nedenleri farklıdır. **Küresel sıra sayacı** bölünemez bir anahtar üzerinde
900/sn ister; bu, tavanın 5,4 katıdır ve tek örnek bunu karşılayamaz. Buradaki uyumsuzluk
hızdandır. **Gecelik uzlaştırma** ise yalnız 5/sn ister ama işin kendisi 40 saniye sürer ve o
süre boyunca örneği kilitler; arkasında **200 istek** bekler. Buradaki uyumsuzluk süredendir.
Aynı model iki ayrı eşikte reddeder: istek başına 6 ms'lik tavan ve isteğin bölünemez uzunluğu.

Beş senaryonun **3'ü uyar**. Kural tek cümleyle yazılır: tek yazarlı nesne, anahtarı çok sayıda
olan, her anahtarı seyrek dokunulan ve işlemleri kısa olan eşgüdüm işleri içindir. Üç koşuldan
biri bozulduğunda model reddeder ve reddi bir sayıyla yazar.

## Özet

- Paylaşılan depoda 400 eşzamanlı artırma sayacı 45'e taşır: kayıp güncelleme 355, yani %88,8.
  Kaybolan şey deponun yanlış yazması değil, araya girmenin görülmemiş olmasıdır.
- Tek yazarlı nesnede aynı iş yükünde kayıp güncelleme üç yük düzeyinde de 0'dır; okuma, hesap ve
  yazma tek örneğin belleğinde bölünemez biçimde olur.
- Karşılığında gelen ilk kısıt tavandır: istek başına 6 ms, örnek başına 166,7 istek/sn. Varış
  100, 150 ve 200/sn iken ortalama bekleme 4,5, 7,5 ve 206,5 ms; %33'lük bir varış artışı beklemeyi
  yaklaşık 28 kat büyütür.
- İkinci kısıt coğrafi sabitlenmedir: ağırlıklı erişim turu en yoğun uçta 48,1 ms, bölgede 62,5
  ms, şube başına bölündüğünde 4,0 ms'dir. Bedel, anahtarın coğrafyayla örtüşmediği durumda doğar.
- Beş senaryonun 3'ü uyar: şube sayacı (tavanın %48'i), şube odası (%60), iş emri kilidi (%1).
  Küresel sıra sayacı hız yüzünden (tavanın 5,4 katı), gecelik uzlaştırma süre yüzünden (40 sn'de
  arkada 200 istek) uymaz.

## Sonraki Adım

Bu dersin reddettiği iki senaryonun ortak yanı, isteğin **yanıtı beklemek zorunda olmasıdır**.
Gecelik uzlaştırma 40 saniye sürüyordu ve arkasında iki yüz istek biriktiriyordu; oysa o işin
sonucunu bekleyen kimse yoktu. Kurgudaki ağda uçtan gelen çoğu kayıt böyledir: sayaç okuması
alınır, alındığı onaylanır ve işlenmesi sonraya bırakılabilir. Uçta bir işi hemen yapmak yerine
bırakabilseydik, tek örneğin tavanı bir sınır olmaktan çıkar mıydı? Bırakılan iş nerede durur,
kaç kez denenir ve uçtaki çalışma zamanının süre sınırı bu bekleyişi nasıl keser? Sonraki ders
uçta işi sonraya bırakmanın yollarını ölçer: bırakılan işin nerede biriktiği, teslim garantisinin
ne olduğu ve uçta zamanlanmış bir tetiklemenin bölgedekinden nerede ayrıldığı.
