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
-
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.
-
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.
-
max_requestskö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ı
-
Ö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’inRequestTerminatedhook’una bir sayaç koyun ve eğrinin şeklini görün. -
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_usagefarkı) hangi tipin biriktiğini daraltır. -
Stateful singleton’ları hook’ta sıfırlayın. Request state tutan binding’leri
RequestReceived/RequestTerminatedhook’larında ya daconfig/octane.phpiçindekiflushlistesiyle temizleyin. Singleton’ı container’da bırakıp içindeki state’i resetlemek, çoğu sızıntıyı tek satırda kapatır. -
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. -
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
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.