İçeriğe geç
academia.sh

Ders 15 / 18

Mikroservis Mimarisi

Paylaşılan sözleşme kaldırıldığında ne kazanıldığı ve ne ödendiği: iki bağlamın ayrı yerel süreçler olarak koşturulması, dağıtım birimi başına yeniden yayınlanan dosya sayısının 1'e indirilmesi, bağımsızlık için ödenen yapıştırma satırının sayılması, bir süreç durdurulduğunda yanıt veren uç sayısının ve kısmi yanıtın ölçülmesi.

İçindekiler

Servis yönelimli düzende yayın bağlaşımının kaynağı paylaşılan sözleşmeydi: on alanlık kanonik kayıt, o alanları okumayan servisi bile yayına bağlıyordu. Bir sonraki adım ortak biçimi kaldırmaktır. Her bağlam kendi sözleşmesini, kendi veri biçimini ve kendi yayın takvimini alır; çağrı ortak bir yüzeyden değil doğrudan karşı servise gider.

Mikroservis mimarisi (microservice architecture) bu düzendir: her servis kendi süreci, kendi verisi ve kendi sözleşmesiyle tek başına yayınlanabilen bir dağıtım birimidir. Servis yönelimli mimariden ayrıldığı yer boyut değil, paylaşılan varlıkların yokluğudur — kurum çapında kanonik model yoktur, ortak çağrı yüzeyi yoktur. Bu dersteki ölçüm iki bağlamı gerçekten ayrı yerel süreçler olarak koşturur.

Üç Süreç

Ücretlendirme bağlamı kendi sunucusudur. Sözleşmesi kendisine aittir: yalnız ihtiyacı olan alanları sorgu dizisinden okur, kendi yanıt biçimini döndürür.

// mikro/ucret.mjs — ucretlendirme baglami: kendi sureci, kendi sozlesmesi, kendi yayin takvimi
import { createServer } from "node:http";

const TARIFE = { kademe: [[1, 3000], [5, 4800], [20, 9600]], bolge: { "34": 100, "06": 115, "35": 125 }, asgari: 2500 };

function fiyatla(s) {
  const agirlik = Number(s.get("agirlik")), oran = Number(s.get("oran") ?? 0);
  const kademe = TARIFE.kademe.find(([k]) => agirlik <= k) ?? [0, 9600];
  const taban = Math.max(TARIFE.asgari, Math.round((kademe[1] * TARIFE.bolge[s.get("bolge")]) / 100));
  return { id: s.get("id"), net: taban - Math.round(taban * Math.min(oran, 0.4)) };
}

const port = Number(process.argv[2]);
if (Number.isInteger(port) === false) console.log("kullanim: node mikro/ucret.mjs <baglanti-noktasi>");
else createServer((istek, yanit) => {
  const govde = JSON.stringify(fiyatla(new URL(istek.url, "http://yerel").searchParams));
  yanit.writeHead(200, { "content-type": "application/json" });
  yanit.end(govde);
}).listen(port);
// mikro/operasyon.mjs — teslimat operasyonu baglami: ayri surec, ayri sozlesme
import { createServer } from "node:http";

const AGAC = { "34": ["34"], "06": ["34", "06"], "35": ["34", "41", "35"] };

function planla(s) {
  const rota = AGAC[s.get("bolge")] ?? ["34"];
  return { id: s.get("id"), rota, gun: rota.length, tasiyici: rota.length > 2 ? "MT" : "AN" };
}

const port = Number(process.argv[2]);
if (Number.isInteger(port) === false) console.log("kullanim: node mikro/operasyon.mjs <baglanti-noktasi>");
else createServer((istek, yanit) => {
  const govde = JSON.stringify(planla(new URL(istek.url, "http://yerel").searchParams));
  yanit.writeHead(200, { "content-type": "application/json" });
  yanit.end(govde);
}).listen(port);

Teklif isteği artık bir fonksiyon çağrısı değil, iki ağ çağrısının birleştirilmesidir. Çağrılar başarısız olabildiği için birleştirici bir karar vermek zorundadır: isteği tümden reddetmek mi, elde edileni döndürüp eksiği bildirmek mi. Aşağıdaki gerçekleştirim ikincisini seçer ve eksik parça sayısını yanıt sözleşmesine yazar.

// mikro/teklif.mjs — birlestirici: iki servisi ag uzerinden cagirir, eksik yaniti isaretler
import { createServer } from "node:http";

async function al(adres, sorgu) {
  const y = await fetch(`${adres}?${sorgu}`);
  if (y.ok === false) throw new Error(`${adres} 200 dondurmedi`);
  return y.json();
}

async function teklif(sorgu, id) {
  const [f, p] = await Promise.allSettled([
    al(process.env.UCRET_ADRES, sorgu), al(process.env.OPERASYON_ADRES, sorgu),
  ]);
  return {
    id, net: f.status === "fulfilled" ? f.value.net : null,
    gun: p.status === "fulfilled" ? p.value.gun : null,
    tasiyici: p.status === "fulfilled" ? p.value.tasiyici : null,
    eksik: [f, p].filter((r) => r.status === "rejected").length,
  };
}

const port = Number(process.argv[2]);
if (Number.isInteger(port) === false) console.log("kullanim: node mikro/teklif.mjs <baglanti-noktasi>");
else createServer(async (istek, yanit) => {
  const s = new URL(istek.url, "http://yerel").searchParams;
  const govde = JSON.stringify(await teklif(s.toString(), s.get("id")));
  yanit.writeHead(200, { "content-type": "application/json" });
  yanit.end(govde);
}).listen(port);

İki Durumun Ölçülmesi

Sürücü betik üç süreci başlatır, üç ucu da ölçer, sonra ücretlendirme sürecini durdurup aynı üç ucu yeniden ölçer. Bağlantı noktası numaraları ortama bağlıdır; makinede kullanımdaysa değiştirilmelidir.

# olc.sh — uc ayri surec baslatilir; hepsi ayaktayken ve ucret durdugunda olculur
node mikro/ucret.mjs 8791 & UCRET=$!
node mikro/operasyon.mjs 8792 & OPERASYON=$!
UCRET_ADRES=http://127.0.0.1:8791/fiyat OPERASYON_ADRES=http://127.0.0.1:8792/plan \
  node mikro/teklif.mjs 8793 & TEKLIF=$!
sleep 1
S="id=G1&agirlik=4&bolge=35&oran=0.15"

olc() {
  for u in 8791/fiyat 8792/plan 8793/teklif; do
    printf "  %-12s %s\n" "$u" "$(curl -s -o /dev/null -w '%{http_code} kod, %{size_download} bayt' "http://127.0.0.1:$u?$S")"
  done
  printf "  teklif govdesi = %s\n" "$(curl -s "http://127.0.0.1:8793/teklif?$S")"
}

echo "durum 1: uc surec ayakta"
olc
kill $UCRET
sleep 0.5
echo "durum 2: ucret sureci durduruldu"
olc
kill $OPERASYON $TEKLIF 2>/dev/null

echo "dagitim birimi = 3"
for d in mikro/ucret.mjs mikro/operasyon.mjs mikro/teklif.mjs; do
  printf "  %-20s ithal = %s, sunucu yapistirmasi = %s satir\n" "$d" \
    "$(grep -c '^import' $d)" "$(grep -cE 'createServer|writeHead|yanit.end|process.argv|Number.isInteger' $d)"
done
durum 1: uc surec ayakta
  8791/fiyat   200 kod, 22 bayt
  8792/plan    200 kod, 59 bayt
  8793/teklif  200 kod, 56 bayt
  teklif govdesi = {"id":"G1","net":5100,"gun":3,"tasiyici":"MT","eksik":0}
durum 2: ucret sureci durduruldu
  8791/fiyat   000 kod, 0 bayt
  8792/plan    200 kod, 59 bayt
  8793/teklif  200 kod, 56 bayt
  teklif govdesi = {"id":"G1","net":null,"gun":3,"tasiyici":"MT","eksik":1}
dagitim birimi = 3
  mikro/ucret.mjs      ithal = 1, sunucu yapistirmasi = 6 satir
  mikro/operasyon.mjs  ithal = 1, sunucu yapistirmasi = 6 satir
  mikro/teklif.mjs     ithal = 1, sunucu yapistirmasi = 6 satir

Sayıların Okunması

Arıza yalıtımı ilk derste sıfır çıkmıştı: tek süreçte bir kusur altı isteğin üçünü yanıtsız bıraktı, ayakta kalan birim 0 oldu. Burada aynı bağlam durdurulduğunda üç uçtan 2’si 200 döndürmeye devam etti. Operasyon ucu 59 baytlık yanıtını tek başına üretti; ücretlendirme tarafına hiç bakmadı. Ölçülen fark budur ve biçemin asıl gerekçesidir.

Birleştirici ucun davranışı ikinci bir sayı üretir. Teklif ucu 200 döndürdü ama gövdesi değişti: net alanı null, eksik alanı 1. Bu kısmi yanıt (partial response) bir kaza değil, biçemin zorladığı bir tasarım kararıdır. Tek parça düzende gerekmiyordu, çünkü çağrı başarısız olamıyordu; burada yanıt sözleşmesine bir alan eklendi ve o alanın anlamını istemcinin bilmesi gerekiyor.

Yayın tarafında kazanç ölçüldü: her dağıtım biriminin kapanışı 1 dosyadır, dolayısıyla ücretlendirme kuralında bir satır değişirse yeniden yayınlanan dosya 1’dir. Tek parça düzende bu sayı 4, servis yönelimli düzende bolge alanı için 3’tü. Ödenen bedel de aynı çıktıda görünüyor: üç dosyanın her birinde 6 satır sunucu yapıştırma kodu tekrarlanıyor, toplam 18 satır. Bu tekrarı ortak bir dosyaya almak yayın bağlaşımını geri getirir — o dosya değiştiğinde üç birim birlikte yayınlanır.

Dağıtık Karmaşıklığın Sayısı

Biçemin faturası tek bir yerde toplanır: birleştirilmiş bir isteğin sonucu artık iki değil, alt servis sayısına bağlı olarak dört durumdan biridir. Ayakta olma durumları 2n2^n ile büyür; iki alt servis için 4 durum vardır ve ölçüm bunların ikisini gerçekten koşturdu. Tek parça düzende n=1n = 1 olduğu için durum sayısı 2’ydi: çalışıyor ya da çalışmıyor.

Durum sayısının büyümesi doğrudan bir sürdürülebilirlik maliyetidir. Her ek durum için bir karar gerekir — reddetmek mi, kısmi yanıt vermek mi, eski bir değeri kullanmak mı — ve o karar bir sözleşme alanına, bir sınama senaryosuna ve bir istemci davranışına dönüşür. Ölçümde 3 uç ve 2 durum sınandı; alt servis sayısı dörde çıksa aynı sınama kümesi 16 duruma bakmak zorunda kalır.

İkinci maliyet sözleşmelerin çoğalmasıdır. Servis yönelimli düzende öğrenilecek biçim sayısı 1’di; burada her servis kendi biçimini yayınlar. Ölçümde üç ucun üçü de farklı bir gövde biçiminde yanıt verdi: 22, 59 ve 56 baytlık üç ayrı sözleşme. Kanonik modelin kaldırılması bayt sayısını düşürdü ve yayın bağlaşımını kırdı, ama öğrenilecek ve sürüm uyumu izlenecek biçim sayısını servis sayısına eşitledi.

Özet

  • Mikroservis mimarisinde her servis kendi süreci, kendi verisi ve kendi sözleşmesiyle tek başına yayınlanabilen bir dağıtım birimidir; paylaşılan kanonik model ve ortak çağrı yüzeyi yoktur.
  • Ücretlendirme süreci durdurulduğunda üç uçtan 2’si 200 döndürmeye devam etti; tek parça düzende aynı kusur ayakta kalan birimi 0’a indirmişti.
  • Birleştirici uç kısmi yanıt verdi: net alanı null, eksik alanı 1: biçem, yanıt sözleşmesine yeni bir alan ve istemciye yeni bir karar yükledi.
  • Her dağıtım biriminin kapanışı 1 dosya olduğu için yeniden yayınlanan dosya sayısı 1’e indi; karşılığında üç dosyada 6’şar satır, toplam 18 satır sunucu yapıştırması tekrarlandı.
  • Birleştirilmiş isteğin sonuç durumu 2n2^n ile büyür: iki alt servis için 4 durum, tek parça düzende 2 durum.
  • Öğrenilecek gövde biçimi sayısı servis sayısına eşitlendi; ölçümde üç uç 22, 59 ve 56 baytlık üç ayrı sözleşme döndürdü.

Sonraki Adım

Buraya kadarki üç biçemde çağrı yönü hiç değişmedi: birleştirici, ücretlendirmeyi ve operasyonu adıyla biliyor, çağırıyor ve yanıtı bekliyor. Bilme yükümlülüğü ve bekleme, ölçülen bütün maliyetlerin ortak kaynağıdır — kısmi yanıt kararı da, sözleşme sayısı da buradan çıktı. Bir sonraki biçem çağrı yönünü tersine çevirir: ücretlendirme bir olay yayınlar, kimin dinlediğini bilmez ve yanıt beklemez. Sonraki ders olayın sistem sınırını geçtiğinde nelerin değiştiğini ölçer: yayıncının bildiği tüketici sayısı, yeni bir tüketici eklemek için düzenlenen dosya sayısı ve aynı olay iki kez geldiğinde iki tüketici tasarımının sonucu arasındaki sapma.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat