Studi Kasus: Ketika OOM Killer Membunuh PHP, Kesalahan Klasik Konfigurasi Memory
3 min read

Studi Kasus: Ketika OOM Killer Membunuh PHP, Kesalahan Klasik Konfigurasi Memory

Kasus OOM Killer tiba-tiba menghentikan proses PHP sering dianggap sebagai masalah misterius: server terlihat “baik-baik saja”, CPU rendah, tidak ada error fatal di aplikasi, namun proses mati mendadak. Padahal, akar masalahnya hampir selalu sederhana: salah memahami bagaimana memory PHP bekerja dalam konteks banyak worker.

Artikel ini membedah kasus nyata: server 4GB RAM, memory_limit PHP 2GB, dan 20 PHP worker. Di sinilah jebakan klasik terjadi.


Studi Kasus Nyata

Konfigurasi Server

  • Total RAM server: 4GB
  • PHP memory_limit: 2GB
  • PHP-FPM max_children: 20
  • Swap: minim / tidak ada

Gejala yang Terjadi

  • Proses PHP mati mendadak

  • Tidak ada fatal error di log PHP

  • dmesg menunjukkan:

    • OOM Killer aktif
    • Proses PHP sebagai korban
  • Log menunjukkan penggunaan memory oleh PHP mencapai ~3GB sebelum kill

Hipotesis Awal

Ada beberapa proses PHP yang secara bersamaan memakan memory besar. Ketika total penggunaan mendekati limit sistem, kernel memilih proses dengan konsumsi terbesar sebagai korban — PHP.

Hipotesis ini terbukti benar.


Kesalahan Paling Umum: Salah Paham memory_limit

Banyak engineer (terutama konfigurasi lama) berpikir:

memory_limit = 2GB artinya PHP secara keseluruhan hanya boleh pakai 2GB.

SALAH BESAR

Fakta Penting

memory_limit adalah:

  • Limit per PHP worker / per request
  • Bukan limit global

Artinya:

2GB x 20 worker = 40GB potensi alokasi memory

Di server 4GB RAM, ini adalah bom waktu.


Analisa Signal Masalah

PHP Tidak Menunjukkan Error

OOM Killer bekerja di level kernel, bukan aplikasi.

  • PHP tidak sempat menulis error
  • Request tiba-tiba terputus

Kernel Log adalah Sumber Kebenaran

Cek dengan:

dmesg | grep -i oom

Biasanya terlihat:

  • Proses
  • PID
  • Memory usage terakhir

Memory Naik Bertahap, Bukan Spike

Biasanya disebabkan oleh:

  • Request berat
  • Data besar
  • Leak halus (bukan leak klasik)

Faktor-Faktor yang Memperparah Situasi

Concurrency Tinggi

Beberapa request berat berjalan bersamaan.

Worker PHP Terlalu Banyak

  • pm.max_children tinggi
  • Tidak sebanding dengan RAM

Request PHP Berat

Contoh:

  • Export CSV / Excel besar
  • Generate PDF
  • Image processing
  • Query tanpa pagination

Tidak Ada Swap atau Swap Terlalu Kecil

Tanpa swap:

  • Kernel tidak punya buffer waktu
  • OOM Killer lebih agresif

Memory Fragmentation

PHP + ekstensi native bisa menyebabkan fragmentasi yang sulit ditebak.


Cara Kerja OOM Killer (Ringkas tapi Akurat)

Ketika sistem:

  • Hampir kehabisan memory
  • Tidak bisa melakukan reclaim

Kernel akan:

  1. Menghitung OOM score setiap proses

  2. Faktor penilaian:

    • Penggunaan memory
    • Privilege
    • Lama hidup proses
  3. Memilih kandidat paling “murah untuk dikorbankan”

  4. Mengirim SIGKILL (tidak bisa ditangkap)

Dalam kasus ini:

PHP adalah proses dengan konsumsi memory terbesar → dieksekusi.


Mengapa Terlihat Mati di ~3GB?

Meskipun RAM 4GB:

  • OS butuh memory
  • Page cache
  • Service lain (Nginx, systemd, dll)

Biasanya:

  • 70–80% RAM = zona bahaya
  • Di ~3GB → OOM Killer mulai bekerja

Best Practice yang Seharusnya Dilakukan

Turunkan memory_limit

Contoh realistis:

memory_limit = 256M

Ini adalah best practice lama yang justru benar.

Hitung Memory Budget Secara Sadar

Rumus kasar:

(max_children x memory_limit) + overhead < total RAM

Contoh aman:

  • 4GB RAM
  • 256MB per worker
  • max 10–12 worker

Bedakan Request Berat

Pisahkan:

  • Web request normal
  • Background job (queue, cron, worker khusus)

Jangan jalankan:

  • Export besar
  • PDF generator

Di PHP web worker biasa.

Gunakan Queue untuk Beban Berat

  • Redis / RabbitMQ / SQS
  • Worker terkontrol
  • Concurrency kecil

Aktifkan Swap (Secukupnya)

Bukan untuk performa, tapi:

  • Memberi waktu observasi
  • Mencegah kill mendadak

Monitor Memory per Worker

Gunakan:

  • ps aux --sort -rss
  • PHP-FPM status page
  • APM (New Relic, Datadog)

Pelajaran Penting

  1. memory_limit bukan limit global
  2. PHP worker adalah proses independen
  3. OOM Killer tidak peduli aplikasi Anda
  4. Setting besar ≠ aman
  5. Konfigurasi lama sering salah kaprah

Penutup

Kasus ini adalah contoh klasik bukan bug, tapi miskonsepsi arsitektur.

OOM Killer bukan musuh — ia hanya mengeksekusi keputusan terakhir dari konfigurasi yang keliru.

Jika Anda membaca artikel ini dan masih menggunakan memory_limit 1–2GB untuk PHP web worker: itu bukan optimasi, itu undangan bencana.

Lebih kecil, terkontrol, dan sadar konteks — selalu menang.