PHP Uygulamalarında Login Yavaşlığı: Session GC Sorunu ve Çözümü
Kategori: Sunucu Yönetimi / PHP / PerformansSüre: ~10 dakika okuma
Sorun
CloudPanel, Plesk veya cPanel gibi panellerle yönetilen bir Ubuntu/Linux sunucusunda PHP uygulamanız var. Uygulama genel olarak hızlı çalışıyor, ancak login sayfasında 1-2 dakika bekliyorsunuz. Giriş yaptıktan sonra her şey normal.
Bu yazıda bu sorunu nasıl teşhis ettiğimizi ve kalıcı olarak nasıl çözdüğümüzü adım adım anlatıyoruz.
Neden Olur?
PHP, session yönetimi için varsayılan olarak /var/lib/php/sessions/ klasörünü kullanır. Sunucunuzda birden fazla site varsa, tüm sitelerin session dosyaları bu tek klasörde birikir.
PHP'nin session GC (Garbage Collection) mekanizması, eski session dosyalarını temizlemek için ara sıra devreye girer. GC tetiklendiğinde klasördeki tüm dosyaları tek tek tarar. Eğer bu klasörde binlerce dosya birikmişse, tarama işlemi onlarca saniye veya birkaç dakika sürebilir.
Login işlemi sırasında session_regenerate_id(true) çağrısı GC'yi tetiklediği için tam login anında bu uzun bekleme yaşanır.
Özetle:
Login isteği geldi
→ session_regenerate_id(true) çağrıldı
→ PHP GC tetiklendi
→ /var/lib/php/sessions/ içindeki 1000+ dosya tarandı
→ 60 saniye bekleme
→ Dashboard'a yönlendirme
Teşhis
1. Nginx Access Log ile Zamanı Tespit Edin
tail -f /home/SITEADI/logs/nginx/access.log | grep -i "login"
Şuna benzer bir çıktı görürsünüz:
21:51:20 → POST /login → 302 (login isteği)
21:52:25 → GET / → 200 (dashboard)
İki istek arasında 65 saniye fark varsa sorun kesinlikle bu.
2. Session Dosyası Sayısını Kontrol Edin
ls /var/lib/php/sessions/ | wc -l
Çıktı 500'ün üzerindeyse sorunun kaynağı budur.
Geçici Çözüm (Anında Etki)
Biriken dosyaları temizleyin:
rm -f /var/lib/php/sessions/sess_*
⚠️ Bu komut aktif session'ları da siler. Kullanıcılar oturumdan çıkmış olur.
Login'i test edin — hızlanmış olmalı. Ancak bu geçici bir çözümdür; dosyalar zamanla yeniden birikir.
Kalıcı Çözüm
İki adımlı kalıcı çözüm: session dosyalarını projeye özel klasöre taşımak ve GC'yi cron'a devretmek.
Adım 1: public/index.php (veya uygulamanızın giriş noktası) Başına Ekleyin
session_start() çağrısından önce şu bloğu ekleyin:
// Session dosyalarını projeye özel klasörde tut
$_sessionPath = dirname(__DIR__) . '/storage/sessions';
if (!is_dir($_sessionPath) && !mkdir($_sessionPath, 0755, true) && !is_dir($_sessionPath)) {
// Klasör oluşturulamazsa varsayılan path'e düş, uygulama çökmesin
error_log('Session path olusturulamadi, varsayilan kullaniliyor.');
$_sessionPath = (string) ini_get('session.save_path');
}
if (is_dir($_sessionPath) && is_writable($_sessionPath)) {
ini_set('session.save_path', $_sessionPath);
}
ini_set('session.gc_maxlifetime', '7200'); // 2 saat
ini_set('session.gc_probability', '0'); // GC'yi request üzerinde kapatıyoruz
ini_set('session.gc_divisor', '1000'); // gc_probability=0 ile birlikte etkisiz
ini_set('session.use_strict_mode', '1');
ini_set('session.lazy_write', '1'); // Değişmeyen session'ı diske yazma
Bu yaklaşımın avantajları:
-
Her sitenin session dosyaları kendi klasöründe izole olur
-
GC sadece o projenin dosyalarını tarar, diğer siteleri etkilemez
-
gc_probability=0ile GC hiçbir zaman bir kullanıcı isteğini yavaşlatmaz -
lazy_write=1ile session değişmemişse diske yazılmaz (ek performans) -
Klasör oluşturulamazsa uygulama çökmez, varsayılan path'e düşer
Adım 2: Klasör İzinlerini Ayarlayın
mkdir -p /home/SITEADI/htdocs/DOMAIN/storage/sessions
chown SITEADI:SITEADI /home/SITEADI/htdocs/DOMAIN/storage/sessions
chmod 755 /home/SITEADI/htdocs/DOMAIN/storage/sessions
Adım 3: Cron Job Ekleyin
GC'yi request üzerinden kapattığımıza göre eski session dosyalarını temizleme işini cron'a veriyoruz:
crontab -e
Şu satırı ekleyin:
# Her gece 03:00'te 1 günden eski session dosyalarını temizle
0 3 * * * find /var/lib/php/sessions/ -name 'sess_*' -mtime +1 -delete
# Projeye özel session klasörü için de ekleyin
0 3 * * * find /home/SITEADI/htdocs/DOMAIN/storage/sessions/ -name 'sess_*' -mtime +1 -delete
Doğrulama
Değişiklikten sonra biri login olsun, ardından kontrol edin:
# Yeni session klasöründe dosya oluştu mu?
ls /home/SITEADI/htdocs/DOMAIN/storage/sessions/
# Artık /var/lib/php/sessions/ dolmuyor mu?
ls /var/lib/php/sessions/ | wc -l
Session klasöründe sess_ ile başlayan dosyalar görünüyorsa her şey doğru çalışıyor.
Neden gc_probability=0 Güvenli?
PHP'nin session GC'si iki şekilde çalışabilir:
|
Yöntem |
Açıklama |
|---|---|
|
Request tabanlı (varsayılan) |
Her X istekte bir rastgele tetiklenir, o isteği yavaşlatır |
|
Cron tabanlı |
Belirli saatte çalışır, kullanıcıları etkilemez |
gc_probability=0 yaparak GC'yi request'ten koparıp cron'a veriyoruz. Bu yaklaşım Laravel, Symfony gibi büyük framework'lerin de önerdiği yöntemdir.
Laravel Kullanıyorsanız
Laravel'de session driver'ı file olarak ayarlıysa aynı sorun yaşanabilir. .env dosyasına şunu ekleyin:
SESSION_DRIVER=file
SESSION_LIFETIME=120
Ve config/session.php dosyasında:
'files' => storage_path('framework/sessions'),
Laravel zaten session'ları storage/framework/sessions/ altında tutar, ancak GC ayarlarını yine de elle yapmanız önerilir.
Özet
|
|
Geçici Çözüm |
Kalıcı Çözüm |
|---|---|---|
|
Yöntem |
|
Session path izolasyonu + Cron GC |
|
Etki |
Anında |
Kalıcı |
|
Risk |
Aktif oturumlar silinir |
Yok |
|
Tekrar eder mi? |
Evet |
Hayır |
Kaynaklar
Bu makale gerçek bir sorun giderme sürecinden üretilmiştir. Benzer bir sorun yaşıyorsanız teşhis adımlarını sırayla uygulayın.
Bu cevap yeterince yardımcı oldu mu?
Görüşünüz bizim için değerli!