---
title: Mikroservisler
source: 'https://academia.sh/tr/kurslar/servis-mimarileri/mikroservisler'
course: 'Servis Mimarileri'
language: tr
updated: '2026-08-17T18:06:53+00:00'
license: 'CC BY-SA 4.0'
---

# Mikroservisler

Aynı ödünç iş akışının gerçekten ayrı süreçlere bölünmesi: beş süreç, sekiz uç, istek başına dokuz ağ atlaması, zincir gecikmesi; tek bir dağıtım biriminin diğerleri durmadan yeniden yayına çıkması ve bir sürecin düşmesiyle doğan yarım kalmış iş akışı.

Önceki derste birimler ayrıldı ama aynı süreçte kaldı: `gonder` bir işlev çağrısıydı, ileti
bir nesneydi. Bu ders aynı ödünç iş akışını **gerçekten ayrı süreçlere** böler. Her birim
kendi bağlantı noktasında dinler, kendi verisini tutar, kendi başına başlatılır ve
durdurulur. Her birimin kendi dağıtım birimi olduğu bu düzene **mikroservis** (microservice)
denir; biçemin tanımı Mimari Biçemler kursunda yapıldı, burada ölçülen şey bölmenin koşumda
ve kodda görünen bedelidir.

**MS5.** Beş süreç aynı makinede, geri döngü arayüzü üzerinden konuşur. Gerçek bir ağın
gecikmesi, paket kaybı ve bölünmesi bu düzenekte yoktur. Modelin taşıdığı özellikler
şunlardır: çağrı **süreç sınırını** geçer, serileştirilir, hedef süreç bağımsız olarak
durabilir ve bağımsız olarak yeniden başlatılabilir.

## Beş Süreç

Her servis bağlantı noktasını komut satırından alır; komşularının adresini ortam
değişkeninden okur. Durum değiştiren uçlar `POST` ile çağrılır.

```js
// katalog-servisi.mjs — kitap birimi; kendi surecinde, kendi verisiyle
import { createServer } from "node:http";
const port = Number(process.argv[2]);
if (!port) { console.log("kullanim: node katalog-servisi.mjs <port>"); process.exit(0); }
const kitap = { 1: { durum: "rafta" }, 2: { durum: "rafta" }, 3: { durum: "rafta" } };
createServer((istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  const no = u.searchParams.get("kitapNo");
  if (u.pathname === "/durum") return yanit.end(JSON.stringify({ durum: kitap[no].durum }));
  if (u.pathname === "/odunc-isaretle") { kitap[no].durum = "odunc"; return yanit.end("{}"); }
  yanit.statusCode = 404;
  yanit.end("{}");
}).listen(port, () => console.log(`katalog ${port}`));
```

```js
// uyelik-servisi.mjs — uye birimi; kendi surecinde, kendi verisiyle
import { createServer } from "node:http";
const port = Number(process.argv[2]);
if (!port) { console.log("kullanim: node uyelik-servisi.mjs <port>"); process.exit(0); }
const uye = { 4: { ad: "Emre", acikOdunc: 1, sinir: 5, borc: 0 },
              5: { ad: "Selin", acikOdunc: 3, sinir: 3, borc: 0 } };
createServer((istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  const k = uye[u.searchParams.get("uyeNo")];
  if (k && u.pathname === "/getir") return yanit.end(JSON.stringify(k));
  if (k && u.pathname === "/odunc-ekle") { k.acikOdunc += 1; return yanit.end("{}"); }
  if (k && u.pathname === "/borc-ekle") {
    k.borc += Number(u.searchParams.get("tutar"));
    return yanit.end("{}");
  }
  yanit.statusCode = 404;
  yanit.end("{}");
}).listen(port, () => console.log(`uyelik ${port}`));
```

```js
// ucret-servisi.mjs — gecikme ucreti birimi; gunluk oran burada
import { createServer } from "node:http";
const port = Number(process.argv[2]);
if (!port) { console.log("kullanim: node ucret-servisi.mjs <port>"); process.exit(0); }
const GUNLUK = 2;
createServer((istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  if (u.pathname !== "/hesapla") { yanit.statusCode = 404; return yanit.end("{}"); }
  const gun = Number(u.searchParams.get("gun"));
  yanit.end(JSON.stringify({ ucret: gun > 0 ? gun * GUNLUK : 0 }));
}).listen(port, () => console.log(`ucret ${port}`));
```

```js
// bildirim-servisi.mjs — bildirim birimi; uye adini uyelik surecinden ister
import { createServer } from "node:http";
const port = Number(process.argv[2]);
if (!port) { console.log("kullanim: node bildirim-servisi.mjs <port>"); process.exit(0); }
createServer(async (istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  if (u.pathname !== "/gonder") { yanit.statusCode = 404; return yanit.end("{}"); }
  const y = await fetch(`http://127.0.0.1:${process.env.UYELIK}/getir?uyeNo=${u.searchParams.get("uyeNo")}`);
  console.log(`bildirim -> ${(await y.json()).ad}: ${u.searchParams.get("metin")}`);
  yanit.end("{}");
}).listen(port, () => console.log(`bildirim ${port}`));
```

Ödünç servisi, üçüncü dersteki `odunc.mjs` ile aynı sırayı yürütür. Tek fark, her adımın
artık bir ağ çağrısı olmasıdır. Yaptığı atlamaları sayar ve zincirin süresini kendi
günlüğüne yazar.

```js
// odunc-servisi.mjs — is akisini yuruten surec; digerlerini ag uzerinden cagirir
import { createServer } from "node:http";
const port = Number(process.argv[2]);
if (!port) { console.log("kullanim: node odunc-servisi.mjs <port>"); process.exit(0); }
const A = { katalog: process.env.KATALOG, uyelik: process.env.UYELIK,
            ucret: process.env.UCRET, bildirim: process.env.BILDIRIM };
let atlama = 0;
const cagir = async (hedef, yol, yontem = "GET") => {
  atlama += 1;
  return (await fetch(`http://127.0.0.1:${A[hedef]}${yol}`, { method: yontem })).json();
};
createServer(async (istek, yanit) => {
  const u = new URL(istek.url, "http://y");
  if (u.pathname !== "/odunc") { yanit.statusCode = 404; return yanit.end("{}"); }
  const uyeNo = u.searchParams.get("uyeNo"), kitapNo = u.searchParams.get("kitapNo");
  const gun = u.searchParams.get("gun") ?? 0;
  atlama = 0;
  const t0 = performance.now();
  try {
    const uye = await cagir("uyelik", `/getir?uyeNo=${uyeNo}`);
    if (uye.acikOdunc >= uye.sinir) throw new Error("odunc siniri asildi");
    if ((await cagir("katalog", `/durum?kitapNo=${kitapNo}`)).durum !== "rafta")
      throw new Error("kitap rafta degil");
    await cagir("katalog", `/odunc-isaretle?kitapNo=${kitapNo}`, "POST");
    await cagir("uyelik", `/odunc-ekle?uyeNo=${uyeNo}`, "POST");
    const { ucret } = await cagir("ucret", `/hesapla?gun=${gun}`);
    if (ucret > 0) await cagir("uyelik", `/borc-ekle?uyeNo=${uyeNo}&tutar=${ucret}`, "POST");
    await cagir("bildirim", `/gonder?uyeNo=${uyeNo}&metin=kitap+${kitapNo}`, "POST");
    console.log(`odunc ${kitapNo}/${uyeNo}: atlama ${atlama}, sure ${Math.round(performance.now() - t0)} ms`);
    yanit.end(JSON.stringify({ durum: "verildi", ucret, atlama }));
  } catch (h) {
    console.log(`odunc ${kitapNo}/${uyeNo}: HATA ${h.message}, atlama ${atlama}`);
    yanit.statusCode = 400;
    yanit.end(JSON.stringify({ durum: "basarisiz", hata: h.message, atlama }));
  }
}).listen(port, () => console.log(`odunc ${port}`));
```

## Ayağa Kaldırma

```sh
# baslat.sh — bes surec ayaga kalkar; her surecin ciktisi kendi gunlugune yazilir
rm -f pid.txt
node katalog-servisi.mjs 8792 >katalog.log 2>&1 & echo "katalog $!" >>pid.txt
node uyelik-servisi.mjs 8793 >uyelik.log 2>&1 & echo "uyelik $!" >>pid.txt
node ucret-servisi.mjs 8794 >ucret.log 2>&1 & echo "ucret $!" >>pid.txt
UYELIK=8793 node bildirim-servisi.mjs 8795 >bildirim.log 2>&1 & echo "bildirim $!" >>pid.txt
KATALOG=8792 UYELIK=8793 UCRET=8794 BILDIRIM=8795 \
  node odunc-servisi.mjs 8791 >odunc.log 2>&1 & echo "odunc $!" >>pid.txt
for p in 8791 8792 8793 8794 8795; do
  for i in $(seq 40); do curl -s -o /dev/null "http://127.0.0.1:$p/" && break; sleep 0.2; done
done
echo "ayaga kalkan surec: $(wc -l <pid.txt | tr -d ' ')   baslatma adimi: 5 arka plan + 1 hazirlik beklemesi"
echo "uc: $(grep -oh '"/[a-z-]*"' ./*.mjs | sort -u | wc -l | tr -d ' ')   dagitim birimi: 5"
grep -oh '"/[a-z-]*"' ./*.mjs | sort -u | tr -d '"' | tr '\n' ' '
echo
```

```
ayaga kalkan surec: 5   baslatma adimi: 5 arka plan + 1 hazirlik beklemesi
uc: 8   dagitim birimi: 5
/borc-ekle /durum /getir /gonder /hesapla /odunc /odunc-ekle /odunc-isaretle
```

Birinci derste bu sayı birdi: `node uygulama.mjs`. Burada beş arka plan süreci ve bir
hazırlık beklemesi var; bağlantı noktaları ve komşu adresleri dışarıdan verilmek zorunda.

## İstek Başına Atlama

```sh
curl -s "http://127.0.0.1:8791/odunc?kitapNo=1&uyeNo=4&gun=3"
echo
curl -s "http://127.0.0.1:8791/odunc?kitapNo=2&uyeNo=5"
echo
```

```
{"durum":"verildi","ucret":6,"atlama":7}
{"durum":"basarisiz","hata":"odunc siniri asildi","atlama":1}
```

Ödünç servisi 7 çağrı yaptı. Bildirim servisi üyenin adını almak için bir çağrı daha yaptı;
istemcinin ödünç servisine gönderdiği istekle birlikte **istek başına toplam 9 ağ atlaması**
oluyor. Üçüncü derste aynı iş akışı 8 ileti üretmişti — ileti sayısı değişmedi, her ileti
süreç sınırını geçer oldu.

Zincir sıralı ilerliyor: her çağrı bir öncekinin dönüşünü bekliyor, yani gecikmeler
toplanıyor. Ödünç servisi `odunc.log` dosyasına her istek için bir satır yazar; birinci
isteğin satırı bu koşumda `odunc 1/4: atlama 7, sure 21 ms` oldu.
Süre alanı makineye, çekirdeğe ve o andaki
yüke bağlıdır — yukarıdaki değer bu koşumda okunmuştur ve her koşumda değişir. Koşumdan
bağımsız nicelik **7 sıralı turdur** ve bu sayı ancak zincir kısaltılarak düşer. İkinci
istek üyelik denetiminde durduğu için tek atlamayla bitti: hata erken çıktığında zincirin
geri kalanı hiç kurulmuyor.

## Bağımsız Dağıtım

Asıl kazanç şurada ölçülür: ücret oranı değişsin.

```sh
# yeniden.sh — yalniz ucret sureci degisir ve yeniden baslatilir; digerleri hic durmaz
kill "$(awk '$1 == "ucret" { print $2 }' pid.txt)"
sed -i.y 's/const GUNLUK = 2;/const GUNLUK = 5;/' ucret-servisi.mjs
rm -f ucret-servisi.mjs.y
node ucret-servisi.mjs 8794 >>ucret.log 2>&1 & echo "ucret $!" >>pid.txt
for i in $(seq 40); do curl -s -o /dev/null "http://127.0.0.1:8794/" && break; sleep 0.2; done
echo "yeniden baslatilan surec: 1 / 5   dokunulan dagitim birimi: 1"
curl -s "http://127.0.0.1:8791/odunc?kitapNo=2&uyeNo=4&gun=3"
echo
```

```
yeniden baslatilan surec: 1 / 5   dokunulan dagitim birimi: 1
{"durum":"verildi","ucret":15,"atlama":7}
```

Yeni oran yürürlükte. Katalog, üyelik, bildirim ve ödünç süreçleri hiç durmadı; bellekteki
durumlarını korudular. Birinci derste aynı tek satırlık değişiklik yedi modülü birlikte
yeniden yayına çıkarıyordu; burada bir dağıtım birimi yeniden başladı.

Bu kazanç sınırsız değil. Kanonik `acikOdunc` alanı iki dağıtım biriminde geçiyor — üyelik
ve ödünç. Onun yeniden adlandırılması, üçüncü derste tek birim içinde 3 dosyaya dokunan bir
değişikken, burada **iki ayrı dağıtım biriminin uyumlu bir sırayla yayına çıkmasını**
gerektirir. Bağımsız dağıtım, sözleşmenin değişmediği değişiklikler için bağımsızdır.

## Kısmi Hata

```sh
# arizali.sh — bildirim sureci durur; ayni istek yolun sonunda kirilir
kill "$(awk '$1 == "bildirim" { print $2 }' pid.txt)"
sleep 0.5
curl -s "http://127.0.0.1:8791/odunc?kitapNo=3&uyeNo=4"
echo
curl -s "http://127.0.0.1:8792/durum?kitapNo=3"
echo
curl -s "http://127.0.0.1:8793/getir?uyeNo=4"
echo
```

```
{"durum":"basarisiz","hata":"fetch failed","atlama":6}
{"durum":"odunc"}
{"ad":"Emre","acikOdunc":4,"sinir":5,"borc":21}
```

İstek başarısız döndü, ama kitap ödünçte ve üyenin açık ödünç sayısı arttı. Altıncı atlamada
kırılan zincir, ilk beş atlamanın etkisini geri almadı. Tek parçada bu durum yoktu: bir
istisna bütün gövdeyi terk ediyor, hiçbir modül yarım bir işi kesinleştirmiş olmuyordu.

Aynı çıktının ikinci satırı başka bir şey söylüyor: katalog servisi hâlâ cevap veriyor.
Bildirim süreci düştüğünde sistemin tamamı durmadı — bildirime dokunmayan yollar çalışmaya
devam eder. Arıza artık **kısmi**dir; bu hem kazanç hem de yeni bir sorun, çünkü sistemin
durumu "ayakta" ve "düşük" arasında bir yerdedir.

```sh
# durdur.sh — butun surecleri durdurur
while read -r ad p; do kill "$p" 2>/dev/null; done <pid.txt
echo "durduruldu"
```

```
durduruldu
```

## Üç Sütun

| | Mikroservisler |
|---|---|
| Ucuzlattığı | Bir oran değişikliği 5 dağıtım biriminin 1'ini yeniden başlattı; her birim kendi verisine sahip, ölçekleme birimi tek servis |
| Pahalılaştırdığı | İstek başına 9 ağ atlaması ve 7 sıralı tur; başlatma 1 adımdan 6 adıma çıktı; adresler dışarıdan verilmek zorunda |
| Doğan arıza kipi | Zincirin ortasında kırılan istek yarım kalmış durum bırakıyor; arıza kısmi, sistem ne tam ayakta ne tam düşük |

## Özet

- Aynı ödünç iş akışı 5 ayrı sürece bölündü: 8 uç, 5 dağıtım birimi, istek başına 9 ağ
  atlaması, 7 sıralı tur.
- İleti sayısı üçüncü derse göre değişmedi; değişen şey her iletinin süreç sınırını geçmesi
  ve sıralı turların gecikmelerinin toplanmasıdır.
- Ayağa kaldırma 1 adımdan 6 adıma çıktı; her sürecin bağlantı noktası ve komşu adresleri
  dışarıdan verilmek zorunda.
- Ücret oranı değişikliği yalnız 1 dağıtım birimini yeniden başlattı; diğer dört süreç hiç
  durmadı. Sözleşmeye dokunan bir değişiklik ise iki birimi uyumlu sırayla yayına zorlar.
- Bildirim süreci düştüğünde istek başarısız döndü, ama kitap ödünçte ve üyenin sayacı artmış
  kaldı: zincirin ortasında kırılan iş akışı yarım bir durum bırakıyor.

## Sonraki Adım

Bu beş süreç uzun ömürlüdür: istek gelsin gelmesin ayakta durur, durumlarını bellekte tutar
ve bir kez başlatılıp bırakılır. Sonraki ders dağıtım birimini bir adım daha küçültür ve
uzun ömürlülüğü kaldırır: birim, yalnız bir olay tetiklediğinde var olan bir işlevdir.
Ölçülecek şeyler, iki çağrı arasında bellekte hiçbir şey tutulamamasının getirdiği ek
çağrılar, işlev başına konan süre sınırının iş akışını bölmesi ve süreç içinde kalmış son
yerel çağrıların da ağ çağrısına dönüşmesidir.
