Server yang lengang tiba-tiba berat: terminal patah-patah, halaman lambat, kipas meraung. Dua tersangka terbesar selalu sama — CPU yang diperebutkan atau memori yang menipis — dan keduanya menuntut reaksi berbeda. CPU penuh hanya membuat proses mengantri, tetapi memori habis memaksa kernel membunuh proses lewat OOM killer tanpa mempersoalkan mana yang paling penting. Chapter ini melatih urutannya: menemukan proses rakus dari satu layar ps, memahami apa yang sedang ia lakukan, menghentikannya dengan tingkatan yang sopan, lalu membaca jejak yang ditinggalkan OOM killer dan swap.

Menemukan Proses Rakus dari Snapshot #

Perintah klasiknya singkat: ps aux --sort=-%cpu | head mengurutkan seluruh proses berdasarkan kolom %CPU — materi lengkapnya di ps, top, dan htop . Namun saat insiden berlalu, yang tersisa biasanya hanya snapshot yang sempat disimpan — file teks berisi output ps aux pada menit kejadian. Keterampilan mengurutkannya kembali dengan awk membuat snapshot mati tetap bisa diinterogasi:

bash
cat > ps-snapshot.txt <<'AKHIR'
USER   PID %CPU %MEM    VSZ   RSS TTY  STAT START  TIME COMMAND
root     1  0.0  0.1 169400 12280 ?    Ss   08:02  0:01 /sbin/init
budi  4712 91.3  2.1 517233 87600 ?    Sl   09:14 12:03 /usr/bin/python3 /opt/analisis.py
mysql  3310  4.2 18.7 1620300 762300 ?  Sl   08:02  3:41 /usr/sbin/mysqld
www-d 5200  3.1  2.4 312450 98210 ?     S    08:03  2:12 /usr/sbin/apache2 -k start
siti  6100  0.6 12.9 421900 524800 ?    Sl   09:31  0:22 /usr/bin/firefox
budi  5120  0.2  0.6  74310 24800 ?     Ss   09:20  0:05 sshd: budi@pts/0
AKHIR
echo "== tiga teratas versi CPU =="
awk 'NR>1 {print $3, $2, $1, $11}' ps-snapshot.txt | sort -rn | head -3
echo "== tiga teratas versi memori =="
awk 'NR>1 {print $4, $2, $1, $11}' ps-snapshot.txt | sort -rn | head -3

Output yang Dihasilkan:

text
== tiga teratas versi CPU ==
91.3 4712 budi /usr/bin/python3
4.2 3310 mysql /usr/sbin/mysqld
3.1 5200 www-d /usr/sbin/apache2
== tiga teratas versi memori ==
18.7 3310 mysql /usr/sbin/mysqld
12.9 6100 siti /usr/bin/firefox
2.4 5200 www-d /usr/sbin/apache2

Mari kita bedah perintah-perintah kuncinya:

  1. Baris 9 (awk 'NR>1 {print $3, $2, $1, $11}' ...): NR>1 melewati baris judul; tiga kolom yang dicetak sengaja dimulai dari angka — %CPU di depan membuat sort -rn bisa mengurutkan seluruh baris secara numerik tanpa opsi kolom.
  2. Baris 10 (sort -rn | head -3): -r mengurutkan terbesar dulu, -n memaksa perbandingan angka — tanpa opsi ini, 9.5 akan menempati urutan setelah 91.3 karena keduanya diawali digit 9.
  3. $11 (kolom COMMAND): karena command bisa mengandung spasi, $11 hanya mengambil kata pertamanya — cukup untuk mengenali program; versi lengkapnya tetap ada di file asli.

Hasilnya menunjuk satu tersangka jauh di atas yang lain: python3 milik budi menggerus 91.3% CPU. Sebelum menghakimi, kita perlu tahu apa yang sedang ia kerjakan.

Membedah Perilaku Tersangka #

Angka %CPU memberi tahu siapa, bukan mengapa. Dua alat menjawab pertanyaan kedua. strace -p PID memperlihatkan system call yang dipanggil proses per detiknya — polanya sangat bicara. Berikut contoh tampilan belasan detik menelusuri proses analisis tadi:

text
read(3, "baris data ke-8124\n", 4096)    = 19
write(1, "interim 41%\n", 12)             = 12
read(3, "baris data ke-8125\n", 4096)    = 19
write(1, "interim 41%\n", 12)             = 12
read(3, "baris data ke-8126\n", 4096)    = 19

Himpunan read-write yang berulang dengan cepat menandakan pekerjaan sungguhan — proses sedang membaca dan memproses data, bukan macet. Bandingkan dengan baris yang sama terus-menerus menampilkan futex(...) (proses mati-matian menunggu lock) atau read( yang tidak pernah kembali (menunggu I/O): itu bukan proses rakus, melainkan proses yang terjebak — dan pembunuhannya tidak akan menambah CPU sedikit pun. Alat kedua, lsof -p PID, mendaftar file yang sedang dibukanya: berguna untuk memastikan proses membaca file yang benar dan tidak sedang menggerus partition backup yang salah sasaran. Konsep system call sebagai gerbang user space ke kernel dibedah di Process Monitoring .

Menghentikan dengan Tingkatan Sinyal #

Setelah yakin proses memang bermasalah, cara menghentikannya pun bertingkat — seperti mengetuk pintu, meminta dengan sopan, baru mendobrak:

SinyalPerintahPerilaku prosesKapan dipakai
SIGHUP (1)kill -HUP PIDumumnya: baca ulang konfigurasimeminta daemon reload tanpa putus layanan
SIGTERM (15)kill PIDberhenti rapi: menyimpan data, menutup filepilihan pertama menghentikan
SIGKILL (9)kill -9 PIDmati seketika, tak bisa ditangkappilihan terakhir saja

SIGTERM adalah permintaan yang bisa ditangkap program — program diberi kesempatan menyelesaikan pekerjaan: menyiram data ke disk, menutup koneksi, menghapus file kuncinya. SIGKILL dikerjakan langsung oleh kernel tanpa sepengetahuan proses, sehingga file setengah tulis dan kunci yang tertinggal menjadi risiko nyata. Materi lengkap sinyal beserta konvensi exit status 128 + nomor sinyal sudah dibahas di Signals dan Process Termination .

Untuk runaway process yang masih sehat — misalnya skrip analisis budi yang memang sedang memproses file besar — opsi paling sopan bukan membunuh sama sekali: turunkan prioritasnya dengan renice agar proses lain tetap lincah, materi nice dan renice . Membunuh hanya jika prosesnya memang salah jalan.

Jejak OOM Killer di Log #

Skenario memori berbeda sama sekali: kita tidak selalu sempat melihat proses rakus sebelum ia memakan semuanya. Yang tersisa adalah korban — proses yang dibunuh kernel untuk menyelamatkan sistem. Jejaknya selalu ada di log kernel, polanya Out of memory: Killed process:

bash
cat > dmesg-oom.log <<'AKHIR'
Jan 15 09:31:44 server-kantor kernel: memori tersisa 3% dari 16361276kB, aktif mencari korban
Jan 15 09:31:45 server-kantor kernel: Out of memory: Killed process 4712 (analisis.py) total-vm:517233kB, anon-rss:87600kB
Jan 15 09:32:40 server-kantor kernel: Out of memory: Killed process 3310 (mysqld) total-vm:1620300kB, anon-rss:762300kB
AKHIR
grep 'Out of memory' dmesg-oom.log | awk '{print "korban :", $12, "— PID", $11}' | tr -d '()'

Output yang Dihasilkan:

text
korban : analisis.py — PID 4712
korban : mysqld — PID 3310

Urutan korban itu justru membingungkan pembaca pemula: korban kedua adalah mysqld yang RSS-nya 762 MB — lebih besar dari analisis.py yang 87 MB. OOM killer tidak membunuh pemakan memori terbesar, melainkan proses dengan skor “kejahatan” tertinggi — perhitungan yang mempertimbangkan total memori, waktu hidup, dan prioritas. Jadi jangan menyalahkan korban: mysqld yang mati adalah gejala, dan pemakan memori sesungguhnya harus dicari dari snapshot ps sebelum insiden. Mekanisme skor ini dibahas dari sisi pemantauan di Memory Monitoring ; pada kasus di atas, analisis.py yang menggelembung adalah tersangka utamanya.

Swap Thrashing: Lambat Meski CPU Santai #

Gejala satu lagi sering menipu: sistem merangkak, tetapi %CPU rendah dan tidak ada proses yang menonjol. Periksa swap. Saat RAM penuh, kernel mulai memindahkan halaman memori bolak-balik ke disk — di vmstat, kolom si/so yang terus berganti angka bukan nol adalah tanda thrashing: mesin menghabiskan waktunya memindahkan memori, bukan menghitung. Solusinya dua arah: hentikan proses pemakan memori terbesar (kembali ke ps aux --sort=-%mem), lalu tinjau ukuran swap dan memori fisiknya di Swap Space . Swap memang menyelamatkan sistem dari OOM, tetapi swap yang sibuk terus-menerus berarti RAM sudah jauh ketinggalan kebutuhan.

Pola Umum dan Skrip Deteksi #

Snapshot sekali pandang bisa ditangkap otomatis dengan ambang sederhana. Skrip berikut menandai proses yang melewati batas CPU atau memori:

bash
cat > deteksi-rakus.sh <<'AKHIR'
#!/bin/bash
# Tandai proses di atas ambang dari snapshot ps.
cpu_min=50
mem_min=15
awk -v c="$cpu_min" -v m="$mem_min" \
  'NR>1 && ($3+0 >= c || $4+0 >= m) {
     printf "PERINGATAN %s (PID %s): CPU %s%%, MEM %s%%\n", $11, $2, $3, $4
   }' ps-snapshot.txt
echo "diperiksa: $(($(wc -l < ps-snapshot.txt) - 1)) proses"
AKHIR
cat > ps-snapshot.txt <<'AKHIR'
USER   PID %CPU %MEM    VSZ   RSS TTY  STAT START  TIME COMMAND
root     1  0.0  0.1 169400 12280 ?    Ss   08:02  0:01 /sbin/init
budi  4712 91.3  2.1 517233 87600 ?    Sl   09:14 12:03 /usr/bin/python3 /opt/analisis.py
mysql  3310  4.2 18.7 1620300 762300 ?  Sl   08:02  3:41 /usr/sbin/mysqld
www-d 5200  3.1  2.4 312450 98210 ?     S    08:03  2:12 /usr/sbin/apache2 -k start
siti  6100  0.6 12.9 421900 524800 ?    Sl   09:31  0:22 /usr/bin/firefox
budi  5120  0.2  0.6  74310 24800 ?     Ss   09:20  0:05 sshd: budi@pts/0
AKHIR
bash deteksi-rakus.sh

Output yang Dihasilkan:

text
PERINGATAN /usr/bin/python3 (PID 4712): CPU 91.3%, MEM 2.1%
PERINGATAN /usr/sbin/mysqld (PID 3310): CPU 4.2%, MEM 18.7%
diperiksa: 6 proses

Bedah baris-per-barisnya:

  1. Baris 4-5 (cpu_min=50 dan mem_min=15): ambang dipasang sebagai variabel di puncak skrip — mudah diubah tanpa menyentuh logika; awk menerimanya lewat opsi -v.
  2. Baris 6 (NR>1 && ($3+0 >= c || $4+0 >= m)): +0 memaksa perbandingan numerik — kolom tetap teks di awk, dan teks "91.3" dibandingkan dengan angka bisa menipu; syaratnya di-OR agar satu layar menangkap dua jenis kerakusan sekaligus.
  3. Baris 13 ($(($(wc -l < ps-snapshot.txt) - 1))): jumlah proses = jumlah baris dikurangi baris judul; tanda $(( )) mengevaluasi aritmetika di dalam echo.

Tabel berikut merangkum pola yang paling sering ditemui beserta langkah pertamanya:

GejalaPenyebab paling umumTindakan pertama
satu proses %CPU jauh di atas lainrunaway process: loop atau pekerjaan sungguhanstrace -p PID; renice bila pekerjaan sah
load tinggi, %CPU rendah, merangkakswap thrashingcek si/so vmstat; hentikan pemakan memori
Out of memory: Killed process di logRAM habis, OOM killer bertindakcari pemakan memori dari snapshot ps
service mati berulang tiap kali sibukOOM memilih service itu sebagai korbankurangi kebutuhan, tambah RAM/swap
%CPU tinggi hanya di %sy (kernel)pekerjaan sistem: I/O berat atau banyak syscallperiksa iowait di Disk Monitoring

Proses rakus biasanya menyelesaikan ceritanya di sini: ditemukan, dipahami, dihentikan dengan sopan. Namun tidak semua masalah tinggal di user space — kadang CPU dan memori yang sehat dikalahkan oleh perangkat keras yang tidak dikenali sistemnya. Cara mengidentifikasi perangkat tanpa driver itulah materi chapter berikutnya.

Referensi lengkapnya: kolom-kolom ps di ps(1) , pengiriman sinyal di kill(1) , dan daftar sinyal beserta perilaku bawaannya di signal(7) .