---
title: 'Geri Basınç'
source: 'https://academia.sh/tr/kurslar/eszamansiz-isleme/geri-basinc'
course: 'Önbellekleme, Kuyruklar ve Eşzamansız İşleme'
language: tr
updated: '2026-08-17T18:06:46+00:00'
license: 'CC BY-SA 4.0'
---

# Geri Basınç

Üretim hızının tüketim hızını aştığı durumun sonuçları: sınırsız kuyrukta bekleme süresinin sınırsız büyümesi, sınırlı kuyruğun üç politikasının benzetimle sayısal karşılaştırılması ve geri basıncın akış üzerinden ölçülerek üreticiye yayılması.

Bir önceki ders tek bir uzun işi ele aldı: parçalara bölmek, ilerlemeyi kaydetmek ve
iptal edilebilir kılmak yeterliydi. Gerçek bir arka planda ise işler tek tek gelmez,
**akar**: her ödünç işlemi bir bildirim işi, her kapak yüklemesi bir görsel işleme işi
doğurur.

İşlerin geliş hızı ile işçilerin bitirme hızı birbirinden bağımsız iki büyüklüktür.
Eşit olmalarını sağlayan hiçbir mekanizma yoktur; geliş hızını istek trafiği, bitirme
hızını işçi sayısı ve işin süresi belirler. Geliş hızı bitirme hızını aştığında kuyruk
büyür. Bu ders o büyümenin ne ürettiğini ölçer ve sistemin bunu üreticiye nasıl
bildirdiğini kurar.

## Hız Uyuşmazlığı

Bir kuyruğa saniyede $\lambda$ iş girip saniyede $\mu$ iş çıkıyorsa, kuyruk uzunluğu
$\lambda - \mu$ hızıyla değişir. $\lambda < \mu$ olduğu sürece kuyruk boş kalır ve
bekleme süresi işin kendi süresine yaklaşır. $\lambda > \mu$ olduğu anda kuyruk her
saniye $\lambda - \mu$ kadar uzar ve bu büyüme kendiliğinden durmaz.

Büyümenin doğrudan sonucu bekleme süresidir. Kuyruk kuramının temel bağıntısı, kararlı
bir kuyrukta ortalama uzunluk $L$, varış hızı $\lambda$ ve ortalama bekleme süresi $W$
arasında şunu söyler:

$$L = \lambda W$$

Bağıntı tersten okunduğunda asıl uyarıyı verir: $W = L / \lambda$. Kuyruk uzunluğu
sınırsızsa **bekleme süresi de sınırsızdır**. Bellek dolmadan çok önce, kuyruktaki iş
hâlâ işlense bile anlamını yitirmiş olur — dört saat geciken bir gecikme bildirimi,
gönderilmemiş bildirimden farklı değildir.

Bu yüzden kuyruk uzunluğu bir kaynak sorunu değil, bir **gecikme bütçesi** sorunudur.

## Sınırlı Kuyruk ve Üç Politika

Çözüm kuyruğu sınırlamaktır. Sınırlama tek başına bir soru doğurur: kuyruk doluyken gelen
iş ne olacak. Üç yanıt vardır ve üçü de bir şeyden vazgeçer.

**Engelleme**: üretici kuyrukta yer açılana kadar bekletilir. Hiçbir iş kaybolmaz, ama
yavaşlama üreticiye geçer — bu, dar anlamıyla **geri basınçtır** (backpressure).
**Yeniyi atma** (tail drop): kuyruk doluyken gelen iş reddedilir. **Eskiyi atma** (head
drop): kuyruğun başındaki en eski iş atılır, yeni iş sona eklenir.

Aşağıdaki benzetim dördünü de aynı yük altında koşturur: saniyede yüz iş üretiliyor,
altmış iş tüketiliyor, pencere on saniye, sınırlı kuyruğun kapasitesi yüz.

```js
// benzetim.mjs — uretim hizi tuketim hizini astiginda kuyrugun dort politikadaki davranisi
const PENCERE = 10_000;            // benzetim penceresi (ms)
const URETIM = 100;                // saniyede uretilen is
const TUKETIM = 60;                // saniyede tuketilen is
const KAPASITE = 100;              // sinirli kuyrugun kapasitesi

function kosum(politika) {
  const kuyruk = [];               // her oge: uretildigi an (ms)
  let uretilen = 0, teslim = 0, atilan = 0, bekleme = 0;
  let zirve = 0, enUzunBekleme = 0;
  let ub = 0, tb = 0;              // birikimler tam sayi: her ms'de hiz kadar artar

  for (let t = 1; t <= PENCERE; t++) {
    ub += URETIM;
    while (ub >= 1000) {
      ub -= 1000;
      uretilen++;
      if (politika === "sinirsiz" || kuyruk.length < KAPASITE) kuyruk.push(t);
      else if (politika === "yeniyi-at") atilan++;
      else if (politika === "eskiyi-at") { kuyruk.shift(); atilan++; kuyruk.push(t); }
      else { uretilen--; ub += 1000; bekleme++; break; }      // engelle: uretici bekler
    }
    tb += TUKETIM;
    while (tb >= 1000 && kuyruk.length) {
      tb -= 1000;
      enUzunBekleme = Math.max(enUzunBekleme, t - kuyruk.shift());
      teslim++;
    }
    zirve = Math.max(zirve, kuyruk.length);
  }
  return { politika, uretilen, teslim, atilan, bekleme, zirve,
           kalan: kuyruk.length, enUzunBekleme };
}

const s3 = (n) => String(n).padStart(6);
console.log("politika    uretilen teslim atilan  kalan  zirve  en-uzun-bekleme uretici-beklemesi");
for (const p of ["sinirsiz", "yeniyi-at", "eskiyi-at", "engelle"]) {
  const s = kosum(p);
  console.log(`${s.politika.padEnd(11)}${s3(s.uretilen)}${s3(s.teslim)}${s3(s.atilan)}` +
    `${s3(s.kalan)}${s3(s.zirve)}${String(s.enUzunBekleme).padStart(13)} ms` +
    `${String(s.bekleme).padStart(14)} ms`);
}
```

```
politika    uretilen teslim atilan  kalan  zirve  en-uzun-bekleme uretici-beklemesi
sinirsiz     1000   600     0   400   400         4000 ms             0 ms
yeniyi-at    1000   600   301    99   100         1664 ms             0 ms
eskiyi-at    1000   600   301    99   100          997 ms             0 ms
engelle       699   600     0    99   100         1666 ms          7490 ms
```

Benzetim gerçek zaman kullanmaz; sanal bir saati milisaniye milisaniye ilerletir ve
hızları tam sayı birikimleriyle uygular. Bu yüzden sayılar makineden bağımsız olarak
aynıdır.

## Sayıların Okunması

Dört satır dört ayrı ödünleşimi gösteriyor.

**Sınırsız** kuyrukta hiçbir iş kaybolmadı, ama kuyruk on saniyede dört yüze çıktı ve en
uzun bekleme dört saniyeye ulaştı. Önemli olan sayının kendisi değil yönü: pencere yirmi
saniye olsaydı kuyruk sekiz yüz, bekleme sekiz saniye olurdu. Bu politika, işi kaybetmeme
karşılığında **gecikmeyi sınırsız bırakır**.

**Yeniyi atma** ve **eskiyi atma** aynı sayıda işi teslim etti (600) ve aynı sayıda işi
attı (301). Aralarındaki tek fark bekleme süresinde: 1664 ms'ye karşı 997 ms. Fark
teslim edilen işlerin **yaşından** gelir. Yeniyi atarken kuyrukta hep en eski yüz iş
durur; eskiyi atarken kuyruk sürekli tazelenir ve tüketiciye daha genç işler ulaşır.
Kayıp oranı aynı olduğunda bu, eskiyi atmayı bildirim gibi tazeliği önemli işler için
üstün kılar; sıraya girmiş bir ödünç isteği gibi **sırası korunması gereken** işlerde ise
en eskiyi atmak kabul edilemez.

**Engelleme** hiçbir işi atmadı ama yalnız 699 iş üretebildi: üretici on saniyenin 7490
milisaniyesinde bekledi. Kaybolan iş yok, çünkü hiç üretilmedi. Geri basıncın tanımı
budur — darboğaz, sonucu kendisine gelen tarafa değil, kendisini besleyen tarafa yansıtır.

Dört satırın ortak dersi şudur: hız uyuşmazlığı yok edilemez, yalnız **nereye
yazılacağı** seçilebilir. Belleğe (sınırsız kuyruk), kayba (atma) ya da üreticinin hızına
(engelleme).

## Geri Basıncın Yayılması

Engelleme kulağa soyut gelir; oysa akış soyutlamasının içine yerleşmiş durumdadır.
`node:stream` üzerinde yazılabilir bir akışın `write` çağrısı bir mantıksal değer
döndürür: `false`, tamponun eşiği aştığını ve üretimin durdurulması gerektiğini bildirir.
Yer açıldığında akış `drain` olayını yayar.

Aşağıdaki ölçüm aynı altmış dört parçayı iki kez yazar. İlkinde dönüş değeri dinlenir,
ikincisinde yok sayılır.

```js
// akis.mjs — node:stream geri basinci: write() donusunu dinlemek ile yok saymak
import { Writable } from "node:stream";

const PARCA = Buffer.alloc(1024, 0x61);          // 1 KiB'lik is govdesi
const ADET = 64;

const yavasAlici = () => new Writable({
  highWaterMark: 16 * 1024,                      // tampon sinirimiz: 16 KiB
  write(_p, _k, bitti) { setTimeout(bitti, 5); },// her parcanin yazimi 5 ms surer
});

async function dinleyerek() {
  const alici = yavasAlici();
  let doluDonus = 0, drain = 0, zirve = 0;
  for (let i = 0; i < ADET; i++) {
    const yerVar = alici.write(PARCA);
    zirve = Math.max(zirve, alici.writableLength);
    if (!yerVar) {                               // tampon doldu: uretimi durdur
      doluDonus++;
      await new Promise((c) => alici.once("drain", () => { drain++; c(); }));
    }
  }
  await new Promise((c) => alici.end(c));
  return { doluDonus, drain, zirve };
}

async function yokSayarak() {
  const alici = yavasAlici();
  let doluDonus = 0, zirve = 0;
  for (let i = 0; i < ADET; i++) {
    if (!alici.write(PARCA)) doluDonus++;         // donus okunuyor ama uyulmuyor
    zirve = Math.max(zirve, alici.writableLength);
  }
  await new Promise((c) => alici.end(c));
  return { doluDonus, drain: 0, zirve };
}

for (const [ad, calis] of [["dinleyerek", dinleyerek], ["yok sayarak", yokSayarak]]) {
  const s = await calis();
  console.log(`${ad.padEnd(12)} dolu-donus=${String(s.doluDonus).padStart(2)}` +
    ` drain=${String(s.drain).padStart(2)} tampon-zirvesi=${s.zirve} B`);
}
```

```
dinleyerek   dolu-donus= 4 drain= 4 tampon-zirvesi=16384 B
yok sayarak  dolu-donus=49 drain= 0 tampon-zirvesi=65536 B
```

Dönüş değeri dinlendiğinde tampon zirvesi tam olarak eşiğin kendisidir: 16384 bayt. Yok
sayıldığında altmış dört parçanın tamamı tamponda birikir: 65536 bayt. Altmış dört
parçada oran dört kat; üretici sınırsız yazmaya devam ederse oran da sınırsızdır, çünkü
`false` dönüşünü yok saymak tamponu bir kuyruğa, üstelik **sınırsız** bir kuyruğa
çevirir.

Buradaki ders akışa özgü değildir. Kuyruğa iş yazan her katman aynı soruyla karşı
karşıyadır: yazma reddedildiğinde durur mu, yoksa arkasında kendi kuyruğunu mu biriktirir.
Durmayan her katman, önündeki sınırı işe yaramaz hale getirir.

## Geri Basınç Nereye Kadar Yayılır

Zincirin son halkası kullanıcıdır ve geri basınç oraya kadar taşınamaz. İstek işleyen bir
sunucu, arka plan kuyruğu dolduğu için HTTP isteğini süresiz bekletemez; bekletirse
bağlantıları tüketir ve sorun kuyruktan ağa taşınır.

Bu yüzden geri basınç sistemin **iç** halkalarında uygulanır: işçi ile veritabanı
arasında, kuyruk yazıcısı ile kuyruk arasında, akış üreticisi ile alıcısı arasında. Dış
sınırda ise başka bir mekanizma gerekir — gelen isteği bekletmek yerine **açıkça
reddetmek**.

## Özet

- Üretim hızı tüketim hızını aştığında kuyruk her saniye aradaki fark kadar uzar; büyüme kendiliğinden durmaz.
- $L = \lambda W$ bağıntısı gereği sınırsız kuyruk uzunluğu sınırsız bekleme süresi demektir; kuyruk sınırı bir bellek kararı değil gecikme bütçesi kararıdır.
- Sınırlı kuyrukta üç politika vardır: engelleme işi kaybetmez ama üreticiyi yavaşlatır, yeniyi atma ile eskiyi atma aynı kaybı üretir ama teslim edilen işlerin yaşı farklıdır.
- Geri basınç, darboğazın sonucunu kendisini besleyen tarafa yansıtmasıdır; `node:stream` bunu yazma dönüşü ve boşalma olayıyla uygular ve tampon zirvesini eşikte tutar.
- Yazma dönüşünü yok sayan katman, önündeki her sınırı geçersiz kılar; geri basınç zincirin tamamında uygulanmadıkça hiçbir yerinde uygulanmış sayılmaz.

## Sonraki Adım

Geri basınç iç halkalarda çalışır, ama zincirin dış ucunda duran istemci bekletilemez.
Kuyruk dolduğunda, işçiler yetişemediğinde ve gecikme bütçesi tükendiğinde sunucunun
elinde tek seçenek kalır: gelen işi kabul etmemek. Bunu rastgele yapmak sistemi
kararsızlaştırır; hangi isteğin reddedileceği, reddin istemciye nasıl bildirileceği ve
reddedilen ile kabul edilenin gecikme farkının ne olduğu ayrı kararlardır. Sonraki ders
aşırı yükte denetimli reddetmeyi kurar ve reddin gecikmeye etkisini ölçer.
