İçeriğe geç
academia.sh

Ders 05 / 19

Enstrümantasyon Standartları

Telemetri toplamanın uygulama kodundan ayrılması: aynı arayüzün iki toplayıcı gerçekleştirmesiyle karşılanması, gerçekleştirme değiştiğinde dokunulan dosya sayısının bağlı ve arayüzlü yerleşimde ölçülmesi ve toplayıcı adının kaç uygulama dosyasında geçtiğinin sayılması.

İçindekiler

Üç sinyal de kodda üretiliyor, ama her birinin nereye yazılacağı servis kodunun içinde duruyor: günlükçü kendi dosyasını açıyor, ölçütler bir uçtan sunuluyor, aralıklar başka bir dosyaya düşüyor. Bu bağ ilk bakışta zararsızdır. Zararı ancak toplama biçimi değiştiğinde görünür ve görüldüğü anda ölçülebilir bir sayıya dönüşür: kaç dosyaya dokunmak gerekti.

Satıcıdan bağımsız enstrümantasyon, uygulama kodunun telemetriyi nereye ve nasıl gönderdiğini bilmemesidir. Bu dersin kurduğu şey bir ad değil, bir arayüztür: uygulama kodu yalnız “şu olay oldu” der; olayın dosyaya mı yazılacağı, sayılacağı mı, bir yere mi gönderileceği başka bir yerin işidir. Ölçü de tek bir soruya iner — gerçekleştirme değişince kaç dosya değişir.

Aynı Arayüzün İki Gerçekleştirmesi

Arayüz iki işlemden oluşur: topla bir olayı alır, ozet toplananın durumunu döndürür. İki gerçekleştirme davranış olarak taban tabana zıttır. Birincisi her olayı ayrı satır olarak diske yazar; ikincisi tekil olayı hiç saklamaz, yalnız türüne göre sayar.

// toplayicilar.mjs — ayni arayuzun iki gerceklestirmesi; ikisi de topla ve ozet uygular
import { appendFileSync, writeFileSync } from "node:fs";
export const dosyaToplayici = (dosya) => {        // her olayi ayri satir olarak yazar
  writeFileSync(dosya, "");
  return { topla: (o) => appendFileSync(dosya, JSON.stringify(o) + "\n"),
    ozet: () => `olaylar ${dosya} dosyasinda` };
};
export const ozetToplayici = () => {              // olaylari turune gore sayar, tekil olay yazmaz
  const say = new Map();
  return { topla: (o) => say.set(o.tur, (say.get(o.tur) ?? 0) + 1),
    ozet: () => [...say].map(([t, n]) => `${t}=${n}`).join(" ") };
};

Uygulama kodunun gördüğü yüz ayrıdır. Servis kodu topla çağırmaz; üç sinyale karşılık gelen üç işlem çağırır ve olayın nereye gittiğini bilmez. Bağlama tek bir dosyada, tek bir satırda yapılır.

// olcum.mjs — uygulama kodunun gordugu tek yuz; hangi toplayicinin baglandigini bilmez
import { toplayici } from "./baglanti.mjs";
export const gunluk = (alanlar) => toplayici.topla({ tur: "gunluk", ...alanlar });
export const olcut = (ad, deger) => toplayici.topla({ tur: "olcut", ad, deger });
export const aralik = (ad, sure) => toplayici.topla({ tur: "iz", ad, sure });
export const ozet = () => toplayici.ozet();
// baglanti.mjs — tek baglama noktasi; gerceklestirme yalniz bu satirda seciliyor
import { dosyaToplayici } from "./toplayicilar.mjs";
export const toplayici = dosyaToplayici("olay-arayuzlu.txt");        // BAGLAMA

TL5 — beş servis ayrı dağıtım birimleridir, dolayısıyla ayrı kaynak dosyalardır. Gerekçe: ölçülen şey bir değişikliğin yayılma yüzeyidir; tek kaynak dosyadan rol argümanıyla türetilen bir düzenekte her değişiklik tanım gereği tek dosyaya düşer ve ölçü anlamını yitirir. Beş dosya aynı şablondan üretilir, aralarındaki tek fark rol adı ve porttur.

İki Yerleşim

İki yerleşim aynı işi yapar. Bağlı yerleşimde servis dosyası toplayıcıyı adıyla çağırır ve olayları kendisi biçimlendirir. Arayüzlü yerleşimde servis dosyasında hiçbir toplayıcı adı geçmez.

// sablon-bagli.mjs — ROL ve PORT yerine konarak bes servis dosyasi uretilir
import { createServer } from "node:http";
import { dosyaToplayici } from "./toplayicilar.mjs";
const toplayici = dosyaToplayici("olay-bagli.txt");                  // BAGLAMA
let istek = 0;
createServer((i, y) => {
  if (i.url === "/ozet") { y.end(toplayici.ozet()); return; }
  const t0 = performance.now(); istek += 1;
  toplayici.topla({ tur: "gunluk", servis: "ROL", olay: "odunc istegi islendi" });
  toplayici.topla({ tur: "olcut", ad: "ROL_istek", deger: istek });
  toplayici.topla({ tur: "iz", ad: "ROL/is", sure: Math.round(performance.now() - t0) });
  y.end("bitti");
}).listen(PORT);
// sablon-arayuzlu.mjs — ROL ve PORT yerine konarak bes servis dosyasi uretilir
import { createServer } from "node:http";
import { gunluk, olcut, aralik, ozet } from "./olcum.mjs";
let istek = 0;
createServer((i, y) => {
  if (i.url === "/ozet") { y.end(ozet()); return; }
  const t0 = performance.now(); istek += 1;
  gunluk({ servis: "ROL", olay: "odunc istegi islendi" });
  olcut("ROL_istek", istek);
  aralik("ROL/is", Math.round(performance.now() - t0));
  y.end("bitti");
}).listen(PORT);

Ölçüm

Ölçüm geçişi gerçekten yapar. Önce iki yerleşim de dosya toplayıcısıyla koşar, sonra gecir işlevi ilgili dosyalarda gerçekleştirmeyi değiştirir, sonra ikisi de yeniden koşar. Dokunulan dosya sayısı tahmin edilmez: geçişten önce alınan dizin kopyasıyla sonrası karşılaştırılır.

SERVIS="odunc uyelik katalog ucretlendirme bildirim"
rm -rf bagli arayuzlu bagli-once arayuzlu-once; mkdir -p bagli arayuzlu
cp toplayicilar.mjs bagli/ ; cp toplayicilar.mjs olcum.mjs baglanti.mjs arayuzlu/
i=0
for s in $SERVIS; do
  sed -e "s/ROL/$s/g" -e "s/PORT/$((9501 + i))/" sablon-bagli.mjs > bagli/$s.mjs
  sed -e "s/ROL/$s/g" -e "s/PORT/$((9511 + i))/" sablon-arayuzlu.mjs > arayuzlu/$s.mjs
  i=$((i + 1))
done
gecir() {   # dosya toplayicisini ozet toplayicisiyla degistirir
  perl -pi -e 's/dosyaToplayici/ozetToplayici/g; s/\("olay-[a-z]+\.txt"\)/()/' "$1"
}
kosur() {   # $1 dizininde odunc servisini ayaga kaldirir, 5 istek atar, ozeti yazar
  (cd "$1" && node odunc.mjs) & PID=$!
  sleep 0.7
  for n in 1 2 3 4 5; do curl -s -o /dev/null "http://127.0.0.1:$2/is"; done
  printf '%-10s %s\n' "$1" "$(curl -s http://127.0.0.1:$2/ozet)"
  kill $PID 2>/dev/null; wait $PID 2>/dev/null
}

echo "gecis oncesi:"
kosur bagli 9501
kosur arayuzlu 9511
echo "ilk olay kaydi: $(head -1 bagli/olay-bagli.txt)"

cp -r bagli bagli-once; cp -r arayuzlu arayuzlu-once
for s in $SERVIS; do gecir bagli/$s.mjs; done
gecir arayuzlu/baglanti.mjs

echo
echo "gecis sonrasi:"
kosur bagli 9501
kosur arayuzlu 9511

echo
printf '%-10s%34s%28s\n' yerlesim "toplayici adi gecen uygulama dosyasi" "gecis icin dokunulan dosya"
for y in bagli arayuzlu; do
  ad=$(grep -l "Toplayici" $y/*.mjs | grep -v toplayicilar | grep -v baglanti | wc -l | tr -d ' ')
  dk=$(diff -rq $y-once $y | wc -l | tr -d ' ')
  printf '%-10s%34s%28s\n' "$y" "$ad" "$dk"
done
echo "dokunulan dosyalar (arayuzlu): $(diff -rq arayuzlu-once arayuzlu | awk '{print $4}' | paste -sd' ' -)"
gecis oncesi:
bagli      olaylar olay-bagli.txt dosyasinda
arayuzlu   olaylar olay-arayuzlu.txt dosyasinda
ilk olay kaydi: {"tur":"gunluk","servis":"odunc","olay":"odunc istegi islendi"}

gecis sonrasi:
bagli      gunluk=5 olcut=5 iz=5
arayuzlu   gunluk=5 olcut=5 iz=5

yerlesim  toplayici adi gecen uygulama dosyasi  gecis icin dokunulan dosya
bagli                                      5                           5
arayuzlu                                   0                           1
dokunulan dosyalar (arayuzlu): arayuzlu/baglanti.mjs

Beş Dosya ile Bir Dosya

İki yerleşim de geçişten sonra aynı özeti veriyor: gunluk=5 olcut=5 iz=5. Davranış eşit, maliyet değil. Bağlı yerleşimde beş dosya değişti, arayüzlü yerleşimde bir. Değişen tek dosyanın adı da basılıyor: baglanti.mjs. Beş servis dosyasının hiçbirine dokunulmadı — geçişten önceki ve sonraki hâlleri bayt bayt aynı.

Orta sütun farkın nedenini veriyor. Bağlı yerleşimde toplayıcı adı beş uygulama dosyasında geçiyor, arayüzlü yerleşimde sıfırında. Dokunulan dosya sayısı bunun doğrudan sonucudur: bir ad kaç yerde yazılıysa, o adı değiştirmek o kadar yere dokunmayı gerektirir. Arayüzün yaptığı şey adı tek bir yere hapsetmektir; yaptığı başka bir şey yoktur.

Sayının nasıl büyüdüğü de ölçünün parçası. Beş servis bugün beş dosya demek; sistem büyüdükçe bu sayı servis sayısıyla birlikte artar ve her artış aynı geçişi bir kat daha pahalı yapar. Arayüzlü yerleşimde ise sayı servis sayısından bağımsızdır: elli servis olsa da bağlama noktası birdir. Bu, önceki derslerdeki ölçüt alanının istek sayısından bağımsız olmasıyla aynı biçimdedir — maliyet büyüyen bir şeye değil, sabit bir şeye bağlanmıştır.

Arayüzün bedeli de ortadadır ve küçümsenmemelidir. İki dosya fazladan yazıldı (olcum.mjs ve baglanti.mjs), uygulama kodu ile toplayıcı arasına bir dolaylılık girdi ve arayüzün kendisi bir karar hâline geldi: topla yalnız tur alanı olan bir nesne alıyor, dolayısıyla bir toplayıcının ihtiyaç duyduğu bir bilgi bu biçime sığmıyorsa arayüz değişmek zorunda. Arayüz değişikliği ise uygulama dosyalarına geri döner — kazanılan bağımsızlık, arayüzün doğru çizildiği ölçüde bağımsızlıktır.

Bir sınır daha var. Geçiş burada bir satırın değiştirilmesiyle yapıldı, çünkü ölçülen şey değişikliğin yayılma yüzeyiydi. Toplayıcının çalışma anında seçilmesi, birden çok toplayıcıya aynı anda yazılması ya da bir toplayıcı ayakta değilken olayların ne olacağı bu dersin ölçüsünün dışındadır; bunların hiçbiri dosya sayısını değiştirmez.

Özet

  • Arayüz iki işlemden ibaret: topla bir olay alır, ozet durumu döndürür; iki gerçekleştirme aynı olayları biri diske yazarak, öteki yalnız sayarak karşıladı.
  • Geçişten sonra iki yerleşim de aynı özeti verdi (gunluk=5 olcut=5 iz=5); fark davranışta değil, değişikliğin maliyetindeydi.
  • Toplayıcı adı bağlı yerleşimde 5 uygulama dosyasında geçiyor, arayüzlü yerleşimde 0’ında.
  • Aynı geçiş bağlı yerleşimde 5 dosyaya, arayüzlü yerleşimde 1 dosyaya dokundu; beş servis dosyası geçiş öncesi ve sonrası bayt bayt aynı kaldı.
  • Bağlı yerleşimde maliyet servis sayısıyla büyür, arayüzlü yerleşimde sabittir; karşılığında iki dosyalık dolaylılık ve arayüzün kendisinin bir karara dönüşmesi vardır.

Sonraki Adım

Üç sinyal artık kodda üretiliyor, biri diğerinin yerini almıyor ve hiçbiri toplayıcıya bağlı değil. Ama hâlâ üç ayrı yerde duruyorlar: bir soru sorulduğunda günlük ayrı, ölçüt ayrı, iz ayrı okunuyor ve aralarındaki bağ her seferinde elle kuruluyor. İkinci ders bağıntı kimliğini üretti, dördüncü ders iz bağlamını sınırdan geçirdi; ikisi de aynı isteği adlandırıyor, ama hiçbir kayıt üçünü bir arada tutmuyor. Sonraki ders bunu yapar ve konuyu kapatır: üç sinyal tek olayda birleştirilir, bir sorunun birleştirmeli ve birleştirmesiz kaç adımda ve kaç sinyalle yanıtlandığı karşılaştırılır.

İ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