Metrik Toplama Yaklaşımları: Temel Farklar
Sistemlerimizin sağlığını ve performansını anlamak için metrik toplama kritik öneme sahip. Bu metrikleri elde etmenin iki ana yöntemi var: Push ve Pull. Kendi projelerimde ve danışmanlık verdiğim yerlerde bu iki modeli de bolca kullandım. Hangisini seçeceğimiz, altyapımızın yapısına, ölçeğine ve hangi metrikleri toplamak istediğimize göre değişiyor.
Push modelinde, metrikleri toplayan sistem (örneğin bir monitoring servisi) metrikleri gönderen uygulamadan veya servisten sürekli bilgi almaz. Bunun yerine, metrikleri toplayan servis, kendi başına gidip ilgili sistemlerden metrikleri çeker. Bu, bir nevi “çekme” operasyonudur. Pull modelinde ise, metrikleri toplayan servis sürekli olarak hedef sistemleri yoklar ve metrikleri talep eder. Bu yaklaşım, özellikle distributed sistemlerde ve mikroservis mimarilerinde oldukça yaygındır.
Push Modelinin Avantajları ve Dezavantajları
Push modelinde, metrikleri üreten uygulama veya servis, kendi belirlediği aralıklarla veya belirli olaylar gerçekleştiğinde metrikleri merkezi bir toplama noktasına gönderir. Bu, “agent” tabanlı çözümlerde sıkça karşımıza çıkar. Örneğin, bir uygulama kendi log’larına veya belirli bir metrik veritabanına (mesela InfluxDB’nin Telegraf agent’ı ile) metrikleri gönderebilir.
Push modelinin en büyük avantajı, hedef sistemin (metrik toplayıcı) sürekli olarak metrik üreticilerini sorgulamasına gerek kalmamasıdır. Metrik üreticisi, kendi kaynaklarını daha verimli kullanabilir ve ağ trafiğini daha kontrollü yönetebilir. Ayrıca, firewall arkasındaki veya NAT’lı sistemlerden metrik toplamak bu modelle daha kolay hale gelir. Ancak, her metrik üreticisinin kendi başına metrik göndermesi gerektiği için, merkezi bir toplama sisteminin tüm bu bağlantıları yönetmesi gerekebilir.
Pull Modelinin Avantajları ve Dezavantajları
Pull modelinde ise, metrikleri toplayan ana servis, metrikleri üretip sunan servisleri belirli aralıklarla yoklar. Prometheus gibi popüler monitoring araçları bu modeli kullanır. Prometheus, yapılandırılmış hedefleri (target) düzenli olarak sorgulayarak metrikleri toplar. Bu modelin en büyük avantajı, merkezi bir kontrol noktasına sahip olmasıdır. Hangi metriklerin, ne sıklıkla toplanacağı tek bir yerden yönetilebilir.
Pull modelinin dezavantajı, metrikleri toplayan servisin, tüm hedef sistemlere ulaşabilir olması gerektiğidir. Eğer bir hedef sistem firewall arkasındaysa veya ulaşılamıyorsa, metrikleri çekmek mümkün olmaz. Ayrıca, çok sayıda hedef sistem olduğunda, metrik toplayıcı üzerinde önemli bir yük oluşabilir. Ancak, bu yük genellikle yönetilebilir düzeydedir ve Prometheus gibi araçlar ölçeklenebilirlik konusunda oldukça başarılıdır.
Pull Modeli: Prometheus ile Somut Örnekler
Pull modeli, özellikle modern, dağıtık sistemlerde ve mikroservis mimarilerinde oldukça popüler. Bu modelin en bilinen örneği şüphesiz Prometheus. Prometheus, HTTP üzerinden /metrics endpoint’ini sorgulayarak metrikleri toplar. Bu metrikler genellikle Prometheus’un kendi text-based formatında veya OpenMetrics formatında sunulur.
Bir örnek üzerinden gidelim. Diyelim ki bir FastAPI uygulamamız var ve bu uygulamanın bazı temel metriklerini toplamak istiyoruz. Bunun için prometheus_client kütüphanesini kullanabiliriz.
from fastapi import FastAPI
from prometheus_client import Counter, Histogram, Gauge, generate_latest
from starlette.responses import Response
import time
import random
app = FastAPI()
# Metrikleri tanımlayalım
REQUEST_COUNT = Counter('http_requests_total', 'Total number of HTTP requests', ['method', 'endpoint', 'status_code'])
REQUEST_LATENCY = Histogram('http_request_duration_seconds', 'HTTP request latency in seconds', ['method', 'endpoint'])
ACTIVE_USERS = Gauge('active_users', 'Number of active users')
@app.middleware("http")
async def add_metrics(request, call_next):
start_time = time.time()
method = request.method
endpoint = request.url.path
response = await call_next(request)
status_code = response.status_code
process_time = time.time() - start_time
REQUEST_COUNT.labels(method=method, endpoint=endpoint, status_code=status_code).inc()
REQUEST_LATENCY.labels(method=method, endpoint=endpoint).observe(process_time)
# Rastgele bir aktif kullanıcı sayısı simüle edelim
if random.random() > 0.5:
ACTIVE_USERS.set(random.randint(10, 100))
else:
ACTIVE_USERS.dec(random.randint(0, 10))
return response
@app.get("/metrics")
async def metrics():
return Response(generate_latest(), media_type="text/plain")
@app.get("/")
async def homepage():
return {"message": "Hello, World!"}
@app.get("/slow")
async def slow_page():
time.sleep(random.uniform(0.5, 2.0))
return {"message": "This is a slow page."}
# Örnek kullanım:
#uvicorn main:app --reload
#Prometheus sunucusunu bu uygulamayı scrape edecek şekilde yapılandırın.
Bu FastAPI uygulaması, gelen her isteği izleyecek ve REQUEST_COUNT, REQUEST_LATENCY, ACTIVE_USERS gibi metrikleri üretecektir. Prometheus sunucusunu, bu uygulamanın /metrics endpoint’ini belirli aralıklarla sorgulayacak şekilde yapılandırdığınızda, pull modeli çalışmış olur.
Prometheus’un scrape_configs bölümünde bu hedefi şöyle tanımlayabiliriz:
scrape_configs:
- job_name: 'my_fastapi_app'
static_configs:
- targets: ['localhost:8000'] # FastAPI uygulamanızın çalıştığı yer
Bu yapılandırma ile Prometheus, her 15 saniyede bir (varsayılan scrape aralığı) http://localhost:8000/metrics adresinden metrikleri çekecektir. Bu, merkezi bir kontrol ve düzenli veri toplama sağlar.
Push Modeli: Metrikleri Merkeze Göndermek
Push modeli, pull modelinin tam tersi bir işleyişe sahiptir. Metrikleri üreten servis veya ajan, metrikleri aktif olarak merkezi bir toplama noktasına gönderir. Bu model, özellikle ağ topolojisinin karmaşık olduğu, firewall kurallarının sıkı olduğu veya kısa ömürlü iş parçacıklarının metrik üretmesi gerektiği durumlarda daha kullanışlıdır.
Örneğin, bir Docker container’ı içinde çalışan bir uygulama düşünelim. Bu container’ın ömrü kısa olabilir ve Prometheus’un onu doğrudan sorgulaması her zaman mümkün olmayabilir. Bu durumda, container içindeki bir ajan, metrikleri toplayıp daha kalıcı bir veritabanına (örneğin InfluxDB veya Graphite) gönderebilir.
Bir başka yaygın kullanım alanı ise, merkezi bir log toplama sistemiyle entegre metriklerdir. Log’larda belirli hata desenlerini yakalayıp, bu desenlere karşılık gelen metrikleri artırabiliriz.
import time
import requests
import random
# Metrik göndereceğimiz endpoint (örneğin InfluxDB'nin Telegraf'ı)
METRIC_ENDPOINT = "http://your-metric-collector:8086/write?db=mydb" # InfluxDB örneği
def send_metric(measurement, tags, fields):
timestamp = int(time.time() * 1e9) # Nanosecond precision for InfluxDB
tag_str = ",".join([f"{k}={v}" for k, v in tags.items()])
field_str = ",".join([f"{k}={v}" for k, v in fields.items()])
payload = f"{measurement},{tag_str} {field_str} {timestamp}"
try:
response = requests.post(METRIC_ENDPOINT, data=payload, timeout=5)
if response.status_code != 204: # InfluxDB write success is 204 No Content
print(f"Error sending metric: {response.status_code} - {response.text}")
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
# Uygulama mantığı simülasyonu
def process_request(request_id):
tags = {"service": "my_app", "request_id": request_id}
start_time = time.time()
try:
# İşlem simülasyonu
time.sleep(random.uniform(0.1, 1.5))
if random.random() < 0.1: # %10 hata oranı
raise Exception("Internal processing error")
fields = {"duration_ms": (time.time() - start_time) * 1000, "status": "success"}
send_metric("request_latency", tags, fields)
print(f"Request {request_id} processed successfully.")
except Exception as e:
fields = {"duration_ms": (time.time() - start_time) * 1000, "status": "error", "error_message": str(e)}
send_metric("request_latency", tags, fields)
print(f"Request {request_id} failed: {e}")
# Ana döngü
if __name__ == "__main__":
for i in range(10): # 10 istek simüle edelim
process_request(f"req_{i}")
time.sleep(random.uniform(0.5, 2.0))
Bu kodda, process_request fonksiyonu her isteği işledikten sonra, işlemin süresini ve sonucunu (başarılı/hatalı) belirten metrikleri send_metric fonksiyonu aracılığıyla merkezi bir endpoint’e gönderiyor. Bu endpoint, bir InfluxDB veritabanına yazan Telegraf ajanı olabilir.
Neden Bu Kadar Çok Metrik Topluyoruz?
Metrik toplamanın temel amacı, sistemlerimizin davranışını anlamak, sorunları tespit etmek ve performansını optimize etmektir. Üretim ortamlarında karşılaştığım bazı kritik metrikler şunlar:
- CPU Kullanımı: Sunucuların veya container’ların işlemci yükü. Yüksek CPU kullanımı, performans sorunlarının veya yetersiz kaynakların bir işareti olabilir.
- Bellek Kullanımı: Uygulamaların ne kadar RAM kullandığı. Bellek sızıntıları veya yetersiz RAM, sistem kararlılığını ciddi şekilde etkileyebilir.
- Disk G/Ç: Disk okuma/yazma hızları. Yavaş diskler, veritabanı veya dosya sistemi işlemlerini yavaşlatarak genel performansı düşürebilir.
- Ağ Trafiği: Gelen ve giden ağ paketlerinin boyutu ve sayısı. Ağ darboğazları veya anormal trafik desenleri tespit edilebilir.
- Hata Oranları: Uygulama içindeki veya HTTP isteklerindeki hata sayıları (örneğin, 5xx HTTP hataları).
- Gecikme Süreleri (Latency): İsteklerin ne kadar sürede yanıtlandığı. Yüksek gecikme süreleri, kullanıcı deneyimini olumsuz etkiler.
Bu metrikleri toplamak, sadece sorun olduğunda değil, normal operasyon sırasında da sistemin “normalini” anlamamızı sağlar. Bu “baseline” bilgisi, anormallikleri (örneğin, normalden %50 daha yüksek CPU kullanımı) tespit etmek için çok değerlidir.
Hangi Modeli Ne Zaman Kullanmalı?
İki modelin de kendi kullanım alanları var. Seçim yaparken dikkate almamız gereken bazı faktörler şunlardır:
- Altyapının Yapısı: Mikroservis mi, monolit mi? Container’lar mı, sanal makineler mi? Ağ yapısı ne kadar karmaşık?
- Metrik Üreticisinin Karakteristiği: Kısa ömürlü mü, sürekli çalışan mı? Ağ erişimi kısıtlı mı? Kendi metrik endpoint’ini sunabiliyor mu?
- Ölçeklenebilirlik İhtiyacı: Ne kadar çok servis ve metrik toplanacak? Merkezi toplayıcının yükü ne kadar olacak?
- Ağ Güvenliği ve Erişilebilirlik: Firewall kuralları, NAT arkasındaki servisler gibi durumlar.
- Operasyonel Karmaşıklık: Hangi modelin yönetimi daha kolay?
Kendi Deneyimlerimden Örnekler
Bir üretim ERP sistemi üzerinde çalışırken, hem ana uygulamayı (monolitik bir yapıdaydı) hem de arka planda çalışan çeşitli işleyicileri izlememiz gerekiyordu. Ana uygulama için Prometheus ile pull modelini kullandık. Uygulamanın /metrics endpoint’i üzerinden CPU, bellek, istek sayısı ve gecikme gibi temel metrikleri topluyorduk.
Ancak, arka planda çalışan ve belirli periyotlarda çalışan (örneğin, saatlik fatura oluşturma, günlük raporlama) işleyiciler vardı. Bu işleyiciler bazen tek seferlik çalışıyor, bazen de birkaç dakika içinde bitiyordu. Bu kısa ömürlü ve bazen de firewall arkasında kalabilen işleyiciler için push modelini tercih ettik. Her işleyici, kendi çalıştığı süre boyunca ürettiği metrikleri (işlem süresi, başarılı/hatalı kayıt sayısı gibi) doğrudan bir InfluxDB’ye gönderiyordu. Bu sayede, hem ana uygulamanın sağlığını anlık olarak takip edebiliyor hem de arka plan işleyicilerinin performansını detaylı olarak analiz edebiliyorduk. Bu karma yaklaşım, yüksek erişilebilirlik hedefimize ulaşmamızda kritik rol oynadı.
Bir başka senaryoda, mobil uygulamamızın performansı için, uygulamanın kendisinden crash raporları ve performans metriklerini (ekran yüklenme süreleri, ağ isteği süreleri) topluyorduk. Bu metrikler, genellikle mobil cihazlardan doğrudan merkezi bir servise push ediliyordu. Çünkü mobil cihazlar sürekli olarak bizim sunucularımıza pull yapmak için açık tutulamazdı ve ağ bağlantıları da güvenilir değildi. Bu tür durumlarda push modeli, veri toplama için neredeyse tek seçenek haline geliyor.
Hangi Durumlarda Pull Modeli Daha Avantajlı?
- Servis Keşfi Kolaylığı: Eğer servislerinizde bir servis keşif mekanizması (service discovery) varsa, Prometheus bunları otomatik olarak bulup metrikleri çekebilir. Bu, özellikle dinamik ortamlarda (Kubernetes gibi) büyük kolaylık sağlar.
- Merkezi Kontrol: Metrik toplama sıklığı, formatı gibi ayarlar tek bir yerden yönetilir.
- Ağ Yükü Dağılımı: Metrikleri çekme yükü, metrik toplayıcı (Prometheus) üzerinde olur. Metrik üreten servislerin ek bir iş yükü olmaz (sadece endpoint sunmak).
- Daha Güvenilir Veri: Hedef servislerin çalışır durumda olup olmadığını, Prometheus düzenli sorgularla kontrol eder. Eğer bir servis yanıt vermezse, bu durum hemen tespit edilir.
Hangi Durumlarda Push Modeli Daha Avantajlı?
- Firewall Arkasındaki Sistemler: Metrik üreticisi, toplama noktasına doğrudan erişemiyorsa.
- Kısa Ömürlü İş Parçacıkları: Bir script veya kısa süreli çalışan bir container’dan metrik toplamak gerektiğinde.
- Event-Driven Metrikler: Belirli bir olayın ardından metrik göndermek için.
- Düşük Bant Genişliği Ortamları: Metrik üreticisinin, toplama noktasına belirli aralıklarla toplu veri göndermesi gerektiğinde.
Metriklerin Görselleştirilmesi ve Analizi
Metrikleri toplamak sadece ilk adımdır. Asıl değer, bu metrikleri anlamlı hale getirmekte yatar. Prometheus ile toplanan metrikler genellikle Grafana gibi görselleştirme araçlarıyla birlikte kullanılır. Grafana, Prometheus’tan aldığı metriklerle zengin ve interaktif dashboard’lar oluşturmamızı sağlar.
Bir dashboard’da genellikle şu paneller bulunur:
- Genel Durum Paneli: CPU, bellek, disk kullanımı gibi temel sistem metriklerini gösterir.
- Uygulama Performans Paneli: İstek sayısı, hata oranları, gecikme süreleri gibi uygulama özel metrikleri içerir.
- Hata Analiz Paneli: Hata türlerini ve sıklıklarını gösteren grafikler.
- Kapasite Planlama Paneli: Kaynak kullanım trendlerini göstererek gelecekteki ihtiyaçları tahmin etmeye yardımcı olur.
Grafana’da oluşturduğumuz bir “request_latency” histogram grafiğini düşünelim. Bu grafik, belirli bir zaman diliminde isteklerin ne kadar sürede tamamlandığını gösterir. Örneğin, %50’lik dilim (p50), isteklerin %50’sinin bu sürenin altında tamamlandığını ifade eder. %99’luk dilim (p99) ise en yavaş %1’lik isteklerin ne kadar sürdüğünü gösterir. Bu metrikler, kullanıcı deneyimini anlamak için kritik öneme sahiptir.
# Grafana PromQL sorgusu örneği:
sum(rate(http_request_duration_seconds_bucket{job="my_fastapi_app", le="0.5"}[5m])) by (le)
/
sum(rate(http_request_duration_seconds_count{job="my_fastapi_app"}[5m])) by (le)
Bu sorgu, son 5 dakika içindeki isteklerin %50’sinin (p50) 0.5 saniye altında olup olmadığını gösteren bir grafik çizer.
Sonuç: Doğru Modeli Seçmek
Metrik toplama için Push ve Pull modelleri arasındaki seçim, tamamen projenizin özel gereksinimlerine bağlıdır. Her iki modelin de güçlü ve zayıf yönleri vardır. Genellikle en iyi yaklaşım, altyapınızın farklı bileşenleri için en uygun olan modeli seçmek veya her iki modeli de bir arada kullanmaktır.
Pull modeli, merkezi kontrol ve servis keşfi gerektiren modern, dağıtık sistemler için harika bir seçenektir. Prometheus bu modelin en popüler temsilcisidir. Push modeli ise, ağ kısıtlamaları olan, kısa ömürlü veya event-driven sistemler için daha esnek bir çözüm sunar.
Unutmamak gerekir ki, metrik toplama sadece bir araçtır. Asıl amaç, bu verileri kullanarak sistemlerimizi daha güvenilir, performanslı ve anlaşılır hale getirmektir. Bu nedenle, doğru metrikleri seçmek, onları doğru şekilde toplamak ve anlamlı bir şekilde görselleştirmek, modern sistem operasyonlarının ayrılmaz bir parçasıdır.