Memecahkan masalah peristiwa OOM

Jika aplikasi Google Kubernetes Engine (GKE) Anda mengalami penghentian container yang tidak terduga, ketidakstabilan, atau error CrashLoopBackOff, hal ini mungkin disebabkan oleh peristiwa Kehabisan Memori (OOM). Peristiwa OOM terjadi saat container atau node kehabisan memori, sehingga menyebabkan Linux OOM Killer menghentikan proses untuk mengklaim kembali resource.

Gunakan halaman ini untuk mengidentifikasi apakah peristiwa OOM terjadi di level container atau level node, dan menerapkan strategi mitigasi yang efektif untuk mencegah terulangnya peristiwa tersebut.

Informasi ini penting bagi developer Aplikasi yang perlu memastikan bahwa aplikasi mereka dikonfigurasi dengan permintaan dan batas memori yang sesuai serta bebas dari kebocoran memori. Hal ini juga penting bagi admin dan operator Platform yang memantau pemanfaatan resource node dan memastikan bahwa cluster memiliki kapasitas memori yang memadai untuk mendukung workload yang di-deploy. Untuk mengetahui informasi selengkapnya tentang peran umum dan contoh tugas yang kami referensikan dalam konten Google Cloud , lihat Peran dan tugas pengguna GKE umum.

Penyebab umum peristiwa OOM

Peristiwa OOM biasanya terjadi selama lonjakan beban atau traffic, saat penggunaan memori aplikasi melonjak dan mencapai batas memori yang dikonfigurasi untuk container.

Skenario berikut dapat menyebabkan peristiwa OOM:

  • Batas memori tidak memadai: setelan resources.limits.memory dalam manifes Pod terlalu rendah untuk permintaan memori standar atau puncak aplikasi.
  • Permintaan atau batas memori yang tidak ditentukan: jika resources.limits.memory dan resources.requests.memory tidak ditentukan, penggunaan memori container tidak dibatasi.
  • Beban tinggi atau melonjak: lonjakan beban yang tiba-tiba dan ekstrem dapat membebani resource sistem, termasuk memori, meskipun batasnya biasanya memadai.
  • Kebocoran memori: aplikasi mungkin memiliki cacat kode yang menyebabkannya gagal melepaskan memori dengan benar.

Peristiwa OOM dapat memulai kegagalan beruntun, karena lebih sedikit container yang tersisa untuk menangani traffic, sehingga meningkatkan beban pada container yang tersisa. Container ini mungkin juga akan dihentikan.

Cara Kubernetes menangani peristiwa OOM

Linux OOM Killer menangani setiap peristiwa OOM. OOM Killer adalah proses kernel yang aktif saat sistem hampir kehabisan memori. Tujuannya adalah untuk mencegah error sistem total dengan menghentikan proses secara strategis untuk mengosongkan resource. Kernel menggunakan sistem penilaian untuk memilih proses yang akan dihentikan, dengan tujuan menjaga stabilitas sistem dan meminimalkan kehilangan data.

Dalam lingkungan Kubernetes, OOM Killer beroperasi pada dua cakupan yang berbeda: grup kontrol (cgroup), yang memengaruhi satu container; dan sistem, yang memengaruhi seluruh node.

Penghentian OOM tingkat container

Penghentian OOM tingkat container terjadi saat container mencoba melebihi batas memori yang telah ditentukan. Kubernetes menetapkan setiap container ke cgroup tertentu dengan batas memori yang ketat. Saat penggunaan memori container mencapai batas ini, kernel akan mencoba mengklaim kembali memori dalam cgroup tersebut terlebih dahulu. Jika kernel tidak dapat mengklaim kembali memori yang cukup menggunakan proses ini, OOM Killer cgroup akan dipanggil. OOM killer menghentikan proses dalam cgroup tertentu untuk menerapkan batas resource.

Saat proses utama dalam container dihentikan dengan cara ini, Kubernetes akan mengamati peristiwa tersebut dan menandai status container sebagai OOMKilled. restartPolicy Pod yang dikonfigurasi kemudian akan menentukan hasilnya:

  • Always atau OnFailure: container dimulai ulang.
  • Never: container tidak dimulai ulang dan tetap dalam status dihentikan.

Dengan mengisolasi kegagalan ke container yang bermasalah, OOM Killer mencegah satu Pod yang rusak menyebabkan error pada seluruh node.

Pengaruh versi cgroup terhadap perilaku OOM Killer

Perilaku penghentian OOM dapat berbeda secara signifikan antara versi cgroup. Jika Anda tidak yakin versi cgroup yang Anda gunakan, periksa mode cgroup node cluster.

  • Di cgroup v1, peristiwa OOM dalam cgroup memori container dapat menyebabkan perilaku yang tidak dapat diprediksi. OOM Killer dapat menghentikan proses apa pun dalam cgroup tersebut, termasuk proses turunan yang bukan merupakan proses utama container (PID 1).

    Perilaku ini menghadirkan tantangan yang signifikan bagi Kubernetes. Karena Kubernetes terutama memantau kondisi proses container utama, Kubernetes tetap tidak menyadari penghentian OOM "parsial" ini. Proses container utama mungkin terus berjalan, meskipun proses turunan penting telah dihentikan. Perilaku ini dapat mengakibatkan kegagalan aplikasi yang tidak kentara, yang tidak langsung terlihat oleh Kubernetes atau operator, tetapi masih terlihat di jurnal sistem node (journalctl).

  • cgroup v2 menawarkan perilaku OOM Killer yang lebih dapat diprediksi.

    Untuk membantu menjamin integritas workload di lingkungan cgroup v2, OOM killer mencegah penghentian sebagian dan memastikan salah satu dari dua hasil: semua tugas yang termasuk dalam cgroup tersebut dan turunannya dihentikan (membuat kegagalan terlihat oleh Kubernetes), atau jika workload tidak memiliki tugas yang menggunakan terlalu banyak memori, workload tidak akan disentuh dan terus berjalan tanpa penghentian proses internal yang tidak terduga.

    Untuk skenario saat Anda menginginkan perilaku cgroup v1 yang menghentikan satu proses, kubelet menyediakan flag singleProcessOOMKill untuk cgroup v2. Flag ini memberi Anda kontrol yang lebih terperinci, sehingga memungkinkan penghentian proses individual selama peristiwa OOM, bukan seluruh cgroup.

Penghentian OOM tingkat sistem

Penghentian OOM tingkat sistem adalah peristiwa yang lebih serius yang terjadi saat seluruh node, bukan hanya satu container, kehabisan memori yang tersedia. Peristiwa ini dapat terjadi jika penggunaan memori gabungan dari semua proses (termasuk semua Pod dan daemon sistem) melebihi kapasitas node.

Saat node ini kehabisan memori, OOM Killer global akan menilai semua proses pada node dan menghentikan proses untuk mengklaim kembali memori untuk seluruh sistem. Proses yang dipilih biasanya berumur singkat dan menggunakan banyak memori.

Untuk mencegah situasi OOM yang parah, Kubernetes menggunakan pengeluaran tekanan node untuk mengelola resource node. Proses ini melibatkan pengeluaran Pod yang kurang penting dari node saat resource, seperti memori atau kapasitas disk, menjadi sangat rendah. Penghentian OOM tingkat sistem menunjukkan bahwa proses penghapusan ini tidak dapat mengosongkan memori dengan cukup cepat untuk mencegah masalah.

Jika OOM Killer menghentikan proses container, efeknya biasanya sama dengan penghentian yang dipicu cgroup: container ditandai OOMKilled dan dimulai ulang berdasarkan kebijakannya. Namun, jika proses sistem yang penting dihentikan (yang jarang terjadi), node itu sendiri dapat menjadi tidak stabil.

Menyelidiki peristiwa OOM

Bagian berikut membantu Anda mendeteksi dan mengonfirmasi peristiwa OOM, dimulai dengan alat Kubernetes yang paling sederhana dan beralih ke analisis log yang lebih mendetail.

Memeriksa status Pod untuk peristiwa OOM yang terlihat

Langkah pertama dalam mengonfirmasi peristiwa OOM adalah memeriksa apakah Kubernetes mengamati peristiwa OOM. Kubernetes mengamati peristiwa saat proses utama container dihentikan, yang merupakan perilaku standar di lingkungan cgroup v2.

  • Periksa status Pod:

    kubectl describe pod POD_NAME
    

    Ganti POD_NAME dengan nama Pod yang ingin Anda selidiki.

    Jika peristiwa OOM yang terlihat terjadi, output-nya akan mirip dengan berikut ini:

    ...
      Last State:     Terminated
        Reason:       OOMKilled
        Exit Code:    137
        Started:      Tue, 13 May 2025 19:05:28 +0000
        Finished:     Tue, 13 May 2025 19:05:30 +0000
    ...
    

Jika Anda melihat OOMKilled di kolom Reason, berarti Anda telah mengonfirmasi peristiwa tersebut. Exit Code 137 juga menunjukkan penghentian OOM. Jika kolom Reason memiliki nilai yang berbeda, atau Pod masih berjalan meskipun ada error aplikasi, lanjutkan ke bagian berikutnya untuk penyelidikan lebih lanjut.

Menelusuri log untuk peristiwa OOM yang tidak terlihat

Penghentian OOM "tidak terlihat" oleh Kubernetes jika proses turunan dihentikan, tetapi proses container utama terus berjalan (skenario umum di lingkungan cgroup v1). Anda harus menelusuri log node untuk menemukan bukti peristiwa ini.

Untuk menemukan penghentian OOM yang tidak terlihat, gunakan Logs Explorer:

  1. Di konsol Google Cloud , buka Logs Explorer.

    Buka Logs Explorer

  2. Di panel kueri, masukkan salah satu kueri berikut:

    • Jika Anda sudah memiliki Pod yang menurut Anda mengalami peristiwa OOM, buat kueri Pod tertentu tersebut:

      resource.type="k8s_node"
      jsonPayload.MESSAGE:(("POD_NAME" AND "ContainerDied") OR "TaskOOM event")
      resource.labels.cluster_name="CLUSTER_NAME"
      

      Ganti kode berikut:

      • POD_NAME: nama Pod yang ingin Anda buat kuerinya.
      • CLUSTER_NAME: nama cluster tempat Pod berada.
    • Untuk menemukan Pod atau node yang mengalami peristiwa OOM, buat kueri semua workload GKE:

      resource.type="k8s_node"
      jsonPayload.MESSAGE:("ContainerDied" OR "TaskOOM event")
      resource.labels.cluster_name="CLUSTER_NAME"
      
  3. Klik Run query.

  4. Dalam output, temukan peristiwa OOM dengan menelusuri entri log yang berisi string TaskOOM.

  5. Opsional: jika Anda menelusuri peristiwa OOM untuk semua workload GKE dan ingin mengidentifikasi Pod tertentu yang mengalami peristiwa OOM, selesaikan langkah-langkah berikut:

    1. Untuk setiap peristiwa, catat ID penampung yang terkait dengannya.
    2. Identifikasi penghentian container dengan mencari entri log yang berisi string ContainerDied, dan yang terjadi segera setelah peristiwa OOM. Cocokkan ID container dari peristiwa OOM dengan baris ContainerDied yang sesuai.

    3. Setelah Anda mencocokkan container IDs, baris ContainerDied biasanya menyertakan nama Pod yang terkait dengan container yang gagal. Pod ini terpengaruh oleh peristiwa OOM.

Menghubungkan peristiwa OOM dengan mulai ulang container

Saat penghentian OOM menghentikan proses utama container, Kubernetes akan memulai ulang container berdasarkan restartPolicy Pod, seperti yang dijelaskan dalam Penghentian OOM tingkat container dan Penghentian OOM tingkat sistem. Untuk melihat peristiwa OOMKilling dan mulai container yang mengikutinya dalam satu daftar kronologis, gunakan Logs Explorer:

  1. Di konsol Google Cloud , buka Logs Explorer.

    Buka Logs Explorer

  2. Di panel kueri, masukkan kueri berikut:

    log_id("events")
    resource.labels.cluster_name="CLUSTER_NAME"
    (
      (
        resource.type="k8s_pod"
        resource.labels.namespace_name="NAMESPACE_NAME"
        jsonPayload.message:"Started container"
      ) OR (
        resource.type="k8s_node"
        jsonPayload.reason="OOMKilling"
      )
    )
    

    Ganti kode berikut:

    • CLUSTER_NAME: nama cluster yang ingin Anda kueri.
    • NAMESPACE_NAME: namespace Pod yang ingin Anda periksa.

    Peristiwa OOMKilling dilaporkan untuk node (jenis resource k8s_node), sehingga tidak memiliki label namespace. Filter namespace hanya berlaku untuk peristiwa Started container, yang dilaporkan untuk Pod (jenis resource k8s_pod).

  3. Klik Run query.

  4. Dalam output, cari peristiwa Started container yang terjadi segera setelah peristiwa OOMKilling pada node yang sama. Pesan peristiwa OOMKilling mengidentifikasi proses yang dihentikan, dan peristiwa Started container mengidentifikasi Pod dan container yang dimulai.

    Tidak semua peristiwa Started container disebabkan oleh penghentian OOM. Untuk mengonfirmasi bahwa container dimulai ulang karena peristiwa OOM, periksa status Pod seperti yang dijelaskan dalam Memeriksa status Pod untuk peristiwa OOM yang terlihat.

Menggunakan journalctl untuk informasi real-time

Jika Anda perlu melakukan analisis real-time pada sistem, gunakan perintah journalctl.

  1. Hubungkan ke node menggunakan SSH:

    gcloud compute ssh NODE_NAME --location ZONE
    

    Ganti kode berikut:

    • NODE_NAME: nama node yang ingin Anda periksa.
    • ZONE: zona Compute Engine tempat node Anda berada.
  2. Di shell, pelajari pesan kernel dari jurnal sistem node:

    journalctl -k
    
  3. Analisis output untuk membedakan jenis peristiwa:

    • Penghentian di tingkat container: entri log berisi istilah seperti memory cgroup, mem_cgroup, atau memcg, yang menunjukkan bahwa batas cgroup diterapkan.
    • Penghentian di tingkat sistem: entri log adalah pesan umum seperti Out of memory: Killed process... tanpa menyebutkan cgroup.

Menyelesaikan peristiwa OOM

Untuk mengatasi peristiwa OOM, coba solusi berikut:

  • Meningkatkan batas memori: ini adalah solusi yang paling sederhana. Edit manifes Pod untuk memberikan nilai resources.limits.memory yang lebih tinggi yang mengakomodasi penggunaan puncak aplikasi. Untuk mengetahui informasi selengkapnya tentang cara menetapkan batas, lihat Pengelolaan Resource untuk Pod dan Container dalam dokumentasi Kubernetes.
  • Menambahkan atau menyesuaikan permintaan memori: dalam manifes Pod, pastikan kolom resources.requests.memory ditetapkan ke nilai yang realistis untuk penggunaan umum. Setelan ini membantu Kubernetes menjadwalkan Pod ke node dengan memori yang cukup.
  • Menskalakan workload secara horizontal: untuk mendistribusikan beban traffic dan mengurangi tekanan memori pada satu Pod, tingkatkan jumlah replika. Agar Kubernetes menskalakan workload secara proaktif, pertimbangkan untuk mengaktifkan penskalaan otomatis Pod horizontal.
  • Menskalakan node secara vertikal: jika banyak Pod di sebuah node mendekati batasnya, node itu sendiri mungkin terlalu kecil. Untuk meningkatkan ukuran node, migrasikan workload Anda ke node pool dengan memori yang lebih besar. Agar Kubernetes menskalakan node secara proaktif, pertimbangkan untuk mengaktifkan penskalaan otomatis Pod vertikal.
  • Optimalkan aplikasi Anda: tinjau aplikasi Anda untuk mengidentifikasi dan mengatasi kebocoran memori serta mengoptimalkan kode yang menggunakan memori dalam jumlah besar selama lonjakan traffic.
  • Hapus workload yang bermasalah: sebagai upaya terakhir untuk workload yang tidak penting, hapus Pod untuk segera mengurangi tekanan pada cluster.

Langkah berikutnya