İçindekiler
- 1 Bir Gece Yarısı Gelen 502’ler ve Düğüm Düğüm Prod Ayarları
- 2 PHP‑FPM Havuzları: Yan Yana Çalışan İşçiler Nasıl Nefes Alır?
- 3 OPcache: Hafızanın İçinde Sıcak Tutan Battaniye
- 4 Octane: Oyun Değiştirici Hız mı, Dikkatli Kullanılması Gereken Güç mü?
- 5 Queue/Horizon: Web İsteğinden Ayrılan Uzun İşlerin Mutlu Dünyası
- 6 Redis Ayarları: Hafızanın Hızlı, Kuralların Net Olduğu Yer
- 7 Dağıtım Ritüeli: Koddan Konfige, Konfigden Gözleme
- 8 Gerçek Bir Akış: Kaynak Planlama, Havuz, Cache ve Kuyruk El Sıkışıyor
- 9 Kapanış: Vidaları Sık, Sahneden Yavaşça Çekil
- 10 Bonus: Küçük Komut Ajandası
- 11 Kaynak Notları
Bir Gece Yarısı Gelen 502’ler ve Düğüm Düğüm Prod Ayarları
Hiç başına geldi mi? Trafik sakin sakin akarken bir kampanya butonu “yayınla” diye parladığında, grafik bir anda dik bir dağa dönüşür. Benim başıma geldi. Gece yarısı, telefon elimde, ekibin chat’inde “502 var” mesajları akıyor. Sunucu güçlü, kod fena değil, ama bir yerler sanki birbirine küs. O an anladım: Prod ortamı sadece güçlü donanımla değil, birbirini tamamlayan ayarlarla ayakta kalıyor. İşte bugün bu düğümü, adım adım, sahiden yaşadığım küçük sarsıntılarla anlatarak çözmek istiyorum.
Laravel’de performans dediğimiz şey tek bir düğmeye basınca açılan gizli bir mod değil. PHP‑FPM havuzları doğru ayarlanmamışsa OPcache’in hakkını veremiyorsun. Octane’i kurup bıraktığında, paylaşılan durumlar seni terletiyor. Queue/Horizon gücünü sahaya süremezsen web istekleri kuyruğa takılıyor, Redis ayarları dikkat edilmezse en kritik anda cache çözümleri ayağına dolanıyor. Bu yazıda tam olarak bunları konuşacağız: PHP‑FPM havuzlarından başlayıp OPcache’e uzanacağız, oradan Octane’in hız hissine göz kırpıp Queue/Horizon ve Redis’in kulisteki marifetlerini birlikte toplayacağız. Hadi, yavaşça vidaları sıkalım.
PHP‑FPM Havuzları: Yan Yana Çalışan İşçiler Nasıl Nefes Alır?
Mesela şöyle düşünün: Bir pizzacıdasınız, fırın var, hamur hazır, ama tezgâh dar. Şef sayısını artırınca tezgâh yetmeyebilir, tek şefle bırakırsanız sipariş kuyruğa girer. PHP‑FPM havuzları da buna benziyor. Çok az process açarsanız talepler bekler, çok fazla açarsanız RAM şişer, swap’a düşer ve iş tam tersine yavaşlar. O ilk 502 gecesinde benim hatam buydu. “Biraz daha pm.max_children verelim” dedim, RAM ağladı, I/O takıldı, gecikmeler büyüdü.
Buradaki dengeyi bulmanın en pratik yolu, bir PHP‑FPM işçisinin yaklaşık ne kadar RAM yediğini anlamak. Uygulamanızı gerçek trafik altında birkaç dakika izleyin. Top’ta, htop’ta veya ps ile process başına bellek tüketimini görün. Diyelim ortalama 70–120 MB arası gidip geliyor. Sunucuda PHP için ayırabileceğiniz RAM’i kabaca hesaplayıp, güvenli bir pay bırakarak pm.max_children’ı belirleyin. Bu değeri şişirmektense, pm modunu dynamic veya sakin trafiklerde ondemand yapıp, pm.start_servers, pm.min_spare_servers ve pm.max_spare_servers ile nefes aldırın. Statik mod, her an dolu kadro bekletmek gibi; bazen mantıklı, bazen kaynak israfı.
İlk Temas: Zaman Aşımı ve Kuyruk Etkisi
Web sunucunla PHP‑FPM arasındaki zaman aşımı değerleri gerçekçi olmalı. Nginx veya Apache tarafında upstream timeouts yükselterek sorunu ertelemek kolay, ama bu sefer kuyruğun içi doluyor. Asıl mesele, yavaş işlerin web isteği sırasında yapılmaması. Rapora PDF gömmek, üçüncü parti entegrasyondan cevap beklemek gibi işler queue’ya kaymalı. FPM’de request_terminate_timeout gibi ayarlarla korkunç uzayan talepleri kesmek, logda ne olduğunu görmek ve kuyruklara aktarmak kritik.
Loglar, yavaşlar ve görünürlük
“Niye yavaş?” sorusu gecenin köründe en sinir bozucu olanı. php-fpm slowlog açın, threshold’u makul ayarlayın. pm.status_path ile durum sayfası ekleyin, anlık yoğunluğu görün. İstekleri yutar gibi yapan gizli “N+1” sorguları, yanlış yerde yapılan dosya işlemlerini, yersiz cache temizlemelerini böyle yakalarsınız. Bu veriler yoksa, optimize etmek sadece tahmin olur.
OPcache: Hafızanın İçinde Sıcak Tutan Battaniye
OPcache, PHP dosyalarını derleyip bellekte tutar. Böylece her istekte aynı masrafı tekrar yaşamazsınız. Ancak OPcache’i sadece açmak yetmez; küçük ayarlarla büyük rahatlık gelir. Ayırdığınız bellek dar ise parçalanma başlar, “sığmıyorum” mesajları loglara düşer, performans inişli çıkışlı olur. Bir projede 64–128 MB derken yetmediğini, kod sayısı arttıkça opcache.memory_consumption ve opcache.interned_strings_buffer’ı nazikçe büyütmem gerektiğini deneyimledim. OPcache yapılandırma seçeneklerini anlatan resmî doküman bunu sade biçimde özetler.
Prod’da opcache.validate_timestamps=0 yapmak tatlıdır; her deploy’da FPM’i nazikçe yeniden yüklemek yeter. Dosya zaman damgası izleme trafiği hafifler. Eğer paylaşımlı nfs gibi garip bir dosya sistemi yoksa, bu ayar yüksek trafikte bariz nefes aldırır. JIT konusuna gelince, PHP 8 ile geldi ama her Laravel projesinde hissedilir bir fark bırakmayabilir. Mikroservis gibi CPU ağırlıklı hesap yapan özgün kısımlar varsa denersiniz, yoksa bile OPcache tek başına yeterince iş çıkarır.
Deploy Anlarında OPcache’i Ürkütmeden Yenilemek
Klasik akış: build tamam, env ve cache dosyaları güncellendi, sonra PHP‑FPM’ye reload. Sıfırdan açmak yerine “reload” tercihim, ayakta duran süreçlerin bir anda yok olmamasını sağlıyor. Yükseltme sırasında kademeli geçiş hissi geliyor. Bir de opcache.file_cache ile disk tabanlı cache kullanmayı deneyenler var; bazı ortamlarda açılış süresini kısaltıyor, bazılarında disk IO uğultu yapıyor. Küçük bir ortamda deneyip karar vermek en sağlıklısı.
Octane: Oyun Değiştirici Hız mı, Dikkatli Kullanılması Gereken Güç mü?
Octane’i ilk kurduğum gün, sayfalar sanki ayağından zincir çözülmüş gibi açıldı. Fakat işin büyüsü şu: Uygulama süreçleri ayakta kaldığından, bir istekten kalan bazı şeyler diğerine sızabiliyor. Statik değişkenler, singleton’lar, servislerin içinde biriktirilen durumlar… Bunları temizlemezsen, “hayalet veri” dediğim tuhaf bug’lar çıkıyor. O yüzden Octane, disiplin istiyor. Octane’in resmi dokümanlarında istekler arası durum yönetimi ve yeniden başlatmalarla ilgili güzel ipuçları var.
Kaç worker? Sunucudaki CPU çekirdeklerini ve RAM’i düşünerek başlamak en güzeli. Örneğin 4–8 worker ile başlayıp, max requests değerini makul tutmak ve bellek sızıntısı olasılığına karşı periyodik yeniden başlatmalar ayarlamak rahatlatır. Swoole veya RoadRunner seçimi projene ve ekibinin alışkanlıklarına bağlı. Ben genellikle daha sade kurulumlarla başlar, sonra yavaş yavaş yetenekleri açarım. Octane dev ortamda “hot reload” ile iştah açar ama prod’da izleme ve günlüklerle desteklemeden yalnız başına bırakmam.
Octane ile Queue ve Cache’in Dili Aynı Olmalı
Octane hızlıdır ama işi bitiren genellikle sahne arkasındaki işçiler. Web isteğini kısa tutup, pahalı işleri kuyruklara atınca Octane’in gerçek potansiyelini görürsünüz. Ayrıca cache katmanınız tutarlı olmalı. Redis bağlantılarında kalıcı bağlantı kullanmak, saniyelik minik gecikmeleri törpüler. Octane dünyasında her şeyi RAM’e itmek cazip görünür, fakat invalidation stratejisi olmadan cache bir süre sonra çalılık olur. Elle temizle, TTL koy, key adlandırmalarını düzenli yap. İşte huzur burada.
Queue/Horizon: Web İsteğinden Ayrılan Uzun İşlerin Mutlu Dünyası
Bir müşterim için raporlamayı web isteği içinde yapıyorduk. Kullanıcı “indir” deyince PDF üretiliyor, dış servislerle konuşuluyor, derken sayfa bekliyor da bekliyor. Bunu kuyruklara taşıdık; web tarafı sadece işi sıraya koydu, kullanıcı ya bildirim aldı ya da sayfayı yenilediğinde hazır dosyayı gördü. Anında rahatlama. Laravel’in Horizon paneli ise çalışan işçileri izlemek, kuyruk derinliğini görmek ve arıza anında doğru düğmeye basmak için muazzam bir pencere.
Supervisor konfigürasyonunda her kuyruğa aynı gözle bakmıyorum. Kritik e-posta veya ödeme sonrası işlemler daha öncelikli, raporlama ve ithalat daha sabırlı olabilir. timeout’ları gerçekçi tutuyor, retry sayısını gereksiz şişirmiyorum; çünkü yanlış bir iş sonsuza kadar tekrar edilince sadece vakit kaybedersiniz. memory limit ile worker’ları belirli bir noktada kibarca emekli etmek, küçük sızıntıların sisteme yayılmasını engelliyor. Horizon’da balancing ayarlarıyla anlık dalgaları güzelce emmek mümkün; bazen eşit dağıtım, bazen ağırlıklandırılmış bir yaklaşım daha iyi hissediliyor.
Failed Jobs, Günlükler ve Sağduyu
Failed jobs koleksiyonunu çöp sandığı gibi görmeyin. Orada biriken her kayıt, sistemin size verdiği küçük bir hediye. Neden? Hata kalıplarını görür, idempotent tasarımın nereye kadar dayandığını anlarsınız. Bazı işler iki kere yapılınca zarar veriyorsa, önce işi idempotent hale getirin, sonra gönül rahatlığıyla yeniden deneyin. Üçüncü parti kısımlar için backoff stratejileri koymak, bir anda patlayan dalgalarda pristin kalmanızı sağlar.
Redis Ayarları: Hafızanın Hızlı, Kuralların Net Olduğu Yer
Redis, Laravel’de cache, oturum ve kuyruklar için çok sevilen bir partner. Ama onun da sınırları var. Üretimde en çok gördüğüm sorun, “nasıl olsa hızlı” denilerek her şeyin sonsuz tutulması. Sonra bellek dolar, eviction devreye girer, kritik anahtarlar uçarsa kullanıcılar beklenmedik durumlar görür. Çözüm basit gibi: TTL’siz key bırakma, maxmemory ve maxmemory-policy’yi bilinçli seç, ve kritik veriyi ayır. Redis’in resmi konfigürasyon rehberi sade bir referans sunuyor.
Bağlantı sürücüsü olarak PHP’nin yerleşik phpredis eklentisi pratik ve hızlı. Laravel’de sürücüyü ona göre seçip, prod’da mümkünse UNIX socket kullanmak küçük de olsa güzel bir kazanç. Aynı sunucuda Nginx, PHP‑FPM, Redis ve database varsa, hepsi disk ve CPU’yu paylaşır. Kaynak planlamasını yaparken bu “komşuluk” ilişkisini unutmayın. Eğer Redis’i dışarıya alırsanız, ağ gecikmesi eklenir ama CPU ve RAM baskısı sunucudan kalkar; burada dengeyi trafiğin ve bütçenin ritmi belirler.
Key Adlandırma, TTL ve İzleme
Key adlandırmasını düzenli yaparsanız arızayı anlamak kolaylaşır. app:cache:user:123 gibi hiyerarşik adlar, birikimi gözle görünür hale getirir. TTL tarafında kritik girişlere ölçülü yaşam süresi verin; kalıcı olması gerekenleri bilerek kalıcı tutun. “Hepsine bir gün” demek bazen gereksiz invalidation fırtınası yaratır, bazen de gereksiz büyümeye sebep olur. İzleme tarafında latency grafikleri ve evicted_keys sayıları size erken uyarı verir.
Dağıtım Ritüeli: Koddan Konfige, Konfigden Gözleme
Prod’da dağıtım tören gibidir. Heyecanlıdır ama plan varsa sakindir. Kod tarafında config:cache, route:cache, view:cache adımlarını düzenli uygularım. Composer’da –no-dev ve –optimize-autoloader, build sürecinin vazgeçilmezi. Çevresel değişkenleri netleştirip, php artisan optimize ile uygulamayı toparlamak da alışkanlık. Ardından OPcache için nazik bir reload, FPM süreçleri dansını bozmadan tazelenir.
Nginx’te upstream zaman aşımı değerleri, sağlıklı bir iş bölümü için ayarlı olmalı. Web sunucu “iş bende değil” demeyi bilmeli, FPM “bu kadar beklemem” diyebilmeli, kuyruklar “bana bırak” diye almalı. Log rotasyonu, disk doluluk alarmları, CPU/RAM izleme… Bunlar yoksa, sorun dağdayken “neden” sorusunun cevabı şehrin diğer ucunda kalır. İzleme için harici paneller çok yardımcı olur; isterseniz Prometheus ve Grafana ile sessiz alarmları konuşturduğum yazıya da göz atabilirsiniz.
Gerçek Bir Akış: Kaynak Planlama, Havuz, Cache ve Kuyruk El Sıkışıyor
Bir projede sabahları anlık trafik dalgası oluyordu. İlk hamle olarak CPU ve RAM’i ölçtük, en pahalı uçları profilledik. Sonra FPM’de process sayısını kaba kuvvet artırmak yerine, ortalama process RAM tüketimine göre akıllıca ayarladık. OPcache hafızasını biraz genişlettik, validate_timestamps’i kapatıp düzenli reload’a geçtik. Web isteklerinin içindeki raporlar ve dosya içe aktarımlarını kuyruklara taşıyınca, web tepkisi gözle görülür hızlandı. Redis’te TTL’leri yeniden düşünerek kritik anahtarları uçmaktan kurtardık.
Bu düzenin üstüne Octane’i koyduğumuzda, uygulamanın sıcak tutulan belleği hızlı cevaplar vermeye başladı. Stateful sürprizleri yakalamak için birkaç küçük düzeltme yaptık: bazı singleton’ları request başına yenilettik, “kullanıcı bağlamı” gibi verileri asla kalıcı hale getirmedik. Horizon ile sabah dalgası gelmeden worker sayısını artıracak ufak bir otomasyon yazdık, sonra dalga bittikten sonra gereksiz süreçleri azalttık. En sonunda kullanıcılar sadece “hızlı olmuş” dediler. Bazen tek iltifat budur.
Kapasite planlaması tarafında kararsızsanız, zaman ayırıp şuna da bakabilirsiniz: Laravel ve Node.js’de doğru VPS kaynaklarını nasıl seçersiniz. Donanım fikrinizi tazelemek, yazılım ayarları için güzel bir arka plan sağlıyor. Unutmayın, kod, konfig ve kaynaklar birbirini tamamladığında sonuç gerçek anlamda kalıcı hale geliyor.
Kapanış: Vidaları Sık, Sahneden Yavaşça Çekil
Prod ortamını optimize etmek hızlıca biten bir görev değil; biraz gözlem, biraz sabır, bolca küçük dokunuş istiyor. PHP‑FPM havuzlarının nefesini açtığınızda web istekleri boş yere beklemez. OPcache’i doğru kurduğunuzda dosyalar her defasında yeniden ısınmaya çalışmaz. Octane’i disiplinle kullanınca sıcak süreçler size hız kazandırır. Queue/Horizon sayesinde uzun süren işler sahneden çekilir, Redis iyi ayarlandığında cache size dost kalır.
Pratik bir kapanış reçetesi bırakayım: İşleri kuyruklara taşı, FPM’de process sayısını RAM’e göre belirle, OPcache’in belleğini ve doğrulama ayarlarını prod’a uygun yap, Octane’de state’i temiz tuttuğundan emin ol, Redis’te TTL ve maxmemory’yi bilinçli seç. Sonra otur ve gözle. Loglar konuşsun, grafikler rehberlik etsin. Umarım bu yazı işinize yarar ve gece yarısı gelen 502’ler bir daha yolunuzu şaşırmaz. Bir dahaki yazıda görüşmek üzere.
Bonus: Küçük Komut Ajandası
Çoğu zaman not defterime şunları yazarım, burada dursun:
php artisan config:cache, php artisan route:cache, php artisan view:cache
php artisan queue:restart (Horizon/worker’lar nazikçe yenilensin diye)
sudo systemctl reload php-fpm veya dağıtımınıza uygun reload komutu (OPcache tazelenir)
Geri kalan her şey, sakin bir kafayla bakınca zaten kendini gösterir.
Kaynak Notları
Detaylara takıldığınızda şu referanslar sade birer harita gibi iş görüyor: OPcache yapılandırma ayarları, Laravel Octane dokümanları, Redis konfigürasyon rehberi. Hepsini ezberlemek gerekmiyor; aradığınızı hızlıca bulmak yetiyor.
