Yüksek CPU Kullanımı: Sebebi Bulma ve Çözme
Sunucu başı yanıyor, kullanıcılar şikayet ediyor, müdür boyunda soluyor. Yüksek CPU senaryosu her sysadmin’in kabusu. Ama paniklemeden, sistematik bir yaklaşımla sorunu genellikle birkaç dakika içinde tespit edebilirsiniz. Bu yazıda gerçek dünya senaryolarından yola çıkarak yüksek CPU kullanımını nasıl bulacağınızı ve çözeceğinizi adım adım anlatacağım.
İlk Müdahale: Durumu Hızlıca Kavramak
Sunucuya bağlandığınızda ilk yapacağınız şey mevcut durumu anlamak. top komutu eski ama altın. Ama ben genellikle htop ile başlarım, daha okunabilir.
# Temel durum kontrolü
top -b -n 1 | head -20
# Daha okunabilir alternatif
htop
# CPU istatistiklerini anlık görmek için
vmstat 1 5
vmstat 1 5 çıktısında dikkat etmeniz gereken kolonlar şunlar:
- us: Kullanıcı alanı CPU kullanımı
- sy: Sistem/kernel CPU kullanımı
- wa: I/O bekleme süresi
- id: Boşta geçen süre
- st: Sanallaştırma ortamında çalınan CPU süresi
Eğer wa değeri sürekli yüksekse, sorun CPU değil disk I/O’dur. CPU yüksek görünüyor olabilir ama asıl darboğaz başka yerdedir. Bu ayrımı yapmak çok önemli.
Hangi Process CPU Yiyor?
İlk gerçek soru bu. top açıkken P tuşuna basarsanız CPU kullanımına göre sıralama yaparsınız.
# CPU kullanımına göre sıralı process listesi
ps aux --sort=-%cpu | head -20
# Sadece ilk 5 CPU tüketicisi
ps aux --sort=-%cpu | awk 'NR<=6{print}'
# Process ağacıyla birlikte görmek
ps axjf | head -40
Diyelim ki ps aux çıktısında java process’i %350 CPU kullanıyor gördünüz. (Evet, çok çekirdekli sistemlerde %100’ün üzeri mümkün, 4 çekirdek varsa max %400 görürsünüz.) Bu noktada PID’i not alın ve daha derine inmeye başlayın.
Thread Düzeyinde İnceleme
Bir process içinde hangi thread’in CPU yediğini bulmak için top -H kullanabilirsiniz:
# Belirli bir PID'in thread'lerini görmek
top -H -p 12345
# ps ile thread listesi
ps -T -p 12345
# Tüm thread'leri CPU kullanımına göre sıralı
ps -eLo pid,tid,pcpu,comm --sort=-%cpu | head -20
Bu bilgi özellikle Java, Python veya Node.js uygulamalarında thread leak veya dead lock problemlerini tespit etmekte çok işe yarıyor.
Kernel ve Sistem Çağrıları: strace ile Derinleşmek
Process’i buldunuz ama neden bu kadar CPU yediğini anlamak istiyorsunuz. İşte burada strace devreye giriyor.
# Process'in sistem çağrılarını izlemek
strace -p 12345
# İstatistiksel özet almak (hangi syscall kaç kez çağrılmış)
strace -cp 12345
# Çıktıyı dosyaya kaydetmek
strace -p 12345 -o /tmp/strace_output.txt 2>&1
strace -c ile aldığınız özette eğer futex, nanosleep gibi çağrılar çok yüksekse busy-wait veya spin-lock problemi olabilir. read/write çağrıları yüksekse I/O’ya bağlı bir sorun var demektir.
Gerçek bir senaryo paylaşayım: Bir e-ticaret sitesinde gecenin 3’ünde CPU %95’e fırladı. ps aux ile baktım, php-fpm worker’ları CPU yiyordu. strace -c -p ile baktığımda stat sistem çağrısının milyonlarca kez çağrıldığını gördüm. Neden? Bir geliştirici yanlışlıkla her request’te /var/www/html altındaki tüm dosyaları listeleten bir kod deploy etmişti. Dosya sayısı 50 bini aşmıştı.
perf ile CPU Profiling
Daha gelişmiş analiz için perf aracını kullanmak gerekiyor. Kernel destekli bu araç, neyin neden CPU tükettiğini çok net gösteriyor.
# perf kurulumu (Debian/Ubuntu)
apt-get install linux-perf
# 30 saniye boyunca sistem genelinde örnekleme
perf top
# Belirli bir process'i profille
perf record -g -p 12345 sleep 30
perf report
# CPU hotspot'larını bulmak
perf stat -p 12345 sleep 10
perf top çıktısında fonksiyon adlarını ve hangi shared library’den geldiğini görebilirsiniz. [kernel.kallsyms] yazan satırlar kernel space’de, diğerleri user space’de çalışıyor demektir.
Zombie ve Orphan Process’ler
Bazen CPU yüksek görünür ama sorumlu process net değildir. Zombie process’ler CPU yemez ama kaynak tablolarını doldurarak sistemi yavaşlatabilir.
# Zombie process'leri bulmak
ps aux | grep -w Z
# Daha detaylı zombie listesi
ps axo pid,ppid,stat,comm | awk '$3~/^Z/'
# Zombie'nin parent'ını bulmak ve SIGCHLD göndermek
kill -SIGCHLD <parent_pid>
Zombie process’i öldüremezsiniz çünkü teknik olarak zaten ölü. Onu process tablosundan silmek için parent process’e SIGCHLD göndermeniz gerekir. Parent da cevap vermiyorsa parent’ı öldürmeniz gerekir ki bu da bazı durumlarda riskli olabilir.
Runaway Process: Kontrolden Çıkmış İşlemler
Bir process aniden CPU’yu %100 almaya başladıysa ve normal durumda böyle değilse, muhtemelen bir bug tetiklenmiş veya infinite loop’a girmiş demektir.
# Process'in ne kadar süredir çalıştığını görmek
ps -p 12345 -o pid,etime,pcpu,pmem,comm
# Process'in açık dosyalarını kontrol et
lsof -p 12345
# Network bağlantılarını kontrol et
ss -tp | grep 12345
# Process'in memory map'ini gör
cat /proc/12345/maps | head -30
Eğer bu bir web uygulaması process’iyse ve bir request takılıp kalmışsa, uygulamaya timeout mekanizması eklemeniz gerekiyor. Kısa vadeli çözüm olarak process’e SIGTERM gönderin, cevap vermezse SIGKILL kullanın. Ama SIGKILL‘i son çare olarak kullanın, çünkü process cleanup yapmadan ölür ve veri bütünlüğü sorunları yaşanabilir.
Cron Job’lar ve Zamanlanmış Görevler
Yüksek CPU kullanımı periyodik olarak artıp azalıyorsa, suçlu büyük ihtimalle bir cron job’dur.
# Aktif cron job'ları listele
crontab -l
cat /etc/crontab
ls /etc/cron.d/
ls /etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/
# Son çalışan cron'ları logdan takip et
grep CRON /var/log/syslog | tail -50
# Bir script'in CPU kullanımını ölçmek
/usr/bin/time -v /path/to/script.sh
Gerçek bir senaryo daha: Bir müşterinin sunucusunda her gece 02:00’de CPU %80’e çıkıyordu. Log analizi yaptım, /etc/cron.daily altında kimsenin hatırlamadığı eski bir backup script’i vardı. Script çalışıyor, tüm veritabanını mysqldump ile dökü alıyor, sonra bu dökümü sıkıştırmak için gzip yerine bzip2 -9 kullanıyordu. Maksimum sıkıştırma modu, tek thread, 50GB veritabanı. gzip ile değiştirip nice ile çalıştırdım, sorun çözüldü.
# CPU'ya dostu cron job yazımı
# nice ile düşük öncelikli çalıştırma
0 2 * * * nice -n 19 /path/to/heavy-script.sh
# ionice ile I/O önceliğini de kısmak
0 2 * * * nice -n 19 ionice -c 3 /path/to/heavy-script.sh
Load Average Yüksek Ama CPU Düşük: I/O Wait Tuzağı
Bu durum sysadmin’leri sıklıkla yanıltır. uptime veya top çıktısında load average yüksek ama gerçek CPU kullanımı düşük görünüyorsa:
# Disk I/O istatistikleri
iostat -x 1 5
# Hangi process'ler I/O bekliyor
iotop -o
# Spesifik disk'in durumu
iostat -d -x sda 1 10
iostat -x çıktısında dikkat edilecek değerler:
- %util: Disk ne kadar meşgul, %100’e yaklaşıyorsa disk doymuş demektir
- await: Ortalama I/O bekleme süresi milisaniye cinsinden, 20ms üzeri sorunlu
- r/s ve w/s: Saniyedeki okuma ve yazma operasyon sayısı
Eğer disk doluysa çözüm seçenekleri şunlar: SSD’ye geçmek, RAID yapılandırması, veya uygulamada gereksiz disk yazma operasyonlarını azaltmak.
Kernel Process’leri ve Interrupt’lar
Bazen kworker, ksoftirqd, irq gibi kernel process’leri yüksek CPU kullanıyor görünebilir.
# Interrupt istatistikleri
cat /proc/interrupts
# Soft interrupt istatistikleri
cat /proc/softirqs
# IRQ'ları canlı izlemek
watch -n 1 cat /proc/interrupts
# Network interrupt'larını kontrol et
cat /proc/net/softnet_stat
Eğer ksoftirqd yüksekse ve ağ trafiği yoğunsa, RPS (Receive Packet Steering) veya RFS (Receive Flow Steering) konfigürasyonu gerekebilir. Bu özellikle ağır trafik altındaki web sunucularında sık karşılaşılan bir durumdur.
Bir kworker thread’i yüksek CPU yiyorsa, bu genellikle ACPI eventi veya hatalı bir kernel driver’ından kaynaklanır:
# Hangi kworker thread'inin sorunlu olduğunu bulmak
cat /proc/$(pgrep -f kworker)/stack 2>/dev/null | head -5
# ACPI eventlerini kontrol et
journalctl -k | grep -i acpi | tail -20
Uzun Vadeli Monitoring: Sorun Tekrar Etmesin
Anlık sorunu çözdünüz, harika. Ama sorun tekrar ettiğinde hazırlıklı olmak için monitoring kurmanız şart.
# sar ile geçmişe dönük CPU istatistiklerini görmek
# sysstat paketi kurulu olmalı
sar -u 1 10
# Dün aynı saatteki CPU durumunu görmek
sar -u -f /var/log/sysstat/sa$(date -d yesterday +%d)
# Process bazlı geçmiş istatistikler
sar -u ALL 1 5
# Yüksek CPU durumunda otomatik log almak için script
cat > /usr/local/bin/cpu-alert.sh << 'EOF'
#!/bin/bash
THRESHOLD=80
CPU_USAGE=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
if (( $(echo "$CPU_USAGE > $THRESHOLD" | bc -l) )); then
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
ps aux --sort=-%cpu | head -20 > /var/log/cpu_spike_${TIMESTAMP}.log
echo "CPU Spike detected: ${CPU_USAGE}%" | mail -s "CPU Alert" [email protected]
fi
EOF
chmod +x /usr/local/bin/cpu-alert.sh
# Crontab'a ekle
# * * * * * /usr/local/bin/cpu-alert.sh
Veritabanı Kaynaklı Yüksek CPU
Web uygulamalarında CPU spike’larının önemli bir kısmı veritabanından kaynaklanır. MySQL için:
# MySQL'de o an çalışan sorguları görmek
mysql -e "SHOW FULL PROCESSLISTG" | grep -A5 "State: "
# Yavaş sorgu logunu aktifleştirmek
mysql -e "SET GLOBAL slow_query_log = 'ON';"
mysql -e "SET GLOBAL long_query_time = 2;"
mysql -e "SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';"
# Slow query log'unu analiz etmek
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# PostgreSQL için aktif sorguları görmek
psql -c "SELECT pid, now() - query_start AS duration, query FROM pg_stat_activity WHERE state = 'active' ORDER BY duration DESC LIMIT 10;"
Index’siz çalışan bir sorgu, milyonlarca satırlık tabloda full table scan yapıp CPU’yu eritebilir. Bu tür sorguları EXPLAIN ANALYZE ile inceleyip gerekli index’leri eklemek çoğu zaman mucize etkisi yapar.
CPU Throttling ve Thermal Sorunlar
Fiziksel sunucularda ve bazı cloud ortamlarında CPU, ısınma nedeniyle kendini kısıtlayabilir (throttling). Bu durumda CPU meşgul görünmez ama sistem çok yavaş çalışır.
# CPU frekansını kontrol et
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
cat /proc/cpuinfo | grep "cpu MHz"
# Thermal throttling var mı?
dmesg | grep -i "throttl|thermal|temperature"
# CPU sıcaklığını okumak
sensors
# veya
cat /sys/class/thermal/thermal_zone*/temp
# CPU governor ayarı (performance modu)
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# Performance moduna almak için
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
Cloud ortamında çalışıyorsanız, CPU credit sistemine dikkat edin. AWS EC2 T serisi instance’lar, Azure B serisi gibi burstable tipte makinelerde CPU kredisi bittiğinde makine dramatik şekilde yavaşlar. Cloud console’dan CPU credit balance’ı kontrol etmeyi unutmayın.
Hızlı Referans: Sorun Giderme Akışı
Bir CPU sorunu yaşadığınızda takip edebileceğiniz adımlar şunlardır:
- 1. Adım:
topveyahtopile genel tabloya bakın,wadeğerine dikkat edin - 2. Adım:
ps aux --sort=-%cpuile suçlu process’i bulun - 3. Adım: Process bir uygulama mı, kernel thread mi, yoksa sistem servisi mi olduğunu belirleyin
- 4. Adım:
strace -cpile ne yaptığını anlayın - 5. Adım: Log dosyalarını kontrol edin
- 6. Adım: Sorun periyodik mi, yoksa sürekli mi diye ayrım yapın
- 7. Adım: Geçici çözüm uygulayın (process restart, nice ile öncelik düşürme)
- 8. Adım: Kalıcı çözümü planlayın ve uygulayın
- 9. Adım: Monitoring ekleyerek tekrar yaşanırsa haberdar olun
Sonuç
Yüksek CPU sorunları korkutucu görünse de sistematik bir yaklaşımla çoğu zaman hızlıca çözülür. Kritik nokta, paniğe kapılmadan önce veriyi toplamak. Önce top ile genel tablo, sonra ps ile suçlu process, ardından strace veya perf ile detay. Bu üç adım çoğu senaryoyu çözmek için yeterli.
En çok karşılaştığım gerçek hayat nedenlerini özetleyeyim: optimize edilmemiş veritabanı sorguları, kontrolsüz cron job’lar, bellek sızıntısından dolayı swap’e düşüp oradan CPU’ya yansıyan dolaylı sorunlar, ve deploy edilen yeni kodda beklenmedik infinite loop veya regex backtracking sorunları.
Her ciddi sunucuya sysstat paketini kurun, sar loglarını aktif edin. Sorun yaşandığında geçmişe dönük veri çok değerli. Grafana/Prometheus gibi bir monitoring stack’i yoksa bile basit bir shell script ile CPU spike’larını loglamak, sabah geldiğinizde “gece ne oldu?” sorusunu cevaplamanızı sağlar.
Son olarak şunu söyleyeyim: Yüksek CPU genellikle bir semptomun habercisidir, asıl hastalık başka bir yerdedir. I/O sorunları CPU’ya yansır, bellek sorunları CPU’ya yansır, kötü kod CPU’ya yansır. CPU’yu düşürmek sorunu çözmez, sebebi bulmak çözer.
