Inode Penuh No space left on device Padahal Disk Masih Lega

Inode Penuh: No space left on device Padahal Disk Masih Lega

Table of Contents

Ilustrasi – Pukul 02.14, alert masuk: aplikasi gagal menyimpan data. Anda login ke server, menjalankan df -h, dan hasilnya membingungkan: disk baru terpakai 38%. Namun log aplikasi terus mengulang pesan yang sama: “No space left on device.”

Selamat datang di salah satu masalah server yang paling menjebak: kehabisan inode. Ruang disk masih banyak, tetapi “laci katalog” untuk mencatat file baru sudah penuh. Artikel ini tidak berhenti di definisi. Kita akan membedah cara kerja inode, mereproduksi masalahnya secara aman, melacak biang keroknya, lalu menyusun solusi dari level darurat sampai pencegahan jangka panjang.

Catatan penting: semua perintah di artikel ini sebaiknya dicoba di lingkungan staging terlebih dahulu. Perintah penghapusan (-delete, rsync --delete) bersifat permanen.

Apa Itu Inode? Analogi Perpustakaan

Bayangkan sebuah perpustakaan. Buku-bukunya adalah data, sedangkan kartu katalognya adalah inode. Setiap buku wajib punya tepat satu kartu, berisi ukuran buku, pemilik, tanggal, dan lokasi rak tempat buku berada. Rak bisa kosong separuhnya, tetapi jika laci katalog sudah penuh, perpustakaan tidak bisa menerima satu buku baru pun, setipis apa pun buku itu.

Secara teknis, inode (index node) adalah struktur data di filesystem bergaya Unix (ext4, XFS, dan sejenisnya) yang menyimpan metadata sebuah file atau direktori:

  • tipe (file biasa, direktori, symlink, dan lainnya) beserta hak akses;
  • pemilik (UID) dan grup (GID);
  • ukuran file;
  • timestamp (akses, modifikasi, perubahan metadata);
  • jumlah hard link;
  • penunjuk ke blok data di disk tempat isi file sebenarnya disimpan.

Anda bisa melihatnya langsung:

ls -i index.php
stat index.php

Empat Fakta Inode yang Jarang Dibahas

1. Nama file tidak disimpan di inode. Nama disimpan di direktori, yang pada dasarnya adalah daftar pasangan “nama → nomor inode”. Karena itulah satu file bisa punya beberapa nama (hard link) tanpa menggandakan data.

2. Itulah sebabnya mv terasa instan. Memindahkan file 50 GB di dalam satu partisi hanya mengubah entri direktori; inode dan datanya tidak disentuh. cp lebih lama karena harus membuat inode baru dan menyalin seluruh blok data.

3. Hard link gratis, symlink tidak. Hard link hanya menambah nama untuk inode yang sama, sedangkan symlink adalah file tersendiri dengan inode sendiri:

echo halo > a.txt
ln a.txt b.txt       # hard link: nomor inode sama
ln -s a.txt c.txt    # symlink: inode baru
ls -li a.txt b.txt c.txt

4. File 1 byte dan file 10 GB sama-sama memakai satu inode. Inilah akar masalahnya: inode dihitung per file, bukan per byte. Jutaan file kecil bisa menghabiskan inode jauh sebelum ruang disk terpakai.

Mengapa Inode Bisa Habis Lebih Dulu?

Pada ext4, filesystem default di sebagian besar distro Linux, jumlah inode ditentukan sekali saat partisi diformat dan tidak bisa ditambah begitu saja sesudahnya. Rasio bawaannya sekitar satu inode untuk setiap 16 KB ruang, sehingga partisi 1 TB mendapat kira-kira 60 jutaan inode.

Dari sini lahir rumus yang sangat praktis:

Jika rata-rata ukuran file di server Anda lebih kecil dari rasio bytes-per-inode (default 16 KB), inode akan habis lebih dulu daripada ruang disk.

Siapa yang rata-ratanya di bawah 16 KB? File session PHP (biasanya kurang dari 1 KB), potongan cache, email individual, thumbnail kecil, dan hasil npm install.

Filesystem lain berperilaku berbeda. XFS mengalokasikan inode secara dinamis (dengan batas persentase tertentu dari kapasitas), sedangkan Btrfs dan ZFS tidak memiliki jumlah inode tetap sehingga jarang mengalami masalah ini. Di lingkungan multi-tenant seperti hosting, batas inode juga sering diterapkan sebagai kuota per akun, jadi satu akun bisa “kehabisan inode” walau filesystem induknya masih lega.

Lab 5 Menit: Reproduksi Inode Penuh dengan Aman

Daripada menunggu insiden terjadi, buat partisi mini berbasis file dan lihat sendiri kejadiannya:

dd if=/dev/zero of=lab.img bs=1M count=100
mkfs.ext4 -q -F lab.img
mkdir lab && sudo mount -o loop lab.img lab
sudo chown $USER lab
cd lab
df -ih .                       # catat jumlah inode awal
seq 1 40000 | xargs touch      # buat 40.000 file kosong

Pada kisaran puluhan ribu file, touch akan berhenti dengan pesan No space left on device. Sekarang bandingkan:

df -h .    # ruang disk: nyaris kosong
df -i .    # IUse%: 100%

File kosong tidak memakai blok data sama sekali, tetapi tetap memakan inode. Jumlah inode awal bisa berbeda tergantung versi mke2fs di sistem Anda. Bersihkan labnya:

cd .. && sudo umount lab && rm -rf lab lab.img

Gejala: Kenali Sebelum Terlambat

Pesan errornya identik dengan disk penuh, sehingga sering salah didiagnosis. Waspadai tanda-tanda berikut:

  • No space left on device padahal df -h menunjukkan ruang masih tersisa.
  • WordPress gagal mengunggah media, memperbarui plugin, atau menulis cache.
  • Pengguna gagal login atau sesi hilang acak karena PHP tidak bisa membuat file session.
  • Email tidak masuk, atau MTA melaporkan gagal menulis ke mailbox maupun antrean.
  • MySQL/MariaDB gagal membuat tabel sementara atau file baru.
  • Deployment, apt, atau composer install berhenti di tengah jalan.
  • Service gagal start karena tidak bisa membuat file PID atau socket.
  • Backup gagal atau berjalan sangat lambat.

Diagnosis Langkah demi Langkah

Langkah 1: konfirmasi dengan df -i.

df -i

Perhatikan kolom IUse%. Jika sebuah mount point mendekati 100%, itulah lokasi masalahnya.

Langkah 2: cari direktori terberat.

sudo du --inodes -xd1 /var 2>/dev/null | sort -rn | head -15

Masuk ke direktori teratas, lalu ulangi. Sebagai alternatif, lihat sebaran jumlah file per direktori:

sudo find /var -xdev -type f 2>/dev/null | cut -d/ -f1-4 | sort | uniq -c | sort -rn | head -15

Ubah angka pada -f1-4 untuk melihat kedalaman yang lebih dalam atau lebih dangkal. Di server produksi yang sibuk, jalankan dengan prioritas rendah: ionice -c3 nice -n19 <perintah>.

Langkah 3: hindari ls biasa di direktori raksasa. ls mengurutkan semua entri sebelum menampilkannya, dan pada direktori berisi jutaan file hal ini bisa membuat terminal menggantung. Gunakan ls -f | head yang tidak melakukan pengurutan.

Langkah 4: periksa jebakan “file terhapus tapi masih terbuka”. Jika sebuah file sudah di-rm tetapi masih dibuka oleh sebuah proses, inode-nya belum dibebaskan sampai proses itu menutupnya:

sudo lsof +L1

Restart service yang bersangkutan untuk melepaskannya.

Delapan Tersangka Utama

TersangkaMengapa boros inodeLokasi umum
Session PHPSatu file per pengunjung atau bot, ukurannya sangat kecil/var/lib/php/sessions, /tmp
Cache berbasis fileSatu file per halaman atau fragmen cachewp-content/cache
Thumbnail mediaSatu foto yang diunggah menghasilkan banyak file turunanwp-content/uploads
Maildir emailSatu email sama dengan satu file/var/mail, /home/*/Maildir
Antrean emailBounce dan spam menumpuk di antrean MTA/var/spool/postfix
node_modules dan vendorRibuan file per proyek, dikalikan jumlah proyek dan build CIDirektori proyek dan runner CI
DockerLayer image dan build cache berisi jutaan file/var/lib/docker
Log, output cron, file sementaraSatu file per request atau per eksekusi job/var/log, /tmp

Solusi: Dari Darurat sampai Permanen

Tahap 1: Darurat, bebaskan inode dengan aman

Prinsipnya: hapus hanya hal yang jelas bisa dibuat ulang (session kedaluwarsa, cache, log lama) dan pastikan path sudah benar sebelum menekan Enter.

rm -rf folder/* pada direktori berisi jutaan file sering gagal dengan Argument list too long. Gunakan find:

# hapus session PHP yang lebih tua dari 24 jam
sudo find /var/lib/php/sessions -type f -name 'sess_*' -mmin +1440 -delete

# hapus cache lama (contoh WordPress)
find /home/situs/public_html/wp-content/cache -type f -mtime +7 -delete

Untuk direktori yang seluruh isinya memang akan dikosongkan, rsync dengan direktori kosong sering lebih cepat:

mkdir /tmp/kosong
rsync -a --delete /tmp/kosong/ /path/direktori-target/

Setelah itu, jalankan df -i lagi untuk memastikan inode sudah lega.

Tahap 2: Perbaiki akar masalah

PHP session yang tidak pernah dibersihkan. Di Debian dan Ubuntu, pembersihan session dilakukan oleh phpsessionclean, bukan oleh PHP sendiri. Pool PHP-FPM yang memakai session.save_path kustom sering luput dari pembersihan ini, sehingga file session menumpuk tanpa batas. Pastikan ada mekanisme pembersihan untuk path tersebut, atau pindahkan session ke Redis:

session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

Audit juga plugin yang memanggil session_start() untuk pengunjung anonim, karena bot bisa menghasilkan ribuan session per jam.

WordPress dan thumbnail. Satu foto yang diunggah bisa menghasilkan 8 sampai 15 file turunan: thumbnail, medium, large, ukuran bawaan tema, versi -scaled, ditambah WebP bila memakai plugin optimasi. Seribu foto berarti belasan ribu inode. Matikan ukuran yang tidak dipakai (hanya berlaku untuk unggahan baru, uji di staging lebih dulu):

add_filter('intermediate_image_sizes_advanced', function ($sizes) {
    unset($sizes['medium_large'], $sizes['1536x1536'], $sizes['2048x2048']);
    return $sizes;
});

Pertimbangkan juga object cache (Redis) sebagai pengganti cache berbasis file, dan atur jadwal purge pada plugin cache agar file lama tidak menumpuk.

Email. Terapkan kebijakan retensi untuk folder Junk dan Trash (misalnya hapus otomatis setelah 30 hari), matikan catch-all yang menampung spam, dan arsipkan mailbox lama ke dalam tar. Periksa antrean Postfix dengan postqueue -p | tail -1.

Docker dan proyek Node.js. Layer image dan node_modules adalah mesin pencetak file kecil.

docker system df        # lihat pemakaian
docker builder prune    # bersihkan build cache
docker image prune      # hapus image dangling

Hati-hati dengan docker system prune -a di server produksi. Untuk proyek Node.js, pnpm menautkan paket lewat hard link ke store global sehingga bisa menekan pertambahan inode dibanding npm install yang menyalin file di setiap proyek. Hapus juga node_modules dari proyek yang sudah tidak aktif.

Tahap 3: Pencegahan struktural

  1. Pisahkan partisi atau volume untuk beban kerja rawan file kecil (/var/mail, /var/lib/docker, /home) agar insiden inode tidak melumpuhkan root filesystem.
  2. Format dengan rasio yang sesuai beban kerja. Pada ext4 ini hanya bisa ditentukan saat mkfs:
mkfs.ext4 -i 4096 /dev/sdb1        # 1 inode per 4 KB
mkfs.ext4 -N 50000000 /dev/sdb1    # atau tentukan jumlah inode langsung

Ada trade-off: setiap inode memakan sekitar 256 byte. Pada rasio 4 KB, tabel inode menghabiskan kira-kira 6% kapasitas, dibanding sekitar 1,6% pada rasio bawaan.

  1. Pertimbangkan XFS untuk beban kerja dengan banyak file kecil, karena inode-nya dialokasikan dinamis. Periksa konfigurasinya dengan xfs_info.
  2. Arsipkan data dingin. Gabungkan jutaan file kecil menjadi satu tar atau zip, atau simpan sebagai objek.
  3. Pindahkan media ke object storage dan data kecil terstruktur ke database.

Jika partisi ext4 sudah telanjur kehabisan inode dan tidak ada ruang untuk memperbesarnya, jalur yang realistis adalah membuat volume baru dengan rasio inode yang tepat, lalu memigrasikan datanya.

Monitoring: Pantau Kecepatan, Bukan Hanya Persentase

Alert pada 90% sering terlambat jika inode bertambah jutaan per hari. Yang lebih berguna adalah laju pertumbuhannya.

Skrip sederhana untuk cron, peringatan saat pemakaian inode mencapai 80% atau lebih:

#!/bin/bash
df -iP | awk 'NR>1 && $5+0 >= 80 {print $6 " memakai " $5 " inode"}'

Catat tren harian ke file CSV agar mudah dibuat grafik:

echo $(date +%F),$(df -i --output=iused / | tail -1 | tr -d ' ') >> /var/log/inode-harian.csv

Jika memakai Prometheus dan node_exporter, aturan berikut memprediksi inode akan habis dalam 24 jam ke depan:

predict_linear(node_filesystem_files_free{mountpoint="/"}[6h], 24 * 3600) < 0

Inode sebagai Sinyal Keamanan

Lonjakan inode mendadak tanpa ada deployment atau kampanye adalah tanda tanya besar. Penyebabnya bisa bot yang membanjiri session, bug yang menulis file di setiap request, atau yang paling serius: malware yang menyuntikkan ribuan halaman spam ke dalam website. Untuk melihat di mana file baru bermunculan dalam 24 jam terakhir:

find /var/www -xdev -type f -mtime -1 | cut -d/ -f1-5 | sort | uniq -c | sort -rn | head

Jika yang muncul adalah folder atau nama file yang tidak Anda kenali, perlakukan sebagai insiden keamanan, bukan sekadar masalah kapasitas.

FAQ

Apakah inode bisa ditambah tanpa format ulang? Pada ext4, tidak. Jumlah inode ditetapkan saat pembuatan filesystem dan hanya bertambah secara proporsional bila filesystem diperbesar. Opsi paling aman adalah membuat volume baru dengan rasio yang sesuai lalu memigrasikan data. XFS dan Btrfs mengalokasikan inode secara dinamis.

Apakah direktori juga memakai inode? Ya. Setiap direktori memakai satu inode, sama seperti file dan symlink.

Apakah inode penuh merusak data yang sudah ada? Tidak. Data yang sudah tersimpan tetap utuh, tetapi filesystem menolak pembuatan file baru. Dampaknya terasa pada aplikasi yang gagal menulis, database yang error, dan service yang tidak bisa start.

Apakah menghapus satu file besar membebaskan banyak inode? Tidak. File 10 GB hanya memakai satu inode. Yang membebaskan inode adalah menghapus file dalam jumlah banyak.

Bagaimana dengan shared hosting? Biasanya ada kuota inode per akun. Cek penggunaannya di panel hosting, dan jika mendekati batas, bersihkan cache, session, serta email lama sebelum meminta kenaikan kuota.

Step Pengecekan

  • Saat muncul No space left on device, jalankan df -h dan df -i.
  • Lacak direktori penyebab dengan du --inodes atau kombinasi find.
  • Periksa file terhapus yang masih terbuka dengan lsof +L1.
  • Bebaskan inode lewat find ... -delete, bukan rm -rf *.
  • Perbaiki sumbernya: GC session, thumbnail WordPress, retensi email, pembersihan Docker.
  • Pisahkan volume dan sesuaikan rasio inode untuk beban kerja file kecil.
  • Pasang monitoring laju pertumbuhan inode, bukan hanya persentase.

Penutup

Inode jarang dibicarakan sampai server benar-benar bermasalah, padahal pemahaman dasarnya sederhana: kapasitas disk punya dua batas, ruang dan jumlah file. Dengan memantau keduanya, memilih layout storage yang sesuai karakter aplikasi, dan memiliki prosedur darurat yang sudah teruji, insiden jam dua pagi seperti di awal artikel bisa diselesaikan dalam hitungan menit, atau bahkan tidak pernah terjadi.

Perlu bantuan mengaudit kapasitas, merancang layout storage, atau memindahkan workload ke infrastruktur yang lebih siap? Hubungi tim NEX untuk berdiskusi.

Hubungi Kami
0
Chat with us
Select a representative to connect with:

Connecting to WhatsApp...

If WhatsApp does not open automatically, check your browser popup blocker.

CS Fikri Online
Memuat percakapan...

Selamat datang! 👋

Masukan nama & nomor WhatsApp Anda untuk mulai obrolan

Isi nama & no. WhatsApp di atas untuk mulai chat...
Percakapan ini telah selesai.

Terima kasih telah menghubungi kami.