---
title: 'Kenar Kuyrukları ve Zamanlanmış İşler'
source: 'https://academia.sh/tr/kurslar/sunucusuz/kenar-kuyruklari-ve-zamanlanmis-isler'
course: 'Sunucusuz ve Kenar Bilişim'
language: tr
updated: '2026-08-17T18:06:57+00:00'
license: 'CC BY-SA 4.0'
---

# Kenar Kuyrukları ve Zamanlanmış İşler

Aynı iş kümesi merkez ve kenar kuyruğunda işlenir; kuyruğa girme turu, işin koştuğu yer ve sonucun dönüş yolu ayrı sayılır. Kenar kuyruğunun dört kısıtı ile zamanlanmış işin tetiklendiği bölge ölçülür.

Bir önceki ders kenarda eşgüdümlü durumu tutmayı başardı: tek yazarlı nesne kendi anahtarına gelen
yazmaları sıraya koydu. Eşzamansız iş ise hâlâ merkezde koşuyor; doğrulama, fatura satırı ve saha
bildirimi merkez bölgedeki bir kuyruğa yazılıyor. Bu ders aynı iş kümesini iki yerde işletip üç şeyi
ayrı sayar: kuyruğa girme turu, işin koştuğu yer, sonucun dönüş yolu.

Ölçüm **bölgesel ölçüm ağının** altı şube ucu üzerindedir ve **kurgudur**; uçlar, iki kuyruk servisi
ve zamanlayıcı `node` ile kurulmuş bir **modeldir**. Gerçek bir ürün çağrılmaz.

**KE25.** Her uç için merkeze ve en yakın kenar konumuna tek yön gecikme, bir de gecelik okuma
sayısı yazılıdır.
**KE26.** Kuyruğa girme turu, tek yön gecikmenin iki katı artı kuyruğun sabit kabul süresidir.
**KE27.** Merkez kuyruğu 250'lik toplu okuma, 10 deneme, 14 gün saklama ve anahtar başına sıralama
sunar; kenar kuyruğu 25 ve 3 sunar, 4 gün saklar, sıralama vermez.
**KE28.** Tüketici her toplu okumada bir kez başlar: merkezde 40 ms, kenarda 6 ms. Okuma başına
işlem iki yolda da 12 ms'dir.
**KE29.** Sonuç, işin koştuğu yerdeki depoya yazılır. Merkez deposu merkez turu kadar uzaktır;
kenar anahtar–değer deposu yerel okunur, ama yazısının öteki uçlarda görünmesi 480 ms sürer.
**KE30.** Zamanlanmış tetikleme yalnız temel saati bilir; kenar zamanlayıcı tetikleme konumunu
kendi seçer ve seçim kayıt altında değildir.

## Aynı İş Kümesi, İki Kuyruk

```js
// ag.mjs — kurgu olcum agi modeli: uclar, gecikmeler, iki kuyrugun kisitlari.
export const UCLAR = [                              // tek yon gecikme ms, serit temel saatten sapma
  { ad: "uc-bati",  merkez: 12, kenar: 5,  serit: 0, okuma: 610 },
  { ad: "uc-kuzey", merkez: 38, kenar: 7,  serit: 0, okuma: 520 },
  { ad: "uc-dogu",  merkez: 74, kenar: 9,  serit: 2, okuma: 430 },
  { ad: "uc-guney", merkez: 51, kenar: 6,  serit: 1, okuma: 350 },
  { ad: "uc-yayla", merkez: 96, kenar: 11, serit: 3, okuma: 280 },
  { ad: "uc-liman", merkez: 63, kenar: 8,  serit: 2, okuma: 210 },
];
export const TOPLAM = UCLAR.reduce((t, u) => t + u.okuma, 0);
export const KUYRUK = {                             // kalem kalem kisitlar
  merkez: { kabul: 9, toplu: 250, deneme: 10, saklama_gn: 14, baslatma: 40 },
  kenar:  { kabul: 3, toplu: 25,  deneme: 3,  saklama_gn: 4,  baslatma: 6 },
};
export const ISLEME = 12, YAYILMA = 480, DEPO_OKUMA = 5;   // isleme / kenar yayilmasi / depo yaniti, ms
export const tur = (yol, u) => 2 * u[yol] + KUYRUK[yol].kabul;
export const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 13 : 11)).join("").trimEnd());

export function uretec(tohum) {                     // tohum gorunur; kosumdan kosuma ayni dizi
  let s = tohum >>> 0;
  return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296;
}
export function isKumesi(tohum) {                   // okuma: sayac kimligi, artan sira, gereken deneme
  const r = uretec(tohum), sira = new Map(), kume = [];
  for (const u of UCLAR) for (let i = 0; i < u.okuma; i++) {
    const sayac = `s${String(Math.floor(r() * 900)).padStart(3, "0")}`;
    sira.set(sayac, (sira.get(sayac) ?? 0) + 1);
    kume.push({ uc: u.ad, sayac, sira: sira.get(sayac), deneme: 1 });
  }
  for (const i of kume) while (r() < 0.28 && i.deneme < 12) i.deneme++;
  return kume;
}
```

```js
// tur.mjs — ayni is kumesi iki yerde: kuyruga girme turu, isin kostugu yer, sonucun donus yolu.
import { UCLAR, TOPLAM, KUYRUK, ISLEME, YAYILMA, DEPO_OKUMA, tur, sut } from "./ag.mjs";

sut("uc", "okuma", "merkez turu", "kenar turu", "kazanc");
for (const u of UCLAR) sut(u.ad, u.okuma, `${tur("merkez", u)} ms`, `${tur("kenar", u)} ms`,
  `${(tur("merkez", u) / tur("kenar", u)).toFixed(1)}x`);
const agirlik = (yol) => UCLAR.reduce((t, u) => t + u.okuma * tur(yol, u), 0) / TOPLAM;
console.log(`${TOPLAM} okuma icin agirlikli kuyruga girme turu: ` +
  `merkez ${agirlik("merkez").toFixed(1)} ms, kenar ${agirlik("kenar").toFixed(1)} ms\n`);

for (const yol of ["merkez", "kenar"]) {            // tuketici: kac kez basliyor
  const k = KUYRUK[yol], cagri = Math.ceil(TOPLAM / k.toplu);
  const baslatma = cagri * k.baslatma, is = TOPLAM * ISLEME;
  console.log(`${yol.padEnd(7)}toplu okuma ${String(k.toplu).padStart(3)} -> ${String(cagri).padStart(3)} tuketici cagrisi; ` +
    `baslatma ${String(baslatma).padStart(4)} ms + isleme ${is} ms = ${baslatma + is} ms`);
}
console.log(`isin kostugu yer: merkez yolunda bilinen tek bolge; ` +
  `kenar yolunda platformun sectigi konum, secim kayitli degil\n`);

// donus yolu: merkez deposu uzak, kenar deposu yerel ama once yayilmali
const don = (yol) => UCLAR.reduce((t, u) => t + u.okuma * (2 * u[yol] + DEPO_OKUMA), 0) / TOPLAM;
console.log(`agirlikli donus turu: merkez ${don("merkez").toFixed(1)} ms, kenar ${don("kenar").toFixed(1)} ms`);
console.log(`sonuc hazir olana kadar: merkez ${don("merkez").toFixed(1)} ms, ` +
  `kenar ${(don("kenar") + YAYILMA).toFixed(1)} ms (yayilma ${YAYILMA} ms eklendi)`);
console.log(`uctan uca toplam: merkez ${(agirlik("merkez") + don("merkez")).toFixed(1)} ms, ` +
  `kenar ${(agirlik("kenar") + don("kenar") + YAYILMA).toFixed(1)} ms`);
```

```
uc         okuma        merkez turu  kenar turu   kazanc
uc-bati    610          33 ms        13 ms        2.5x
uc-kuzey   520          85 ms        17 ms        5.0x
uc-dogu    430          157 ms       21 ms        7.5x
uc-guney   350          111 ms       15 ms        7.4x
uc-yayla   280          201 ms       25 ms        8.0x
uc-liman   210          135 ms       19 ms        7.1x
2400 okuma icin agirlikli kuyruga girme turu: merkez 106.4 ms, kenar 17.5 ms

merkez toplu okuma 250 ->  10 tuketici cagrisi; baslatma  400 ms + isleme 28800 ms = 29200 ms
kenar  toplu okuma  25 ->  96 tuketici cagrisi; baslatma  576 ms + isleme 28800 ms = 29376 ms
isin kostugu yer: merkez yolunda bilinen tek bolge; kenar yolunda platformun sectigi konum, secim kayitli degil

agirlikli donus turu: merkez 102.4 ms, kenar 19.5 ms
sonuc hazir olana kadar: merkez 102.4 ms, kenar 499.5 ms (yayilma 480 ms eklendi)
uctan uca toplam: merkez 208.8 ms, kenar 517.0 ms
```

Birinci ölçüde kenar açık ara kazanır: ağırlıklı kuyruğa girme turu 106,4 milisaniyeden 17,5
milisaniyeye iner, en uzak uçta kazanç sekiz kata çıkar.

İkinci ölçüde tablo ters döner. Kenar tüketicisi altı milisaniyede başlar, merkez kırkta; ama
kenarın toplu okuma boyutu yirmi beş olduğu için 2400 ileti doksan altı çağrıya bölünür, merkezde
ona. **Çağrı başına daha ucuz olan başlangıç, dokuz kat daha sık başlandığı için toplamda daha
pahalıya gelir.** İşin koştuğu yer de belirsizleşir: merkezde bilinen tek bir bölge, kenarda
platformun seçtiği kayıtsız bir konum.

Üçüncü ölçü dönüş yoludur. Kenarın dönüş turu 19,5 milisaniyeyle kısadır, ama sonuç kenar deposuna
yazıldığı için kullanıcının ucunda görünmesi 480 milisaniyelik yayılmayı bekler: uçtan uca toplam
merkezde 208,8, kenarda 517,0 milisaniye. **Kuyruğa girmede kazanılan 89 milisaniye, sonucun
okunabilir olmasında kaybedilen 397 milisaniyeyi karşılamaz.**

## Kenar Kuyruğunun Dört Kısıtı

```js
// kisit.mjs — kenar kuyrugunun dort kisiti ayni is kumesinde sayilir: deneme, saklama, sira, toplu.
import { TOPLAM, KUYRUK, isKumesi, uretec } from "./ag.mjs";

const sut = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 15 : 17)).join("").trimEnd());
const kume = isKumesi(20260731);                    // tohum gorunur
sut("kisit", "merkez", "kenar", "olcum", "kenarin kaybi");

const olu = (k) => kume.filter((i) => i.deneme > k.deneme).length;   // deneme hakkini asan ileti
sut("yeniden deneme", KUYRUK.merkez.deneme, KUYRUK.kenar.deneme,
  `${TOPLAM} ileti`, `${olu(KUYRUK.kenar)} olu mektup (${(100 * olu(KUYRUK.kenar) / TOPLAM).toFixed(1)}%)`);

const KESINTI_GN = 6, GUNLUK = TOPLAM;              // tuketici alti gun durdu
const kalan = (k) => Math.min(KESINTI_GN, k.saklama_gn) * GUNLUK;
sut("saklama suresi", `${KUYRUK.merkez.saklama_gn} gn`, `${KUYRUK.kenar.saklama_gn} gn`,
  `${KESINTI_GN} gn kesinti`, `${KESINTI_GN * GUNLUK - kalan(KUYRUK.kenar)} ileti dustu`);

const r = uretec(770419), karisik = kume.map((i) => [r(), i]).sort((a, b) => a[0] - b[0]).map((x) => x[1]);
const uygula = (akis) => { const son = new Map(); for (const i of akis) son.set(i.sayac, i.sira); return son; };
const dogru = uygula([...kume].sort((a, b) => a.sira - b.sira)), bozuk = uygula(karisik);
const yanlis = [...dogru].filter(([s, n]) => bozuk.get(s) !== n).length;
sut("siralama", "anahtar basina", "yok", `${dogru.size} sayac`,
  `${yanlis} sayacta yanlis endeks (${(100 * yanlis / dogru.size).toFixed(1)}%)`);

const cagri = (k) => Math.ceil(TOPLAM / k.toplu);
sut("toplu okuma", KUYRUK.merkez.toplu, KUYRUK.kenar.toplu, `${TOPLAM} ileti`,
  `${cagri(KUYRUK.kenar) - cagri(KUYRUK.merkez)} fazla cagri`);

const cok = [...dogru.values()].filter((n) => n > 1).length, b = KUYRUK.kenar;
console.log("\ndolasmanin bedeli, kalem kalem:");
for (const s of [
  `deneme: ${olu(b)} olu mektup elle geri konur -> ${olu(b)} ek yazma; saklama sayaci sifirlanir, sira bastan gelir`,
  `saklama: ${KESINTI_GN * GUNLUK - kalan(b)} ileti icin ikinci dayanikli kopya; ${KESINTI_GN * GUNLUK} iletinin tamami iki yere yazilir`,
  `siralama: ${cok} cok okumali sayac icin tampon; ${TOPLAM} ek durum yazmasi, ileti basina 3000 ms bekleme`,
  `toplu okuma: ${cagri(b)} x ${b.baslatma} ms = ${cagri(b) * b.baslatma} ms, merkezin ${cagri(KUYRUK.merkez) * KUYRUK.merkez.baslatma} ms'sinden fazla`,
]) console.log("  " + s);
```

```
kisit            merkez         kenar          olcum          kenarin kaybi
yeniden deneme   10             3              2400 ileti     50 olu mektup (2.1%)
saklama suresi   14 gn          4 gn           6 gn kesinti   4800 ileti dustu
siralama         anahtar basina yok            842 sayac      438 sayacta yanlis endeks (52.0%)
toplu okuma      250            25             2400 ileti     86 fazla cagri

dolasmanin bedeli, kalem kalem:
  deneme: 50 olu mektup elle geri konur -> 50 ek yazma; saklama sayaci sifirlanir, sira bastan gelir
  saklama: 4800 ileti icin ikinci dayanikli kopya; 14400 iletinin tamami iki yere yazilir
  siralama: 667 cok okumali sayac icin tampon; 2400 ek durum yazmasi, ileti basina 3000 ms bekleme
  toplu okuma: 96 x 6 ms = 576 ms, merkezin 400 ms'sinden fazla
```

Dört kısıt dört ayrı sayı verir. Deneme hakkı ondan üçe inince aynı hata dağılımında 50 ileti ölü
mektup kutusuna düşer; merkez yolunda hepsi geçer. Saklama on dörtten dört güne inince, altı günlük
bir kesintide biriken 14400 iletinin **4800'ü kuyruktan düşer**; merkez kuyruğu hiçbirini kaybetmez.

En pahalı kalem sıralamadır. Garanti olmadığında 842 sayacın **438'i** yanlış endeksle biter: son
uygulanan okuma en büyük sıra numarası olmayabilir, fatura eksik ya da fazla çıkar. Bu,
ayarla düzeltilecek bir kalem değil, kuyruğun hiç sunmadığı bir garantidir.

Dolaşmanın bedeli son bloktadır. Ölü mektupları elle geri koymak 50 ek yazma demektir, ama geri konan
ileti yenidir: saklama sayacı sıfırlanır, sıra numarası baştan gelir. Uzun saklama ancak ikinci bir
dayanıklı kopyayla, sıralama da 667 sayaç adına tutulan tamponla sağlanır: 14400 iletinin tamamı iki
yere yazılır, 2400 ek durum yazması ve ileti başına üç saniye bekleme çıkar. **Üçü de kenarda
kazanılan 89 milisaniyeden büyüktür.**

## Zamanlanmış İş Hangi Bölgede Tetiklenir

```js
// zaman.mjs — zamanlanmis is: hangi bolgede tetiklendigi ve saat dilimi karari kimde kaldi.
import { UCLAR, DEPO_OKUMA } from "./ag.mjs";

const TEMEL = 2, KAYMA_GUN = 217, KAYAN_SERIT = [2, 3];   // temel saat 02:00, mevsimlik kayma penceresi
const saat = (h) => `${String(((h % 24) + 24) % 24).padStart(2, "0")}:00`;
const gun = (h) => (h < 0 ? " (bir onceki gun)" : "");

const s1 = (...s) => console.log(s.map((x, i) => String(x).padEnd(i ? 14 : 11)).join("").trimEnd());
s1("uc", "serit", "tek tetikleme", "yerel saat", "kayma penceresi");
for (const u of UCLAR) s1(u.ad, `+${u.serit}`, saat(TEMEL), saat(TEMEL + u.serit),
  KAYAN_SERIT.includes(u.serit) ? `${KAYMA_GUN} gun 60 dk` : "yok");

const yerel = new Set(UCLAR.map((u) => TEMEL + u.serit));
const seritler = [...new Set(UCLAR.map((u) => u.serit))].sort();
console.log(`\ntek tetikleme -> ${yerel.size} ayri yerel saat; ` +
  `${UCLAR.filter((u) => u.serit === 0).length}/${UCLAR.length} uc istenen ${saat(TEMEL)} saatini goruyor`);
console.log(`her ucta ${saat(TEMEL)} icin ${seritler.length} ayri tetikleme tanimi: ` +
  seritler.map((s) => `+${s} temel ${saat(TEMEL - s)}${gun(TEMEL - s)}`).join(", "));
const kayan = UCLAR.filter((u) => KAYAN_SERIT.includes(u.serit));
console.log(`mevsimlik kayma: ${kayan.length} uc x ${KAYMA_GUN} gun = ${kayan.length * KAYMA_GUN} uc-gun ` +
  `60 dk sapma; zamanlayici yalniz temel saati bilir, cevrimi islev kendi yapar\n`);

const OKUMA = 2400, PAKET = 100, tur = Math.ceil(OKUMA / PAKET);
const sure = (u) => tur * (2 * u.merkez + DEPO_OKUMA);
const l = UCLAR.map(sure), en_az = Math.min(...l), en_cok = Math.max(...l);
console.log(`gecelik is ${tur} tur x ${PAKET} okuma; tetikleme yeri secilemedigi icin sure ` +
  `${en_az}-${en_cok} ms araliginda, ortalama ${(l.reduce((a, b) => a + b) / l.length).toFixed(0)} ms ` +
  `(${(en_cok / en_az).toFixed(1)}x fark)`);
console.log(`sabitlemenin bedeli: is merkez bolgeye pinlenirse sure ${en_az} ms'de sabitlenir, ` +
  `ama kenarda kosma ozelligi bu is icin tumden birakilir`);
```

```
uc         serit         tek tetikleme yerel saat    kayma penceresi
uc-bati    +0            02:00         02:00         yok
uc-kuzey   +0            02:00         02:00         yok
uc-dogu    +2            02:00         04:00         217 gun 60 dk
uc-guney   +1            02:00         03:00         yok
uc-yayla   +3            02:00         05:00         217 gun 60 dk
uc-liman   +2            02:00         04:00         217 gun 60 dk

tek tetikleme -> 4 ayri yerel saat; 2/6 uc istenen 02:00 saatini goruyor
her ucta 02:00 icin 4 ayri tetikleme tanimi: +0 temel 02:00, +1 temel 01:00, +2 temel 00:00, +3 temel 23:00 (bir onceki gun)
mevsimlik kayma: 3 uc x 217 gun = 651 uc-gun 60 dk sapma; zamanlayici yalniz temel saati bilir, cevrimi islev kendi yapar

gecelik is 24 tur x 100 okuma; tetikleme yeri secilemedigi icin sure 696-4728 ms araliginda, ortalama 2792 ms (6.8x fark)
sabitlemenin bedeli: is merkez bolgeye pinlenirse sure 696 ms'de sabitlenir, ama kenarda kosma ozelligi bu is icin tumden birakilir
```

Gecelik işin "her şubede 02:00'de koşsun" isteği tek tetikleme tanımıyla karşılanamaz. Temel saate
kurulan tetikleme dört ayrı yerel saate düşer, altı uçtan yalnız ikisi istenen saati görür. Her uçta
02:00 için dört tanım gerekir ve şerit +3'ünki temel saat 23:00'e, yani **bir önceki güne** düşer.
İki şerit ayrıca yılın 217 gününde altmış dakika kayar: 651 uç-gün sapma. **Zamanlayıcı yalnız temel
saati bilir; yerel saate çevirme kararı devredilmez, işlevin kodunda kalır.**

Son iki satır tetiklemenin nerede koştuğunu sayar. Gecelik iş merkez deposunu yirmi dört turda okur;
koştuğu konum seçilemediği için aynı iş 696 ile 4728 milisaniye arasında, ortalama 2792 milisaniyede
biter — **6,8 katlık bir aralık ve hangi ucuna düşeceği bizim kararımız değil.** Süreyi sabitlemenin
tek yolu işi merkeze sabitlemektir; o zaman iş kenarda koşmaz.

## Özet

- Kuyruğa girme turu kenarda 106,4 milisaniyeden 17,5 milisaniyeye indi, en uzak uçta kazanç 8 kata
  çıktı; ama toplu okuma 250'den 25'e indiği için 2400 ileti 10 yerine 96 çağrıya bölündü ve
  başlatma toplamı 400 yerine 576 milisaniye oldu.
- Sonuç kenar deposuna yazıldığı için 480 milisaniye yayılma bekledi; uçtan uca toplam merkezde
  208,8, kenarda 517,0 milisaniye çıktı. Kabul hızlandı, teslim yavaşladı.
- Dört kısıt dört sayı verdi: 3 deneme hakkı 50 ölü mektup, 4 gün saklama 6 günlük kesintide 4800
  ileti kaybı, sıralama garantisinin yokluğu 842 sayacın 438'inde yanlış endeks, 25'lik toplu okuma
  86 fazla çağrı. Dolaşmanın bedeli 50 ek yazma, 14400 iletiyi iki yere yazma, 2400 ek durum
  yazması ve 3000 milisaniye bekleme oldu.
- Tek tetikleme 4 ayrı yerel saate düştü, 6 uçtan 2'si istenen saati gördü; 651 uç-gün
  mevsimlik sapma çıktı ve gecelik iş tetiklendiği yere göre 696-4728 milisaniye sürdü.

## Sonraki Adım

Kenar çalışma zamanı bir kuyruğa ve bir zamanlayıcıya erişti, ama erişimin nasıl kurulduğu
sorulmadı. Kaynak adresi ve kimlik bilgisi çalışma zamanında istemci kurularak da verilebilir,
dağıtım anında **bildirimsel bağlamayla** da. Bir sonraki ders aynı kaynağa iki yoldan erişip
dördünü sayar: kod satırı, açılış işi, kimlik bilgisinin yeri, ve yanlış yapılandırmanın fark
edilme anı.
