Apache’de Segmentation Fault ve Core Dump Analizi

Gece 2’de telefonun çalması ve “Apache çöktü, siteler erişilemez durumda” mesajını almak, hiçbir sysadmin’in istemediği bir senaryodur. Ama daha kötüsü de var: Apache çöküyor, yeniden başlıyor ve sen neden çöktüğünü bir türlü bulamıyorsun. İşte tam bu noktada segmentation fault analizi ve core dump okuma becerisi devreye giriyor.

Bu yazıda Apache’nin segfault verdiği durumlarda ne yapmanız gerektiğini, core dump dosyalarını nasıl okuyacağınızı ve gerçek dünya senaryolarında bu bilgileri nasıl kullanacağınızı adım adım anlatacağım.

Segmentation Fault Nedir, Apache Neden Segfault Verir?

Segmentation fault, bir programın kendisine tahsis edilmemiş bir bellek alanına erişmeye çalışması durumunda işletim sistemi tarafından gönderilen SIGSEGV sinyalidir. Apache gibi karmaşık bir web sunucusunda bu durum genellikle şu sebeplerden kaynaklanır:

  • Hatalı veya uyumsuz modüller: mod_php, mod_security, mod_rewrite gibi modüllerin belirli versiyonları Apache ile uyumsuzluk yaşayabilir
  • Bellek sızıntıları: Uzun süre çalışan worker process’lerin bellek birikmesi
  • Hatalı Apache konfigürasyonu: Yanlış konfigüre edilmiş VirtualHost veya direktifler
  • Üçüncü parti kütüphane sorunları: OpenSSL, libxml2 gibi bağımlılıkların versiyonları
  • Kaynak tükenmesi: Çok sayıda eş zamanlı bağlantı altında arabellek taşmaları

Apache, multi-process veya multi-thread modelde çalıştığı için bir worker process segfault verdiğinde ana process (parent) genellikle ayakta kalır ve sistemi yeniden başlatır. Bu yüzden “Apache çalışıyor ama bir şeyler ters gidiyor” durumunu yaşarsınız.

İlk Adım: Logları Doğru Okumak

Segfault şüphesi uyandığında ilk yapmanız gereken şey Apache hata loglarına bakmaktır.

# Apache error log'u canlı takip et
tail -f /var/log/apache2/error.log

# Ya da RHEL/CentOS sistemlerde
tail -f /var/log/httpd/error_log

# Segfault içeren satırları filtrele
grep -i "segfault|sigsegv|child pid" /var/log/apache2/error.log | tail -50

Tipik bir segfault log girdisi şöyle görünür:

[Thu Nov 14 02:17:43.421094 2024] [core:notice] [pid 1234] AH00052: child pid 5678 exit signal Segmentation fault (11), possible coredump in /var/crash

Bu satırda birkaç kritik bilgi var: hangi PID’in çöktüğü, hangi sinyalin geldiği ve core dump’ın nerede olabileceği. Eğer “possible coredump” yazıyorsa Apache’nin core dump oluşturmaya çalıştığını anlıyoruz, ama bu her zaman başarılı olmaz.

Sistem loglarına da bakmanız gerekiyor:

# Kernel mesajlarında segfault ara
dmesg | grep -i "apache|httpd|segfault" | tail -20

# journald üzerinden (systemd sistemler)
journalctl -u apache2 --since "1 hour ago" | grep -i "fault|signal|crash"

# journalctl ile kernel mesajları
journalctl -k | grep segfault | tail -20

Kernel’in segfault mesajı şöyle görünür:

httpd[5678]: segfault at 0 ip 00007f1234567890 sp 00007ffd12345678 error 4 in libphp7.4.so[7f1234000000+800000]

Bu kernel mesajı altın değerindedir. “at 0” kısmı null pointer dereference olduğunu, “in libphp7.4.so” kısmı ise suçlunun PHP modülü olduğunu söylüyor.

Core Dump Konfigürasyonu

Varsayılan olarak birçok sistemde core dump devre dışıdır veya kısıtlıdır. Apache’nin core dump oluşturmasını sağlamak için birkaç adım atmanız gerekiyor.

Sistem Genelinde Core Dump Ayarları

# Mevcut core dump limitini kontrol et
ulimit -c

# Eğer 0 ise core dump disabled demektir
# Geçici olarak unlimited yap
ulimit -c unlimited

# Kalıcı değişiklik için
echo "* soft core unlimited" >> /etc/security/limits.conf
echo "* hard core unlimited" >> /etc/security/limits.conf

# systemd sistemlerde core dump boyut limitini kontrol et
cat /proc/sys/kernel/core_pattern

Apache Konfigürasyonunda Core Dump

Apache’nin kendi core dump direktifi var. /etc/apache2/apache2.conf veya /etc/httpd/conf/httpd.conf dosyasına şunu ekleyin:

# Core dump dizinini belirt
CoreDumpDirectory /var/crash/apache

# Debug log seviyesi için
LogLevel debug

Dizini oluşturun ve izinleri ayarlayın:

mkdir -p /var/crash/apache
chown root:www-data /var/crash/apache
chmod 1777 /var/crash/apache

# Apache'yi yeniden başlat
systemctl restart apache2

systemd ile Core Dump

Modern systemd sistemlerde core dump yönetimi systemd-coredump üzerinden yapılır:

# systemd-coredump konfigürasyonu
cat /etc/systemd/coredump.conf

# Core dump'ları listele
coredumpctl list

# Apache ile ilgili son core dump
coredumpctl list httpd

# Belirli bir core dump'ı çıkar
coredumpctl dump httpd -o /tmp/apache.core

GDB ile Core Dump Analizi

Core dump dosyasını aldıktan sonra asıl iş başlıyor. GDB (GNU Debugger) bu noktada en güçlü aracınız.

GDB Kurulumu ve Apache Debug Sembolleri

# Debian/Ubuntu
apt-get install gdb apache2-dbg

# RHEL/CentOS
yum install gdb httpd-debuginfo

# Debug sembolleri olmadan analiz yarı kör olarak yapılır
# Hangi debug paketleri kurulu?
dpkg -l | grep dbg | grep apache

Core Dump’ı GDB ile Açma

# Core dump analizi
gdb /usr/sbin/apache2 /var/crash/apache/core.5678

# Veya systemd-coredump üzerinden
coredumpctl gdb httpd

GDB açıldıktan sonra kullanacağınız temel komutlar:

# Crash anındaki stack trace
(gdb) bt

# Daha detaylı backtrace
(gdb) bt full

# Tüm thread'lerin backtrace'i (Apache multi-thread modda önemli)
(gdb) thread apply all bt

# Belirli bir frame'e git
(gdb) frame 3

# O frame'deki local değişkenleri göster
(gdb) info locals

# Belirli bir adresi inceleme
(gdb) x/10x 0x7f1234567890

Tipik bir GDB çıktısı şöyle görünür:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f1234567890 in zend_execute_ex () from /usr/lib/apache2/modules/libphp7.4.so
#1  0x00007f1234abcdef in execute_ex () from /usr/lib/apache2/modules/libphp7.4.so
#2  0x00007f1234fedcba in mod_php_handler () from /usr/lib/apache2/modules/libphp7.4.so
#3  0x0000555555abcdef in ap_run_handler (r=0x7f...) at request.c:345
#4  0x0000555555123456 in ap_invoke_handler (r=0x7f...) at config.c:456

Bu backtrace bize çok şey söylüyor: crash PHP modülü içinde, zend_execute_ex fonksiyonunda gerçekleşmiş. Sorun Apache’nin kendisinde değil, PHP modülünde.

Gerçek Dünya Senaryosu 1: mod_php Kaynaklı Segfault

Bir e-ticaret sitesinde Apache sabah saatlerinde çöküyor, yeniden başlıyor, kullanıcılar 5-10 saniye erişim kaybı yaşıyor. Log analizi şunu gösteriyor:

grep "Segmentation fault" /var/log/apache2/error.log | awk '{print $1, $2}' | sort | uniq -c | sort -rn

Çıktıda çökmelerin hep aynı saatler civarında, yoğun trafik dönemlerinde gerçekleştiği görülüyor. Bu bir bellek baskısı problemi olabilir.

# Apache'nin kullandığı belleği izle
ps aux | grep apache2 | awk '{sum+=$6} END {print "Total RSS:", sum/1024, "MB"}'

# Worker process başına bellek kullanımı
ps -ylC apache2 | awk '{sum+=$8} END {print sum/1024, "MB"}'

# Hangi modüller yüklenmiş?
apache2ctl -M 2>&1 | grep -i "php|security|rewrite"

GDB analizi bt full ile incelendiğinde PHP’nin bir zend_mm_heap fonksiyonunda crashladığı görülüyor. Bu genellikle PHP memory manager ile ilgili bir sorundur.

Çözüm: PHP’nin memory_limit direktifini düşürmek ve php_value memory_limit ile VirtualHost bazında ayarlamak sorunu çözdü. Aynı zamanda PHP 7.4’ten 8.0’a yükseltme de bu tür Zend Engine memory corruption hatalarını giderdi.

Gerçek Dünya Senaryosu 2: mod_security Uyumsuzluğu

Yeni bir güvenlik güncellemesinin ardından Apache rastgele segfault vermeye başlıyor. Kernel mesajı şöyle:

apache2[12345]: segfault at 8 ip 00007f9876543210 sp 00007ffedcba9876 error 4 in mod_security2.so

“error 4” kodu burada önemli: bu, okuma erişimi sırasında gerçekleşen bir page fault anlamına geliyor.

# mod_security versiyonunu kontrol et
apt-cache policy libapache2-mod-security2

# Hangi kurallar aktif?
modsec_audit_log=/var/log/apache2/modsec_audit.log
tail -100 $modsec_audit_log | grep -i "error|critical"

# Geçici olarak mod_security'yi devre dışı bırak ve test et
a2dismod security2
systemctl restart apache2

# Apache stabil çalışıyor mu?
for i in {1..60}; do
    sleep 10
    systemctl is-active apache2 || echo "Apache çöktü!"
done

mod_security devre dışı bırakıldıktan sonra çökmeler durdu. Sorun, yeni kuralların belirli HTTP başlıklarını işlerken buffer overflow’a yol açmasıydı. Çözüm: mod_security’yi bir sonraki stable versiyona güncellemek veya sorunlu kuralları SecRuleRemoveById ile devre dışı bırakmak.

Valgrind ile Bellek Hataları Araştırma

Core dump analizi yeterli olmadığında, sorunu üretmek için Valgrind kullanabilirsiniz. Production ortamında değil, test ortamında:

# Valgrind kurulumu
apt-get install valgrind

# Apache'yi Valgrind altında çalıştır (test için)
valgrind --leak-check=full 
         --show-leak-kinds=all 
         --track-origins=yes 
         --log-file=/tmp/valgrind-apache.log 
         /usr/sbin/apache2 -X -f /etc/apache2/apache2.conf

# Çıktıyı analiz et
grep "Invalid read|Invalid write|definitely lost" /tmp/valgrind-apache.log | head -30

-X parametresi Apache’yi single process modda başlatır, bu Valgrind ile kullanım için zorunludur. Valgrind çıktısında “Invalid read of size 4” gibi mesajlar tam olarak hangi satırda, hangi fonksiyonda bellek hatasının gerçekleştiğini gösterir.

Apache’yi Debug Modda Çalıştırma

Production’da uygulayamayacağınız ama staging ortamında işe yarayan bir yaklaşım, Apache’yi direkt debug modda çalıştırmaktır:

# Apache'yi foreground'da, single process modda başlat
# Bu şekilde segfault doğrudan terminale düşer
apache2 -X -e debug 2>&1 | tee /tmp/apache-debug.log

# Ayrı bir terminal'den GDB ile attach et
# Çalışan Apache process PID'ini bul
pgrep -f "apache2 -X"

# GDB ile canlı process'e attach et
gdb -p <PID>

# Signal handler koy
(gdb) handle SIGSEGV stop print
(gdb) continue

Bu yöntemle crash anında GDB otomatik olarak duruyor ve o anki stack trace’i alabiliyorsunuz.

strace ile Sistem Çağrılarını İzleme

Segfault öncesinde ne olduğunu anlamak için strace kullanışlıdır:

# Apache worker process'leri izle
strace -p $(pgrep -f "apache2" | head -1) -o /tmp/apache-strace.log &

# Daha kapsamlı: tüm fork'ları da takip et
strace -f -p $(pgrep apache2 | head -1) 
    -e trace=memory,process,signal 
    -o /tmp/apache-strace-detailed.log

# Belirli sistem çağrılarını filtrele
cat /tmp/apache-strace.log | grep -E "mmap|mprotect|brk|SIGSEGV"

strace çıktısında crash öncesi mmap veya brk çağrılarının başarısız olması bellek tükenmesine işaret eder. EFAULT hatası ise erişilmeye çalışılan adresin geçersiz olduğunu gösterir.

Otomatik Core Dump Analizi Scripti

Her seferinde manuel analiz yapmak yorucu. İşte basit bir otomatik analiz scripti:

#!/bin/bash
# apache-core-analyzer.sh

CORE_DIR="/var/crash/apache"
APACHE_BIN="/usr/sbin/apache2"
REPORT_DIR="/var/log/apache-crashes"
DATE=$(date +%Y%m%d_%H%M%S)

mkdir -p "$REPORT_DIR"

for corefile in "$CORE_DIR"/core.*; do
    [ -f "$corefile" ] || continue
    
    REPORT="$REPORT_DIR/crash_report_$DATE.txt"
    
    echo "=== Apache Crash Report ===" > "$REPORT"
    echo "Tarih: $DATE" >> "$REPORT"
    echo "Core file: $corefile" >> "$REPORT"
    echo "" >> "$REPORT"
    
    # GDB ile backtrace al
    gdb -batch 
        -ex "set pagination off" 
        -ex "bt full" 
        -ex "thread apply all bt" 
        -ex "info registers" 
        -ex "quit" 
        "$APACHE_BIN" "$corefile" >> "$REPORT" 2>&1
    
    # Core dosyasini arsivle
    mv "$corefile" "$REPORT_DIR/core_$DATE"
    
    # Mail gonder (mail komutu kuruluysa)
    if command -v mail &>/dev/null; then
        mail -s "Apache Crash Detected - $DATE" [email protected] < "$REPORT"
    fi
    
    echo "Rapor olusturuldu: $REPORT"
done

Bu scripti cron’a ekleyip her 5 dakikada bir çalıştırabilirsiniz:

chmod +x /usr/local/bin/apache-core-analyzer.sh
echo "*/5 * * * * root /usr/local/bin/apache-core-analyzer.sh" >> /etc/crontab

Segfault Sonrası Hızlı Stabilizasyon

Problemi analiz ederken sunucuyu ayakta tutmak için birkaç pratik önlem:

# Apache otomatik restart konfigurasyonu
# /etc/systemd/system/apache2.service.d/restart.conf
mkdir -p /etc/systemd/system/apache2.service.d/
cat > /etc/systemd/system/apache2.service.d/restart.conf << EOF
[Service]
Restart=on-failure
RestartSec=5s
StartLimitIntervalSec=60
StartLimitBurst=5
EOF

systemctl daemon-reload

# MaxRequestWorkers degerini dusurerek bellek baskisini azalt
# mpm_prefork kullaniyorsaniz
grep -n "MaxRequestWorkers|ServerLimit" /etc/apache2/mods-enabled/mpm_prefork.conf

# Sorunlu modulu geçici olarak disable et
a2dismod problematic_module
systemctl reload apache2

Log Rotation ve Core Dump Yönetimi

Core dump dosyaları çok büyük olabilir. Disk alanını yönetmek için:

# Eski core dosyalari temizle (7 gunden eski)
find /var/crash/apache -name "core.*" -mtime +7 -delete

# logrotate ile yonet
cat > /etc/logrotate.d/apache-cores << EOF
/var/crash/apache/core.* {
    weekly
    rotate 4
    compress
    missingok
    notifempty
}
EOF

# systemd-coredump saklama suresini ayarla
# /etc/systemd/coredump.conf
sed -i 's/#MaxUse.*/MaxUse=2G/' /etc/systemd/coredump.conf
sed -i 's/#KeepFree.*/KeepFree=1G/' /etc/systemd/coredump.conf

Yaygın Segfault Nedenleri ve Çözümleri

Analiz sonrasında sıkça karşılaşılan durumları ve çözümlerini şöyle özetleyebilirim:

  • mod_php ve APC/OPcache uyumsuzluğu: PHP’yi FastCGI (php-fpm) moduna geçmek hem stabilite hem performans açısından daha iyi sonuç verir. a2dismod php7.4 ve a2enmod proxy_fcgi ile geçiş yapabilirsiniz.
  • OpenSSL versiyon uyumsuzluğu: openssl version ile Apache’nin linkleme yaptığı OpenSSL versiyonunu kontrol edin. Sistem OpenSSL ile Apache’nin kullandığı arasında fark varsa sorun çıkabilir.
  • mod_rewrite döngüleri: Sonsuz redirect döngüleri worker process’in belleğini tüketir. RewriteLog aktive edip döngüyü tespit edin.
  • Büyük dosya yüklemeleri: LimitRequestBody direktifini ayarlayın. Sınırsız dosya yüklemesi bellek tükenmesine yol açar.
  • Üçüncü parti modüllerin eski versiyonları: apache2 -M ile aktif modülleri listeleyin ve hepsinin güncel olduğundan emin olun.

Sonuç

Apache segfault analizi ilk bakışta karmaşık görünse de sistematik bir yaklaşımla oldukça yönetilebilir. Önce hata loglarını okuyun, kernel mesajlarına bakın, core dump’ı aktif edin ve GDB ile analiz edin. Stack trace size genellikle suçlu modülü gösterecektir.

En önemli kural: her zaman debug sembolleri yükleyin. apache2-dbg ve ilgili modüllerin debug paketleri olmadan GDB analizi karanlıkta el yordamıyla yürümek gibidir. Production sunucularınıza bu paketleri kurmaktan çekinmeyin, ek bir performans yükü getirmezler.

Uzun vadede Apache’yi mod_php yerine php-fpm ile çalıştırmak, segfault sorunlarının büyük çoğunluğunu ortadan kaldırır. PHP’nin kendi process’inde izole çalışması, bir PHP hatasının tüm Apache worker’ı çökertmesini engeller. Bu geçişi henüz yapmadıysanız, bir sonraki maintenance penceresi tam zamanıdır.

Son olarak, bu tür analizleri düzenli aralıklarla yapmak ve crash raporlarını arşivlemek, ilerde yaşanacak benzer sorunlarda size büyük zaman kazandırır. Geçmiş crash’lere bakarak pattern tanımak ve önlem almak, reaktif değil proaktif bir sistem yönetimi anlayışının temelidir.

Benzer Konular

Bir yanıt yazın

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