Apache web sunucunuzu kurdunuz, siteniz yayında ve her şey güzel gidiyor. Sonra bir gün trafik artıyor, sunucu kasılmaya başlıyor ve loglarınızda şu korkutucu mesajı görüyorsunuz: server reached MaxRequestWorkers setting, consider raising the MaxRequestWorkers setting. İşte tam bu noktada Apache’nin bellek ve process yönetimini anlamanız gerekiyor. Bu yazıda ServerLimit ve MaxRequestWorkers direktiflerini derinlemesine inceleyeceğiz, yanlış yapılandırmanın nasıl felaket yarattığını göreceğiz ve gerçek dünya senaryolarıyla optimum değerleri nasıl hesaplayacağınızı öğreneceğiz.
Apache MPM Nedir ve Neden Önemli?
ServerLimit ve MaxRequestWorkers değerlerini ayarlamadan önce Apache’nin hangi modda çalıştığını anlamanız şart. Apache, farklı Multi-Processing Module (MPM) modlarını destekler ve her modun davranışı birbirinden farklıdır.
prefork MPM: Her istek için ayrı bir process oluşturur. PHP’nin mod_php ile kullanıldığı klasik yapılarda tercih edilir. Thread-safe olmayan kütüphanelerle güvenli çalışır ama bellek tüketimi yüksektir.
worker MPM: Her process içinde birden fazla thread çalıştırır. Daha az bellek kullanır, daha fazla eş zamanlı bağlantı yönetebilir.
event MPM: Worker MPM’e benzer ama keep-alive bağlantılarını çok daha verimli yönetir. Modern Apache kurulumlarında varsayılan ve önerilen moddur.
Hangi MPM’i kullandığınızı öğrenmek için:
apache2ctl -V | grep MPM
# veya
httpd -V | grep MPM
# Çıktı: Server MPM: event
Mevcut yüklü MPM modüllerini görmek için:
apache2ctl -M | grep mpm
# Çıktı: mpm_event_module (shared)
ServerLimit ve MaxRequestWorkers Farkı
Bu iki direktif birbiriyle karıştırılıyor ve yanlış anlaşılıyor. Net bir şekilde tanımlayalım:
MaxRequestWorkers: Aynı anda kaç tane isteğin karşılanacağını belirler. Eski Apache sürümlerinde MaxClients olarak geçiyordu. Bu değere ulaşıldığında yeni gelen bağlantılar kuyrukta bekler (kernel’in ListenBacklog ayarına kadar) ya da reddedilir.
ServerLimit: MaxRequestWorkers değerinin üst sınırını belirler. Prefork MPM’de bu değer aynı zamanda maksimum process sayısını ifade eder. Eğer MaxRequestWorkers değerini 256’nın üzerine çıkarmak istiyorsanız ServerLimit’i de artırmanız zorunludur.
Arasındaki ilişkiyi şöyle özetleyebiliriz:
- ServerLimit: Fiziksel üst sınır, Apache’nin hiçbir zaman aşamayacağı değer
- MaxRequestWorkers: Aktif olarak kullanılacak maksimum worker sayısı
- MaxRequestWorkers her zaman ServerLimit’e eşit ya da küçük olmak zorundadır
- ServerLimit değişikliği Apache’nin tamamen yeniden başlatılmasını gerektirir, sadece
reloadyetmez
Mevcut Durumunuzu Analiz Edin
Optimizasyona başlamadan önce mevcut durumu anlamak gerekiyor. Apache’nin o anki durumunu görmek için mod_status modülünü aktif edin:
# Debian/Ubuntu
sudo a2enmod status
# mod_status yapılandırması
sudo nano /etc/apache2/conf-available/server-status.conf
<Location "/server-status">
SetHandler server-status
Require local
# Ya da belirli IP'den erişim için:
# Require ip 192.168.1.0/24
</Location>
ExtendedStatus On
Komut satırından anlık durumu görüntülemek için:
# Curl ile server-status çıktısını al
curl -s http://localhost/server-status?auto | grep -E "BusyWorkers|IdleWorkers|Scoreboard"
# Daha detaylı görünüm
watch -n 2 'curl -s http://localhost/server-status?auto'
Çıktıda göreceğiniz Scoreboard satırındaki karakterlerin anlamları:
- _: Boşta bekleyen worker (idle)
- S: Başlatılıyor (starting up)
- R: İstek okuma
- W: İsteğe yanıt yazıyor
- K: Keep-alive bağlantısı bekliyor
- D: DNS sorgusu
- C: Bağlantı kapanıyor
- .: Açık olmayan slot
Eğer Scoreboard’da sürekli W ve R harfleri dolup taşıyorsa ve _ karakterleri azalıyorsa, worker sayısını artırmayı düşünme zamanı gelmiş demektir.
Bellek Hesaplama: En Kritik Adım
Burada sysadminlerin en büyük hatası, mantıklı bir hesap yapmadan keyfi değerler girmek. MaxRequestWorkers’ı 1000 yapayım, ne olur ki? diyenler sunucuyu OOM (Out of Memory) killer’ın eline teslim eder.
Doğru hesaplama şu şekilde yapılır:
# Mevcut Apache process'lerinin bellek kullanımını öğren
ps aux | grep apache2 | grep -v grep | awk '{print $6}' | sort -n
# Ortalama bellek kullanımı (KB cinsinden)
ps aux | grep apache2 | grep -v grep | awk '{sum += $6; count++} END {print "Ortalama:", sum/count, "KB =", sum/count/1024, "MB"}'
# En büyük process'i bul
ps aux | grep apache2 | grep -v grep | sort -k6 -rn | head -5
Gerçek dünya örneği verelim. Diyelim ki yukarıdaki komut şu çıktıyı verdi:
Ortalama: 45231 KB = 44.17 MB
Şimdi hesaplama:
# Sistemde kullanılabilir toplam RAM'i öğren
free -m
# Çıktı örneği:
# total used free shared buff/cache available
# Mem: 7962 1823 412 234 5726 5652
# Hesaplama mantığı:
# Kullanılabilir RAM: ~5500 MB (available)
# Sistem ve diğer servisler için ayır: 1000 MB
# Apache için kalan: 4500 MB
# Her process ~45 MB alıyorsa: 4500 / 45 = 100 worker
Bu hesabı script haline getirin:
#!/bin/bash
# apache_memory_calc.sh
AVAILABLE_MEM=$(free -m | awk '/^Mem:/{print $7}')
SYSTEM_RESERVE=1024 # MB olarak sistem rezervi
APACHE_MEM=$((AVAILABLE_MEM - SYSTEM_RESERVE))
# Apache process başına ortalama bellek (MB)
AVG_PROCESS_MEM=$(ps aux | grep apache2 | grep -v grep |
awk '{sum += $6; count++} END {printf "%.0f", sum/count/1024}')
if [ -z "$AVG_PROCESS_MEM" ] || [ "$AVG_PROCESS_MEM" -eq 0 ]; then
echo "Apache process bulunamadi veya henuz calismıyor."
AVG_PROCESS_MEM=50 # Varsayılan tahmin
fi
MAX_WORKERS=$((APACHE_MEM / AVG_PROCESS_MEM))
echo "Kullanilabilir RAM: ${AVAILABLE_MEM} MB"
echo "Sistem rezervi: ${SYSTEM_RESERVE} MB"
echo "Apache için RAM: ${APACHE_MEM} MB"
echo "Process başına ortalama RAM: ${AVG_PROCESS_MEM} MB"
echo "Önerilen MaxRequestWorkers: ${MAX_WORKERS}"
echo "Önerilen ServerLimit: ${MAX_WORKERS}"
Prefork MPM Yapılandırması
PHP uygulamaları mod_php ile çalışıyorsa büyük ihtimalle prefork MPM kullanıyorsunuzdur. Yapılandırma dosyasını açalım:
# Ubuntu/Debian
sudo nano /etc/apache2/mods-available/mpm_prefork.conf
# CentOS/RHEL
sudo nano /etc/httpd/conf.modules.d/00-mpm.conf
<IfModule mpm_prefork_module>
# Başlangıçta oluşturulacak child process sayısı
StartServers 5
# Her zaman hazırda bekleyen minimum idle process
MinSpareServers 5
# Maksimum idle process sayısı (bunun üzeri öldürülür)
MaxSpareServers 10
# Mutlak maksimum - bellek hesabına göre belirle
MaxRequestWorkers 150
# MaxRequestWorkers 256'yı geçiyorsa bu değeri de artır
ServerLimit 150
# Her child process kaç istek karşıladıktan sonra yeniden başlar
# Memory leak olan PHP uygulamaları için önemli
MaxConnectionsPerChild 10000
</IfModule>
Burada MaxConnectionsPerChild direktifine dikkat edin. PHP uygulamalarında memory leak riski varsa bu değeri düşük tutmak (örneğin 1000-5000) process’lerin periyodik olarak yeniden başlamasını sağlar ve bellek sızıntısının birikmesini önler. Elbette bu trade-off içerir, process başlatma maliyeti artar.
Worker ve Event MPM Yapılandırması
Modern PHP-FPM + Nginx/Apache kurulumlarında ya da statik/PHP dışı içerik sunan sunucularda worker veya event MPM çok daha verimlidir:
sudo nano /etc/apache2/mods-available/mpm_event.conf
<IfModule mpm_event_module>
# Başlangıç process sayısı
StartServers 3
# Minimum idle thread sayısı
MinSpareThreads 25
# Maksimum idle thread sayısı
MaxSpareThreads 75
# Her process içindeki thread sayısı
ThreadsPerChild 25
# Maksimum eş zamanlı istek (MaxRequestWorkers)
MaxRequestWorkers 200
# Maksimum process sayısı
# MaxRequestWorkers / ThreadsPerChild = gereken process sayısı
# 200 / 25 = 8, biraz üstünde tutalım
ServerLimit 16
# Keep-alive bağlantıları için ayrılan thread sayısı
AsyncRequestWorkerFactor 2
MaxConnectionsPerChild 0
</IfModule>
Event MPM’de ServerLimit hesabı farklıdır. Process başına thread çalıştığı için:
- MaxRequestWorkers: 200
- ThreadsPerChild: 25
- Gereken minimum ServerLimit: 200 / 25 = 8
- Güvenli ServerLimit: 16 (biraz marj bırakıyoruz)
Gerçek Dünya Senaryo 1: Orta Ölçekli E-Ticaret Sitesi
4 GB RAM’li bir VPS üzerinde WooCommerce çalıştıran bir senaryo düşünelim. Prefork MPM kullanılıyor, PHP mod_php ile entegre.
Sorun: Yoğun saatlerde sayfa yüklemeleri 30-40 saniyeye çıkıyor, hatta zaman zaman 503 hatası alınıyor.
Analiz aşaması:
# Error log'a bak
sudo tail -f /var/log/apache2/error.log | grep -i "maxrequestworkers|maxclients|reached"
# Process başına bellek kullanımını ölç
# WooCommerce + WordPress ortalaması genelde 80-120 MB arasında
ps aux | grep apache2 | grep -v grep | awk '{sum+=$6; n++} END {print sum/n/1024 " MB"}'
# Çıktı: 95.3 MB
Hesaplama:
- Toplam RAM: 4096 MB
- İşletim sistemi: ~400 MB
- MySQL: ~600 MB
- Diğer servisler: ~200 MB
- Apache için kalan: ~2900 MB
- Process başına: ~95 MB
- MaxRequestWorkers: 2900 / 95 = 30 (yaklaşık)
Yapılandırma:
<IfModule mpm_prefork_module>
StartServers 3
MinSpareServers 3
MaxSpareServers 8
MaxRequestWorkers 30
ServerLimit 30
MaxConnectionsPerChild 5000
</IfModule>
Bu örnek küçük gözükebilir ama 4 GB RAM’li bir sunucuda WordPress+WooCommerce için 30 eş zamanlı istek gayet makul bir değerdir. Gerçek şu ki çoğu orta ölçekli e-ticaret sitesi aynı anda 30’dan fazla PHP isteği görmez. Üzerine bir CDN ve sayfa önbellekleme (Varnish veya LiteSpeed Cache) eklendiğinde bu değer çok yeterli olur.
Gerçek Dünya Senaryo 2: Yüksek Trafikli API Sunucusu
8 GB RAM, PHP-FPM kullanan bir REST API sunucusu. Event MPM ile Apache ters proxy olarak çalışıyor, PHP-FPM arka planda işlemleri karşılıyor.
Bu senaryoda Apache process’leri hafiftir çünkü PHP işlemlerini kendi üstlenmez:
# Apache worker'larının bellek kullanımı (PHP-FPM kurulumunda çok düşük olur)
ps aux | grep apache2 | grep -v grep | awk '{sum+=$6; n++} END {print sum/n/1024 " MB"}'
# Çıktı: 8.7 MB (evet, bu kadar düşük olabilir)
<IfModule mpm_event_module>
StartServers 4
MinSpareThreads 50
MaxSpareThreads 150
ThreadsPerChild 50
MaxRequestWorkers 500
ServerLimit 20
AsyncRequestWorkerFactor 4
MaxConnectionsPerChild 0
</IfModule>
Bu yapılandırmada Apache tek başına 500 eş zamanlı isteği yönetebilir ve sadece ~70-80 MB bellek kullanır. PHP-FPM tarafındaki pool ayarlarını da buna göre yapılandırmanız gerektiğini unutmayın.
Yapılandırmayı Test Edin
Değişiklik yapmadan önce syntax kontrolü şart:
# Syntax kontrolü
sudo apache2ctl configtest
# ya da
sudo apachectl -t
# Sorun yoksa yeniden başlat (ServerLimit değişikliği reload ile uygulanmaz!)
sudo systemctl restart apache2
# Yalnızca MaxRequestWorkers değiştirdiyseniz reload yeterli
sudo systemctl reload apache2
Yük testi için Apache Bench kullanarak yapılandırmanızı doğrulayın:
# 1000 istek, 50 eş zamanlı bağlantı
ab -n 1000 -c 50 http://localhost/
# Daha gerçekçi test: keep-alive ile
ab -n 5000 -c 100 -k http://localhost/
# Sonuçlarda dikkat edilecek değerler:
# - Requests per second: ne kadar istek/saniye karşılıyorsunuz
# - Failed requests: başarısız istek var mı
# - Time per request: ortalama yanıt süresi
Yük testi sırasında başka bir terminal açıp sunucuyu izleyin:
# Anlık worker durumu
watch -n 1 'curl -s http://localhost/server-status?auto | grep -E "BusyWorkers|IdleWorkers"'
# Bellek kullanımı
watch -n 1 'free -m'
# Apache process sayısı
watch -n 1 'ps aux | grep apache2 | grep -v grep | wc -l'
Sık Yapılan Hatalar ve Çözümleri
Hata 1: ServerLimit’i değiştirip sadece reload yapmak. ServerLimit değişikliği Apache’nin belleğe yükleme biçimini etkiler ve sadece tam yeniden başlatma ile aktif olur. Reload yaparsanız değişiklik görmezden gelinir ve log’da uyarı bile göremezsiniz.
Hata 2: MaxRequestWorkers’ı çok yüksek tutmak. Bellek dolunca Linux kernel’in OOM killer’ı devreye girer ve rastgele process’leri öldürür. Çoğunlukla Apache process’lerini hedef alır ama bazen MySQL’i de vurabilir. Bunun yerine düşük bir MaxRequestWorkers ile sağlıklı bir sistem, yüksek değerle çöken bir sistem arasında tercih yapmanız gerekirse düşük değeri seçin.
Hata 3: ServerLimit’i MaxRequestWorkers’dan düşük tutmak.
# Bu yanlış yapılandırma Apache'nin startup log'unda uyarı verir:
# WARNING: MaxRequestWorkers of 300 exceeds ServerLimit value
# of 256 servers, lowering MaxRequestWorkers to 256.
# To increase, please see the ServerLimit directive.
# Doğrusu: ServerLimit >= MaxRequestWorkers olmalı
ServerLimit 300
MaxRequestWorkers 300
Hata 4: Swap alanını hesaba katmak. Swap kullanımına güvenerek MaxRequestWorkers değerini RAM kapasitesinin ötesine taşıyanlar büyük hayal kırıklığı yaşar. Disk tabanlı swap üzerinde Apache worker çalıştırmak, yanıt sürelerini saniyelerle ölçülür hale getirir. Swap’ı acil durum tamponu olarak görün, normal operasyon belleği olarak değil.
Monitoring ve Log Analizi
Yapılandırmanızın ne kadar iyi çalıştığını sürekli izlemeniz gerekiyor:
#!/bin/bash
# apache_monitor.sh - Cron ile her 5 dakikada çalıştırın
LOG_FILE="/var/log/apache_monitor.log"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
BUSY=$(curl -s http://localhost/server-status?auto | grep BusyWorkers | awk '{print $2}')
IDLE=$(curl -s http://localhost/server-status?auto | grep IdleWorkers | awk '{print $2}')
TOTAL=$((BUSY + IDLE))
MAX=$(grep MaxRequestWorkers /etc/apache2/mods-enabled/mpm_prefork.conf 2>/dev/null |
awk '{print $2}' | tr -d ' ')
USAGE_PCT=$((BUSY * 100 / MAX))
echo "${TIMESTAMP} | Busy: ${BUSY} | Idle: ${IDLE} | Total: ${TOTAL} | Kullanım: %${USAGE_PCT}"
>> "$LOG_FILE"
# %80 üzerine çıkınca uyar
if [ "$USAGE_PCT" -gt 80 ]; then
echo "${TIMESTAMP} UYARI: Worker kullanımı %${USAGE_PCT}'e ulasti!"
| mail -s "Apache Worker Uyarisi" [email protected]
fi
Error log’unda düzenli olarak arama yapın:
# Son 24 saatte MaxRequestWorkers uyarısı var mı
grep -c "MaxRequestWorkers" /var/log/apache2/error.log
# Hangi saatlerde yoğunluk var
grep "MaxRequestWorkers" /var/log/apache2/error.log |
awk '{print $1, $2}' | cut -d: -f1-2 | sort | uniq -c | sort -rn | head -20
Sonuç
ServerLimit ve MaxRequestWorkers tuning’i, Apache optimizasyonunun belki de en kritik adımıdır. Yanlış yapılandırılmış bir sunucu ya kaynak israfeder ya da trafik yükü altında çöker. Doğru yaklaşım her zaman ölçümle başlar: önce process başına gerçek bellek kullanımını öğrenin, sonra kullanılabilir RAM’i hesaba katarak mantıklı bir üst sınır belirleyin.
MPM seçiminiz de kritik öneme sahip. PHP-FPM kullanıyorsanız event MPM ile çok daha hafif ve verimli bir yapı kurabilirsiniz. Mod_php ile devam etmek zorundaysanız prefork MPM ile çalışın ama MaxConnectionsPerChild ile bellek sızıntılarının önüne geçmeyi unutmayın.
Son olarak şunu vurgulayayım: bu değerler bir kez ayarlanıp unutulan parametreler değil. Uygulamanız büyüdükçe, trafik arttıkça, sunucunuza RAM ekledikçe bu değerleri gözden geçirin. Monitoring kurulmadan yapılan her optimizasyon körler tarafından yapılan bir çalışmadır. mod_status aktif olsun, loglarınızı düzenli inceleyin ve Apache Bench gibi araçlarla periyodik yük testleri yapın.