Sunucun yavaşladığında, kullanıcılar şikayet etmeye başladığında ve sen de neyin nerede takıldığını bulmaya çalışırken geçirdiğin o gergin dakikaları hepimiz yaşadık. CPU darboğazları bu senaryoların en yaygın nedenlerinden biri. Ama “CPU yüksek” demek tek başına bir anlam ifade etmiyor. Hangi process, hangi fonksiyon, hangi sistem çağrısı, ne zaman, ne kadar süreyle? İşte bu soruların cevabını bulmak için perf ve sar araçlarını derinlemesine öğrenmek gerekiyor.
Bu yazıda gerçek dünya senaryoları üzerinden giderek her iki aracın da nasıl kullanıldığını, çıktıların nasıl yorumlandığını ve elde ettiğin veriyi nasıl aksiyon planına dönüştüreceğini anlatacağım.
Önce Temeli Atalım: CPU Darboğazı Nedir?
CPU darboğazı, sistemdeki işlemcinin kapasitesinin üzerinde iş yüküne maruz kalması durumudur. Ama işin ayrıntısına girince bu tanım yetersiz kalıyor. Çünkü “CPU yüksek” durumu birkaç farklı şekilde tezahür edebilir:
- User space CPU kullanımı yüksek: Uygulama kodu çok fazla hesaplama yapıyor.
- Kernel space CPU kullanımı yüksek: Sistem çağrıları, sürücüler veya interrupt handling çok zaman alıyor.
- iowait yüksek: CPU aslında disk veya ağ I/O bekliyor, bu teknik olarak CPU kullanımı değil ama runqueue’yu şişiriyor.
- Steal time yüksek: Sanallaştırma ortamında fiziksel CPU’nun diğer VM’lere verilmesi.
- Soft/Hard IRQ yüksek: Donanım interrupt’larının işlenmesi zaman alıyor.
Bu farklılıkları anlamadan yanlı bir teşhis koyabilirsin. sar sana bu kategorileri zaman serisi olarak verir, perf ise hangi kodun bu CPU’yu yaktığını gösterir.
sar ile Tarihsel ve Anlık CPU Analizi
sar, System Activity Reporter’ın kısaltmasıdır ve sysstat paketinin bir parçasıdır. Güzel tarafı, sistem kurulduğunda cron ile otomatik veri toplaması ayarlanabilir. Böylece bir sorun sonrasında “dün gece 3’te ne olmuştu?” sorusunu cevaplayabilirsin.
sar Kurulumu ve Ayarı
# Debian/Ubuntu
sudo apt install sysstat
# RHEL/CentOS/Rocky Linux
sudo dnf install sysstat
# Veri toplama servisini aktif et
sudo systemctl enable --now sysstat
# Cron ile her 10 dakikada bir veri toplanmasını sağla (varsayılan genellikle bu şekilde gelir)
# /etc/cron.d/sysstat dosyasını kontrol et
cat /etc/cron.d/sysstat
Veri toplama aktif hale geldikten sonra loglar /var/log/sysstat/ dizininde saXX formatında birikir. Buradaki XX, ayın gün numarasını temsil eder.
Anlık CPU İstatistikleri Almak
# 1 saniye aralıklarla 5 ölçüm al, CPU bazında göster
sar -u ALL 1 5
# Çıktı örneği:
# 14:23:01 CPU %usr %nice %sys %iowait %steal %irq %soft %guest %idle
# 14:23:02 all 45.2 0.0 12.3 8.1 0.0 0.5 1.2 0.0 32.7
# 14:23:03 all 48.1 0.0 14.1 7.9 0.0 0.4 1.3 0.0 28.2
Burada dikkat etmen gereken alanlar şunlardır:
- %usr: Kullanıcı seviyesi proseslerin harcadığı CPU zamanı
- %sys: Kernel modunda harcanan CPU zamanı
- %iowait: I/O tamamlanmasını bekleyen süre
- %steal: Hypervisor’ın başka VM’lere verdiği CPU zamanı
- %soft: Soft interrupt işleme zamanı
- %idle: Boşta geçen süre
Çekirdek Bazlı Analiz
Çok çekirdekli sistemlerde bazı çekirdekler aşırı yüklüyken diğerleri boşta olabilir. Bu durum özellikle single-threaded uygulamalarda veya IRQ affinity yanlış ayarlanmışsa görülür.
# Her CPU çekirdeğini ayrı ayrı göster
sar -u ALL -P ALL 1 3
# Sadece belirli bir core'u izle (örneğin core 2)
sar -u ALL -P 2 1 5
Burada bir çekirdek %99 kullanımdayken diğerleri %10-15 bandındaysa, uygulamanın tek thread üzerinde çalıştığını veya IRQ’ların tek bir core’a yığıldığını düşünmeye başlayabilirsin.
Geçmiş Verilere Bakmak
Gerçek dünyadaki senaryolarda sorun genellikle sen monitörün başında otururken olmaz. Sabah gelip “dün gece sistemi yavaşlamış” duyduğunda işte sar’ın tarihi verileri hayat kurtarır:
# Bugünün tüm gününe ait CPU verisini göster
sar -u ALL
# Belirli bir tarihe ait veriyi göster (örneğin ayın 15'i)
sar -u ALL -f /var/log/sysstat/sa15
# Belirli bir zaman aralığını filtrele
sar -u ALL -s 02:00:00 -e 04:00:00 -f /var/log/sysstat/sa15
Bu komutla dün gece 02:00-04:00 arasında neler olduğunu dakika bazlı görebilirsin. %idle değerinin 5’in altına düştüğü zamanları tespit ettiğinde, o zaman dilimine karşılık gelen uygulama loglarına bak.
Load Average ve CPU Kuyruğu Analizi
CPU kullanım yüzdesi tek başına yeterli değildir. Runqueue’daki iş sayısını da takip etmek gerekir:
# CPU çalışma kuyruğunu ve load average değerlerini göster
sar -q 1 5
# Çıktı:
# runq-sz plist-sz ldavg-1 ldavg-5 ldavg-15 blocked
# 12 1234 8.5 6.2 4.1 3
runq-sz: Çalışmayı bekleyen process sayısı. CPU sayısından fazlaysa gerçek bir darboğaz var.
blocked: I/O bekleyen process sayısı. Bu değer yüksekse CPU değil disk veya ağ problemi.
Genel kural şudur: runq-sz değeri CPU çekirdeği sayısının 2-3 katını aşıyorsa sistem baskı altındadır.
perf ile Derinlemesine CPU Profilleme
sar sana “ne kadar” sorusunu cevaplar. perf ise “neden” sorusunu cevaplar. Linux kernel’inin içine gömülü olan perf subsystem’i üzerinden çalışan bu araç, CPU’nun tam olarak neyle meşgul olduğunu fonksiyon seviyesinde gösterir.
perf Kurulumu
# Ubuntu/Debian
sudo apt install linux-tools-common linux-tools-$(uname -r)
# RHEL/CentOS/Rocky
sudo dnf install perf
# Versiyonu kontrol et
perf --version
# Kernel sembollerinin yüklü olduğundan emin ol
sudo apt install linux-image-$(uname -r)-dbg # Debian/Ubuntu için
Eğer cloud instance kullanıyorsan paranoid ayarını kontrol et:
cat /proc/sys/kernel/perf_event_paranoid
# 2 dönerse kısıtlı, root olmadan sınırlı kullanım
# Geçici olarak açmak için
sudo sysctl -w kernel.perf_event_paranoid=1
İlk perf Komutu: stat
perf stat en basit kullanım şeklidir. Bir komut çalıştırırken CPU counter’larını ölçer:
# Belirli bir komutun CPU metriklerini ölç
perf stat ls -la /etc
# Çalışmakta olan bir prosesi izle (PID ile)
perf stat -p 1234 sleep 10
# Daha fazla event göster
perf stat -d -p 1234 sleep 10
Çıktıdaki önemli değerler:
- instructions per cycle (IPC): 1’in altındaysa CPU stall yaşanıyor, yani cache miss veya branch misprediction var.
- cache-misses: L1/L2/L3 cache miss oranı yüksekse bellek bant genişliği darboğazı olabilir.
- branch-misses: Yüksekse CPU branch prediction verimli çalışmıyor.
perf top ile Gerçek Zamanlı Profilleme
top komutuna benzer şekilde çalışır ama process değil fonksiyon seviyesinde gösterir:
# Sistem genelinde hangi fonksiyonlar CPU yakıyor
sudo perf top
# Belirli bir prosesi izle
sudo perf top -p 1234
# Kernel sembollerini de göster
sudo perf top -K
Bu komut çalıştığında bir tablo görürsün. Üstteki fonksiyonlar CPU’yu en çok kullananlar. Eğer listede [kernel.kallsyms] veya [unknown] gibi şeyler görüyorsan semboller eksik demektir.
perf record ve report: Asıl Güç Burada
Gerçek analizler perf record + perf report kombinasyonuyla yapılır. Önce örnekleme yaparsın, sonra analiz edersin:
# 30 saniye boyunca sistem genelinde örnekle
sudo perf record -g -a sleep 30
# Belirli bir prosesi örnekle
sudo perf record -g -p 1234 sleep 30
# Kayıtları analiz et
sudo perf report
# Daha detaylı görmek için
sudo perf report --stdio | head -50
-g flag’i call graph (çağrı ağacı) toplar. Bu sayede bir fonksiyonun hangi üst fonksiyon tarafından çağrıldığını da görebilirsin. Bu kritik önemde çünkü bazen sorunlu fonksiyon masum bir yerde, onu çağıran caller asıl problemli olabilir.
Gerçek Dünya Senaryosu 1: Web Sunucusu Yavaşlıyor
Diyelim ki bir Nginx + PHP-FPM stack’i çalıştırıyorsun ve kullanıcılar sayfa yükleme sürelerinin arttığından şikayet ediyor. CPU %80-90 bandında geziniyor.
İlk adım olarak sar ile tabloya bak:
# Son 1 saatlik veriyi incele
sar -u ALL -s $(date -d '1 hour ago' +%H:%M:%S) | tail -20
Diyelim ki %usr yüksek, %sys ve %iowait normal. Bu user-space’de bir problem olduğunu gösteriyor. Şimdi perf ile hangi process olduğunu bul:
# Hangi processler CPU yakıyor, fonksiyon bazında
sudo perf top -s pid,comm,dso
# PHP-FPM worker'ların PID'lerini bul
pgrep -a php-fpm
# En yoğun worker'ı profilele
sudo perf record -g -p <php-fpm-pid> sleep 20
sudo perf report --stdio 2>/dev/null | head -60
Raporda zend_execute veya belirli bir PHP extension fonksiyonunun tepede olduğunu görürsen PHP kodu sorumludur. Eğer malloc veya memcpy tepedeyse bellek yönetimi problemi olabilir.
Gerçek Dünya Senaryosu 2: Gece Yarısı CPU Spike
Sabah işe geldin, gecenin 2’sinde 15 dakika boyunca sistem load average’ı çatlamış. Cron job’lardan birinin neden olduğunu şüpheleniyorsun.
# Gece 01:45 - 02:30 arasını incele
sar -u ALL -s 01:45:00 -e 02:30:00 -f /var/log/sysstat/sa$(date +%d)
# Aynı dönem için runqueue'ya bak
sar -q -s 01:45:00 -e 02:30:00 -f /var/log/sysstat/sa$(date +%d)
# O saatte çalışan cron'ları kontrol et
grep "02:" /var/log/syslog | grep CRON | head -20
Eğer %sys değeri yüksekse sistem çağrıları çok yoğundur. Bu durumda bir sonraki oluşumda perf ile yakalamak için otomatik bir script yazabilirsin:
#!/bin/bash
# cpu_spike_catcher.sh
THRESHOLD=85
while true; do
CPU_IDLE=$(sar -u 1 1 | tail -1 | awk '{print $NF}')
CPU_USAGE=$(echo "100 - $CPU_IDLE" | bc)
if (( $(echo "$CPU_USAGE > $THRESHOLD" | bc -l) )); then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
perf record -g -a -o /tmp/perf_spike_${TIMESTAMP}.data sleep 15 &
echo "Spike yakalandı: $TIMESTAMP - CPU: %${CPU_USAGE}" >> /var/log/cpu_spikes.log
fi
sleep 5
done
Bu script CPU %85’i geçtiğinde otomatik olarak 15 saniyelik perf kaydı alır.
perf Flame Graph: Görselleştirme
Ham perf çıktısı deneyimliler için bile yorucu olabilir. Flame graph bu noktada devreye girer. Brendan Gregg’in geliştirdiği bu görselleştirme tekniği call stack’leri renk ve genişlik ile ifade eder. Geniş bir blok, o fonksiyonun çok CPU yaktığı anlamına gelir.
# FlameGraph scriptlerini indir
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
# perf verisini al
sudo perf record -F 99 -g -a sleep 30
sudo perf script > /tmp/out.perf
# Flame graph oluştur
./stackcollapse-perf.pl /tmp/out.perf > /tmp/out.folded
./flamegraph.pl /tmp/out.folded > /tmp/cpu_flamegraph.svg
Oluşan SVG dosyasını tarayıcında aç. Interaktif olarak zoom yapabilir, fonksiyonlara tıklayabilirsin. Geniş “platolar” darboğazları temsil eder.
Soft IRQ ve Kernel CPU Problemleri
Bazen %soft veya %sys değerleri yüksek çıkar. Bu durumda sar çıktısı sana nerede olduğunu söyler ama perf seni kernel içine kadar götürür:
# Soft IRQ dağılımına bak
sar -I ALL 1 3
# Hangi IRQ en çok tetikleniyor
cat /proc/interrupts
# Kernel fonksiyonlarında zaman harcayan kodları bul
sudo perf record -g -a -e cpu-clock sleep 10
sudo perf report --sort=dso,symbol | grep -v "^#" | head -30
Eğer listede net_rx_action veya ixgbe_poll gibi ağ sürücüsü fonksiyonları üstteyse, yüksek ağ trafiği kernel’i yoruyor demektir. Bu durumda IRQ affinity ayarını gözden geçirmek ve RSS/RPS konfigürasyonuna bakmak gerekir.
sar ve perf’i Birlikte Kullanmak: Metodoloji
İki aracı birlikte kullanmanın sistematik bir yolu şöyledir:
Adım 1 – Triage ile başla: sar -u ALL ile genel tabloya bak. %usr, %sys, %iowait değerlerinden hangisi yüksek?
Adım 2 – Zaman damgasını bul: Sorunun ne zaman başladığını ve bittiğini belirle. sar -q ile runqueue’nun ne zaman şiştiğini gör.
Adım 3 – Sebebi daralt: Eğer %usr yüksekse kullanıcı space prosesi var. perf top ile hangi prosesi olduğunu bul.
Adım 4 – Fonksiyon seviyesine in: perf record -g ile o prosesi örnekle, perf report ile analiz et.
Adım 5 – Flame graph ile görselleştir: Karmaşık call stack’lerde flame graph yorumlamayı kolaylaştırır.
Adım 6 – Tekrarlanabilirliği kontrol et: sar geçmişine bakarak bu sorunun ne sıklıkla yaşandığını anla. Tek seferlik mi, periyodik mi?
Önemli İpuçları ve Yaygın Hatalar
perf Kullanırken Dikkat Edilmesi Gerekenler
- Semboller olmadan kör uçarsın: Uygulama binary’leri debug sembolleriyle derlenmemişse
perf reportanlamsız adresler gösterir. Production’da stripped binary varsa ayrı bir debug package kurman gerekebilir. - -g flag’ini unutma: Call graph olmadan hangi fonksiyonun çalıştığını görürsün ama neden çalıştığını göremezsin.
- Sampling overhead’ini unutma:
-F 999gibi yüksek frekans değerleri zaten yüklü sistemlerde ek yük yaratır.-F 99genellikle yeterlidir.
sar Kullanırken Dikkat Edilmesi Gerekenler
- sysstat servisinin çalıştığından emin ol: Veri toplanmıyorsa geçmişe bakamazsın.
systemctl status sysstatile kontrol et. - Timezone farkına dikkat: Loglardaki timestamp ile olayın zamanını karşılaştırırken timezone’u unutma.
- iowait yanıltıcı olabilir: Yüksek iowait CPU’yu meşgul etmez ama sistem yavaş görünür. Bunu gerçek CPU darboğazıyla karıştırma.
Steel Time Özel Durumu
VPS veya cloud sunucularda %steal değeri önem taşır. Bu değer sürekli %5’in üzerindeyse hosting sağlayıcın “noisy neighbor” problemi yaşıyor olabilir:
# steal time'ı anlık izle
sar -u ALL 2 30 | awk 'NR>3 {print $1, "steal:", $8"%", "idle:", $9"%"}'
Steal değeri yüksekse ne kadar optimize edersen et, fiziksel CPU zamanını başkaları çalıyor demektir. Bu durumda sağlayıcıyla iletişime geç veya dedicated sunucuya geç.
Sonuç
CPU darboğazlarını tespit etmek ve çözmek, doğru araçları doğru sırayla kullanmakla doğru orantılıdır. sar sana zamansal bir perspektif verir. Sorunun ne zaman başladığını, ne kadar sürdüğünü, hangi CPU metriğinin yükseldiğini görmeni sağlar. perf ise seni kaynak koduna yaklaştırır. Hangi fonksiyon, hangi modül, hangi çağrı zinciri CPU’yu tüketiyor, bunu anlaman için tasarlanmıştır.
Bu iki aracı birlikte kullandığında “sunucu yavaş” gibi muğlak bir şikayeti somut bulgulara dönüştürebilirsin. “PHP-FPM worker’larından biri regex parsing fonksiyonunda zamanının %40’ını harcıyor” veya “gece 02:15’te çalışan backup script’i fork bomb gibi davranıyor” gibi tanımlanabilir, aksiyon alınabilir tespitler yapabilirsin.
Flame graph ve call graph analizi başta biraz kafa karıştırıcı gelebilir. Ama birkaç gerçek problem üzerinde pratik yaptıktan sonra bu çıktıları okumak ikinci bir doğa haline gelir. Sistemini tanı, verilerini topla, analiz et. Panik yapmadan, sistematik bir şekilde.