# Container'larım sürekli OOMKilled oluyor, memory limit'lerini PHP-FPM ve Go için nasıl doğru ayarlarım?

> Limiti körlemesine yükseltmek yerine working set'i ölçün; PHP-FPM'de max_children'ı limite göre hesaplayın, Go'da GOMEMLIMIT ve GOMAXPROCS ayarlayın.

- Soruldu: 2026-10-07
- Yanıtlandı: 2026-10-13
- Soran: Melis
- Etiketler: docker, kubernetes, performans
- Kaynak: https://muhammetsafak.com/tr/sor-bakalim/containerlarim-oomkilled-memory-limitlerini-php-fpm-go-ayarlarim/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**Soru:** Kubernetes'te hem PHP-FPM (Laravel) hem de Go servislerimiz var. Lokalde limit koymadan çalıştırınca her şey yolunda görünüyor ama production'da yük altında pod'lar sürekli OOMKilled olup yeniden başlıyor.

Memory request/limit değerlerini PHP-FPM ve Go container'ları için nasıl doğru ayarlarım? Sürekli limiti yükseltmek dışında hangi uygulama seviyesi ayarlara bakmalıyım?


Kısa cevap: OOMKilled bir uygulama hatası değil, container'ın cgroup memory limitini aştığının sinyalidir.

## Kısa cevap

Lokalde limit yok, kernel büyümeye izin veriyor; production'da limit + yük altında tavana çarpıp öldürülüyor. Çözüm limiti körlemesine yükseltmek değil, gerçek peak'i ölçüp uygulama knob'larını ona göre ayarlamak.

## Neden

1. **Önce ölçün: working set ne kadar?** `container_memory_working_set_bytes` metriğine bakın. Limiti gözlenen peak'in üzerine, makul bir pay bırakarak koyun. "Lokalde sorun yok" yanıltıcıdır çünkü orada limit yoktur; gerçek soru yük altındaki tepe kullanımdır.

2. **PHP-FPM'de katil pm.max_children'dır.** Toplam bellek ≈ `max_children × istek başına ortalama bellek`. Tutorial'dan kopyalanan devasa bir `max_children` yük altında tüm worker'ları açar ve limiti patlatır. Formül: `max_children = (container limit − pay) / worker peak`. Worker peak'i tek bir process'in gerçek RSS'inden ölçün.

3. **PHP `memory_limit` container'ı korumaz.** O ayar per-process'tir; container geneline dair hiçbir garanti vermez, hatta tek bir worker'ın `memory_limit`'e kadar büyümesine izin verir. Container'a karşı asıl kalkanınız `max_children`'dır; `memory_limit`'i makul tutun ama container koruması sanmayın.

4. **Go runtime cgroup limitini varsayılan olarak bilmez.** GC'yi heap büyümesine (`GOGC`) göre tempolar, container limitine göre değil; limitli bir container'da bu, [fazla allocate edip OOM olmak](/tr/sor-bakalim/go-da-gc-baskisini-sync-pool-ve-escape-analizi-ile-azaltmak/) demektir. Çözüm: `GOMEMLIMIT`'i (Go 1.19+) limitin biraz altına ayarlayın — bu soft limit, belleğe yaklaştıkça GC'yi agresifleştirir. Ayrıca `GOMAXPROCS`'u CPU limitine eşitleyin (`automaxprocs`); Go 1.25 öncesinde bunu yapmazsanız scheduler node'un tüm çekirdeklerine göre çalışırdı, Go 1.25'ten (Ağustos 2025) itibaren runtime bunu cgroup CPU limitine göre otomatik ayarlıyor.

   ```yaml
   # Go container
   resources:
     requests: { memory: "256Mi" }
     limits:   { memory: "512Mi" }
   env:
     - { name: GOMEMLIMIT, value: "450MiB" } # limit − pay (soft limit)
     - { name: GOMAXPROCS, value: "1" }      # CPU limitine eşitle
   ```

## Ne yapmalı

1. **K8s'te requests = tipik, limits = peak + pay.** Heap dışı kullanım (stack, buffer, off-heap, PHP extension'ları) için mutlaka pay bırakın; limiti çok sıkarsanız normal bir burst bile pod'u öldürür. Sürprizsiz davranış istiyorsanız request = limit ile Guaranteed QoS düşünün.

2. **Leak mi, yüksek peak mi ayırın.** `working_set` yük altında yüksek bir seviyede plato yapıyorsa bu bir boyutlandırma problemidir; limiti ve knob'ları ona göre ayarlayın. Monoton tırmanıp hiç plato yapmıyorsa bu bir memory leak'tir; limiti yükseltmek onu yalnızca geciktirir, kodu düzeltmeniz gerekir.

**Sonuç:** Ben olsam önce working set'i ölçer, limiti gözlenen peak + pay olarak koyardım. PHP-FPM'de `max_children`'ı limite karşı formülle sabitler, Go'da `GOMEMLIMIT` + `GOMAXPROCS` ayarlardım. Heap dışı için her zaman pay bırakır ve grafiği izleyerek bunun bir leak mı yoksa yüksek peak mi olduğunu ayırt ederdim. Limiti sonsuza dek yükseltmek bir çözüm değil, gerçek problemi erteleme biçimidir.

## İlgili Yazılar

- [Container'daki healthcheck'i Dockerfile'a mı yazmalıyım yoksa Kubernetes probe'larına mı bırakmalıyım?](https://muhammetsafak.com/tr/sor-bakalim/containerdaki-healthchecki-dockerfilea-mi-yazmaliyim-yoksa-kubernetes-probelarina-mi-birakmaliyim/) — Sor Bakalım
- [Attribute tabanlı bir mapping katmanında reflection maliyetini production'da nasıl kontrol altında tutarım?](https://muhammetsafak.com/tr/sor-bakalim/attribute-mapping-katmaninda-reflection-maliyetini-kontrol-altinda-tutarim/) — Sor Bakalım
- [Container'daki Go worker'ım SIGTERM almıyor ve graceful kapanmıyor, bu bir PID 1 sorunu mu?](https://muhammetsafak.com/tr/sor-bakalim/containerdaki-go-workerim-sigterm-almiyor-pid-1-sorunu/) — Sor Bakalım
