---
title: 'Yük Dengeleyici ve Ters Vekil'
source: 'https://academia.sh/tr/kurslar/trafik-katmani/yuk-dengeleyici-ve-ters-vekil'
course: 'Trafik Katmanı'
language: tr
updated: '2026-08-17T18:11:03+00:00'
license: 'CC BY-SA 4.0'
---

# Yük Dengeleyici ve Ters Vekil

İki bileşenin aynı programla anlatılması ve ayrımın nerede olduğu: tek bir aktarma programının kural tablosuyla iki rolü de üstlenmesi, rollerin ayrı süreçlere bölünmesiyle tek süreçte toplanmasının durak zinciri ve durdurma etkisi üzerinden ölçülmesi, ayrımın sorumluluk ve konum olarak yazılması ve durak eklemenin giriş kursundaki bileşik erişilebilirlik hesabına faturasının çıkarılması.

Önceki üç ders dengeleyiciyi bir yönlendirme aygıtı olarak kurdu: isteği alır, bir kural
uygular, bir sürece iletir, yanıtı geri yazar. Aynı tanım Sunucu Tarafı Temelleri kursunda başka
bir bileşen için de verilmişti. **Ters vekil** (reverse proxy) de isteği alır, bir kurala göre
arka sunuculardan birine iletir ve yanıtı geri yazar. İki tanım birbirinden ayrılmıyor.

Bu ders örtüşmeyi kabul ederek başlar ve ayrımı başka bir yerde arar. İkisi de yeniden
tanımlanmaz; ölçülen şey, iki rolün aynı süreçte toplanmasıyla ayrı süreçlere bölünmesinin ne
değiştirdiğidir.

## Aynı Program, İki Kural Tablosu

Örtüşmenin en kısa kanıtı tek bir programdır. Aşağıdaki aktarıcı bir kural tablosu alır: yol
öneki, hedef listesi. Liste tek elemanlıysa yapılan iş **yönlendirmedir** — hangi bileşene.
Listede aynı bileşenin birden çok kopyası varsa yapılan iş **dağıtımdır** — hangi kopyaya. İkisi
aynı tabloda yan yana durabilir.

```js
// vekil/aktarici.mjs — tek bir aktarma programi. Kural tablosu iki rolu de anlatir:
//   "/varlik=8891;*=8850"            -> yola gore ayri bilesenlere yonlendirme (ters vekil)
//   "*=8892,8893,8894"               -> ayni bilesenin kopyalari arasinda dagitim (yuk dengeleyici)
//   "/varlik=8891;*=8892,8893,8894"  -> ikisi birden (birlesik surec)
// Kullanim: node vekil/aktarici.mjs <nokta> <ad> <kural>
import { createServer, request } from "node:http";

const [nokta, ad, kuralMetni] = [Number(process.argv[2]), process.argv[3], process.argv[4] ?? ""];
const KURAL = kuralMetni.split(";").filter(Boolean)
  .map((p) => { const [onek, liste] = p.split("="); return { onek, hedef: liste.split(",").map(Number), sira: 0 }; });

if (Number.isInteger(nokta) === false || KURAL.length === 0) {
  console.log("kullanim: node vekil/aktarici.mjs <nokta> <ad> <onek=hedef[,hedef];...>");
} else createServer((istekDisi, yanitDisi) => {
  yanitDisi.sendDate = false;
  const yol = new URL(istekDisi.url, "http://yerel").pathname;
  const k = KURAL.find((r) => r.onek !== "*" && yol.startsWith(r.onek)) ?? KURAL.find((r) => r.onek === "*");
  if (k === undefined) { yanitDisi.writeHead(404).end("kural yok"); return; }
  const hedef = k.hedef[k.sira++ % k.hedef.length];
  const onceki = istekDisi.headers["x-durak"];
  const istekIc = request({ port: hedef, path: istekDisi.url, method: istekDisi.method,
    headers: { ...istekDisi.headers, "x-durak": onceki === undefined ? ad : `${onceki} > ${ad}` } },
  (yanitIc) => { yanitDisi.writeHead(yanitIc.statusCode, yanitIc.headers); yanitIc.pipe(yanitDisi); });
  istekIc.on("error", () => yanitDisi.writeHead(502, { "x-durak": `${ad} > ulasilamadi` }).end("yok"));
  istekDisi.pipe(istekIc);
}).listen(nokta, "127.0.0.1");
```

Zincirin sonundaki süreçler yalnız adlarını bildirir; `x-durak` başlığı istek boyunca birikerek
isteğin dokunduğu durakları taşır.

```js
// vekil/uc.mjs — zincirin sonundaki surec: adini x-durak basligina ekler
import { createServer } from "node:http";

const [port, ad] = [Number(process.argv[2]), process.argv[3]];

if (Number.isInteger(port) === false) console.log("kullanim: node vekil/uc.mjs <nokta> <ad>");
else createServer((istek, yanit) => {
  yanit.sendDate = false;
  const onceki = istek.headers["x-durak"];
  yanit.writeHead(200, { "content-type": "application/json",
    "x-durak": onceki === undefined ? ad : `${onceki} > ${ad}` });
  yanit.end(JSON.stringify({ durum: "aktarma merkezinde", bolge: "35" }));
}).listen(port, "127.0.0.1");
```

```js
// vekil/istemci.mjs — iki yolu da dener, dokunulan durak zincirini ve yanitlanan istegi yazar
import { request } from "node:http";

const [nokta, etiket] = [Number(process.argv[2]), process.argv[3] ?? "-"];
const YOL = ["/varlik/stil.css", "/takip"];
const ADET = 6;

function bir(yol) {
  return new Promise((coz) => {
    const r = request({ port: nokta, path: yol }, (y) => {
      y.resume();
      y.on("end", () => coz({ kod: y.statusCode, durak: y.headers["x-durak"] ?? "-" }));
    });
    r.on("error", () => coz({ kod: 0, durak: "baglanti yok" }));
    r.end();
  });
}

if (Number.isInteger(nokta) === false) console.log("kullanim: node vekil/istemci.mjs <nokta> <etiket>");
else for (const yol of YOL) {
  const zincir = new Map();
  let yanitlanan = 0;
  for (let i = 0; i < ADET; i += 1) {
    const s = await bir(yol);
    if (s.kod === 200) yanitlanan += 1;
    zincir.set(s.durak, (zincir.get(s.durak) ?? 0) + 1);
  }
  const d = [...zincir].sort().map(([a, n]) => `${a} (${n})`).join("  |  ");
  console.log(`${etiket.padEnd(22)} ${yol.padEnd(17)} ${String(yanitlanan)}/${ADET}  ${d}`);
}
```

Düzenek aynı işi iki yerleşimle koşar. **Ayrı** yerleşimde iki aktarıcı süreci vardır: `tv`
içerik yolu ile uygulama yolunu ayırır, `yd` kopyalar arasında dağıtır. **Birleşik** yerleşimde
tek bir `tvyd` süreci ikisini de yapar. Her yerleşimde kopya listesini tutan süreç durdurulur ve
hangi yolun ayakta kaldığı sayılır.

```bash
# olc.sh — ayni is iki yerlesimle: iki ayri aktarici sureci, sonra tek birlesik surec.
# Ikinci asamada kopya listesini tutan surec durduruluyor ve hangi yolun ayakta kaldigi sayiliyor.
node vekil/uc.mjs 8891 statik & S=$!
node vekil/uc.mjs 8892 k1 & K1=$!
node vekil/uc.mjs 8893 k2 & K2=$!
node vekil/uc.mjs 8894 k3 & K3=$!

node vekil/aktarici.mjs 8860 tv "/varlik=8891;*=8850" & TV=$!
node vekil/aktarici.mjs 8850 yd "*=8892,8893,8894" & YD=$!
sleep 1
node vekil/istemci.mjs 8860 "ayri: tv + yd"
kill $YD; sleep 0.5
node vekil/istemci.mjs 8860 "ayri: yd durduruldu"
kill $TV; sleep 0.3

node vekil/aktarici.mjs 8861 tvyd "/varlik=8891;*=8892,8893,8894" & B=$!
sleep 1
node vekil/istemci.mjs 8861 "birlesik: tvyd"
kill $B; sleep 0.5
node vekil/istemci.mjs 8861 "birlesik: durduruldu"

kill $S $K1 $K2 $K3
```

```
ayri: tv + yd          /varlik/stil.css  6/6  tv > statik (6)
ayri: tv + yd          /takip            6/6  tv > yd > k1 (2)  |  tv > yd > k2 (2)  |  tv > yd > k3 (2)
ayri: yd durduruldu    /varlik/stil.css  6/6  tv > statik (6)
ayri: yd durduruldu    /takip            0/6  tv > ulasilamadi (6)
birlesik: tvyd         /varlik/stil.css  6/6  tvyd > statik (6)
birlesik: tvyd         /takip            6/6  tvyd > k1 (2)  |  tvyd > k2 (2)  |  tvyd > k3 (2)
birlesik: durduruldu   /varlik/stil.css  0/6  baglanti yok (6)
birlesik: durduruldu   /takip            0/6  baglanti yok (6)
```

## İki Sayı, İki Yön

Bu sayılar **ölçüm** sınıfındadır ve belirlenimlidir. İki yerleşim iki ayrı sütunda ters
sıralanıyor.

**Durak sayısı.** Ayrı yerleşimde takip isteği üç durağa dokunuyor: `tv > yd > k1`. Birleşik
yerleşimde iki durağa: `tvyd > k1`. İçerik yolu ikisinde de iki duraktır. Her durak bir ağ
atlaması, bir ayrıştırma ve bir yeniden yazma demektir; ayrı yerleşim aynı isteği bir kez fazla
elden geçiriyor.

**Yalıtım.** Kopya listesini tutan süreç durdurulduğunda ayrı yerleşimde içerik yolu 6/6
yanıtlanmaya devam ediyor, yalnız takip yolu 0/6'ya düşüyor — ve düşüş bile `tv` üzerinden bir 502
olarak dönüyor, yani istemci bir yanıt alıyor. Birleşik yerleşimde ikisi de 0/6 ve istemci hiçbir
yanıt alamıyor, çünkü bağlanacağı bir bağlantı noktası kalmıyor. Kopya listesinin değişmesi bir
yapılandırma değişikliğidir ve sık olur; birleşik süreçte o değişiklik içerik yolunu da
durdurur.

İki sayı aynı kararın iki yüzüdür: **bölmek bir durak ekler, birleştirmek bir arıza yüzeyi
ekler.**

## Ayrım Nerede

Aynı program iki rolü de üstlenebildiğine göre ayrım programda değildir. İki yerdedir.

**Sorumluluk.** Ters vekil "hangi bileşen" sorusunu yanıtlar: `/varlik` ile başlayan yol içerik
sürecine, geri kalanı uygulamaya. Kural tablosundaki önekler farklı işler yapan bileşenlere
işaret eder ve hedef listeleri tek elemanlıdır. Yük dengeleyici "hangi kopya" sorusunu yanıtlar:
hedef listesi aynı işi yapan süreçlerden oluşur ve içlerinden hangisinin seçildiği isteğin
sonucunu değiştirmez. İlk soruda yanlış seçim **yanlış davranıştır**, ikincisinde yalnız farklı
bir kopyadır.

**Konum.** Ters vekil uygulama sınırında durur: sistemin dış yüzünü tek bir yol uzayı olarak
gösterir ve arkasındaki bileşen bölünmesini gizler. Yük dengeleyici kopya sınırında durur: bir
bileşenin kaç kopyayla çalıştığını gizler. İki gizleme farklı ölçeklerde işler ve bu yüzden ikisi
zincirde farklı yerlerde durabilir — ölçümdeki `tv > yd` sırası bunun ifadesidir, tersi
anlamsızdır.

Bir sürecin ikisini birden üstlenmesi bu ayrımı ortadan kaldırmaz, yalnız aynı yapılandırma
dosyasına yazar. Ayrımı görünür tutan şey kural tablosunun biçimidir: hangi satırın öneki bir
bileşen ayrımı, hangisinin hedef listesi bir kopya kümesidir.

## Hesaba Geri Dönüş

Bölmenin faturası durak sayısında görünüyordu; o sayının hizmet erişilebilirliğindeki karşılığı
K01'de kurulmuştu. Erişilebilirliğin Sayısal İfadesi dersi takip yolunu dört bileşenli seri bir
zincir olarak almış, bileşen başına yüzde 99,9 ile bileşik erişilebilirliği yüzde 99,6006 ve
aylık kesintiyi 172,5 dakika bulmuştu. Aktarıcı süreçler o zincire eklenen yeni bileşenlerdir.

```js
// vekil/zincir.mjs — durak eklemenin K01 bilesik erisilebilirlik hesabindaki karsiligi
const AY = 30 * 24 * 60;           // dakika
const TABAN = 4;                   // K01 Erisilebilirligin Sayisal Ifadesi: dort bilesenli takip yolu
const BILESEN = 0.999;             // K01 varsayim: bilesen basina hizmet erisilebilirligi

const seri = (a, n) => a ** n;
const kopyali = (a, k) => 1 - (1 - a) ** k;
const dakika = (a) => (1 - a) * AY;

console.log("yerlesim              durak  zincir bileseni  bilesik erisilebilirlik  aylik kesinti  tabana gore");
const taban = seri(BILESEN, TABAN);
for (const [ad, durak, kopya] of [
  ["durak yok (K01)", 0, 1], ["birlesik surec", 1, 1], ["ayri iki surec", 2, 1],
  ["ayri, her biri 2 kopya", 2, 2], ["birlesik, 2 kopya", 1, 2]]) {
  const a = taban * seri(kopyali(BILESEN, kopya), durak);
  console.log(`${ad.padEnd(22)}${String(durak).padStart(6)}${String(TABAN + durak).padStart(17)}  ` +
    `${(a * 100).toFixed(4).padStart(22)}%  ${dakika(a).toFixed(1).padStart(11)} dk  ` +
    `${(dakika(a) - dakika(taban)).toFixed(1).padStart(9)} dk`);
}

const birlesik = taban * seri(BILESEN, 1), ayri = taban * seri(BILESEN, 2);
console.log(`\nrolleri iki surece bolmenin faturasi = ${(dakika(ayri) - dakika(birlesik)).toFixed(1)} dk/ay`);
console.log(`ayni fatura duraklar ikiser kopyali oldugunda = ` +
  `${(dakika(taban * seri(kopyali(BILESEN, 2), 2)) - dakika(taban * seri(kopyali(BILESEN, 2), 1))).toFixed(2)} dk/ay`);
console.log(`K01 aylik kesinti butcesi (%99.9) = ${((1 - 0.999) * AY).toFixed(1)} dk; ` +
  `ayri yerlesimin kesintisi butcenin ${(dakika(ayri) / ((1 - 0.999) * AY)).toFixed(2)} kati`);
```

```
yerlesim              durak  zincir bileseni  bilesik erisilebilirlik  aylik kesinti  tabana gore
durak yok (K01)            0                4                 99.6006%        172.5 dk        0.0 dk
birlesik surec             1                5                 99.5010%        215.6 dk       43.0 dk
ayri iki surec             2                6                 99.4015%        258.6 dk       86.0 dk
ayri, her biri 2 kopya     2                6                 99.6004%        172.6 dk        0.1 dk
birlesik, 2 kopya          1                5                 99.6005%        172.6 dk        0.0 dk

rolleri iki surece bolmenin faturasi = 43.0 dk/ay
ayni fatura duraklar ikiser kopyali oldugunda = 0.04 dk/ay
K01 aylik kesinti butcesi (%99.9) = 43.2 dk; ayri yerlesimin kesintisi butcenin 5.99 kati
```

Bu sayılar **hesap** sınıfındadır. İlk üç satır bölmenin faturasını veriyor: tek kopyalı
duraklarla, rolleri iki sürece ayırmak aylık kesintiyi 215,6 dakikadan 258,6 dakikaya çıkarıyor —
ayda 43,0 dakika. Sayı K01'in yüzde 99,9 hedefi için ayırdığı **bütün aylık bütçeye** (43,2
dakika) neredeyse eşittir. Yani rolleri ayırma kararı, tek başına, bir aylık kesinti bütçesi
kadar tutuyor.

Dördüncü ve beşinci satır faturanın nereden geldiğini gösteriyor. Duraklar ikişer kopyalı
olduğunda aynı bölme 0,04 dakikaya iniyor ve iki yerleşim ayırt edilemez hâle geliyor. K01'in
kopya tablosundaki kural burada da geçerli: koşut kopyalarda kesinti payı üs alır. **Durak
eklemenin faturası durak eklemekten değil, durağı tek kopyalı bırakmaktan geliyor.**

Son satır tabloyu bir ölçütle bitiriyor. Ayrı yerleşimin aylık kesintisi 258,6 dakikadır ve yüzde
99,9 bütçesinin 5,99 katıdır. Bu, yerleşimin kötü olduğunu değil, **yüzde 99,9 hedefinin bileşen
başına yüzde 99,9 ile karşılanamayacağını** söyler; K01 aynı sonucu dört bileşenle bulmuştu, iki
durak eklemek onu keskinleştiriyor. Bir kenar katmanı tasarlanırken durak sayısı bir mimari
tercih değil, doğrudan bir erişilebilirlik kalemidir.

## Özet

- Yük dengeleyici ile ters vekil aynı programla yazılabilir: kural tablosunda hedef listesi tek
  elemanlıysa yapılan iş yönlendirme, aynı bileşenin kopyalarından oluşuyorsa dağıtımdır.
- Ayrı yerleşimde takip isteği üç durağa dokundu (`tv > yd > k1`), birleşik yerleşimde ikiye
  (`tvyd > k1`); bölmek isteği bir kez fazla elden geçiriyor.
- Kopya listesini tutan süreç durdurulduğunda ayrı yerleşimde içerik yolu 6/6 yanıtlanmaya devam
  etti, birleşik yerleşimde iki yol da 0/6 oldu ve istemci hiç yanıt alamadı.
- Ayrım sorumluluktadır ve konumdadır: ters vekil "hangi bileşen" sorusunu uygulama sınırında,
  yük dengeleyici "hangi kopya" sorusunu kopya sınırında yanıtlar; ilkinde yanlış seçim yanlış
  davranış, ikincisinde yalnız farklı bir kopyadır.
- Tek kopyalı duraklarla rolleri ayırmak aylık kesintiyi 215,6'dan 258,6 dakikaya çıkarıyor: ayda
  43,0 dakika, yüzde 99,9 hedefinin bütün aylık bütçesi kadar.
- Duraklar ikişer kopyalı olduğunda aynı fatura 0,04 dakikaya iniyor; durak eklemenin bedeli
  durağı tek kopyalı bırakmaktan gelir.

## Sonraki Adım

Buraya kadarki beş ders bir şeyi hiç sorgulamadı: dengeleyicinin seçimi **serbesttir**. Sıralı
kural, en az bağlantı kuralı ve iki yerleşimin hepsi, bir isteğin herhangi bir kopyaya
gönderilebileceğini varsaydı; tutarlı karma bile seçimi kararlı tutmayı isterken zorunlu
kılmıyordu. Kopyaların birbirinin eşi olmaktan çıktığı bir durum vardır: bir istemcinin önceki
isteğinden kalan bir durum belirli bir kopyanın belleğinde durursa, o istemcinin sonraki isteği
artık herhangi bir kopyaya gidemez. Seçim bir tercih olmaktan çıkıp bir kısıt hâline gelir.
Sonraki ders bu kısıtı adlandırır ve ölçer: dağılımın ne kadar bozulduğunu, bir kopya düştüğünde
ne kadar durumun kaybolduğunu ve kopya eklemenin tepe yükü neden düşürmediğini sayar.
