LocalAI Prometheus Metrikleri ile İzleme
Üretim ortamında bir LLM servisi çalıştırıyorsunuz ve sabah işe geldiğinizde ekipten birinin “dün gece modeller çok yavaş yanıt verdi” dediğini duyuyorsunuz. Logları karıştırıyorsunuz, systemd journal’a bakıyorsunuz ama somut bir şey bulamıyorsunuz. İşte tam bu noktada Prometheus metrikleri devreye giriyor. LocalAI, yerleşik Prometheus endpoint’i sayesinde ne zaman, ne kadar yük altında çalıştığını, hangi modelin ne kadar sürede yanıt verdiğini ve sistem kaynaklarını nasıl kullandığını size eksiksiz raporlayabiliyor.
Bu yazıda LocalAI’ın Prometheus entegrasyonunu sıfırdan kuracağız, anlamlı dashboard’lar oluşturacağız ve gerçek senaryolarda alarm mekanizmalarını nasıl ayarlayacağınızı göreceğim. Grafana da dahil olacak tabii ki.
LocalAI’da Metrik Sistemi Nasıl Çalışıyor
LocalAI, Go ile yazılmış bir servis ve Go ekosisteminin Prometheus client kütüphanesi olan prometheus/client_golang ile doğrudan entegre geliyor. Bu sayede herhangi bir ek yapılandırma olmaksızın /metrics endpoint’i aktif oluyor.
Varsayılan kurulumda LocalAI 8080 portunda çalışır ve metrikler şu adresten erişilebilir:
http://localhost:8080/metrics
Şimdi şunu doğrulayalım:
curl -s http://localhost:8080/metrics | head -50
Eğer LocalAI çalışıyorsa şuna benzer bir çıktı görürsünüz:
# HELP localai_api_calls_total Total number of API calls
# TYPE localai_api_calls_total counter
localai_api_calls_total{model="llama-2-7b",status="success"} 142
localai_api_calls_total{model="mistral-7b",status="success"} 89
localai_api_calls_total{model="mistral-7b",status="error"} 3
# HELP localai_api_request_duration_seconds Duration of API requests
# TYPE localai_api_request_duration_seconds histogram
localai_api_request_duration_seconds_bucket{model="llama-2-7b",le="1"} 12
localai_api_request_duration_seconds_bucket{model="llama-2-7b",le="5"} 98
LocalAI’ın sunduğu temel metrikler şunlardır:
- localai_api_calls_total: Model ve durum (success/error) etiketiyle toplam API çağrısı sayısı
- localai_api_request_duration_seconds: İstek süresi histogramı, model bazında
- localai_tokens_generated_total: Toplam üretilen token sayısı
- localai_tokens_per_second: Anlık token üretim hızı
- localai_active_backends: Şu anda yüklenmiş ve aktif backend sayısı
- localai_model_load_duration_seconds: Model yükleme süresi (cold start ölçümü için kritik)
- localai_inference_duration_seconds: Sadece inference kısmının süresi (network overhead hariç)
Bu ayrım önemli: api_request_duration ile inference_duration arasındaki fark size network ve overhead maliyetini gösterir.
Docker Compose ile LocalAI ve Prometheus Kurulumu
Tipik bir üretim senaryosunu simüle edelim. LocalAI, Prometheus ve Grafana’yı birlikte ayağa kaldıracağız.
# docker-compose.yml
version: '3.8'
services:
localai:
image: quay.io/go-skynet/local-ai:latest-aio-cpu
container_name: localai
ports:
- "8080:8080"
volumes:
- ./models:/build/models
- ./localai-config:/build/config
environment:
- MODELS_PATH=/build/models
- THREADS=8
- CONTEXT_SIZE=4096
- DEBUG=false
restart: unless-stopped
deploy:
resources:
limits:
memory: 16G
prometheus:
image: prom/prometheus:latest
container_name: prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
- '--web.enable-lifecycle'
restart: unless-stopped
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/provisioning:/etc/grafana/provisioning
environment:
- GF_SECURITY_ADMIN_PASSWORD=gizlisifre123
- GF_USERS_ALLOW_SIGN_UP=false
restart: unless-stopped
volumes:
prometheus_data:
grafana_data:
Şimdi Prometheus konfigürasyonunu yazalım:
# prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
scrape_timeout: 10s
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
rule_files:
- "rules/localai_alerts.yml"
scrape_configs:
- job_name: 'localai'
static_configs:
- targets: ['localai:8080']
metrics_path: '/metrics'
scrape_interval: 10s
scrape_timeout: 8s
honor_labels: true
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
scrape_interval: 30s
scrape_interval için 10 saniye iyi bir başlangıç noktası. LocalAI gibi inference yük altında çalışan servislerde 5 saniyeye kadar indirip anlık değişimleri daha iyi yakalayabilirsiniz, ama Prometheus’un kendi yüküne de dikkat edin.
Alerting Kuralları: Gerçekten Önemli Olanları Yakalayın
Alarm konusunda çoğu kişi aşırıya kaçıyor. Her şey için alarm kurunca “alarm yorgunluğu” başlıyor ve önemli bildirimler gürültüde kayboluyor. Şu kural setini genellikle yeterli buluyorum:
# prometheus/rules/localai_alerts.yml
groups:
- name: localai_performance
interval: 30s
rules:
# P95 yanıt süresi 30 saniyeyi geçerse
- alert: LocalAIHighLatency
expr: |
histogram_quantile(0.95,
rate(localai_api_request_duration_seconds_bucket[5m])
) > 30
for: 5m
labels:
severity: warning
team: platform
annotations:
summary: "LocalAI yüksek gecikme süresi"
description: "{{ $labels.model }} modeli için P95 gecikme {{ $value | humanizeDuration }} seviyesinde, 5 dakikadır 30s üzerinde"
# Hata oranı %10 üzerine çıkarsa
- alert: LocalAIHighErrorRate
expr: |
rate(localai_api_calls_total{status="error"}[5m])
/
rate(localai_api_calls_total[5m])
> 0.10
for: 3m
labels:
severity: critical
team: platform
annotations:
summary: "LocalAI hata oranı yüksek"
description: "{{ $labels.model }} modeli hata oranı %{{ $value | humanizePercentage }}"
# Token üretim hızı aniden düşerse (olası OOM veya model çöküşü)
- alert: LocalAILowThroughput
expr: |
rate(localai_tokens_generated_total[5m]) < 5
and
rate(localai_api_calls_total[5m]) > 0
for: 10m
labels:
severity: warning
annotations:
summary: "Token üretim hızı düşük"
description: "Aktif istekler var ama token/s oranı {{ $value }} seviyesinde"
# Hiç aktif backend yoksa
- alert: LocalAINoActiveBackend
expr: localai_active_backends == 0
for: 2m
labels:
severity: critical
annotations:
summary: "LocalAI aktif backend yok"
description: "Tüm model backend'leri çevrimdışı, servis kullanılamıyor olabilir"
for parametresine dikkat edin. Anlık spike’lar için alarm üretmemek, gerçek problemleri yakalamak için for değeri kritik. 2-5 dakikalık for değerleri çoğu senaryoda yeterli.
Grafana Dashboard Yapılandırması
Grafana’yı provisioning ile otomatik yapılandırmak, “elle kurdum, bir daha nasıl kurarım bilmiyorum” durumundan sizi kurtarır.
# grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus:9090
isDefault: true
editable: true
jsonData:
timeInterval: "10s"
queryTimeout: "60s"
httpMethod: POST
Dashboard’ları JSON olarak da provisioning edebilirsiniz ama önce hangi PromQL sorgularının işe yaradığını bilmeniz gerekiyor. Grafana’da kullanacağınız temel sorgular:
İstek başarı oranı (son 5 dakika):
rate(localai_api_calls_total{status="success"}[5m])
/
rate(localai_api_calls_total[5m])
* 100
Model bazında P50, P90, P99 gecikme:
histogram_quantile(0.99,
sum(rate(localai_api_request_duration_seconds_bucket[5m])) by (le, model)
)
Saatlik token üretim toplamı:
increase(localai_tokens_generated_total[1h])
Model yükleme süreleri (cold start analizi):
localai_model_load_duration_seconds
Bu son sorgu özellikle disk I/O optimizasyonu yaparken değerli. Hangi modelin kaç saniyede yüklendiğini görmek, SSD vs HDD farkını veya model quantization’ın yükleme süresine etkisini ölçmenizi sağlar.
Node Exporter ile Sistem Metriklerini Bağlamak
LocalAI metrikleri tek başına yeterli değil. Bir modelin yavaş yanıt vermesinin sebebi inference algoritması olmayabilir, CPU throttling ya da bellek baskısı da olabilir. Node Exporter’ı da karışıma katmalısınız:
# docker-compose.yml'e ekleyin
node-exporter:
image: prom/node-exporter:latest
container_name: node-exporter
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.rootfs=/rootfs'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
restart: unless-stopped
network_mode: host
Node Exporter’ı network_mode: host ile çalıştırmanın nedeni, container network’ü yerine gerçek host metriklerini görmek. Özellikle GPU sunucularda bu önemli çünkü container içinden bazı sistem metrikleri doğru görünmeyebilir.
GPU kullanıyorsanız nvidia-smi çıktısını Prometheus’a aktaran nvidia-gpu-exporter veya dcgm-exporter da kurmanız gerekiyor. Bu olmadan GPU inference senaryolarında yarım kalmış bir görüntünüz olur.
Gerçek Dünya Senaryosu: Yük Testi ve Metrik Analizi
Bir müşteri projesinde 3 farklı model servis ediyorduk: mistral-7b-instruct, llama2-13b-chat ve küçük bir phi-2. Akşam 18:00-22:00 arası kullanım pikini göstermek için basit bir yük testi kurdum:
#!/bin/bash
# load_test.sh - Basit bir LocalAI yük test scripti
ENDPOINT="http://localhost:8080/v1/chat/completions"
MODELS=("mistral-7b-instruct" "llama2-13b-chat" "phi-2")
CONCURRENT=5
test_model() {
local model=$1
local payload=$(cat <<EOF
{
"model": "$model",
"messages": [
{"role": "user", "content": "Linux sistem yönetiminde en kritik 5 güvenlik önlemini listele"}
],
"max_tokens": 200,
"temperature": 0.7
}
EOF
)
start_time=$(date +%s%N)
response=$(curl -s -w "n%{http_code}" -X POST "$ENDPOINT"
-H "Content-Type: application/json"
-d "$payload")
end_time=$(date +%s%N)
http_code=$(echo "$response" | tail -1)
duration=$(( (end_time - start_time) / 1000000 ))
echo "Model: $model | Status: $http_code | Süre: ${duration}ms"
}
# Paralel test
for i in $(seq 1 $CONCURRENT); do
for model in "${MODELS[@]}"; do
test_model "$model" &
done
done
wait
echo "Yük testi tamamlandı"
Bu test çalışırken Prometheus’tan şu sorguyu izleyin:
# Anlık aktif istek sayısını kontrol et
curl -s "http://localhost:9090/api/v1/query?query=rate(localai_api_calls_total[1m])" |
python3 -m json.tool | grep value
Yük testi sonrası fark ettiğimiz şey ilginçti: llama2-13b-chat için P95 gecikme 45 saniyenin üzerine çıkıyordu ama phi-2 3 saniyenin altında kalıyordu. Prometheus’taki histogram verileri bunu net gösterdi ve modeli GGUF Q4_K_M formatından Q5_K_M formatına geçirme kararını bu veriye dayanarak verdik.
Metrik Verilerini Script ile Sorgulamak
Bazen Grafana’yı açmak yerine terminal’den hızlıca bir kontrol yapmak istersiniz. Prometheus HTTP API’sini doğrudan kullanabilirsiniz:
#!/bin/bash
# localai_health_check.sh
PROM_URL="http://localhost:9090"
echo "=== LocalAI Sağlık Durumu Raporu ==="
echo "Tarih: $(date)"
echo ""
# Toplam başarılı istek sayısı (son 1 saat)
echo "--- Son 1 Saatlik İstatistikler ---"
SUCCESS=$(curl -sg "${PROM_URL}/api/v1/query?query=increase(localai_api_calls_total{status='success'}[1h])" |
python3 -c "import sys,json; data=json.load(sys.stdin); print(sum(float(r['value'][1]) for r in data['data']['result']))")
echo "Başarılı istek: $SUCCESS"
# Hata sayısı
ERROR=$(curl -sg "${PROM_URL}/api/v1/query?query=increase(localai_api_calls_total{status='error'}[1h])" |
python3 -c "import sys,json; data=json.load(sys.stdin); print(sum(float(r['value'][1]) for r in data['data']['result']))")
echo "Hatalı istek: $ERROR"
# P95 gecikme
P95=$(curl -sg "${PROM_URL}/api/v1/query?query=histogram_quantile(0.95,rate(localai_api_request_duration_seconds_bucket[5m]))" |
python3 -c "import sys,json; data=json.load(sys.stdin); results=data['data']['result']; print(f'{float(results[0]["value"][1]):.2f}s' if results else 'Veri yok')")
echo "P95 Gecikme: $P95"
# Aktif backend sayısı
BACKENDS=$(curl -sg "${PROM_URL}/api/v1/query?query=localai_active_backends" |
python3 -c "import sys,json; data=json.load(sys.stdin); results=data['data']['result']; print(results[0]['value'][1] if results else '0')")
echo "Aktif Backend: $BACKENDS"
echo ""
echo "=== Rapor Sonu ==="
Bu scripti cron’a ekleyip sabahları mail ile raporlayabilirsiniz ya da monitoring sistemlerinizle entegre edebilirsiniz:
# Crontab - her sabah 08:00'de rapor gönder
0 8 * * * /opt/scripts/localai_health_check.sh | mail -s "LocalAI Günlük Rapor" [email protected]
Uzun Süreli Veri Saklama ve Thanos Entegrasyonu
Prometheus varsayılan olarak 15 günlük veri saklar (yapılandırmanızda 30 gün yaptık). Eğer aylık trend analizi yapmak istiyorsanız Thanos veya Cortex gibi uzun süreli depolama çözümlerine bakmanız gerekiyor.
Basit Thanos Sidecar kurulumu için:
# docker-compose.yml'e eklenecek Thanos sidecar
thanos-sidecar:
image: thanosio/thanos:latest
container_name: thanos-sidecar
command:
- sidecar
- --tsdb.path=/prometheus
- --prometheus.url=http://prometheus:9090
- --grpc-address=0.0.0.0:10901
- --http-address=0.0.0.0:10902
- --objstore.config-file=/etc/thanos/objstore.yml
volumes:
- prometheus_data:/prometheus
- ./thanos/objstore.yml:/etc/thanos/objstore.yml
depends_on:
- prometheus
# thanos/objstore.yml - S3 uyumlu depolama için
type: S3
config:
bucket: localai-metrics
endpoint: s3.amazonaws.com
region: eu-central-1
access_key: ${AWS_ACCESS_KEY}
secret_key: ${AWS_SECRET_KEY}
Küçük ekipler için MinIO ile kendi S3 uyumlu depolamanızı kurabilirsiniz. Bu kombinasyon, LocalAI metriklerini yıllarca saklamanızı ve mevsimsel kullanım örüntülerini analiz etmenizi sağlar.
Dikkat Edilmesi Gereken Noktalar
Birkaç pratik uyarı ile bitirelim:
- Cardinality kontrolü: LocalAI her model için ayrı etiket oluşturuyor. Çok sayıda model çalıştırıyorsanız (özellikle fine-tuned versiyonlar) Prometheus’un bellek kullanımı artabilir.
prometheus_tsdb_symbol_table_size_bytesmetriğini takip edin.
- Scrape timeout ayarı: LocalAI yoğun inference yaparken
/metricsendpoint’i yanıt vermekte gecikmez ama ihtiyatlı olmak içinscrape_timeoutdeğeriniscrape_interval‘dan biraz düşük tutun.
- Güvenlik:
/metricsendpoint’i varsayılan olarak herkese açık. Üretimde Nginx ile basic auth veya network policy ile sadece Prometheus’un erişmesine izin verin.
- Model label’larını standartlaştırın: LocalAI konfigürasyon dosyasındaki model adları ile Prometheus’ta görülen etiketler birebir eşleşiyor. Ekip içinde tutarlı bir isimlendirme politikası olmadan metrikler karmaşıklaşıyor.
Sonuç
LocalAI’ın Prometheus entegrasyonu, “acaba model çalışıyor mu?” sorusunu “model şu an 12 token/saniye üretiyor, P95 gecikme 8 saniye, son 1 saatte 3 hata aldı” düzeyine taşıyor. Bu fark, reaktif sorun çözmekten proaktif kapasite planlamasına geçmenizi sağlıyor.
Kurulumun karmaşık bir yanı yok, gerçekten. 30 dakikada temel stack’i ayağa kaldırabilir, birkaç saatte anlamlı alarm kuralları yazabilirsiniz. Zor olan kısım, hangi metriklerin sizin senaryonuzda önemli olduğunu anlamak. Bunu da ancak veriyle oynayarak, yük testleri yaparak ve “o gece ne olmuştu” sorularını metrik verileriyle cevaplayarak öğreniyorsunuz.
Eğer GPU inference yapıyorsanız DCGM Exporter’ı da bu stack’e ekleyin ve GPU utilization ile inference süresini birlikte grafikleyin. O görüntü, donanım yatırımı kararlarını çok daha kolay gerekçelendirmenizi sağlıyor.
