---
title: 'Hız Sınırlayıcı'
source: 'https://academia.sh/tr/kurslar/vaka-calismalari/hiz-sinirlayici'
course: 'Vaka Çalışmaları'
language: tr
updated: '2026-08-17T18:10:56+00:00'
license: 'CC BY-SA 4.0'
---

# Hız Sınırlayıcı

İşi isteği reddetmek olan bileşenin tasarlanması: sabit pencere, kaydırmalı dilim ve belirteç kovasının izin verdiği aşımın üç istek deseninde ölçülmesi, pencere sınırındaki iki katına çıkan geçişin sayılması, dağıtık sayacın merkezî, bölünmüş kota ve gecikmeli eşitleme düzenlerinde ürettiği aşım ile yanlış ret sayısı ve eşitleme aralığının eşiği belirlemesi.

Önceki iki vakada sistemin işi bir isteği karşılamaktı; başarısızlık kötü bir sonuçtu. Bu vaka
tersini tasarlar: işi isteği **reddetmek** olan bir bileşeni. Hız sınırlama bir eylem olarak
Trafik Katmanı ve Eşzamansız İşleme kurslarında kurulmuştu; orada kararın **yeri** ele alındı,
algoritması değil. Burada tasarlanan şey **hız sınırlayıcı** bileşenin kendisidir.

Reddetme kararı paylaşılan bir sayaca bakarak verilir ve sayaç dağıtıktır. İki soru buradan
çıkar: sayacın tuttuğu pencere hangi biçimde tanımlanırsa ilan edilen sınırın üstüne
çıkılabilir, ve eşzamanlı okuyup yazan düğümler sayaçta ne kadar sapma üretir.

## Kısıtlar ve Kapsam

İşlevsel gereksinimler: istemci başına isteği saymak, sınırı aşan isteği reddetmek, kalan hakkı
ve bekleme süresini yanıtta bildirmek, sınırı bir kural kümesinden okumak.

Tasarlanmayan işler: kimlik doğrulama, kotanın ücretlendirilmesi, kötüye kullanım tespiti ve
kural yönetim arayüzü.

İşlevsel olmayan gereksinimler eşikle ve kaynağıyla yazılır: bir istemcinin herhangi bir 60
saniyelik aralıkta geçirdiği istek sayısı ilan edilen sınırın **1,1 katını geçmez** (kaynak:
sınırın istemciye verilmiş bir söz olması), sınırın altında kalan bir istemci hiç
reddedilmez (kaynak: aynı sözün karşı yönü), sayaç deposu düştüğünde istek reddedilmez
(kaynak: sınırlayıcının kendisinin kesinti kaynağı olmaması).

## Varsayımlar ve Ölçek

| Kod | Varsayım | Değer | Gerekçe |
|---|---|---|---|
| HS1 | izlenen istemci | 200.000 | sınır uygulanan ayrı anahtar sayısı |
| HS2 | uçta tepe istek | 40.000/s | sınırlayıcıdan geçen toplam istek hızı |
| HS3 | istemci başına ilan edilen sınır | 600 istek / 60 s | sözleşmede yazılı hak |
| HS4 | sınırlayıcı düğüm sayısı | 8 | uçtaki yatay ölçek |
| HS5 | sayaç eşitleme aralığı | 0,2 saniye | düğümlerin ortak görüntüyü tazeleme sıklığı |
| HS6 | sayaç kaydı | 48 bayt | anahtar, sayı, pencere damgası |
| HS7 | kaydırmalı pencere dilimi | 12 (5 saniyelik) | 60 saniyenin bölünme inceliği |
| HS8 | belirteç kovası kapasitesi | 60 belirteç | ani yığına bırakılan pay |

```js
// hiz/olcek.mjs — HS varsayim tablosundan cikan kabaca buyukluk hesabi
const HS = { istemci: 200_000, tepeIstek: 40_000, sinir: 600, pencereS: 60,
  dugum: 8, esitlemeS: 0.2, kayitBayt: 48, dilim: 12 };  // HS1..HS8

const dugumBasina = HS.tepeIstek / HS.dugum;
console.log(`dugum basina tepe istek/s   ${dugumBasina}`);
console.log(`merkezi sayac kullanilirsa dokunus/s   ${HS.tepeIstek}`);
console.log(`istemci sinirinin saniye karsiligi     ${HS.sinir / HS.pencereS}`);

console.log(`\n${"sayac duzeni".padEnd(18)}${"istemci basina kayit".padStart(21)}${"toplam MB".padStart(11)}`);
for (const [ad, n] of [["sabit pencere", 1], ["belirtec kovasi", 1], ["kaydirmali dilim", HS.dilim]])
  console.log(`${ad.padEnd(18)}${String(n).padStart(21)}` +
    `${((HS.istemci * n * HS.kayitBayt) / 1e6).toFixed(2).padStart(11)}`);

const korTavan = (HS.sinir / HS.pencereS) * HS.esitlemeS * HS.dugum;
console.log(`\nesitleme koru: bir dugumun ${HS.esitlemeS} s icinde gormedigi istek = ` +
  `${dugumBasina * HS.esitlemeS} (tum istemciler)`);
console.log(`tek istemci icin kor tavan = (sinir/s) x esitleme x dugum = ${korTavan} istek`);
console.log(`esik: sinirin 1.1 kati = ${HS.sinir * 1.1}; kor tavanla ${HS.sinir + korTavan} -> ` +
  `${HS.sinir + korTavan <= HS.sinir * 1.1 ? "gecer" : "gecmez"}`);
```

```
dugum basina tepe istek/s   5000
merkezi sayac kullanilirsa dokunus/s   40000
istemci sinirinin saniye karsiligi     10

sayac duzeni       istemci basina kayit  toplam MB
sabit pencere                         1       9.60
belirtec kovasi                       1       9.60
kaydirmali dilim                     12     115.20

esitleme koru: bir dugumun 0.2 s icinde gormedigi istek = 1000 (tum istemciler)
tek istemci icin kor tavan = (sinir/s) x esitleme x dugum = 16 istek
esik: sinirin 1.1 kati = 660; kor tavanla 616 -> gecer
```

Bu sayılar **hesap** sınıfındadır. Üçü tasarımı belirliyor. Birincisi, merkezî bir sayaç
kullanılırsa tepe uçta saniyede 40.000 dokunuş gerekir; bu, sınırlayıcının kendisini
sistemdeki en yoğun yazma kaynağı yapar. İkincisi, kaydırmalı dilim 115,20 MB istiyor, sabit
pencerenin 9,60 MB'ının tam 12 katı; incelik doğrudan belleğe yazılıyor. Üçüncüsü, kör tavan
16 istektir: 0,2 saniyelik eşitleme aralığında sekiz düğüm bir istemci için en çok 16 isteği
birbirinden habersiz geçirebilir, bu da 616 eder ve 660 eşiğinin altında kalır. Eşitleme
aralığı bu hesapla seçilmiştir.

## Pencerenin Biçimi Aşımı Belirliyor

Ölçüm süreç içi bir modeldir: gerçek saat, ağ ya da depo yoktur; zaman model saatidir ve istek
listesi belirlenimlidir. Üç desen denenir: sınırın iki katı hızda **düzgün** akış, pencere
sınırının iki yanına **yığılan** akış ve sınırın tam üstünde ama aralıklı gelen akış. Ölçülen
şey, kabul edilen isteklerin herhangi bir 60 saniyelik kayan aralıkta ulaştığı en yüksek
sayıdır.

```js
// hiz/pencere.mjs — uc pencere algoritmasinin surec ici modeli. Gercek saat, ag ya da depo
// yoktur: zaman model saatidir (ms) ve istek listesi belirlenimlidir.
const SINIR = 600, PENCERE = 60_000, DILIM = 5_000, SURE = 180_000;   // HS3, HS7
const KOVA = 60, DOLDURMA = SINIR / (PENCERE / 1000);                 // HS8

const desen = {
  "duzgun 2x": () => Array.from({ length: (SURE / 1000) * 20 }, (_, i) => i * 50),
  "sinirda yigin": () => {
    const t = [];
    for (const sinir of [PENCERE, 2 * PENCERE])
      for (const [bas, n] of [[sinir - DILIM, SINIR], [sinir, SINIR]])
        for (let i = 0; i < n; i += 1) t.push(bas + Math.floor((i * DILIM) / n));
    return t.sort((a, b) => a - b);
  },
  "aralikli tam sinir": () => {
    const t = [];
    for (let k = 0; k < SURE / PENCERE; k += 1)
      for (let i = 0; i < SINIR; i += 1) t.push(k * PENCERE + Math.floor((i * DILIM) / SINIR));
    return t;
  },
};

const ALGORITMA = {
  "sabit pencere": () => {
    let p = -1, n = 0;
    return (t) => {
      const k = Math.floor(t / PENCERE);
      if (k !== p) { p = k; n = 0; }
      return n < SINIR && (n += 1, true);
    };
  },
  "kaydirmali dilim": () => {
    const say = new Map();
    return (t) => {
      const d = Math.floor(t / DILIM), ilk = d - PENCERE / DILIM + 1;
      for (const k of say.keys()) if (k < ilk) say.delete(k);
      let toplam = 0;
      for (const v of say.values()) toplam += v;
      if (toplam >= SINIR) return false;
      say.set(d, (say.get(d) ?? 0) + 1);
      return true;
    };
  },
  "belirtec kovasi": () => {
    let belirtec = KOVA, son = 0;
    return (t) => {
      belirtec = Math.min(KOVA, belirtec + ((t - son) / 1000) * DOLDURMA);
      son = t;
      return belirtec >= 1 && (belirtec -= 1, true);
    };
  },
};

const enYogunPencere = (kabul) => {
  let en = 0;
  for (let i = 0, j = 0; i < kabul.length; i += 1) {
    while (kabul[i] - kabul[j] >= PENCERE) j += 1;
    en = Math.max(en, i - j + 1);
  }
  return en;
};

console.log(`model: ${SURE / 1000} s, sinir ${SINIR}/${PENCERE / 1000} s, kova ${KOVA} belirtec, doldurma ${DOLDURMA}/s`);
for (const [dad, uret] of Object.entries(desen)) {
  const istek = uret();
  console.log(`\ndesen "${dad}": ${istek.length} istek`);
  console.log(`${"algoritma".padEnd(18)}${"kabul".padStart(8)}${"red".padStart(8)}` +
    `${"en yogun 60 s".padStart(15)}${"asim".padStart(8)}${"asim orani".padStart(12)}`);
  for (const [aad, kur] of Object.entries(ALGORITMA)) {
    const izin = kur(), kabul = istek.filter((t) => izin(t));
    const en = enYogunPencere(kabul);
    console.log(`${aad.padEnd(18)}${String(kabul.length).padStart(8)}${String(istek.length - kabul.length).padStart(8)}` +
      `${String(en).padStart(15)}${String(en - SINIR).padStart(8)}${`x${(en / SINIR).toFixed(3)}`.padStart(12)}`);
  }
}
```

```
model: 180 s, sinir 600/60 s, kova 60 belirtec, doldurma 10/s

desen "duzgun 2x": 3600 istek
algoritma            kabul     red  en yogun 60 s    asim  asim orani
sabit pencere         1800    1800            600       0      x1.000
kaydirmali dilim      1800    1800            600       0      x1.000
belirtec kovasi       1859    1741            659      59      x1.098

desen "sinirda yigin": 2400 istek
algoritma            kabul     red  en yogun 60 s    asim  asim orani
sabit pencere         1800     600           1200     600      x2.000
kaydirmali dilim      1200    1200            600       0      x1.000
belirtec kovasi        318    2082            159    -441      x0.265

desen "aralikli tam sinir": 1800 istek
algoritma            kabul     red  en yogun 60 s    asim  asim orani
sabit pencere         1800       0            600       0      x1.000
kaydirmali dilim      1800       0            600       0      x1.000
belirtec kovasi        327    1473            109    -491      x0.182
```

Bu sayılar **ölçüm** sınıfındadır ve belirlenimlidir; rastgelelik yoktur.

Birinci desen üç algoritmayı da sınırın içinde tutuyor, tek istisna belirteç kovasıdır: 659,
yani 1,098 kat. Bu 59 isteklik fazlalık kovanın kapasitesidir ve HS8 doğrudan bu sayıyı seçer.
1,1 katlık eşikle karşılaştırıldığında kapasite 60'ın tavan olduğu görülüyor; 66'ya
çıkarılsaydı eşik aşılırdı.

İkinci desen sabit pencerenin bilinen kusurunu sayıya çeviriyor: pencere sınırının iki yanına
yığılan istekler iki ayrı sayacın içine düşüyor ve kayan 60 saniyelik aralıkta 1200 istek
geçiyor, tam **iki kat**. Sınır 600 diye ilan edilmiş bir sistemde bir istemci 1200 istek
geçirebiliyor. Kaydırmalı dilim aynı desende 600'de kalıyor.

Üçüncü desen belirteç kovasının bedelini gösteriyor. İstemci sınırın tam üstünde, penceresi
başına 600 istek gönderiyor ve hiçbir sınırı aşmıyor; kaydırmalı dilim hepsini geçiriyor,
belirteç kovası 1800 isteğin 1473'ünü **reddediyor**. Kova boşta geçen zamanı biriktirmez;
aralıklı çalışan bir istemci hakkını kullanamaz. İkinci işlevsel olmayan gereksinim bu satırla
ihlal ediliyor, dolayısıyla seçilen algoritma **kaydırmalı dilim**dir.

## Dağıtık Sayacın Sapması

Seçilen algoritma tek düğümde doğru çalışıyor. Sekiz düğüm aynı istemciyi sayınca soru
değişir. Üç düzen karşılaştırılır: her isteğin ortak sayaca dokunduğu **merkezî** düzen, sınırın
düğüm sayısına bölündüğü **bölünmüş kota** ve düğümlerin yerel sayıp aralıkla eşitlendiği
**gecikmeli eşitleme**.

```js
// hiz/dagitik.mjs — dagitik sayacin surec ici modeli. Gercek dugum, ag ya da depo yoktur:
// dugum atamasi tohumlu bir uretecle, esitleme model saatiyle yapilir.
const SINIR = 600, PENCERE = 60, DUGUM = 8;          // HS3, HS4

function uretec(tohum) {                              // 32 bitlik dogrusal esitlikli uretec
  let s = tohum >>> 0;
  return () => { s = (Math.imul(s, 1103515245) + 12345) >>> 0; return s / 4294967296; };
}

export function kos({ duzen, hiz, aralik = 0.2, tohum }) {
  const rnd = uretec(tohum);
  const n = hiz * PENCERE;
  const yerel = new Array(DUGUM).fill(0);
  let global = 0, sonGlobal = 0, sonEsitleme = 0, kabul = 0, red = 0, dokunus = 0;
  for (let i = 0; i < n; i += 1) {
    const t = (i / hiz), d = Math.floor(rnd() * DUGUM);
    if (duzen === "gecikmeli esitleme" && t - sonEsitleme >= aralik) {
      sonGlobal = global; sonEsitleme = t;
      for (let j = 0; j < DUGUM; j += 1) yerel[j] = 0;
    }
    let izin;
    if (duzen === "merkezi") { dokunus += 1; izin = global < SINIR; }
    else if (duzen === "bolunmus kota") izin = yerel[d] < SINIR / DUGUM;
    else izin = sonGlobal + yerel[d] < SINIR;
    if (izin) { kabul += 1; global += 1; yerel[d] += 1; } else red += 1;
  }
  if (duzen === "gecikmeli esitleme") dokunus = DUGUM * Math.floor(PENCERE / aralik);
  return { istek: n, kabul, red, dokunus, asim: Math.max(0, kabul - SINIR) };
}

const DUZEN = ["merkezi", "bolunmus kota", "gecikmeli esitleme"];
for (const hiz of [10, 90]) {
  console.log(`\nistemci hizi ${hiz}/s -> ${hiz * PENCERE} istek, sinir ${SINIR}, ${DUGUM} dugum, tohum 20260730`);
  console.log(`${"duzen".padEnd(20)}${"kabul".padStart(8)}${"red".padStart(7)}${"asim".padStart(7)}` +
    `${"yanlis ret".padStart(12)}${"sayac dokunusu".padStart(16)}`);
  for (const d of DUZEN) {
    const r = kos({ duzen: d, hiz, tohum: 20260730 });
    const yanlis = hiz * PENCERE <= SINIR ? r.red : 0;
    console.log(`${d.padEnd(20)}${String(r.kabul).padStart(8)}${String(r.red).padStart(7)}` +
      `${String(r.asim).padStart(7)}${String(yanlis).padStart(12)}${String(r.dokunus).padStart(16)}`);
  }
}

console.log(`\ngecikmeli esitleme, istemci hizi 90/s (yigin)`);
console.log(`${"esitleme araligi".padEnd(18)}${"kabul".padStart(8)}${"asim".padStart(7)}` +
  `${"asim orani".padStart(12)}${"dokunus/s".padStart(12)}${"esik 660".padStart(10)}`);
for (const a of [0.2, 1, 2, 5]) {
  const r = kos({ duzen: "gecikmeli esitleme", hiz: 90, aralik: a, tohum: 20260730 });
  console.log(`${`${a} s`.padEnd(18)}${String(r.kabul).padStart(8)}${String(r.asim).padStart(7)}` +
    `${`x${(r.kabul / SINIR).toFixed(3)}`.padStart(12)}${(r.dokunus / PENCERE).toFixed(1).padStart(12)}` +
    `${(r.kabul <= SINIR * 1.1 ? "gecer" : "gecmez").padStart(10)}`);
}
```

```
istemci hizi 10/s -> 600 istek, sinir 600, 8 dugum, tohum 20260730
duzen                  kabul    red   asim  yanlis ret  sayac dokunusu
merkezi                  600      0      0           0             600
bolunmus kota            575     25      0          25               0
gecikmeli esitleme       600      0      0           0            2400

istemci hizi 90/s -> 5400 istek, sinir 600, 8 dugum, tohum 20260730
duzen                  kabul    red   asim  yanlis ret  sayac dokunusu
merkezi                  600   4800      0           0            5400
bolunmus kota            600   4800      0           0               0
gecikmeli esitleme       609   4791      9           0            2400

gecikmeli esitleme, istemci hizi 90/s (yigin)
esitleme araligi     kabul   asim  asim orani   dokunus/s  esik 660
0.2 s                  609      9      x1.015        40.0     gecer
1 s                    630     30      x1.050         8.0     gecer
2 s                    720    120      x1.200         4.0    gecmez
5 s                    900    300      x1.500         1.6    gecmez
```

İlk tablo bölünmüş kotayı eliyor. İstemci sınırının tam üstünde, 600 istek gönderiyor ve
hiçbirini aşmıyor; buna karşın 25 isteği reddediliyor, yüzde 4,17. Sebep dağılım
dengesizliğidir: istekler sekiz düğüme eşit dağılmaz ve payını dolduran düğüm, öteki düğümlerde
kullanılmamış kota dururken reddeder. Kotayı bölmek sınırı bölmez, **hakkı** böler.

İkinci tablo merkezî sayacı fiyatlandırıyor. Aşımı sıfırdır, bu doğrudur; bedeli tepe uçta
saniyede 40.000 sayaç dokunuşudur ve tek istemcilik bu modelde bile 5400 dokunuşla gecikmeli
eşitlemenin 2400'ünün iki katından fazladır. Gecikmeli eşitleme 609 kabul ediyor, aşım 9.

Üçüncü tablo parametreyi seçiyor. Eşitleme aralığı büyüdükçe aşım büyüyor: 0,2 saniyede 1,015
kat, 1 saniyede 1,050 kat, 2 saniyede 1,200 kat. Eşik 1,1 kat olduğuna göre 1 saniye geçiyor,
2 saniye geçmiyor. Sayaç dokunuşu ise ters yönde küçülüyor: saniyede 40'tan 4'e. HS5'in 0,2
saniye seçilmesi bu iki eğrinin kesişme noktasıdır ve eşik 1,05'e sıkılaştırılsaydı aralığın
0,2 saniyede kalması zorunlu olurdu.

## Tasarım, Arıza Davranışı ve Feda Edilen

Karar noktası ağ geçididir: Trafik Katmanı kursunun Ağ Geçidi Yük Boşaltma dersindeki
taşınabilirlik kuralı burada geçerlidir, çünkü istemci kimliği bir üstveri alanıdır ve karar
alan girdisi okumaz. Sayaç, Veri Katmanı Ölçekleme kursunun Depo Türleri dersindeki
anahtar–değer deposunda tutulur; anahtar `(istemci, dilim)` ikilisi, kayıt 48 bayt, süre sonu
60 saniyedir. Bileşenin kendisi Dayanıklılık ve Güvenilirlik kursunun Kısıtlama ve Yük Boşaltma
dersindeki **kısıtlamadır**: bilinen bir hızın üstünü keser, anlık kapasiteye bakmaz.

**Bilerek kullanılmayan kalıp.** Kuyruk tabanlı yük dengeleme (Uygulama Katmanı ve Servis
Etkileşimi) kullanılmaz: aşan isteği kuyruğa alıp sonra işlemek sınırı bir gecikmeye çevirir,
oysa bileşenin sözleşmesi reddetmektir.

Arıza senaryosu sayaç deposunun düşmesidir. Üçüncü eşik gereği sınırlayıcı açık kalır: düğümler
son bilinen ortak görüntüyle ve yalnız kendi yerel sayacıyla karar verir. Bu, bölünmüş kotanın
davranışına yaklaşmaktır ve arıza süresince istemci başına aşım sekiz kata kadar çıkabilir.
Feda edilen tek cümlededir: bu tasarım aşımı sıfırlamaz, onu 1,015 katta tutmayı 40.000 yerine
40 sayaç dokunuşuyla satın alır.

## Özet

- Sabit pencere, sınırın iki yanına yığılan istekte kayan 60 saniyelik aralıkta 1200 istek
  geçirdi: ilan edilen sınırın tam iki katı.
- Belirteç kovası düzgün akışta 659 geçirdi (1,098 kat, kova kapasitesi kadar), ama sınırın
  tam üstünde aralıklı çalışan istemcinin 1800 isteğinden 1473'ünü reddetti.
- Kaydırmalı dilim üç desende de 600'de kaldı ve hiçbir geçerli isteği reddetmedi; bedeli 12
  kat bellektir, 9,60 MB yerine 115,20 MB.
- Bölünmüş kota, sınırının tam üstündeki bir istemcinin 25 isteğini (yüzde 4,17) dağılım
  dengesizliği yüzünden reddetti; kotayı bölmek hakkı böler.
- Merkezî sayacın aşımı sıfırdır ama tepe uçta saniyede 40.000 dokunuş ister; gecikmeli
  eşitleme 0,2 saniyelik aralıkta 1,015 kat aşımı saniyede 40 dokunuşla veriyor.
- Eşitleme aralığı eşiği belirliyor: 1 saniyede 1,050 kat (geçer), 2 saniyede 1,200 kat
  (geçmez).

## Sonraki Adım

Bu vakada sayaç bir eşiği koruyordu ve eşik aşıldığında kaybedilen şey bir istekti; istemci
yeniden dener. Sonraki vaka aynı sayma sorununu, sayılan şeyin **geri getirilemez** olduğu
yerde sorar. Sınırlı sayıda koltuk ya da stok kalemi vardır; sayacın iki fazla saymasının
karşılığı reddedilmiş bir istek değil, satılmış ama var olmayan bir kalemdir. O zaman
ölçülecek sayı çekişme altında üretilen fazla satıştır ve yanında ikinci bir sayı durur:
aynı korumanın reddettiği geçerli istek.
