ELK Stack ile Uygulama APM İzleme Kurulumu
Prodüksiyonda bir uygulama yavaşladığında ilk yapacağın şey muhtemelen sunucu metriklerine bakmak olur. CPU mu? RAM mi? Disk I/O mu? Ama çoğu zaman sorun bunların hiçbirinde değildir. Veritabanı sorgusu 800ms sürüyor, bir dış servis timeout veriyor ya da belirli bir endpoint her istekte memory leak yapıyor. İşte bu noktada klasik metrik izleme yetmez, APM’e ihtiyaç duyarsın. Bu yazıda ELK Stack üzerine kurulu bir APM çözümünü sıfırdan nasıl kuracağını, gerçek hayatta nasıl kullanacağını ve en önemlisi bu kurulumdan gerçekten değer nasıl çıkaracağını anlatacağım.
APM Nedir ve Neden ELK?
APM, Application Performance Monitoring’in kısaltması. Temelde uygulamanın içine girerek her işlemi, her sorguyu, her dış servis çağrısını milisaniye düzeyinde takip etmek demek. Datadog, New Relic gibi SaaS çözümler var elbette, ama Türkiye’deki çoğu şirket için ya bütçe problemi, ya da KVKK/veri yerleşimi sebebiyle bu seçenekler masada değil. Elastic APM ise ELK Stack’in native bir bileşeni ve zaten Elasticsearch/Kibana altyapın varsa üstüne APM Server ekleyerek dakikalar içinde çalışır hale getirebilirsin.
Elastic APM’in mimari olarak nasıl çalıştığını anlamak önemli:
- APM Agent: Uygulamanın içine eklenen kütüphane. Java, Python, Node.js, Go, PHP, Ruby, .NET için resmi agent var.
- APM Server: Agent’lardan gelen verileri alıp Elasticsearch’e yazan ara katman.
- Elasticsearch: Tüm trace, transaction ve metrik verisinin depolandığı yer.
- Kibana APM UI: Görselleştirme ve analiz arayüzü.
Ortam Hazırlığı
Ben bu kurulumu Ubuntu 22.04 üzerinde yapacağım. Elasticsearch ve Kibana’nın halihazırda kurulu olduğunu varsayıyorum. Yoksa önce onları kurman lazım ama o ayrı bir konu. APM Server için minimum 2 CPU ve 4GB RAM öneririm, prodüksiyonda trafik yoğunluğuna göre bu rakam yukarı çıkabilir.
Önce sistemi güncel tutalım ve gerekli paketleri ekleyelim:
apt update && apt upgrade -y
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | tee /etc/apt/sources.list.d/elastic-8.x.list
apt update
APM Server Kurulumu
apt install apm-server -y
systemctl enable apm-server
Şimdi ana konfigürasyon dosyasını düzenleyelim. /etc/apm-server/apm-server.yml dosyasını açıp aşağıdaki gibi yapılandır:
apm-server:
host: "0.0.0.0:8200"
# Secret token - agent'larla authentication için
auth:
secret_token: "buraya-guclu-bir-token-yaz"
# RUM (Real User Monitoring) etkinleştirmek istersen
rum:
enabled: true
allow_origins: ["https://uygulamaniz.com"]
output.elasticsearch:
hosts: ["localhost:9200"]
username: "elastic"
password: "elasticsearch-sifren"
# SSL kullanıyorsan
# ssl:
# certificate_authorities: ["/etc/elasticsearch/certs/ca.crt"]
setup.kibana:
host: "localhost:5601"
username: "elastic"
password: "kibana-sifren"
Konfigürasyonu test edip servisi başlatalım:
apm-server test config
apm-server setup --index-management
systemctl start apm-server
systemctl status apm-server
apm-server setup komutu Elasticsearch’te gerekli index template’lerini ve ILM policy’lerini oluşturuyor. Bunu atlamayın, sonradan “neden veri gelmiyor” diye saatlerce uğraşırsınız.
Java Uygulamasına APM Agent Entegrasyonu
Diyelim ki Spring Boot uygulamanız var. Java agent’ı JAR olarak geliyor ve JVM parametresiyle ekleniyor, kodda hiçbir değişiklik yapmana gerek yok. Bu özellikle legacy uygulamalarda büyük avantaj.
# Agent'ı indir
mkdir -p /opt/elastic-apm
wget -O /opt/elastic-apm/elastic-apm-agent.jar
https://search.maven.org/remotecontent?filepath=co/elastic/apm/elastic-apm-agent/1.44.0/elastic-apm-agent-1.44.0.jar
Uygulamayı başlatırken JVM parametrelerini ekle:
java -javaagent:/opt/elastic-apm/elastic-apm-agent.jar
-Delastic.apm.service_name="siparis-servisi"
-Delastic.apm.server_url="http://apm-server-ip:8200"
-Delastic.apm.secret_token="buraya-guclu-bir-token-yaz"
-Delastic.apm.environment="production"
-Delastic.apm.application_packages="com.sirketiniz"
-Delastic.apm.transaction_sample_rate=0.1
-jar uygulama.jar
transaction_sample_rate parametresine dikkat: prodüksiyonda her isteği kaydetmek Elasticsearch’i boğar. 0.1 değeri, isteklerin %10’unu örneklediği anlamına gelir. Yüksek trafikli servislerde bu yeterli. Hata ayıklama sırasında geçici olarak 1.0 yapabilirsin.
Python/Django Uygulaması İçin Agent Kurulumu
Microservice mimarisinde Python servisleri sık karşılaşılan senaryo. Django projesi için:
pip install elastic-apm
settings.py dosyasına ekle:
INSTALLED_APPS = [
# diğer app'ler...
'elasticapm.contrib.django',
]
ELASTIC_APM = {
'SERVICE_NAME': 'kullanici-servisi',
'SECRET_TOKEN': 'buraya-guclu-bir-token-yaz',
'SERVER_URL': 'http://apm-server-ip:8200',
'ENVIRONMENT': 'production',
'TRANSACTION_SAMPLE_RATE': 0.2,
# Yavaş sorguları yakalamak için
'SPAN_FRAMES_MIN_DURATION': '5ms',
# Stack trace için minimum süre
'STACK_TRACE_LIMIT': 50,
}
MIDDLEWARE = [
'elasticapm.contrib.django.middleware.TracingMiddleware',
# diğer middleware'ler...
]
Django ORM sorguları, Redis çağrıları, dış HTTP istekleri otomatik olarak yakalanır. Celery task’larını da izlemek istersen:
# celery.py
from elasticapm.contrib.celery import register_exception_tracking, register_instrumentation
register_instrumentation(app)
register_exception_tracking(app)
Node.js Servisi İçin Entegrasyon
Express.js tabanlı bir API servisini izlemek için agent’ı uygulamanın en tepesine, diğer tüm require’lardan önce eklemek zorundasın:
// app.js - EN BAŞA EKLENMELİ
const apm = require('elastic-apm-node').start({
serviceName: 'odeme-servisi',
secretToken: 'buraya-guclu-bir-token-yaz',
serverUrl: 'http://apm-server-ip:8200',
environment: process.env.NODE_ENV || 'production',
transactionSampleRate: 0.15,
// Hangi route'ları izleyeceğini özelleştir
ignoreUrls: ['/health', '/metrics', '/favicon.ico'],
// Custom label eklemek için
globalLabels: {
region: 'tr-west',
datacenter: 'dc1'
}
})
const express = require('express')
// ... geri kalan kod
ignoreUrls listesini doğru yapılandırmak önemli. Health check endpoint’i genellikle saniyede birkaç kez çağrılır ve bu veriniz içinde büyük gürültü oluşturur.
Kubernetes Ortamında APM
Kubernetes üzerinde çalışıyorsanız APM Server’ı da cluster içine almak mantıklı. Helm ile kurulum:
helm repo add elastic https://helm.elastic.co
helm repo update
# values.yaml ile özelleştirilmiş kurulum
cat <<EOF > apm-values.yaml
apmConfig:
apm-server.yml: |
apm-server:
host: "0.0.0.0:8200"
auth:
secret_token: "${APM_SECRET_TOKEN}"
output.elasticsearch:
hosts: ["http://elasticsearch-master:9200"]
username: "elastic"
password: "${ES_PASSWORD}"
service:
type: ClusterIP
port: 8200
EOF
helm install apm-server elastic/apm-server
--namespace monitoring
--values apm-values.yaml
Pod’larınıza agent eklerken environment variable üzerinden konfigürasyon yapın. Secret’ları kodda saklamayın:
env:
- name: ELASTIC_APM_SERVER_URL
value: "http://apm-server.monitoring.svc.cluster.local:8200"
- name: ELASTIC_APM_SECRET_TOKEN
valueFrom:
secretKeyRef:
name: apm-secret
key: token
- name: ELASTIC_APM_SERVICE_NAME
value: "stok-servisi"
- name: ELASTIC_APM_ENVIRONMENT
valueFrom:
fieldRef:
fieldPath: metadata.namespace
Kibana’da APM Dashboard Yapılandırması
APM Server kurulduktan ve agent’lardan veri gelmeye başladıktan sonra Kibana’da sol menüden “Observability > APM” bölümüne gidebilirsin. Ama bazı önemli yapılandırmaları atlamak istemiyorum.
Anomaly Detection açmak için Machine Learning lisansı gerekiyor, ama temel threshold tabanlı alert’lar ücretsiz. Kibana’da bir alert kuralı oluşturalım:
# Kibana API üzerinden alert oluşturma
curl -X POST "http://localhost:5601/api/alerting/rule"
-H "kbn-xsrf: true"
-H "Content-Type: application/json"
-u elastic:sifren
-d '{
"name": "Yüksek Response Time Uyarısı",
"rule_type_id": "apm.transaction_duration",
"consumer": "apm",
"schedule": { "interval": "5m" },
"params": {
"serviceName": "siparis-servisi",
"transactionType": "request",
"windowSize": 15,
"windowUnit": "m",
"threshold": 2000,
"aggregationType": "95th"
},
"actions": []
}'
Bu kural “siparis-servisi” için 15 dakikalık pencerede p95 response time 2000ms’i geçerse tetikleniyor.
Distributed Tracing: Mikroservisler Arası İz Takibi
APM’nin en güçlü özelliği distributed tracing. Bir istek birden fazla servisten geçiyorsa tüm zinciri tek bir trace olarak görebiliyorsunuz. Bu otomatik çalışıyor, ama bazı durumlarda custom span eklemek gerekebilir.
Python’da bir veritabanı işlemini custom olarak span’lamak:
from elasticapm import capture_span
def musteri_bilgilerini_getir(musteri_id):
with capture_span('veritabani.musteri_sorgu', span_type='db', span_subtype='postgresql'):
# Ağır veritabanı işlemi
musteri = db.session.query(Musteri).filter_by(id=musteri_id).first()
with capture_span('redis.cache_guncelle', span_type='cache', span_subtype='redis'):
cache.set(f"musteri:{musteri_id}", musteri.to_dict(), ex=300)
return musteri
Bu sayede “veritabanı mı yavaş yoksa Redis mi?” sorusunu Kibana’da görsel olarak görebilirsiniz.
Yaygın Sorunlar ve Çözümleri
Gerçek hayatta kurulumda en çok karşılaştığım problemleri paylaşayım:
APM Server’a veri gelmiyor:
# Agent'ın APM Server'a erişip erişemediğini test et
curl -v http://apm-server-ip:8200/
# APM Server loglarını kontrol et
journalctl -u apm-server -f
# Elasticsearch'e yazma izni var mı?
curl -u elastic:sifren http://localhost:9200/_cat/indices?v | grep apm
Çok fazla veri geliyor, Elasticsearch doldu:
ILM (Index Lifecycle Management) policy’sini sıkılaştır:
curl -X PUT "localhost:9200/_ilm/policy/apm-rollover-30-days"
-H "Content-Type: application/json"
-u elastic:sifren
-d '{
"policy": {
"phases": {
"hot": {
"min_age": "0ms",
"actions": {
"rollover": {
"max_primary_shard_size": "20gb",
"max_age": "1d"
}
}
},
"delete": {
"min_age": "30d",
"actions": { "delete": {} }
}
}
}
}'
Java agent performans etkisi fazla:
# Profiling özelliklerini kapat, sadece transaction izle
-Delastic.apm.profiling_inferred_spans_enabled=false
-Delastic.apm.capture_body=off
-Delastic.apm.transaction_sample_rate=0.05
Gerçek Dünya Senaryosu: Yavaş Sipariş API’si
Geçen ay bir e-ticaret platformunda yaşanan gerçek bir vakayı anlatayım. Sipariş oluşturma endpoint’i zaman zaman 8-10 saniye sürüyordu ama sunucu metrikleri normaldi. APM olmasa saatlerce uğraşırdık.
APM trace’ini açtığımızda şunu gördük: stok_kontrol_servisi her sipariş için ortalama 12 ayrı sorgu atıyordu. N+1 problemi. Her ürün için ayrı ayrı stok sorgusu. Geliştirici tek bir IN sorgusuyla halledilebileceğini bilmiyordu bile. APM olmadan bu sorunu bulmak için ya tüm kodu okumak ya da rastlantıyla fark etmek gerekiyordu.
Düzeltme sonrası p95 response time 8.2 saniyeden 340 milisaniyeye düştü. Bu veriden yola çıkarak geliştirici ekibine SQL optimization eğitimi de verildi.
Güvenlik Notları
Prodüksiyon ortamında APM kurulumunda güvenliği es geçmeyin:
- APM Server’a doğrudan internet erişimini kapatın. Uygulamalarınız APM Server’a internal network üzerinden ulaşmalı.
secret_tokenyerine daha güvenli olanapi_keyauthentication kullanın.- Elasticsearch iletişiminde TLS zorunlu tutun.
capture_bodyözelliğini dikkatli kullanın. Request body’sinde şifre, kredi kartı numarası gibi hassas veri varsa otomatik sanitization’ı mutlaka etkinleştirin.
# APM Server'da hassas veri maskeleme
apm-server:
auth:
api_key:
enabled: true
sanitize_field_names:
- "password"
- "passwd"
- "secret"
- "token"
- "credit_card"
- "cvv"
Sonuç
ELK Stack üzerinde APM kurmak, teknik olarak birkaç saatlik iş. Asıl değer ise kurulum sonrasında yavaş yavaş ortaya çıkıyor. İlk hafta “neden bu servis bu kadar yavaş?” sorusuna artık tahmin değil, veriyle cevap veriyorsunuz. İkinci haftada N+1 sorgularını, gereksiz dış servis çağrılarını, bellek sızıntılarını görmeye başlıyorsunuz. Bir ay sonra geliştirici ekibi kod yazarken “bu APM’de nasıl görünür?” diye düşünmeye başlıyor, ki bu kültürel dönüşüm belki de en değerli kısım.
Sampling oranlarını ve ILM policy’lerini iyi ayarlamazsanız Elasticsearch depolama maliyetleri hızla artabilir. İlk kurulumda her şeyi izleme moduyla başlayıp bir hafta sonra ihtiyaca göre budama yapmak benim tercih ettiğim yaklaşım. Ayrıca APM verisi, log verisiyle birleştiğinde asıl gücünü gösteriyor. Bir trace ID’yi alıp direkt o isteğe ait logları Kibana’da açabilmek, hata ayıklama süresini dramatik biçimde kısaltıyor. Bunu da ayrı bir yazıda ele alacağım.
