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

# Servis Keşfi

Adres çözümlemenin bir gerçekleştirme olarak kurulması: kira süreli kayıt defteri süreci, kopyaların kendini kaydetmesi ve sağlık bilgisinin yönlendirmeye bağlanması; sabit yapılandırmayla dağıtımda dokunulan dosya ve ölü adrese giden istek üzerinden karşılaştırma.

Önceki iki dersin de sessiz bir ortak kabulü vardı: karşı tarafın adresi kodun içinde sabit bir
dizedir. Ödünç servisi ücret servisine `127.0.0.1:8751` diye gitti; ondan önceki toplama
katmanları katalog servisine `127.0.0.1:8741` diye gitti. Tek kopyalı bir düzenekte bu doğrudur.
Kütüphane ödünç sisteminin katalog servisi ise tek kopya değildir: yük arttıkça kopya eklenir,
bir kopya çöker, bir kopya bakıma alınır. Sabit dizenin karşılığı olmayan bir adres, çağrının
kendisi kadar kesin bir arızadır.

Bu dersin işi adres çözümlemeyi bir **gerçekleştirme** olarak kurmaktır. Servis keşfi ile kayıt
defterinin ne olduğu Uygulama Katmanı ve Servis Etkileşimi kursunda tanımlandı; burada kayıt
defteri gerçekten bir süreç olarak koşar, kayıtlara bir kira süresi verilir, sağlık bilgisi
yönlendirmeye bağlanır ve sonuç sabit yapılandırmayla iki sayı üzerinden karşılaştırılır: bir
kopya eklendiğinde dağıtımda dokunulan dosya, bir kopya öldüğünde ölü adrese giden istek.

Varsayımlar: **SS16** katalog servisinin üç kopyası vardır ve üçü de aynı veriyi sunar.
**SS17** kayıt defterinde kira süresi 900 ms, kopyaların yenileme aralığı 300 ms'dir; bu
oranlar gerçek bir sistemdekinden küçüktür, ölçüm süresini kısaltmak içindir. **SS18** katalog
servisini çağıran üç istemci vardır (ödünç, bildirim, ücret) ve sabit yapılandırmada her biri
kendi adres dosyasını taşır.

## Kayıt Defteri Süreci

Kayıt defteri, adres ile kayıt zamanını tutan tek bir süreçtir. Kaydın geçerliliği süreye
bağlıdır: son yenilemesinin üzerinden kira süresi geçmiş bir kayıt listeden düşer. Çözümleme
yanıtı iki sayı döndürür — diri kayıt sayısı ve yönlendirilebilir adresler. İkisinin ayrı
olmasının nedeni sağlık bilgisidir.

```js
// kesif/kayit-defteri.mjs — kayit defteri 8761: kira sureli kayit ve saglik bilgisi
import { createServer } from "node:http";

const KIRA = 900;                     // ms: yenilenmeyen kayit bu surenin sonunda listeden duser
const kayit = new Map();              // adres -> { ad, saglik, son yenileme }

createServer((q, y) => {
  const [kok, deger] = q.url.split("/").filter(Boolean);
  if (kok === "kayit") {                                   // /kayit/<ad>|<adres>|<saglik>
    const [ad, adres, saglik] = decodeURIComponent(deger).split("|");
    kayit.set(adres, { ad, saglik: saglik === "1", son: Date.now() });
  }
  const ad = kok === "cozumle" ? deger : "katalog";
  const diri = [...kayit.entries()]
    .filter(([, k]) => k.ad === ad && Date.now() - k.son < KIRA);
  y.writeHead(200, { "Content-Type": "application/json" });
  y.end(JSON.stringify({ kira: KIRA, kayit: diri.length,
    adres: diri.filter(([, k]) => k.saglik).map(([a]) => a) }));
}).listen(8761, "127.0.0.1", () => console.log("kayit-defteri 127.0.0.1:8761"));
```

Kayıt defterinde silme ucu yoktur. Bir kopya düzgün kapanırken kaydını sildirebilirdi, ama
çöken bir kopya bunu yapamaz; bu yüzden kaydın geçerliliği kopyanın iyi niyetine değil, süreye
bağlanır. Kayıt defteri hiçbir kopyaya kendisi soru sormaz.

## Kaydolan Kopya

Her kopya ayağa kalkarken kendini kaydeder ve kira süresinin üçte biri kadar bir aralıkla
kaydını yeniler. Yenileme çağrısı sağlık bilgisini de taşır. `/bozul` ucu, sürecin yaşadığı ama
iş göremediği durumu üretmek içindir: süreç yenilemeyi sürdürür, bildirdiği sağlık bilgisi
değişir.

```js
// kesif/katalog.mjs — katalog kopyasi: node kesif/katalog.mjs 8762
import { createServer } from "node:http";

const port = Number(process.argv[2] ?? 8762);
const YENILEME = 300;                        // ms: kira suresinin ucte biri
let saglik = true;

const kaydol = () => fetch("http://127.0.0.1:8761/kayit/" +
  encodeURIComponent(`katalog|127.0.0.1:${port}|${saglik ? "1" : "0"}`)).catch(() => {});

createServer((q, y) => {
  if (q.url === "/bozul") saglik = false;    // surec yasiyor ve kaydini yeniliyor, is goremiyor
  const kod = saglik ? 200 : 503;
  y.writeHead(kod, { "Content-Type": "application/json" });
  y.end(JSON.stringify({ port, saglik }));
}).listen(port, "127.0.0.1", () => {
  kaydol();
  setInterval(kaydol, YENILEME).unref();
});
```

Yenileme aralığının kira süresinden küçük olması zorunludur; oran, bir kopyanın kaç yenileme
kaçırdıktan sonra listeden düşeceğini belirler. Burada oran üçtür: iki yenileme kaçıran kopya
hâlâ listededir, üçüncüsünü de kaçıran düşer.

## İki Çözümleme Yolu, Aynı İş

Ölçüm betiği kayıt defterini ve üç kopyayı kendisi başlatır, sabit yapılandırma dosyasını
kendisi yazar ve beş aşamanın her birinde aynı altı isteği iki yolla dağıtır. Sabit yolda
adresler dosyadan okunur; keşif yolunda her aşamanın başında kayıt defterine sorulur.

```js
// kesif/olc.mjs — sabit yapilandirma ile kayit defteri ayni is uzerinde kosturulur
import { spawn } from "node:child_process";
import { writeFileSync, readFileSync } from "node:fs";

const bekle = (ms) => new Promise((c) => setTimeout(c, ms));
const surec = {};
const baslat = (p) => (surec[p] = spawn("node", ["kesif/katalog.mjs", String(p)], { stdio: "ignore" }));
const ISTEK = 6;                        // asama basina istek; adresler arasinda sirayla dagitilir
const ISTEMCI = 3;                      // katalogu cagiran servis: odunc, bildirim, ucret

const defter = spawn("node", ["kesif/kayit-defteri.mjs"], { stdio: "ignore" });
await bekle(400);
[8762, 8763, 8764].forEach(baslat);
writeFileSync("kesif/adresler.json",     // dagitim sirasinda elle yazilan yapilandirma dosyasi
  JSON.stringify([8762, 8763, 8764].map((p) => `127.0.0.1:${p}`)));
await bekle(500);

const cagir = async (adres) => {
  try { return (await fetch(`http://${adres}/kitap/978-0`)).status === 200; } catch { return false; }
};
const dagit = async (adres) => {
  let ok = 0;
  for (let i = 0; i < ISTEK && adres.length; i += 1) if (await cagir(adres[i % adres.length])) ok += 1;
  return ok;
};
const sabit = async () => {
  const a = JSON.parse(readFileSync("kesif/adresler.json", "utf8"));
  return { ok: await dagit(a), kayit: a.length, adres: a.length };
};
const kesif = async () => {
  const d = await (await fetch("http://127.0.0.1:8761/cozumle/katalog")).json();
  return { ok: await dagit(d.adres), kayit: d.kayit, adres: d.adres.length };
};

const asama = [];
const olc = async (ad) => asama.push({ ad, s: await sabit(), k: await kesif() });

await olc("hepsi diri");
surec[8764].kill();
await olc("kopya olduruldu (hemen)");
await bekle(1200);
await olc("kira suresi doldu");
await fetch("http://127.0.0.1:8763/bozul").catch(() => {});
await bekle(400);
await olc("kopya bozuk bildirdi");
baslat(8765);
await bekle(600);
await olc("yeni kopya eklendi");

const B = ["sabit b/i", "sabit adres", "defter b/i", "defter kayit", "defter adres"];
console.log(`${"asama".padEnd(26)}${B.map((b) => b.padStart(14)).join("")}`);
for (const a of asama) {
  console.log(`${a.ad.padEnd(26)}${[`${a.s.ok}/${ISTEK}`, a.s.adres, `${a.k.ok}/${ISTEK}`,
    a.k.kayit, a.k.adres].map((v) => String(v).padStart(14)).join("")}`);
}
console.log(`\nkira suresi 900 ms, yenileme araligi 300 ms; kesif penceresinde olu adrese ` +
  `giden istek = ${ISTEK - asama[1].k.ok}/${ISTEK}`);
console.log(`yeni kopya eklendiginde dokunulan yapilandirma dosyasi: sabit ${ISTEMCI}, defter 0; ` +
  `yeniden baslatilan istemci: sabit ${ISTEMCI}, defter 0`);
console.log(`kayit defteri = 1 ek surec, her cagri oncesi 1 ek cozumleme istegi`);

Object.values(surec).forEach((s) => s.kill());
defter.kill();
```

```
asama                          sabit b/i   sabit adres    defter b/i  defter kayit  defter adres
hepsi diri                           6/6             3           6/6             3             3
kopya olduruldu (hemen)              4/6             3           4/6             3             3
kira suresi doldu                    4/6             3           6/6             2             2
kopya bozuk bildirdi                 2/6             3           6/6             2             1
yeni kopya eklendi                   2/6             3           6/6             3             2

kira suresi 900 ms, yenileme araligi 300 ms; kesif penceresinde olu adrese giden istek = 2/6
yeni kopya eklendiginde dokunulan yapilandirma dosyasi: sabit 3, defter 0; yeniden baslatilan istemci: sabit 3, defter 0
kayit defteri = 1 ek surec, her cagri oncesi 1 ek cozumleme istegi
```

## Sayıların Okunması

İlk aşamada iki yol da aynı sonucu veriyor: altı istek, altı başarı, üç adres. Keşfin hiçbir
katkısı görünmüyor ve bu doğrudur — her şey yolundayken sabit yapılandırma da doğru çalışır.
Keşfin ölçüsü ancak yerleşim değiştiğinde ortaya çıkar.

İkinci aşama, bir kopya öldürüldükten hemen sonra ölçülüyor. İki yol da 4/6 veriyor. Kayıt
defteri henüz üç adres döndürüyor, çünkü ölen kopyanın son yenilemesinin üzerinden kira süresi
geçmedi. Bu aralığa **keşif penceresi** denir ve ölçümdeki karşılığı 2/6'dır: pencerede giden
her altı istekten ikisi ölü bir adrese gitmiştir. Kayıt defteri, ölümü öğrenme süresini sıfıra
indirmez; yalnız sınırlar.

Üçüncü aşama pencerenin kapanmasını gösteriyor. Kira süresi dolduktan sonra kayıt defteri iki
adres döndürüyor ve altı istek iki adrese üçer dağılıyor: 6/6. Sabit yapılandırma ise hâlâ üç
adres taşıyor ve 4/6 vermeye devam ediyor. Bu fark keşfin bütün karşılığıdır: sabit
yapılandırmanın yanlışı, bir kişi dosyayı düzeltene kadar sürer.

Dördüncü aşama, sağlık bilgisinin neden ayrı bir bilgi olduğunu gösteriyor. `8763` kopyası
`/bozul` çağrısından sonra yaşamayı ve kaydını yenilemeyi sürdürüyor; kayıt defterindeki diri
kayıt sayısı 2 kalıyor, ama yönlendirilebilir adres 1'e düşüyor. Sürecin ayakta olması, işi
yapabildiği anlamına gelmez. Sabit yapılandırma bu ayrımı hiç yapamaz ve 2/6'ya iner: iki istek
ölü adrese, iki istek de 503 döndüren kopyaya gider.

Beşinci aşama dağıtım tarafını ölçüyor. Dördüncü bir kopya başlatıldığında kayıt defteri
tarafında hiçbir dosyaya dokunulmuyor; kopya kendini kaydediyor ve bir sonraki çözümlemede
yönlendirilebilir adres 2'ye çıkıyor. Sabit yapılandırma tarafında ise sonuç değişmiyor: yeni
kopya hiçbir isteği karşılamıyor, çünkü üç istemcinin adres dosyası hâlâ eski üçlüyü taşıyor.
Değişikliğin bedeli çıktının son satırlarındadır: dokunulan yapılandırma dosyası 3'e karşı 0,
yeniden başlatılan istemci 3'e karşı 0.

## Kayıt Defterinin Bedeli ve Doğan Arıza Kipleri

Ödenen bedel üç kalemdir. Birincisi bir ek süreçtir ve bu süreç sıradan bir servis değildir:
kayıt defteri düştüğünde hiçbir istemci adres çözemez. Sabit yapılandırmanın tek üstünlüğü tam
buradadır — dosya, hiçbir şeye bağlı olmadan okunur. Bu yüzden kayıt defterine yaslanan
istemciler genellikle son çözümlemenin sonucunu ellerinde tutar; o zaman da elde tutulan liste
eskiyebilir ve keşif penceresi yeniden büyür.

İkincisi çözümleme isteğidir. Ölçümde her aşama başında bir çözümleme yapıldı; her çağrı öncesi
çözümleme yapılsaydı katalog servisine giden her istek iki isteğe dönüşecekti. Bu, bir önceki
dersteki yerel durak ölçüsünün keşif tarafındaki karşılığıdır ve çözümlemenin önbelleğe
alınmasını zorunlu kılar.

Üçüncüsü kira süresinin kendisidir ve iki yönü de arıza doğurur. Süre uzatılırsa keşif
penceresi büyür, yani ölü adrese giden istek artar. Süre kısaltılırsa kopyalar daha sık
yenileme yapar; kayıt defterine gelen yazma yükü kopya sayısıyla çarpılır ve ağdaki kısa bir
kesinti diri kopyaların listeden düşmesine yol açar. Listeden düşen kopya geri döndüğünde
istekler yeniden dağılır; bu salınım, kayıt defteri gerçekleştirmelerinin en tanıdık arızasıdır.

Doğan arıza kiplerinin ortak kaynağı şudur: kayıt defteri gerçeği değil, **gerçeğin gecikmeli
bir kopyasını** tutar. Sabit yapılandırmada gecikme sınırsızdır ve bir insanın dosyayı
düzeltmesine bağlıdır; kayıt defterinde gecikme kira süresiyle sınırlıdır. Keşfin sattığı şey
doğruluk değil, **yanlışın ömrüne konan üst sınırdır.**

## Özet

- Kayıt defteri kira süreli kayıt tutar; silme ucu yoktur, çünkü çöken bir kopya kaydını
  sildiremez. Kopyalar kira süresinin üçte biri aralıkla kaydını yeniler.
- Her şey yolundayken iki yol da 6/6 verir; fark yalnız yerleşim değiştiğinde ortaya çıkar.
- Bir kopya öldürüldükten hemen sonra iki yol da 4/6 verir: keşif penceresinde altı istekten
  ikisi ölü adrese gider. Kira süresi dolduktan sonra kayıt defteri 6/6'ya döner, sabit
  yapılandırma 4/6'da kalır.
- Sağlık bilgisi diri kayıttan ayrıdır: bozuk bildiren kopya kayıtta kalır (kayıt 2) ama
  yönlendirmeden düşer (adres 1); sabit yapılandırma bu ayrımı yapamaz ve 2/6'ya iner.
- Yeni kopya eklendiğinde dokunulan yapılandırma dosyası 3'e karşı 0, yeniden başlatılan
  istemci 3'e karşı 0'dır.
- Ödenen bedel: 1 ek süreç ve tek arıza noktası, çağrı başına 1 ek çözümleme isteği, kira
  süresinin iki yönlü arızası (uzun süre keşif penceresini, kısa süre yenileme yükünü ve
  salınımı büyütür).

## Sonraki Adım

Bu konu sınırın nereden geçeceğiyle başladı, sınırın iki yanının nasıl konuşacağıyla sürdü ve
adresin nasıl çözüleceğiyle bitti. Sınır çizildi, eşzamanlı ve eşzamansız iletişim kuruldu,
kenar sorumlulukları toplandı, istemciye özel katman eklendi, ağ ilgileri uygulamadan çıkarıldı
ve adres kodun dışından çözüldü. Yedi dersin ölçtüğü her şeyin altında duran bir kabul ise hiç
sınanmadı: bir işin ortasında sınırın iki yanındaki veri, sanki tek bir işlemin güvencesi
altındaymış gibi ele alındı. Ödünç servisi kaydı yazdı ve ücret servisi cezayı tahsil etti;
ikisi ayrı süreçlerde, ayrı veriler üzerinde ve ayrı zamanlarda oldu. Bir önceki dersin çift
tahsilat ölçümü bu kabulün ilk çatlağıydı. Sonraki konu tam olarak bunu ele alır: bir iş akışı
birden çok servisin verisine dokunduğunda, hepsinin birlikte olması ya da hiçbirinin olmaması
nasıl sağlanır, sağlanamadığında ne olur ve bunun bedeli hangi birimlerle ölçülür.
