---
title: 'API Ağ Geçidi'
source: 'https://academia.sh/tr/kurslar/servis-mimarileri/api-ag-gecidi'
course: 'Servis Mimarileri'
language: tr
updated: '2026-08-17T18:06:53+00:00'
license: 'CC BY-SA 4.0'
---

# API Ağ Geçidi

Kenar sorumluluklarının uygulama tarafında toplanmasının ölçülmesi: kimlik ve hız sınırı kodunun kaç serviste kaç satır olarak yinelendiği, sorumluluk ağ geçidine taşındığında değişen dosya, dışarıya açık uç ve istemci çağrısı sayısı, birleştirmenin turlara etkisi ve istek başına eklenen atlama.

Önceki iki ders sınırın iki yanını çalıştı: sınırın nereden geçeceği, karşıya nasıl çağrı
yapılacağı, hangi çağrının hiç yapılmayıp olaya dönüşeceği. Bir taraf hiç ele alınmadı — dışarısı.
İstemci servislerin adreslerini tek tek biliyor, her servis kendi kimlik denetimini kendi kodunda
taşıyor ve aynı hız sınırı kuralı birden çok yerde yazılı duruyor.

API ağ geçidi, ön yüz için backend ve kapı bekçisi kalıpları Trafik Katmanı kursunda kuruldu ve
trafik tarafında ölçüldü; o ölçüm burada tekrarlanmaz. Buradaki soru uygulama tarafındadır: aynı
kenar sorumluluğu kaç serviste kaç satır olarak duruyor, tek yere taşındığında kaç dosya ve kaç uç
değişiyor, istek başına kaç atlama ekleniyor.

Through-line ödünç sayfasıdır: bir sayfanın çizilmesi için katalog, üyelik ve ödünç servislerinin
üçünden de veri gerekir.

## Aynı Sorumluluk, İki Yerleşim

Aşağıdaki blok aynı üç servisi iki biçimde yazar. Kenar sorumluluğunu taşıyan satırlar kaynakta
işaretlidir; yalın biçim aynı dosyalardan o satırların çıkarılmasıyla üretilir ve işaretli satırlar
tek bir ağ geçidi sürecinde bir kez yazılır. İki biçim de gerçekten koşan kaynaktır.

```js
// kur.mjs — ayni uc servisi iki bicimde yazar: kenar sorumlulugu serviste ve gecitte
import { mkdirSync, writeFileSync } from "node:fs";
const SERVIS = { katalog: 8961, uyelik: 8962, odunc: 8963 }, GECIT = 8960;

const servis = (ad, port) => [
  `// servis-${ad}.mjs — odunc sayfasinin bir parcasini ureten servis`,
  'import { createServer } from "node:http";',
  `const PORT = ${port}, IS = 25;`,
  "let islenen = 0, sifirla = () => {};",
  "const SAYAC = new Map(), SINIR = 3; sifirla = () => SAYAC.clear();          // kenar: hiz siniri",
  "createServer(async (istek, yanit) => {",
  '  if (istek.url === "/sayac") { yanit.end(String(islenen)); return; }',
  '  if (istek.url === "/sifirla") { islenen = 0; sifirla(); yanit.end("s"); return; }',
  '  const uye = istek.headers["x-uye"];                                       // kenar: kimlik',
  '  if (!uye) { yanit.statusCode = 401; yanit.end("kimlik yok"); return; }    // kenar: kimlik',
  "  const n = (SAYAC.get(uye) ?? 0) + 1; SAYAC.set(uye, n);                   // kenar: hiz siniri",
  '  if (n > SINIR) { yanit.statusCode = 429; yanit.end("hiz siniri"); return; } // kenar: hiz siniri',
  "  islenen += 1;",
  "  await new Promise((c) => setTimeout(c, IS));",
  `  yanit.end(JSON.stringify({ ad: "${ad}" }));`,
  "}).listen(PORT);",
];
const gecit = [
  "// gecit.mjs — kenar sorumluluklarini toplayan ve yanitlari birlestiren surec",
  'import { createServer } from "node:http";',
  `const PORT = ${GECIT}, ARDIL = [${Object.values(SERVIS).join(", ")}];`,
  "let sifirla = () => {};",
  "const SAYAC = new Map(), SINIR = 3; sifirla = () => SAYAC.clear();          // kenar: hiz siniri",
  "createServer(async (istek, yanit) => {",
  '  if (istek.url === "/sifirla") { sifirla(); yanit.end("s"); return; }',
  '  const uye = istek.headers["x-uye"];                                       // kenar: kimlik',
  '  if (!uye) { yanit.statusCode = 401; yanit.end("kimlik yok"); return; }    // kenar: kimlik',
  "  const n = (SAYAC.get(uye) ?? 0) + 1; SAYAC.set(uye, n);                   // kenar: hiz siniri",
  '  if (n > SINIR) { yanit.statusCode = 429; yanit.end("hiz siniri"); return; } // kenar: hiz siniri',
  "  const parca = await Promise.all(ARDIL.map((p) =>",
  '    fetch(`http://127.0.0.1:${p}/veri`).then((y) => y.json())));            // kenar: birlestirme',
  "  yanit.end(JSON.stringify({ birlesik: parca }));",
  "}).listen(PORT);",
];
const kenar = (satirlar) => satirlar.filter((s) => s.includes("// kenar:")).length;
const yaz = (dizin, dosya, satirlar) => {
  mkdirSync(dizin, { recursive: true });
  writeFileSync(`${dizin}/${dosya}`, `${satirlar.join("\n")}\n`);
  return satirlar.length;
};

let kenarliSatir = 0, kenarliIsaret = 0, yalinSatir = 0, yalinIsaret = 0;
for (const [ad, port] of Object.entries(SERVIS)) {
  const tam = servis(ad, port), sade = tam.filter((s) => !s.includes("// kenar:"));
  kenarliSatir += yaz("kenarli", `servis-${ad}.mjs`, tam);
  kenarliIsaret += kenar(tam);
  yalinSatir += yaz("yalin", `servis-${ad}.mjs`, sade);
  yalinIsaret += kenar(sade);
}
const gecitSatir = yaz("yalin", "gecit.mjs", gecit);
const n = Object.keys(SERVIS).length;
console.log(`${"bicim".padEnd(22)}${"dosya".padStart(7)}${"satir".padStart(7)}` +
  `${"kenar satiri".padStart(14)}${"kural degisince dokunulan".padStart(27)}${"disariya acik uc".padStart(18)}`);
console.log(`${"kenar servislerde".padEnd(22)}${String(n).padStart(7)}${String(kenarliSatir).padStart(7)}` +
  `${String(kenarliIsaret).padStart(14)}${String(n).padStart(27)}${String(n).padStart(18)}`);
console.log(`${"kenar gecitte".padEnd(22)}${String(n + 1).padStart(7)}` +
  `${String(yalinSatir + gecitSatir).padStart(7)}${String(yalinIsaret + kenar(gecit)).padStart(14)}` +
  `${"1".padStart(27)}${"1".padStart(18)}`);
console.log(`kenar sorumlulugu ${n} serviste ${kenarliIsaret / n} satir olarak yinelenmisti; ` +
  `gecitte ${kenar(gecit)} satirda tek kopya`);
```

```
bicim                   dosya  satir  kenar satiri  kural degisince dokunulan  disariya acik uc
kenar servislerde           3     48            15                          3                 3
kenar gecitte               4     48             6                          1                 1
kenar sorumlulugu 3 serviste 5 satir olarak yinelenmisti; gecitte 6 satirda tek kopya
```

Toplam satır sayısı iki biçimde de aynıdır; taşınan kod yok olmadı, yer değiştirdi. Değişen üç
sayı var: yinelenen kenar satırı 15'ten 6'ya indi, kimlik ya da hız sınırı kuralı değiştiğinde
dokunulacak dosya sayısı 3'ten 1'e düştü, dışarıya açık uç sayısı 3'ten 1'e indi. Ağ geçidinin
altıncı işaretli satırı servislerde hiç bulunmayan bir sorumluluktur: birleştirme.

## Koşumdaki Fark

**SS4 — hız sınırı üye başına üç istektir.** Gerekçe: değer gerçek bir eşik değil, sınırın on iki
istekte görünür olmasını sağlayan bir ölçü büyüklüğüdür. Ölçülen nicelik sınırın değeri değil,
sınırın kaç yerde uygulandığı ve aynı kuralın dışarıya kaç istek hakkı tanıdığıdır.

```js
// olc.mjs — <olcum: tur|sinir> <kip: dogrudan|gecit>; surecler ayaktayken kosar
const IS = 25, S = [8961, 8962, 8963], GECIT = 8960;
const BASLIK = { headers: { "x-uye": "7" } };
let cagri = 0, servisCagrisi = 0;
const uc = new Set();
const al = async (p, yol) => {
  cagri += 1; uc.add(p);
  if (S.includes(p)) servisCagrisi += 1;
  const y = await fetch(`http://127.0.0.1:${p}${yol}`, BASLIK);
  await y.text();
  return y.status;
};
const kimliksiz = async (p, yol) => {         // x-uye basligi olmadan istek
  const y = await fetch(`http://127.0.0.1:${p}${yol}`);
  await y.text();
  return y.status;
};
const sifirla = async () => {
  for (const p of [...S, GECIT]) await fetch(`http://127.0.0.1:${p}/sifirla`).catch(() => {});
};
const ulasan = async () => {
  let t = 0;
  for (const p of S) t += Number(await (await fetch(`http://127.0.0.1:${p}/sayac`)).text());
  return t;
};
const [olcum, kip] = process.argv.slice(2);
const YOL = {
  "dogrudan-sirali": async () => { for (const p of S) await al(p, "/veri"); },
  "dogrudan-paralel": () => Promise.all(S.map((p) => al(p, "/veri"))),
  gecit: () => al(GECIT, "/sayfa"),
};

if (olcum === "tur") {
  console.log(`${"istemci yolu".padEnd(18)}${"istemci cagrisi".padStart(16)}${"ag atlamasi".padStart(13)}` +
    `${"dokunulan uc".padStart(14)}${"servise ulasan".padStart(16)}${"olculen tur".padStart(13)}`);
  for (const ad of Object.keys(YOL).filter((a) => a.startsWith(kip))) {
    const sure = [];
    for (let i = 0; i < 3; i += 1) {
      await sifirla();
      const t = performance.now();
      await YOL[ad]();
      sure.push(performance.now() - t);
    }
    await sifirla();
    cagri = 0; servisCagrisi = 0; uc.clear();
    await YOL[ad]();
    const u = await ulasan();
    console.log(`${ad.padEnd(18)}${String(cagri).padStart(16)}` +
      `${String(cagri + u - servisCagrisi).padStart(13)}${String(uc.size).padStart(14)}` +
      `${String(u).padStart(16)}${String(Math.floor(sure.sort((a, b) => a - b)[1] / IS)).padStart(13)}`);
  }
} else if (olcum === "sinir") {
  await sifirla();
  let kabul = 0, red = 0;
  for (let i = 0; i < 12; i += 1) {
    const durum = kip === "gecit" ? await al(GECIT, "/sayfa") : await al(S[i % S.length], "/veri");
    if (durum === 200) kabul += 1; else red += 1;
  }
  console.log(`hiz siniri (uye basina 3): 12 dis istek -> ${kabul} kabul, ${red} red, ` +
    `servise ulasan ${await ulasan()}`);
  await sifirla();
  const durum = kip === "gecit" ? [await kimliksiz(GECIT, "/sayfa")]
    : await Promise.all(S.map((p) => kimliksiz(p, "/veri")));
  console.log(`kimliksiz istek: ${durum.length} uc denetledi -> ` +
    `${durum.filter((d) => d === 401).length} kez 401, servise ulasan ${await ulasan()}`);
}
```

```bash
echo "-- kenar sorumlulugu her serviste --"
for a in katalog uyelik odunc; do node kenarli/servis-$a.mjs & done
sleep 1
node olc.mjs tur dogrudan
node olc.mjs sinir dogrudan
pkill -f "kenarli/servis" ; sleep 0.3

echo
echo "-- kenar sorumlulugu gecitte --"
for a in katalog uyelik odunc; do node yalin/servis-$a.mjs & done
node yalin/gecit.mjs &
sleep 1
node olc.mjs tur gecit
node olc.mjs sinir gecit
pkill -f "yalin/servis" ; pkill -f "yalin/gecit"
```

```
-- kenar sorumlulugu her serviste --
istemci yolu       istemci cagrisi  ag atlamasi  dokunulan uc  servise ulasan  olculen tur
dogrudan-sirali                  3            3             3               3            3
dogrudan-paralel                 3            3             3               3            1
hiz siniri (uye basina 3): 12 dis istek -> 9 kabul, 3 red, servise ulasan 9
kimliksiz istek: 3 uc denetledi -> 3 kez 401, servise ulasan 0

-- kenar sorumlulugu gecitte --
istemci yolu       istemci cagrisi  ag atlamasi  dokunulan uc  servise ulasan  olculen tur
gecit                            1            4             1               3            1
hiz siniri (uye basina 3): 12 dis istek -> 3 kabul, 9 red, servise ulasan 9
kimliksiz istek: 1 uc denetledi -> 1 kez 401, servise ulasan 0
```

## Birleştirme ve Turlar

İlk iki satır istemcinin ödünç sayfasını kendisi topladığı durumdur. İstemci üç çağrı yapıyor, üç
ayrı ucu tanıyor ve üç servise ulaşıyor. Çağrıları sırayla yaparsa sayfa üç turda, paralel yaparsa
bir turda çiziliyor. Aradaki fark istemcinin elindedir ve sunucu tarafından denetlenemez: aynı
sayfanın gecikmesi istemcinin nasıl yazıldığına bağlıdır.

Üçüncü satır aynı sayfayı ağ geçidi üzerinden çiziyor. İstemci bir çağrı yapıyor, tek uç tanıyor,
servislere yine üç istek ulaşıyor ve sayfa bir turda dönüyor. Birleştirme sunucu tarafına
geçtiğinde en kötü durum en iyi duruma eşitlenir: paralel çağrıyı yapmayı istemcinin bilmesi
gerekmez, ağ geçidi zaten yapar. **Kazanılan şey ortalama gecikme değil, gecikmenin
denetlenebilirliğidir.**

Dördüncü kolon bedeli veriyor: istek başına ağ atlaması üçten dörde çıkıyor. Doğrudan yerleşimde
istemcinin üç çağrısı doğrudan servislere gidiyordu; geçitli yerleşimde bir dış atlama ve üç iç
atlama var. Ağ geçidi kendi işini yapmadığı için bu atlama bir tur eklemedi, ama gecikme
bütçesinden pay aldı.

## Aynı Kural, İki Farklı Hak

Hız sınırı satırları dersin en keskin sayısını üretiyor. Kural iki yerleşimde birebir aynıdır:
üye başına üç istek. On iki istek gönderildiğinde doğrudan yerleşim dokuzunu kabul ediyor, geçitli
yerleşim üçünü.

Nedeni sınırın **birimidir**. Servis başına sayan bir sınır, üç servisli bir sistemde üyeye üç
değil dokuz istek hakkı tanır; üye isteklerini servislere dağıttığı sürece hiçbir sınıra
çarpmaz. Ağ geçidinde sayan sınır, sayfa isteğine göre sayar. Son kolon iki yerleşimin servis
yükünü eşitliyor: her iki durumda da servislere dokuz istek ulaşıyor. Yani aynı yazılı kural, aynı
servis yükü altında dışarıya üç kat farklı hak tanıyor. **Bir kenar kuralı, uygulandığı yer
değişmeden okunamaz.**

Kimlik satırı aynı şeyi denetim tarafında gösteriyor. Kimliksiz istek doğrudan yerleşimde üç ayrı
uçta üç kez reddediliyor, geçitli yerleşimde bir kez. Üç ret aynı kuralın üç ayrı kopyasıdır ve
kopyaların birbirinden ayrılması yalnız zaman meselesidir.

## Üçlü

**Neyi ucuzlattı.** Yinelenen kenar satırı 15'ten 6'ya, kural değiştiğinde dokunulan dosya 3'ten
1'e, dışarıya açık uç 3'ten 1'e, istemci çağrısı 3'ten 1'e indi; sıralı çalışan bir istemcide
sayfa 3 turdan 1 tura düştü.

**Neyi pahalılaştırdı.** İstek başına atlama 3'ten 4'e çıktı, sisteme yeni bir dağıtım birimi ve
yeni bir süreç eklendi. Ağ geçidi üç servisin uçlarını kendi kaynağında taşır: bir servisin uç
yolu ya da yanıt biçimi değiştiğinde dokunulan dosya sayısı yeniden ikiye çıkar. Kenar
sorumluluğunda kazanılan tek dosya, sözleşme tarafında geri verilmiştir.

**Hangi yeni arıza kipi doğdu.** Dış trafiğin tamamı tek süreçten geçiyor. Önceki dersin ölçüsüyle
söylenirse, ağ geçidinin bağımlılık kapanışı bütün giriş uçlarıdır: kapandığında etkilenen istek
payı birdir. Doğrudan yerleşimde katalog kapandığında sayfa eksik çiziliyordu; geçitli yerleşimde
geçit kapandığında sayfa hiç çizilmiyor. İkinci arıza kipi daha sessizdir: hız sınırı ve kimlik
artık servislerde durmadığı için, geçidi atlayan bir çağrı hiçbir denetimden geçmez. Yalın
servisler kendilerini savunmaz; savunma tek bir yerin doğru yapılandırılmasına bağlıdır.

## Özet

- Kenar sorumluluğu üç serviste 5'er satır olarak yinelenmişti (toplam 15); ağ geçidinde 6 satırda
  tek kopya oldu ve toplam satır sayısı değişmedi.
- Kimlik ya da hız sınırı kuralı değiştiğinde dokunulan dosya 3'ten 1'e, dışarıya açık uç 3'ten
  1'e, istemci çağrısı 3'ten 1'e indi.
- Birleştirme sunucuya geçtiğinde sıralı istemcinin 3 turu 1 tura indi; karşılığında istek başına
  ağ atlaması 3'ten 4'e çıktı ve yeni bir dağıtım birimi eklendi.
- Aynı "üye başına 3 istek" kuralı, servis başına sayıldığında 12 istekten 9'unu, ağ geçidinde
  sayıldığında 3'ünü kabul ediyor; servise ulaşan istek her iki durumda da 9.
- Ağ geçidi bütün dış trafiğin bağımlılık kapanışıdır ve yalın servisler kendilerini savunmaz;
  denetim tek bir yerin doğruluğuna bağlanmıştır.

## Sonraki Adım

Ağ geçidi tek bir sayfayı topladı ve o sayfanın tek bir alıcısı olduğu varsayıldı. Kütüphanenin
ödünç sayfası ise birden çok yerde çiziliyor: raf başındaki dokunmatik uçbirim yalnız nüsha
durumunu ister, elde taşınan bir istemci küçük bir özet ister, personel ekranı üyenin bütün
geçmişini ister. Üçü de aynı geçitten geçtiğinde geçidin birleştirme kodu üç ayrı biçimi birden
taşımak zorunda kalır ve her istemci değişikliği ortak bir dosyaya dokunur. Sonraki ders bu yükü
sayar ve tek bir genel geçit yerine istemci başına ayrı bir toplama katmanı kurmanın kod tarafında
neyi ucuzlatıp neyi pahalılaştırdığını ölçer.
