İçeriğe geç
Muhammet Şafak
en
Soran: Yiğit Cevaplandı:

Laravel Octane (FrankenPHP) altında bellek sızıntısını nasıl debug ederim?


Soru

Laravel Octane'i FrankenPHP sürücüsüyle `max-requests=500` ile çalıştırıyoruz. Yüksek trafikte worker'ların bellek tüketimi hızla artıyor, RAM şişip sunucu kilitlenme noktasına geliyor. PHP-FPM'de her istek sonrası bellek temizlenirken Octane'in durumsal yapısında singleton'lar, static değişkenler ve third-party paketlerin yol açtığı bu sızıntıyı nasıl debug ederim? Worker'ları kalıcı tutarken belleği nasıl optimize ederim?

Cevap

Kısa cevap: Tahmin etmeyin, ölçün — Octane’de worker uzun ömürlü olduğu için istekler arasında biriken her şey sızar; önce neyin biriktiğini izleyip yakalayın, sonra stateful tarafı hook’larda sıfırlayın.

Kısa cevap

Asıl mesele şu: PHP-FPM “her istekte taze süreç” varsayar, Octane ise worker’ı ayakta tutar. Bu varsayımı bozan her şey — büyüyen static array’ler, request state tutan singleton’lar, her istekte yeniden register edilen listener/binding’ler, sıfırlanmayan global store’lar (Log, Auth, current request) — sessizce belleği şişirir. Kalıcı sürecin bu modeli neyi değiştirdiğini Laravel Octane yazısında anlatmıştım.

Neden

  1. Sızıntı bir kod hatası değil, bir varsayım ihlali. PHP-FPM’de her istek kendi sürecinde doğup ölüyordu; sızdıran kod da onunla birlikte ölüyordu. Octane bu güvenlik ağını kaldırıyor, aynı kod aynı sürecde biriktirmeye başlıyor.

  2. Suçlu çoğu zaman kendi kodunuz değil. “Her istekte taze süreç” varsayan bir third-party paket PHP-FPM’de görünmez, Octane’de patlar. Bu yüzden okuma değil ölçüm gerekiyor.

  3. max_requests kök nedeni gizler. Worker’ı belli sayıda istekten sonra geri dönüştürmek RAM’i sınırlar ama sızıntıyı kapatmaz — 500’ü düşürmek sizi sadece geç çökmeye taşır.

Ne yapmalı

  1. Önce ölçün, sonra konuşun. Her N istekte bir memory_get_usage(true)’yi loglayın; bellek monoton artıyorsa sızıntı vardır, dalgalanıp düşüyorsa normaldir. Octane’in RequestTerminated hook’una bir sayaç koyun ve eğrinin şeklini görün.

  2. Bisect ile suçluyu bulun. Service provider’ları ve şüpheli paketleri tek tek devre dışı bırakıp eğriyi tekrar ölçün; artış nerede duruyorsa sızıntı oradadır. Snapshot diff’i (iki noktada memory_get_usage farkı) hangi tipin biriktiğini daraltır.

  3. Stateful singleton’ları hook’ta sıfırlayın. Request state tutan binding’leri RequestReceived/RequestTerminated hook’larında ya da config/octane.php içindeki flush listesiyle temizleyin. Singleton’ı container’da bırakıp içindeki state’i resetlemek, çoğu sızıntıyı tek satırda kapatır.

  4. Static birikimi öldürün, servisi request başına yeniden bağlayın. Büyüyen static $cache = [] array’leri, kapanmayan bağlantılar, istek başına şişen koleksiyonlar tipiktir. Request scope’una ait servisi singleton yapmayın; her istekte yeniden bind edin ki taşıdığı veri istekle birlikte ölsün.

  5. max_requests’i emniyet supabı olarak açık tutun. Ama asıl işi sızıntıyı kapatarak yapın; ona bel bağlamayın.

Sonuç: Ben olsam sırayı şöyle kurardım: önce memory_get_usage ile eğriyi çıkarın, sonra service provider/paketleri bisect ederek suçluyu daraltın, ardından stateful singleton’ları Octane hook’larında sıfırlayın ve static birikimi temizleyin. max_requests’i bir güvenlik ağı olarak elinizde tutun ama ona bel bağlamayın. Octane’in hızını alacaksanız, “süreç her istekte ölmüyor” gerçeğini kodun her katmanında kabul etmeniz gerekir.

İlgili Yazılar

Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi