PHP OPcache Yapılandırması ve Performans Artırma
Bir web sunucusunda PHP uygulamanız yavaş çalışıyorsa ve her şeyi denediyseniz ama performans sorunu hâlâ devam ediyorsa, bakmanız gereken ilk yerlerden biri OPcache yapılandırmasıdır. PHP’nin her istek için kaynak dosyaları tekrar tekrar parse etmek zorunda kalması, özellikle yüksek trafik altında ciddi bir yük oluşturur. OPcache bu sorunu bytecode önbelleğe alarak çözer ve doğru yapılandırıldığında uygulama hızında dramatik iyileşmeler sağlayabilir.
OPcache Nedir ve Nasıl Çalışır?
PHP çalışma şekline bakalım. Normalde bir PHP dosyası her çağrıldığında şu adımlar yaşanır: dosya diskten okunur, lexer ve parser tarafından işlenerek AST (Abstract Syntax Tree) oluşturulur, bu AST bytecode’a dönüştürülür ve Zend Engine tarafından çalıştırılır. Bu süreç, her istek için baştan sona tekrarlanır.
OPcache bu sürecin ilk adımlarını atlar. Derleme aşamasından üretilen bytecode’u paylaşılan bellekte saklar. Bir dahaki istekte PHP, diski okumak ve parse etmek yerine doğrudan bellekteki bytecode’u kullanır. Sonuç? CPU kullanımı düşer, yanıt süresi kısalır, throughput artar.
OPcache, PHP 5.5 sürümünden itibaren çekirdek bir bileşen olarak gelir. Ayrıca yüklemeniz gerekmez, sadece etkinleştirmeniz ve doğru yapılandırmanız yeterlidir. Ancak çoğu sunucuda varsayılan ayarlar iş yükünüze göre optimize edilmemiş durumdadır ve bu durum performansın masada bırakılması anlamına gelir.
OPcache Kurulumu ve Etkinleştirme
Çoğu modern Linux dağıtımında OPcache paketi PHP ile birlikte gelir ama etkin olmayabilir. Önce durumu kontrol edelim.
# PHP modüllerini kontrol et
php -m | grep opcache
# Eğer çıktı geliyorsa etkin, gelmiyorsa aşağıdaki komutla yükle
# Ubuntu/Debian için:
sudo apt install php8.2-opcache
# RHEL/CentOS/AlmaLinux için:
sudo dnf install php-opcache
# PHP versiyon bağımsız genel yükleme (phpize kullanımı)
pecl install ZendOpcache
Kurulumdan sonra OPcache’in gerçekten yüklenip yüklenmediğini doğrulayalım.
# CLI üzerinden kontrol
php -r "echo ini_get('opcache.enable');"
# Tüm OPcache ayarlarını listele
php -r "print_r(opcache_get_configuration());"
# Web sunucusu üzerinden kontrol için küçük bir test scripti
echo '<?php phpinfo(); ?>' | sudo tee /var/www/html/phpinfo.php
# Tarayıcıdan açıp OPcache bölümüne bakın
# Test sonrası silmeyi unutmayın!
sudo rm /var/www/html/phpinfo.php
Temel OPcache Yapılandırması
OPcache ayarları genellikle /etc/php/8.2/fpm/conf.d/10-opcache.ini veya /etc/php.ini içinde bulunur. Dağıtıma göre yol değişebilir.
# Yapılandırma dosyasını bul
php --ini | grep opcache
# veya
find /etc -name "*opcache*" 2>/dev/null
İşte production ortamı için optimize edilmiş temel bir yapılandırma. Bu ayarları /etc/php/8.2/fpm/conf.d/99-opcache-custom.ini gibi ayrı bir dosyaya eklemek, paket güncellemelerinden etkilenmemenizi sağlar.
; OPcache temel yapılandırması
[opcache]
; OPcache'i etkinleştir
opcache.enable=1
; CLI için etkinleştir (worker süreçleri, cron joblar için gerekli olabilir)
opcache.enable_cli=0
; Önbellek için ayrılacak bellek miktarı (MB cinsinden)
; Küçük projeler için 128MB, büyük projeler için 256MB veya üzeri
opcache.memory_consumption=256
; Interned string buffer boyutu (MB)
opcache.interned_strings_buffer=32
; Önbelleklenebilecek maksimum dosya sayısı
opcache.max_accelerated_files=20000
; Dosya değişiklik kontrolü (0=devre dışı, production için önerilen)
opcache.validate_timestamps=0
; Her istekte dosya timestamp kontrolü yapılacaksa bu süre (saniye)
; validate_timestamps=1 ise geçerli
opcache.revalidate_freq=60
; Hızlı kapatma sırasını optimize et
opcache.fast_shutdown=1
; OPcache istatistiklerini topla
opcache.enable_statistics=1
Kritik Parametre Açıklamaları
Yapılandırma dosyasındaki her parametre önemlidir ama özellikle birkaçı doğru ayarlanmadığında ciddi sorunlara yol açar.
opcache.memory_consumption: OPcache’in kullanabileceği paylaşılan bellek miktarını belirler. Bu değer çok düşükse önbellek dolup taşar ve eski girdiler silinerek önbellek etkinliği azalır. Değeri belirlemek için şu scripti kullanabilirsiniz.
<?php
// opcache_status.php - OPcache durumunu raporla
$status = opcache_get_status();
$memory = $status['memory_usage'];
$total = $memory['used_memory'] + $memory['free_memory'] + $memory['wasted_memory'];
$usedPercent = round($memory['used_memory'] / $total * 100, 2);
$wastedPercent = round($memory['wasted_memory'] / $total * 100, 2);
echo "Toplam Bellek: " . round($total / 1024 / 1024, 2) . " MBn";
echo "Kullanılan: " . round($memory['used_memory'] / 1024 / 1024, 2) . " MB ({$usedPercent}%)n";
echo "Boş: " . round($memory['free_memory'] / 1024 / 1024, 2) . " MBn";
echo "Atık: " . round($memory['wasted_memory'] / 1024 / 1024, 2) . " MB ({$wastedPercent}%)n";
echo "Önbelleklenen dosya sayısı: " . $status['opcache_statistics']['num_cached_scripts'] . "n";
echo "Hit rate: " . round($status['opcache_statistics']['opcache_hit_rate'], 2) . "%n";
if ($wastedPercent > 5) {
echo "UYARI: Atık bellek yüksek, opcache.max_wasted_percentage değerini gözden geçirinn";
}
opcache.max_accelerated_files: Önbelleklenebilecek maksimum dosya sayısıdır. Laravel, Symfony gibi büyük frameworklerde bu değer çok düşük kalabilir. Projenizin dosya sayısını öğrenmek için şu komutu kullanın.
# Proje dizinindeki PHP dosyalarını say
find /var/www/html -name "*.php" | wc -l
# Vendor dizini dahil (Laravel gibi projeler için)
find /var/www/laravel -name "*.php" -not -path "*/storage/*" | wc -l
Bu sayının 1.5-2 katı kadar bir değer ayarlamak mantıklıdır. Örneğin 8000 PHP dosyanız varsa max_accelerated_files=16384 şeklinde ayarlayabilirsiniz (2’nin kuvvetleri daha verimli çalışır).
opcache.validate_timestamps: Production ortamında 0 yapın. Bu, PHP’nin dosya değişikliğini kontrol etmesini engeller ve önemli CPU tasarrufu sağlar. Deployment sonrası OPcache’i manuel olarak temizlemek zorunlu olur ama bu zaten deployment sürecinizin parçası olmalıdır.
Deployment Sürecinde OPcache Yönetimi
validate_timestamps=0 ayarıyla production ortamında OPcache kullanıyorsanız, her deployment sonrası önbelleği temizlemeniz şarttır. Aksi takdirde kullanıcılar eski kod çalıştırmaya devam eder.
#!/bin/bash
# deploy_opcache_reset.sh
# Deployment sonrası OPcache temizleme scripti
WEBROOT="/var/www/html"
PHP_FPM_SOCKET="/run/php/php8.2-fpm.sock"
TEMP_FILE="${WEBROOT}/opcache_reset_$(date +%s).php"
# Geçici reset dosyası oluştur
cat > "$TEMP_FILE" << 'EOF'
<?php
if (function_exists('opcache_reset')) {
opcache_reset();
echo "OPcache temizlendin";
} else {
echo "OPcache etkin değiln";
exit(1);
}
unlink(__FILE__);
EOF
# Web üzerinden çağır
RESPONSE=$(curl -s "http://localhost/$(basename $TEMP_FILE)")
echo "$RESPONSE"
# Dosya hâlâ varsa sil
[ -f "$TEMP_FILE" ] && rm -f "$TEMP_FILE"
# PHP-FPM servisini yeniden yükle (graceful reload)
# Bu method, aktif bağlantıları kesmeden worker'ları yeniler
sudo systemctl reload php8.2-fpm
echo "Deployment OPcache reset tamamlandı: $(date)"
PHP-FPM kullanıyorsanız servis reload da OPcache’i temizler. Birçok deployment pipeline için en temiz yöntem budur.
# PHP-FPM graceful reload - aktif istekleri kesmez
sudo systemctl reload php8.2-fpm
# Veya kill -USR2 ile
sudo kill -USR2 $(cat /var/run/php/php8.2-fpm.pid)
Farklı Ortamlar İçin Yapılandırma
Development ve production ortamları için farklı OPcache ayarları kullanmak mantıklıdır. Development’ta dosya değişikliklerinin anında yansıması önemlidir; production’da ise maksimum performans hedeflenir.
; development.ini - Geliştirme ortamı için
[opcache]
opcache.enable=1
opcache.enable_cli=1
; Dosya değişikliklerini kontrol et (development için açık)
opcache.validate_timestamps=1
; Her istekte kontrol et
opcache.revalidate_freq=0
opcache.memory_consumption=128
opcache.max_accelerated_files=10000
; Development'ta istatistikleri topla
opcache.enable_statistics=1
; production.ini - Üretim ortamı için
[opcache]
opcache.enable=1
opcache.enable_cli=0
; Dosya değişikliği kontrolü KAPALI - performans için
opcache.validate_timestamps=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=32
opcache.max_accelerated_files=20000
opcache.fast_shutdown=1
; Atık bellek %10'u geçince önbelleği yeniden başlat
opcache.max_wasted_percentage=10
; JIT etkinleştir (PHP 8.0+)
opcache.jit=tracing
opcache.jit_buffer_size=128M
PHP 8.x ile Gelen JIT Desteği
PHP 8.0 ile birlikte OPcache’e JIT (Just-In-Time) derleyici desteği eklendi. JIT, bytecode’u doğrudan makine koduna çevirerek CPU yoğun işlemlerde ek hız sağlar. Ancak web uygulamalarındaki etkisi her zaman dramatik olmaz; hesaplama yoğun işlemlerde (görüntü işleme, matematiksel hesaplamalar, machine learning inference) en çok kazanım sağlar.
JIT yapılandırması biraz daha karmaşıktır. opcache.jit parametresi 4 haneli bir sayı alır.
Birinci hane (optimizasyon seviyesi):
0: JIT devre dışı1: Minimal optimizasyon2: Seçici optimizasyon3: Maksimum optimizasyon
İkinci hane (register kullanımı):
0: Register kullanma1: Yerel değişkenler için register2: Yerel değişkenler ve fonksiyon argümanları için register
Üçüncü hane (JIT tetikleme):
0: Her şeyi JIT ile derle1: Sık çağrılan fonksiyonları JIT ile derle2: İlk çağrıda JIT uygula
Dördüncü hane (JIT modu):
0: JIT devre dışı1: Tracing JIT (genellikle en iyi)2: Function JIT
# JIT'in etkin olup olmadığını kontrol et
php -r "
$status = opcache_get_status();
if (isset($status['jit'])) {
echo 'JIT durumu: ' . ($status['jit']['enabled'] ? 'Etkin' : 'Devre dışı') . PHP_EOL;
echo 'JIT buffer boyutu: ' . round($status['jit']['buffer_size'] / 1024 / 1024, 2) . ' MB' . PHP_EOL;
echo 'JIT buffer kullanımı: ' . round($status['jit']['buffer_free'] / 1024 / 1024, 2) . ' MB boş' . PHP_EOL;
} else {
echo 'JIT desteği bulunamadı (PHP 8.0+ gerekir)' . PHP_EOL;
}
"
OPcache İzleme ve Performans Testi
Yapılandırmayı uyguladıktan sonra etkisini ölçmek önemlidir. Basit bir kıyaslama testi şöyle yapılabilir.
#!/bin/bash
# opcache_benchmark.sh
# Apache Bench ile OPcache öncesi/sonrası kıyaslama
TARGET_URL="http://localhost/index.php"
REQUESTS=1000
CONCURRENCY=10
echo "=== OPcache Performans Testi ==="
echo "Hedef: $TARGET_URL"
echo "İstek sayısı: $REQUESTS"
echo "Eş zamanlı bağlantı: $CONCURRENCY"
echo ""
# İlk warmup isteği (önbelleği doldur)
echo "Önbellek ısınıyor..."
for i in {1..20}; do
curl -s "$TARGET_URL" > /dev/null
done
# Ana test
echo "Test çalışıyor..."
ab -n $REQUESTS -c $CONCURRENCY "$TARGET_URL" 2>&1 | grep -E "(Requests per second|Time per request|Failed requests)"
# OPcache istatistiklerini göster
echo ""
echo "=== OPcache İstatistikleri ==="
php -r "
$s = opcache_get_status()['opcache_statistics'];
echo 'Hit rate: ' . round($s['opcache_hit_rate'], 4) . '%' . PHP_EOL;
echo 'Cache hits: ' . $s['hits'] . PHP_EOL;
echo 'Cache misses: ' . $s['misses'] . PHP_EOL;
echo 'Önbelleklenen scriptler: ' . $s['num_cached_scripts'] . PHP_EOL;
"
Gerçek dünyada gördüğüm bir örnek: Orta büyüklükte bir Laravel uygulamasında OPcache olmadan saniyede 45-50 istek işlenirken, doğru yapılandırılmış OPcache ile bu sayı 180-200 isteğe çıkabilir. Yani 4 kat civarında bir artış. Hit rate %90’ın altındaysa yapılandırmanızda bir sorun var demektir.
Yaygın Sorunlar ve Çözümleri
Önbellek dolması sorunu: Hit rate yüksek ama wasted_memory de yüksekse, OPcache önbelleği sürekli dolup taşıyor demektir. Çözüm olarak opcache.memory_consumption değerini artırın ya da opcache.max_wasted_percentage değerini düşürün (daha agresif temizleme için).
Yanlış kaynak görüntüleme: Production’da kod değişikliği yapıldı ama kullanıcılar eski kodu görüyor. validate_timestamps=0 ayarıyla bu beklenen bir durumdur. Deployment scriptinizin OPcache’i temizlediğinden emin olun.
Bellek sınırı hataları: PHP süreçleri beklenmedik şekilde ölüyorsa ve /var/log/syslog içinde OOM killer mesajları görüyorsanız, OPcache için ayırdığınız bellek çok yüksek olabilir. Sistemin toplam RAM’ini, PHP-FPM worker sayısını ve OPcache belleğini birlikte değerlendirin.
# Mevcut OPcache kullanımını anlık izle
watch -n 2 'php -r "
$s = opcache_get_status();
$m = $s["memory_usage"];
$total = $m["used_memory"] + $m["free_memory"] + $m["wasted_memory"];
echo "Kullanım: " . round($m["used_memory"]/1024/1024,1) . "MB / " . round($total/1024/1024,1) . "MBn";
echo "Hit rate: " . round($s["opcache_statistics"]["opcache_hit_rate"],2) . "%n";
echo "Atık: " . round($m["wasted_memory"]/1024/1024,1) . "MBn";
"'
Preloading ile Ekstra Hız
PHP 7.4 ile gelen preloading özelliği, OPcache’i bir adım ileriye taşır. Framework dosyaları gibi sık kullanılan PHP dosyaları, PHP-FPM başlangıcında bir kez yüklenir ve tüm worker süreçleri bu yüklenmiş kodu paylaşır. Bellek kullanımı artar ama ortak framework dosyaları için tekrar tekrar önbellek araması yapmaya gerek kalmaz.
; php.ini veya opcache.ini içine ekle
opcache.preload=/var/www/html/preload.php
opcache.preload_user=www-data
<?php
// preload.php - Sık kullanılan dosyaları preload et
// Laravel için örnek
$preloadFiles = [
'/var/www/html/vendor/laravel/framework/src/Illuminate/Support/Collection.php',
'/var/www/html/vendor/laravel/framework/src/Illuminate/Http/Request.php',
'/var/www/html/vendor/laravel/framework/src/Illuminate/Http/Response.php',
// Daha fazla kritik dosya ekleyebilirsiniz
];
foreach ($preloadFiles as $file) {
if (file_exists($file)) {
opcache_compile_file($file);
}
}
echo count($preloadFiles) . " dosya preload edildi.n";
Laravel için hazır preload scripti php artisan vendor:publish ile elde edilebilir, Symfony da benzer araçlar sunar.
Sonuç
OPcache, doğru yapılandırıldığında PHP uygulamalarının performansı için alabileceğiniz en kolay ve en etkili önlemlerden biridir. Kurulum ve temel yapılandırma için 15-20 dakika yeterlidir, ama bu yatırımın geri dönüşü sunucu maliyetlerinde ve kullanıcı deneyiminde doğrudan hissedilir.
Özetlemek gerekirse önemli adımlar şunlardır: memory_consumption değerini projenizin gerçek ihtiyacına göre ayarlayın, max_accelerated_files değerinin proje dosya sayısından büyük olduğundan emin olun, production ortamında validate_timestamps=0 kullanın ve deployment sürecinize OPcache temizleme adımını ekleyin. PHP 8.x kullanıyorsanız JIT desteğini de değerlendirin, özellikle hesaplama ağırlıklı işlemler yapan uygulamalar için anlamlı bir kazanım sağlayabilir.
Hit rate’i düzenli olarak izleyin. %95 ve üzeri ideal bir hedeftir. Bu değerin altında kalıyorsanız bellek ya da dosya sayısı limitlerinizi gözden geçirmeniz gerekiyor demektir. Monitoring altyapınıza OPcache metriklerini eklemeniz, uzun vadede kapasiteye ne zaman ihtiyaç duyduğunuzu önceden görmenizi sağlar.
