---
title: 'Eşzamanlı Servis Çağrıları'
source: 'https://academia.sh/tr/kurslar/servis-mimarileri/eszamanli-servis-cagrilari'
course: 'Servis Mimarileri'
language: tr
updated: '2026-08-17T18:06:53+00:00'
license: 'CC BY-SA 4.0'
---

# Eşzamanlı Servis Çağrıları

Sınırın karşısına geçen çağrının gerçek süreçlerle ölçülmesi: zincir uzunluğuna göre uçtan uca turun büyümesi, dağıtılan çağrının aynı işi daha az turda bitirmesi, bir dış isteğin kaç iç isteğe dönüştüğünü veren çağrı çarpanı ve bir sürecin kapanmasında yanıtsız kalan giriş uçlarının payı.

Önceki ders sınırı bir ölçüte bağladı ve tabloda sessizce duran bir sayı bıraktı: ağa dönüşen
ithal. Aynı süreçteki bir ithal kenarı işlev çağrısıdır; iki dağıtım birimi arasındaki aynı kenar
ağ çağrısıdır. Bu ders o dönüşümü modelle değil, gerçekten ayrı işletim sistemi süreçleriyle
kurar ve farkı tur cinsinden sayar.

Zaman aşımı, yeniden deneme ve uçtan uca bütçenin zincire bölüştürülmesi Uygulama Katmanı ve
Servis Etkileşimi kursunda kuruldu ve ölçüldü; o aritmetik burada tekrarlanmaz. Buradaki üç ölçü
şudur: zincir uzunluğuna göre uçtan uca tur, bir dış isteğin doğurduğu iç istek sayısı ve bir
süreç kapandığında yanıtsız kalan isteklerin payı. Eşzamanlı çağrı, çağıranın yanıtı bekleyip
sonucu kendi yanıtına kattığı çağrıdır.

## Aynı İş, İki Yerleşim

Ödünç verme iş akışı dört adımdan oluşur: ödünç kaydı, üyelik denetimi, ödenmemiş ücret denetimi
ve nüsha ayırma. Aşağıdaki servis tek bir kaynak dosyadır; hangi rolü üstleneceği komut satırı
değişkenlerinden gelir. Her adım aynı süreyi harcar, böylece ölçülen süre iş adımı sayısına
bölünebilir.

```js
// servis.mjs — <ad> <port> <kip: paralel|sirali> <adim> [ardil-port...]; uzun omurlu surec
import { createServer } from "node:http";
const [ad, port, kip, adim, ...ardil] = process.argv.slice(2);
if (!port) { console.log("kullanim: node servis.mjs <ad> <port> <kip> <adim> [ardil...]"); process.exit(1); }
const IS = 25;                        // bir is adiminin suresi (ms); olcum bu birime bolunur
let islenen = 0;
const cagir = async (p) => {          // ardilin durum kodu denetlenir: hata sinirin karsisina gecer
  const y = await fetch(`http://127.0.0.1:${p}/is`);
  if (y.status !== 200) throw new Error(`ardil ${p} durum ${y.status}`);
  return y.json();
};

createServer(async (istek, yanit) => {
  if (istek.url === "/sayac") { yanit.end(JSON.stringify({ ad, islenen })); return; }
  if (istek.url === "/sifirla") { islenen = 0; yanit.end("sifir"); return; }
  islenen += 1;
  for (let i = 0; i < Number(adim); i += 1) await new Promise((c) => setTimeout(c, IS));
  try {
    let alt = [];
    if (kip === "sirali") for (const p of ardil) alt.push(await cagir(p));
    else alt = await Promise.all(ardil.map(cagir));
    yanit.end(JSON.stringify({ ad, adim: Number(adim), alt }));
  } catch (e) {
    yanit.statusCode = 502;
    yanit.end(JSON.stringify({ ad, hata: e.message }));
  }
}).listen(Number(port));
```

Aynı dört adım iki yerleşimde koşacak. Bölünmüş yerleşimde dört süreç vardır: ödünç servisi üyelik
ile katalog servislerini çağırır, üyelik servisi ücretlendirme servisini çağırır. Tek parça
yerleşiminde dört adımın dördü de tek süreçte ardışık koşar; ödünç ucundaki `adim` değeri dörttür
ve hiç ardıl çağrısı yoktur. Üçüncü bir yerleşim karşılaştırma içindir: ödünç servisi iki ardılını
paralel yerine sırayla çağırır.

Ardıl çağrısında durum kodunun denetlendiği satır dersin geri kalanını belirler. Süreç içinde bir
adımın başarısızlığı özel durum olarak yukarı yayılır; sınırın karşısında ise yalnız bir durum
kodudur. Çağıran o kodu denetlemezse hata yayılmaz, yutulur: yanıt başarılı görünür ama içindeki
üyelik denetimi hiç yapılmamıştır.

## Ölçüm

Ölçüm aracı üç kipte çalışır. Gecikme kipi her giriş ucuna üç istek gönderir ve ortancayı iş adımı
süresine bölerek turu bulur; süre ölçümü ortama bağlıdır, tur sayısı değildir. Çarpan kipi
sayaçları sıfırlar, tek uca beş istek gönderir ve süreçlerin işlediği istekleri toplar. Arıza kipi
her giriş ucuna birer istek atıp yanıtsız kalanları sayar.

**SS2 — dış istekler dört giriş ucuna eşit dağılır.** Gerekçe: etkilenen istek payı, kapanan
servise bağımlı giriş uçlarının trafikteki ağırlığıdır; ağırlıklar bilinmediğinde eşit dağılım
payı ölçülebilir kılar. Gerçek dağılım bilindiğinde aynı hesap ağırlıklarla yapılır.

```js
// olc.mjs — <kip: gecikme|carpan|ariza> [ad]; servis.mjs surecleri ayaktayken kosar
const IS = 25;                                   // servis.mjs ile ayni is adimi suresi
const UC = { ucretlendirme: 8941, uyelik: 8942, katalog: 8943, odunc: 8944,
  "sirali-odunc": 8945, "tek-surec": 8946 };
const ARIZA_GIRIS = ["ucretlendirme", "uyelik", "katalog", "odunc"];
const iste = async (p) => {
  const y = await fetch(`http://127.0.0.1:${p}/is`);
  if (y.status !== 200) throw new Error(`durum ${y.status}`);
  return y.json();
};
const dugum = (a) => 1 + (a.alt ?? []).reduce((s, x) => s + dugum(x), 0);
const adimlar = (a) => a.adim + (a.alt ?? []).reduce((s, x) => s + adimlar(x), 0);
const [kip, hedef] = process.argv.slice(2);

if (kip === "gecikme") {
  console.log(`${"giris".padEnd(14)}${"surec".padStart(7)}${"ag atlamasi".padStart(13)}` +
    `${"is adimi".padStart(10)}${"olculen tur".padStart(13)}`);
  let enBuyukEk = 0;
  for (const ad of Object.keys(UC)) {
    const sure = [];
    let agac;
    for (let i = 0; i < 3; i += 1) {
      const t = performance.now();
      agac = await iste(UC[ad]);
      sure.push(performance.now() - t);
    }
    const orta = sure.sort((a, b) => a - b)[1];
    const d = dugum(agac), tur = Math.floor(orta / IS);
    enBuyukEk = Math.max(enBuyukEk, orta - tur * IS);
    console.log(`${ad.padEnd(14)}${String(d).padStart(7)}${String(d - 1).padStart(13)}` +
      `${String(adimlar(agac)).padStart(10)}${String(tur).padStart(13)}`);
  }
  console.log(`olculen sure = tur x ${IS} ms + ek yuk; ek yuk bu kosumda ` +
    `${Math.ceil(enBuyukEk / IS) * IS} ms altinda (bir is adimindan az)`);
} else if (kip === "carpan") {
  for (const ad of Object.keys(UC)) await fetch(`http://127.0.0.1:${UC[ad]}/sifirla`);
  const N = 5;
  for (let i = 0; i < N; i += 1) await iste(UC.odunc);
  let toplam = 0;
  for (const ad of Object.keys(UC)) {
    const { islenen } = await (await fetch(`http://127.0.0.1:${UC[ad]}/sayac`)).json();
    toplam += islenen;
    if (islenen > 0) console.log(`  ${ad.padEnd(14)}${String(islenen).padStart(8)} istek`);
  }
  console.log(`odunc ucuna ${N} dis istek -> toplam ${toplam} islenen istek, ` +
    `cagri carpani x${toplam / N} (dis istek basina ${toplam / N - 1} ic istek)`);
} else if (kip === "ariza") {
  const dusen = [];
  for (const ad of ARIZA_GIRIS) {
    try { await iste(UC[ad]); } catch { dusen.push(ad); }
  }
  console.log(`${hedef.padEnd(16)}${(dusen.join(",") || "-").padEnd(36)}` +
    `${dusen.length}/${ARIZA_GIRIS.length}`);
}
```

Aşağıdaki kabuk bloğu altı süreci ayağa kaldırır, üç ölçümü koşturur, sonra sırayla üç servisi
kapatıp her defasında arıza kipini çalıştırır ve kapattığı servisi geri başlatır.

```bash
baslat() {
  case $1 in
    ucretlendirme) node servis.mjs ucretlendirme 8941 paralel 1 & ;;
    uyelik)        node servis.mjs uyelik 8942 paralel 1 8941 & ;;
    katalog)       node servis.mjs katalog 8943 paralel 1 & ;;
    odunc)         node servis.mjs odunc 8944 paralel 1 8942 8943 & ;;
  esac
}
for s in ucretlendirme uyelik katalog odunc; do baslat $s; done
node servis.mjs sirali-odunc 8945 sirali 1 8942 8943 &
node servis.mjs tek-surec 8946 paralel 4 &
sleep 1

node olc.mjs gecikme
echo
echo "cagri carpani:"
node olc.mjs carpan
echo
printf '%-16s%-36s%s\n' "kapali servis" "yanitsiz kalan giris" "etkilenen istek payi"
for s in ucretlendirme katalog odunc; do
  pkill -f "servis.mjs $s" ; sleep 0.3
  node olc.mjs ariza $s
  baslat $s ; sleep 0.5
done
pkill -f "node servis.mjs"
```

```
giris           surec  ag atlamasi  is adimi  olculen tur
ucretlendirme       1            0         1            1
uyelik              2            1         2            2
katalog             1            0         1            1
odunc               4            3         4            3
sirali-odunc        4            3         4            4
tek-surec           1            0         4            4
olculen sure = tur x 25 ms + ek yuk; ek yuk bu kosumda 25 ms altinda (bir is adimindan az)

cagri carpani:
  ucretlendirme        5 istek
  uyelik               5 istek
  katalog              5 istek
  odunc                5 istek
odunc ucuna 5 dis istek -> toplam 20 islenen istek, cagri carpani x4 (dis istek basina 3 ic istek)

kapali servis   yanitsiz kalan giris                etkilenen istek payi
ucretlendirme   ucretlendirme,uyelik,odunc          3/4
katalog         katalog,odunc                       2/4
odunc           odunc                               1/4
```

## Zincir Uzunluğu Turu Belirliyor

İlk üç satır zinciri uzatarak okunuyor. Ücretlendirme ucuna gelen istek bir süreçte biter: sıfır
atlama, bir tur. Üyelik ucu ücretlendirmeyi çağırır: iki süreç, bir atlama, iki tur. Ödünç ucu
dört süreci birden işletir: üç atlama, dört iş adımı. **Zincir gecikmesi** burada tur cinsinden
görünür hâle geliyor: uçtan uca tur, zincirin ardışık adım sayısıdır ve ölçüm bunu geri veriyor.

Dördüncü ve altıncı satır dersin asıl karşılaştırmasıdır. Ödünç ucu dört iş adımını **üç** turda
bitiriyor, tek süreç aynı dört adımı **dört** turda. Kazanç bölünmeden gelmiyor, bölünmenin
açtığı fırsattan geliyor: üyelik dalı ile katalog dalı birbirini beklemek zorunda olmadığı için
paralel çağrılıyor ve uçtan uca süre iki dalın toplamı değil büyüğü oluyor. Beşinci satır bunu
doğruluyor — aynı dört süreç, aynı üç atlama, ama ardılları sırayla çağıran ödünç servisi dört
turda bitiriyor. **Dağıtılan çağrı bir turu geri kazandırır; sıralı çağrı kazanmaz.**

Süre ölçümü ortama bağlıdır ve loopback üzerinde bir atlamanın bedeli küçüktür; ek yükün tamamı
bir iş adımının altında kaldı. Gerçek bir ağda aynı üç atlama bu kadar ucuz değildir, ama tur
sayısı değişmez: tur, koşumdan bağımsız niceliktir ve gecikme bütçesi turlarla çarpılır.

## Çarpan ve Etkilenen Pay

Çağrı çarpanı ikinci ölçüdür. Ödünç ucuna gelen beş dış istek, süreçlerde toplam yirmi istek
işletiyor: çarpan dört, yani her dış istek başına üç iç istek. Bu sayı doğrudan sınır kararının
sonucudur; önceki dersin ölçtüğü sınırı geçen ithal kenarları, koşum sırasında iç isteğe dönüşen
kenarlardır. Sınırı geçen kenar sayısı arttıkça çarpan artar ve her servis kendi kapasitesini
kendi trafiğine göre değil, çarpanla büyütülmüş trafiğe göre seçmek zorunda kalır.

Son tablo yeni arıza kipini sayıya çeviriyor. Ücretlendirme süreci kapandığında yalnız kendi ucu
değil, ona bağımlı olan üyelik ve ödünç uçları da yanıtsız kalıyor: dört giriş ucunun üçü, SS2
altında isteklerin yüzde yetmiş beşi. Katalog kapandığında iki uç, ödünç kapandığında bir uç
etkileniyor. **Etkilenen pay, kapanan servisin bağımlılık kapanışıdır**: zincirin dibindeki servis
en pahalıdır, çünkü üstündeki her uç ona bağlıdır. Tek parça yerleşiminde bu tablo tek satırdır —
süreç kapanırsa isteklerin tamamı düşer, ama kısmi arıza diye bir durum da yoktur.

Üçlü şöyle toparlanır. **Ucuzlayan:** dört iş adımı üç turda bitiyor ve her servis kendi başına
ölçeklenebiliyor; bir servisin kapanması diğer üç ucu ayakta bırakıyor. **Pahalılaşan:** istek
başına üç ağ atlaması, dört süreç, dört kat işlenen istek ve dörde bölünmüş bir başlatma düzeni.
**Doğan arıza kipi:** kısmi arıza. Sistem artık ya tamamen ayakta ya tamamen kapalı değil; giriş
ucuna göre değişen bir yanıt verme oranı var ve ardıl hatasının durum kodu denetlenmezse bu oran
hiç görünmeden, eksik iş yapılmış başarılı yanıtlara dönüşüyor.

## Özet

- Uçtan uca tur zincirin ardışık adım sayısıdır: ölçüm sıfır, bir ve üç atlamalı uçlarda sırasıyla
  1, 2 ve 3 tur verdi; ek yük bir iş adımının altında kaldı.
- Aynı dört iş adımı tek süreçte 4 turda, dört süreçte 3 turda bitiyor; kazanç bölünmenin değil,
  bölünmenin açtığı paralel çağrının sonucudur — ardılları sırayla çağıran yerleşim 4 turda bitiyor.
- Çağrı çarpanı sınırı geçen kenarların koşum karşılığıdır: 5 dış istek 20 işlenen isteğe dönüştü,
  dış istek başına 3 iç istek.
- Bir sürecin kapanmasında etkilenen istek payı, o servisin bağımlılık kapanışıdır: ücretlendirme
  için 3/4, katalog için 2/4, ödünç için 1/4.
- Sınır, hatayı özel durumdan durum koduna çevirir; çağıran durum kodunu denetlemezse arıza
  yayılmaz, yutulur ve başarılı görünen yanıt eksik iş içerir.

## Sonraki Adım

Bu ölçümlerin hepsi tek bir varsayımın içindeydi: çağıran, ardılın işi bitene kadar bekliyor.
Çarpan da, tur da, etkilenen pay da o beklemeden doğuyor — ödünç servisi bildirimin gönderilmesini
beklediği için bildirim servisinin kapanması ödünç isteğini düşürüyor. Oysa iş akışındaki her adım
yanıtın verilebilmesi için tamamlanmak zorunda değil. Sonraki ders aynı iş akışını ikinci kez
kurar: yanıt yolundaki adımlardan biri çağrı olmaktan çıkıp bir olaya dönüşür ve tüketicisi
kendi zamanında işler. Ölçülecek olanlar da bellidir — yanıt yolundan düşen iş adımı, yayıncı ile
tüketici ayrı dağıtım birimleri olduğunda ortaya çıkan sözleşme yükü ve olayın yazılmasıyla
etkisinin görünmesi arasındaki tutarlılık penceresi.
