Apache Performans Sorunları: Yüksek CPU ve Bellek Kullanımı

Sunucunuza sabah erken saatlerde bağlandığınızda Apache’nin %90 CPU kullandığını görüyorsunuz, web siteniz yavaşlamış ya da tamamen çökmüş durumda. Bu senaryo, her sysadmin’in kabusu. Ama paniklemeden, sistematik bir şekilde ilerlediğinizde bu sorunların büyük çoğunluğunun çözülmesi oldukça mümkün. Bu yazıda Apache’nin yüksek CPU ve bellek kullanımı sorunlarını nasıl tespit edip çözeceğinizi, gerçek dünya senaryolarıyla birlikte ele alacağız.

Sorunu Tespit Etmek: İlk Adımlar

Herhangi bir performans sorununda ilk işiniz sisteme ne olduğunu anlamak olmalı. Apache’ye hemen dalmadan önce genel sistem durumunu kontrol edin.

# Genel sistem durumuna bakın
top -b -n 1 | head -30

# Apache işlemlerine özel bakış
ps aux | grep apache2 | sort -k3 -rn | head -20

# Bellek kullanımı
free -h

# Apache işlem sayısını öğrenin
ps aux | grep -c apache2

top çıktısında Apache işlemlerinin toplam CPU ve bellek kullanımına bakın. Eğer apache2 işlemleri toplamda %80’in üzerinde CPU kullanıyorsa ciddi bir sorun var demektir. Bu noktada acele kararlar vermek yerine önce veri toplayın.

Apache Durum Modülü ile Anlık İzleme

Apache’nin kendi içindeki mod_status modülü, ne olduğunu anlamak için altın değerinde bilgiler sunar. Eğer henüz aktif değilse hemen açın:

# mod_status durumunu kontrol edin
apache2ctl -M | grep status

# Eğer aktif değilse /etc/apache2/mods-enabled/ altında etkinleştirin
a2enmod status
systemctl reload apache2

/etc/apache2/mods-enabled/status.conf dosyanıza veya VirtualHost konfigürasyonunuza şu bloğu ekleyin:

<Location /server-status>
    SetHandler server-status
    Require ip 127.0.0.1
    Require ip 192.168.1.0/24
</Location>

# Genişletilmiş durum bilgisi için
ExtendedStatus On

Sonra curl http://localhost/server-status?refresh=5 komutuyla anlık durumu izleyebilirsiniz. Bu sayfa size kaç işçinin meşgul olduğunu, hangi isteklerin işlendiğini ve bağlantı sürelerini gösterir.

Yüksek CPU Kullanımının Yaygın Nedenleri

1. MPM Konfigürasyonu Yanlış Ayarlanmış

Apache’nin Multi-Processing Module (MPM) ayarları, performans sorunlarının en yaygın kaynağıdır. prefork, worker veya event modundan hangisini kullandığınızı ve bu modun doğru yapılandırılıp yapılandırılmadığını kontrol etmelisiniz.

# Hangi MPM kullandığınızı öğrenin
apache2ctl -V | grep MPM

# Ya da
apache2ctl -M | grep mpm

prefork MPM kullanıyorsanız ve PHP-FPM’e geçmediyseniz, her istek için ayrı bir işlem fork’lanır. Bu hem CPU hem de bellek açısından çok maliyetlidir. Tipik bir sorunlu konfigürasyon şöyle görünür:

/etc/apache2/mods-enabled/mpm_prefork.conf dosyasını kontrol edin:

# Sorunlu bir prefork konfigürasyonu
<IfModule mpm_prefork_module>
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxRequestWorkers    150
    MaxConnectionsPerChild   0
</IfModule>

MaxConnectionsPerChild 0 değeri işçilerin hiçbir zaman yeniden başlatılmamasına neden olur. Bu, bellek sızıntısı olan PHP uygulamalarında felakete yol açar. Bunu düzeltin:

# Daha sağlıklı bir prefork konfigürasyonu
<IfModule mpm_prefork_module>
    StartServers          5
    MinSpareServers       5
    MaxSpareServers      10
    MaxRequestWorkers    50
    MaxConnectionsPerChild   1000
</IfModule>

MaxRequestWorkers değerini hesaplarken şu formülü kullanın: (Toplam RAM – OS için ayrılan RAM) / Ortalama Apache işlem boyutu. Ortalama işlem boyutunu şu komutla öğrenebilirsiniz:

ps aux | grep apache2 | awk '{sum += $6; count++} END {print sum/count/1024 " MB"}'

2. Keep-Alive Ayarları

KeepAlive özelliği doğru ayarlanmadığında sunucunuz gereksiz yere bağlantıları açık tutar ve bu da CPU ile belleği tüketir.

# /etc/apache2/apache2.conf veya ilgili konfigürasyonda
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5

KeepAliveTimeout değerini 15-30 saniye gibi yüksek tutarsanız, her bağlantı o süre boyunca bir Apache işçisini meşgul eder. Statik içerik ağırlıklı sitelerde bu değeri 2-5 saniyeye düşürmek büyük fark yaratır.

3. .htaccess Dosyaları Her İstekte Okunuyor

Bu konu çok hafife alınan bir performans katilidir. AllowOverride All ayarı yapıldığında Apache her istek için tüm dizin hiyerarşisindeki .htaccess dosyalarını okur. 10 katman derinliğinde bir dizin yapınız varsa her istek için 10 disk okuma işlemi gerçekleşir.

# Sorunlu konfigürasyon
<Directory /var/www/>
    AllowOverride All
</Directory>

# Daha iyi yaklaşım - .htaccess kurallarını ana konfigürasyona taşıyın
<Directory /var/www/>
    AllowOverride None
</Directory>

.htaccess içindeki kuralları VirtualHost konfigürasyonuna taşıdıktan sonra Apache’yi yeniden yükleyin. Yoğun trafik altında bu değişiklik CPU kullanımını %20-30 oranında düşürebilir.

Log Analizi ile Sorun Tespiti

Yüksek CPU kullanımının arkasında çoğu zaman belirli URL’lere gelen anormal trafik ya da yavaş sorgular vardır. Log analizi bu noktada kritik bilgiler verir.

# En çok istek gelen URL'ler
awk '{print $7}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

# En çok istek gönderen IP'ler
awk '{print $1}' /var/log/apache2/access.log | sort | uniq -c | sort -rn | head -20

# Son 1 saatteki istek sayısı
awk -v d="$(date -d '1 hour ago' '+%d/%b/%Y:%H')" '$4 > "["d' /var/log/apache2/access.log | wc -l

# Yavaş istekler için (5 saniyeden uzun)
grep -E '"[0-9]{6,}"$' /var/log/apache2/access.log

GoAccess aracı gerçek zamanlı log analizi için mükemmeldir:

# GoAccess kurulumu
apt install goaccess

# Anlık terminal analizi
goaccess /var/log/apache2/access.log --log-format=COMBINED

# HTML raporu oluşturma
goaccess /var/log/apache2/access.log -o /var/www/html/report.html --log-format=COMBINED

Yavaş İstek Loglama

Apache’nin mod_logio ve özel log formatlarıyla yavaş istekleri tespit edebilirsiniz:

# /etc/apache2/apache2.conf içinde özel log formatı
LogFormat "%h %l %u %t "%r" %>s %b %D" combined_with_time

# VirtualHost içinde kullanım
CustomLog /var/log/apache2/slow_requests.log combined_with_time

# 2 saniyeden uzun süren istekleri filtrele (2000000 mikrosaniye)
awk '$NF > 2000000' /var/log/apache2/slow_requests.log | awk '{print $7}' | sort | uniq -c | sort -rn

%D log değişkeni isteğin mikrosakiye cinsinden ne kadar sürdüğünü kaydeder. Bu verilerle hangi endpoint’lerin sorun çıkardığını net olarak görebilirsiniz.

Bellek Sızıntısı Tespiti

Bellek kullanımı zamanla artıyor ve Apache yeniden başlatıldığında normale dönüyorsa bellek sızıntısından şüphelenmelisiniz. PHP uygulamalarında bu çok yaygındır.

# Apache işlemlerinin bellek kullanımını zaman içinde izleyin
watch -n 5 'ps aux | grep apache2 | awk "{sum += $6} END {print sum/1024 " MB"}"'

# Belirli bir işlemin bellek büyümesini takip edin
PID=$(pgrep -o apache2)
while true; do
    cat /proc/$PID/status | grep VmRSS
    sleep 30
done

Eğer işlem boyutları sürekli büyüyorsa MaxConnectionsPerChild değerini düşürün. Bu ayar, bir işçinin belirli sayıda istek sonrası yeniden başlatılmasını sağlar ve bellek sızıntısının etkisini sınırlar.

PHP-FPM’e Geçiş: Kalıcı Çözüm

Hâlâ mod_php kullanıyorsanız ve prefork MPM üzerinde çalışıyorsanız, en büyük performans kazancını PHP-FPM’e geçerek elde edersiniz. Bu geçiş Apache’nin event MPM kullanmasını sağlar ve aynı donanımla çok daha fazla isteği karşılayabilirsiniz.

# PHP-FPM kurulumu (örnek: PHP 8.1)
apt install php8.1-fpm

# Apache modüllerini düzenleyin
a2dismod php8.1
a2dismod mpm_prefork
a2enmod mpm_event
a2enmod proxy_fcgi setenvif
a2enconf php8.1-fpm

# PHP-FPM'i başlatın
systemctl start php8.1-fpm
systemctl enable php8.1-fpm

# Apache'yi yeniden yükleyin
systemctl reload apache2

PHP-FPM konfigürasyonunu da optimize etmeniz gerekir. /etc/php/8.1/fpm/pool.d/www.conf dosyasında:

# PHP-FPM pool konfigürasyonu
[www]
pm = dynamic
pm.max_children = 20
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 8
pm.max_requests = 500

# Yavaş logları etkinleştirin
slowlog = /var/log/php8.1-fpm-slow.log
request_slowlog_timeout = 5s

pm.max_requests = 500 ayarı ile her FPM işçisi 500 istek sonrası yeniden başlatılır. Bu bellek sızıntısı olan uygulamalarda hayat kurtarıcıdır.

Önbelleğe Alma ile CPU Yükünü Azaltma

mod_cache Kullanımı

Dinamik içeriği bile önbelleğe alarak CPU kullanımını dramatik şekilde düşürebilirsiniz:

# mod_cache ve mod_cache_disk etkinleştirme
a2enmod cache
a2enmod cache_disk
a2enmod headers

# VirtualHost konfigürasyonuna ekleyin
<IfModule mod_cache.c>
    CacheEnable disk /
    CacheRoot /var/cache/apache2/mod_cache_disk
    CacheDefaultExpire 3600
    CacheMaxExpire 86400
    CacheIgnoreNoLastMod On
    
    # Belirli dosya tiplerini önbellekle
    <LocationMatch ".(jpg|jpeg|png|gif|css|js)$">
        CacheEnable disk
        Header merge Cache-Control public
        ExpiresDefault "access plus 1 week"
    </LocationMatch>
</IfModule>
# Önbellek dizinini oluşturun
mkdir -p /var/cache/apache2/mod_cache_disk
chown www-data:www-data /var/cache/apache2/mod_cache_disk

mod_deflate ile Bant Genişliği Optimizasyonu

Sıkıştırma hem bant genişliğini azaltır hem de daha hızlı yanıtlar üretir:

# mod_deflate konfigürasyonu
a2enmod deflate

# apache2.conf veya VirtualHost'a ekleyin
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/plain text/xml
    AddOutputFilterByType DEFLATE text/css text/javascript
    AddOutputFilterByType DEFLATE application/javascript application/json
    DeflateCompressionLevel 6
</IfModule>

Gerçek Dünya Senaryosu: DDoS ve Bot Trafiği

Bir müşterinin sunucusunda CPU’nun %100’e çıkması sorununu incelerken log analizinde şunu bulduk: Tek bir IP’den saniyede 50’nin üzerinde istek geliyordu ve tüm bu istekler dinamik PHP sayfalarına yapılıyordu.

# Anlık bağlantı sayısını kontrol edin
netstat -an | grep ESTABLISHED | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -20

# Apache'de zaten bağlı olan bağlantılar
apachectl fullstatus | grep -E "^[0-9]" | head -30

Bu tür durumlarda mod_evasive veya mod_security kullanmak uzun vadeli çözümdür. Kısa vadede ise:

# Saldıran IP'yi iptables ile engelle
iptables -A INPUT -s 1.2.3.4 -j DROP

# Veya .htaccess ile (eğer AllowOverride açıksa)
# /var/www/html/.htaccess
Order Allow,Deny
Deny from 1.2.3.4
Allow from all

mod_evasive kurulumu ve konfigürasyonu:

apt install libapache2-mod-evasive
a2enmod evasive

# /etc/apache2/mods-enabled/evasive.conf
<IfModule mod_evasive20.c>
    DOSHashTableSize    3097
    DOSPageCount        5
    DOSSiteCount        50
    DOSPageInterval     1
    DOSSiteInterval     1
    DOSBlockingPeriod   10
    DOSEmailNotify      [email protected]
    DOSLogDir           /var/log/apache2/evasive
</IfModule>

Sistem Seviyesinde Optimizasyonlar

Apache’nin performansını etkileyen sistem parametrelerini de unutmayın:

# /etc/sysctl.conf dosyasına ekleyin
# TCP bağlantı yönetimi
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.core.somaxconn = 65535
net.ipv4.ip_local_port_range = 1024 65535

# Değişiklikleri uygulayın
sysctl -p

# Dosya tanımlayıcı limitlerini artırın
# /etc/security/limits.conf
www-data soft nofile 65536
www-data hard nofile 65536

Apache’nin kendi limitlerini de ayarlayın. /etc/apache2/envvars dosyasına ekleyin:

# Ulimit ayarları
ulimit -n 65536

İzleme ve Alarm Sistemi Kurma

Sorun çıktıktan sonra değil, çıkmadan önce haberdar olmak istersiniz. Basit bir izleme scripti:

#!/bin/bash
# /usr/local/bin/apache_monitor.sh

CPU_THRESHOLD=80
MEM_THRESHOLD=80
EMAIL="[email protected]"

# Apache CPU kullanımı
APACHE_CPU=$(ps aux | grep apache2 | grep -v grep | awk '{sum += $3} END {print int(sum)}')

# Apache bellek kullanımı (MB)
APACHE_MEM=$(ps aux | grep apache2 | grep -v grep | awk '{sum += $6} END {print int(sum/1024)}')

# Apache işlem sayısı
APACHE_PROCS=$(ps aux | grep apache2 | grep -v grep | wc -l)

if [ "$APACHE_CPU" -gt "$CPU_THRESHOLD" ]; then
    echo "UYARI: Apache CPU kullanimi ${APACHE_CPU}% - $(date)" | mail -s "Apache CPU Alarm" $EMAIL
    logger "Apache yuksek CPU: ${APACHE_CPU}%"
fi

if [ "$APACHE_MEM" -gt 1024 ]; then
    echo "UYARI: Apache bellek kullanimi ${APACHE_MEM}MB - $(date)" | mail -s "Apache Bellek Alarm" $EMAIL
fi

Bu scripti cron’a ekleyin:

# Crontab'a ekleyin
*/5 * * * * /usr/local/bin/apache_monitor.sh

Hızlı Kontrol Listesi

Yüksek CPU/bellek sorunuyla karşılaştığınızda sırayla yapmanız gerekenler:

  • top ve ps aux ile mevcut durumu belgeleyin
  • Apache işlem sayısını kontrol edin, MaxRequestWorkers sınırına yaklaşılıyor mu?
  • Log analizi yapın, anormal trafik var mı?
  • mod_status çıktısını inceleyin, hangi istekler uzun sürüyor?
  • MaxConnectionsPerChild değerinin ayarlı olduğundan emin olun
  • KeepAliveTimeout değerini gözden geçirin
  • PHP kullanıyorsanız mod_php yerine PHP-FPM kullanmayı değerlendirin
  • .htaccess ve AllowOverride All konfigürasyonunu gözden geçirin
  • Sıkıştırma ve önbelleğe almanın aktif olup olmadığını kontrol edin

Sonuç

Apache performans sorunları genellikle tek bir nedenden kaynaklanmaz. Yanlış MPM ayarları, uygunsuz KeepAlive konfigürasyonu, aşırı .htaccess kullanımı, bellek sızdıran PHP uygulamaları ve bot/DDoS trafiği bir arada rol oynayabilir. Bu yüzden sistematik bir yaklaşımla önce veri toplamak, sonra çözüme gitmek en sağlıklı yolu oluşturur.

PHP-FPM’e geçiş ve event MPM kombinasyonu, modern web sunucuları için neredeyse her zaman doğru tercih olmaktadır. Prefork MPM hâlâ kullanıyorsanız ve bunu değiştirme imkânınız yoksa en azından MaxConnectionsPerChild ve MaxRequestWorkers değerlerini doğru ayarladığınızdan emin olun.

Uzun vadede ise proaktif izleme kurmanız, sorunları kullanıcılarınız fark etmeden önce tespit etmenizi sağlar. Alarm sistemleri yazmak, düzenli log analizi yapmak ve konfigürasyon değişikliklerini versiyon kontrolünde tutmak, bir sysadmin olarak sizi reaktif değil proaktif konuma getirir. Ve bu fark, gece 3’te telefon alıp almamak arasındaki fark olabilir.

Benzer Konular

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir