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:
toplabir olay alır,ozetdurumu 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.