Inode เต็ม: แก้ดิสก์ยังว่างแต่สร้างไฟล์ไม่ได้บน Linux Server

Inode เต็มทำให้ Linux ฟ้อง No space left on device ทั้งที่ดิสก์ยังว่าง ตรวจด้วย df -i หาโฟลเดอร์ไฟล์เล็กจำนวนมาก ลบอย่างปลอดภัย และตั้งระบบล้างอัตโนมัติ

โดย ทีมงาน THAI DATA CLOUD อ่าน 12 นาที

แชร์FacebookXLINELinkedIn
Inode — Inode เต็ม: แก้ดิสก์ยังว่างแต่สร้างไฟล์ไม่ได้บน Linux Server
Inode เต็ม: แก้ดิสก์ยังว่างแต่สร้างไฟล์ไม่ได้บน Linux Server

คำตอบสั้น ๆ: Inode เต็มทำให้ Linux ฟ้อง No space left on device ทั้งที่ดิสก์ยังว่าง ตรวจด้วย df -i หาโฟลเดอร์ไฟล์เล็กจำนวนมาก ลบอย่างปลอดภัย และตั้งระบบล้างอัตโนมัติ

คู่มือนี้อธิบาย Inode ทีละขั้นตอน พร้อมคำสั่งที่ใช้ได้จริงและปัญหาที่พบบ่อย

Inode คือโครงสร้างข้อมูลในระบบไฟล์ Linux ที่เก็บรายละเอียดของไฟล์หนึ่งไฟล์ เช่น เจ้าของ สิทธิ์ ขนาด และตำแหน่งข้อมูลบนดิสก์ ทุกไฟล์ ทุกโฟลเดอร์ และทุก symbolic link ใช้ Inode หนึ่งตัวเสมอ ไม่ว่าไฟล์นั้นจะใหญ่หรือเล็กแค่ไหน ระบบไฟล์ ext4 กำหนดจำนวน Inode ไว้ตายตัวตั้งแต่ตอนฟอร์แมต ถ้าเครื่องมีไฟล์เล็ก ๆ หลายล้านไฟล์ Inode จะหมดก่อนพื้นที่ดิสก์ แล้วระบบจะฟ้อง No space left on device ทั้งที่ df -h ยังเห็นพื้นที่ว่างหลายสิบ GB

คู่มือนี้เหมาะกับผู้ดูแล Linux Server ที่เจอเว็บบันทึก session ไม่ได้ อัปโหลดไฟล์ไม่ได้ หรือติดตั้งแพ็กเกจไม่ได้ทั้งที่ดิสก์ยังว่าง เมื่อทำครบ คุณจะยืนยันได้ว่าปัญหามาจาก Inode เต็ม หาโฟลเดอร์ที่มีไฟล์จำนวนมากที่สุด ลบอย่างปลอดภัยโดยไม่ทำเครื่องค้าง และตั้งระบบป้องกันไม่ให้เกิดซ้ำ

สิ่งที่ต้องเตรียม

  • สิทธิ์ root หรือ sudo และการเข้าเครื่องผ่าน SSH หรือ Console ของผู้ให้บริการ
  • รู้ว่าแอปในเครื่องเก็บไฟล์ชั่วคราวไว้ที่ใด เช่น โฟลเดอร์ cache ของเว็บ, session ของ PHP, คิวอีเมล หรือโฟลเดอร์อัปโหลด
  • Snapshot หรือข้อมูลสำรองล่าสุดก่อนลบไฟล์จำนวนมาก โดยเฉพาะถ้าไม่แน่ใจว่าโฟลเดอร์นั้นเป็นข้อมูลถาวรหรือไม่ ดูวิธีได้ที่ คู่มือ Backup Server บน Cloud ของ TDC
แผนภาพความสัมพันธ์ระหว่างชื่อไฟล์ในโฟลเดอร์ Inode และบล็อกข้อมูล โดย ext4 มีตาราง Inode จำนวนคงที่ตั้งแต่ตอนฟอร์แมต
พื้นที่ดิสก์กับจำนวน Inode เป็นทรัพยากรแยกกัน อย่างใดหมดก่อนก็สร้างไฟล์ใหม่ไม่ได้

ขั้นตอนที่ 1: ยืนยันว่า Inode เต็ม ไม่ใช่พื้นที่ดิสก์เต็ม

รันสองคำสั่งนี้คู่กัน คำสั่งแรกดูพื้นที่ คำสั่งที่สองดูจำนวน Inode ของแต่ละระบบไฟล์

df -h /
df -i /

ถ้า df -h แสดง Use% ต่ำ แต่ df -i แสดงคอลัมน์ IUse% ที่ 100% และ IFree เป็น 0 แปลว่า Inode หมด ถ้าทั้งสองคำสั่งเต็มพร้อมกัน ให้แก้เรื่องพื้นที่ก่อนตาม คู่มือดิสก์เต็ม: หาไฟล์ขนาดใหญ่บน Linux และดูรายละเอียดของระบบไฟล์ ext4 ได้ด้วยคำสั่งนี้

sudo tune2fs -l /dev/vda1 | grep -iE "^inode count|^free inodes|^inode size"

เปลี่ยน /dev/vda1 เป็นอุปกรณ์ที่ df แสดง ถ้าระบบไฟล์เป็น XFS (ค่าเริ่มต้นของ AlmaLinux และ Rocky Linux) ใช้ xfs_info / แทน XFS สร้าง Inode เพิ่มได้เองจนถึงเพดาน imaxpct จึงเจอปัญหานี้น้อยกว่า ext4 มาก

ผลคำสั่ง df -h แสดงดิสก์ใช้ไป 38% แต่ df -i แสดง Inode ใช้ไป 100% และ du --inodes ชี้ไปที่โฟลเดอร์ session ของ PHP
ดู IUse% ใน df -i ทุกครั้งที่เจอ No space left on device ทั้งที่ df -h ยังว่าง

ขั้นตอนที่ 2: หาโฟลเดอร์ที่ใช้ Inode มากที่สุด

ใช้ du --inodes นับจำนวน Inode ของแต่ละโฟลเดอร์ ตัวเลือก -x ทำให้นับเฉพาะระบบไฟล์เดียว ไม่ข้ามไปดิสก์อื่นหรือ /proc

sudo du --inodes -x / 2>/dev/null | sort -n | tail -15

ผลลัพธ์เรียงจากน้อยไปมาก บรรทัดท้ายสุดคือ / ซึ่งเป็นยอดรวม ให้ไล่ดูโฟลเดอร์ที่ลึกที่สุดที่ยังมีตัวเลขสูง แล้วเจาะลงไปทีละชั้นด้วยคำสั่งเดิม เช่น sudo du --inodes -x /var | sort -n | tail ถ้าต้องการรู้ว่าไฟล์อยู่ในโฟลเดอร์ใดโดยตรง ไม่ใช่โฟลเดอร์ย่อย ให้นับจากโฟลเดอร์แม่ของแต่ละไฟล์

sudo find /var -xdev -type f -printf '%h\n' | sort | uniq -c | sort -n | tail -10

ทั้งสองคำสั่งอาจใช้เวลาหลายนาทีเมื่อมีไฟล์หลายล้านไฟล์ และทำให้ดิสก์ทำงานหนักชั่วคราว ควรรันในช่วงที่ผู้ใช้น้อย

ขั้นตอนที่ 3: แยกสาเหตุจากโฟลเดอร์ที่เจอ

บนเซิร์ฟเวอร์จริง Inode เต็มเกือบทุกครั้งมาจากโฟลเดอร์ไม่กี่แบบ ให้เทียบกับรายการนี้ก่อนลบอะไร

  • Session ของ PHP: /var/lib/php/sessions บน Ubuntu และ Debian หรือ /var/lib/php/session บน AlmaLinux แต่ละครั้งที่มีผู้เข้าเว็บ (รวมบอต) อาจสร้างไฟล์ sess_* ใหม่ Ubuntu มีตัวล้างอัตโนมัติ (phpsessionclean) ซึ่งล้างตามพาธที่ตั้งใน php.ini เท่านั้น ถ้าแอปตั้ง session.save_path เองในโค้ดหรือใน pool ของ PHP-FPM ไฟล์จะสะสมไม่หยุด
  • คิวอีเมลที่ส่งไม่ออก: /var/spool/postfix/maildrop, /var/spool/postfix/deferred หรือ /var/spool/clientmqueue มักเกิดจาก cron ส่งผลลัพธ์ทางอีเมลทุกนาทีแต่ส่งไม่ออก วิธีเคลียร์คิวดู คู่มือ Mail Queue บน Postfix
  • Cache ของแอป: เช่น wp-content/cache ของ WordPress, var/cache ของ Magento หรือ storage/framework ของ Laravel
  • Kernel headers เก่า: /usr/src/linux-headers-* บน Ubuntu แต่ละเวอร์ชันมีไฟล์หลายหมื่นไฟล์ สะสมเมื่อไม่ได้รัน autoremove
  • Docker: /var/lib/docker/overlay2 จาก image และ container เก่า ล้างตาม คู่มือคืนพื้นที่ดิสก์ที่ Docker ใช้
  • อีเมลแบบ Maildir: อีเมลหนึ่งฉบับคือหนึ่งไฟล์ กล่องจดหมายใหญ่จึงใช้ Inode มาก ซึ่งเป็นข้อมูลจริง ห้ามลบ ต้องขยายดิสก์แทน

ตรวจอายุไฟล์ก่อนตัดสินใจ เช่น sudo ls -lt /var/lib/php/sessions | tail -3 ดูไฟล์เก่าที่สุด และนับจำนวนด้วย sudo find /var/lib/php/sessions -type f | wc -l

ตารางเปรียบเทียบโฟลเดอร์ที่ทำให้ Inode เต็ม เช่น session ของ PHP คิวอีเมล kernel headers และ Docker พร้อมวิธีแก้แต่ละกรณี
ไฟล์ชั่วคราวลบได้ตามอายุ แต่ไฟล์ที่เป็นข้อมูลจริงอย่าง Maildir ต้องแก้ด้วยการขยายดิสก์

ขั้นตอนที่ 4: ลบไฟล์เพื่อคืน Inode อย่างปลอดภัย

คำสั่ง rm * ใช้ไม่ได้กับโฟลเดอร์ที่มีไฟล์หลายแสนไฟล์ จะขึ้น Argument list too long ให้ใช้ find กับ -delete แทน และ ทดลองด้วย -print ก่อนเสมอ เพื่อดูว่าเงื่อนไขจับเฉพาะไฟล์ที่ตั้งใจ คำสั่งลบไม่มีถังขยะ ถ้าเลือกโฟลเดอร์ผิดจะกู้คืนได้จากข้อมูลสำรองเท่านั้น

# 1) ดูตัวอย่างไฟล์ที่จะถูกลบ และนับจำนวน
sudo find /var/lib/php/sessions -type f -name 'sess_*' -mmin +1440 -print | head
sudo find /var/lib/php/sessions -type f -name 'sess_*' -mmin +1440 | wc -l

# 2) ลบจริง ด้วยลำดับความสำคัญต่ำ ไม่ให้เว็บช้า
sudo ionice -c3 nice -n19 find /var/lib/php/sessions -type f -name 'sess_*' -mmin +1440 -delete

# 3) ล้าง kernel headers และแพ็กเกจที่ไม่ใช้แล้วบน Ubuntu
sudo apt autoremove --purge

ตัวอย่างนี้ลบเฉพาะ session ที่ไม่ถูกแตะเกิน 24 ชั่วโมง ผู้ใช้ที่ยังล็อกอินอยู่จึงไม่หลุด ถ้า apt ทำงานไม่ได้เพราะ Inode เต็ม ให้ลบไฟล์ session หรือ cache ก่อนสักชุดให้มี Inode ว่าง แล้วค่อยรัน apt autoremove สำหรับ cache ของแอป ใช้ปุ่มหรือคำสั่งล้าง cache ของแอปนั้นเองถ้ามี เช่น php artisan cache:clear ของ Laravel หรือ bin/magento cache:flush ของ Magento เพราะปลอดภัยกว่าลบไฟล์ตรง ๆ ระหว่างที่แอปทำงาน

ขั้นตอนที่ 5: ตั้งการล้างอัตโนมัติและแจ้งเตือน

ใช้ systemd-tmpfiles ล้างไฟล์เก่าตามอายุแทนการเขียนสคริปต์เอง สร้างไฟล์ /etc/tmpfiles.d/app-cleanup.conf

# ประเภท  พาธ                              สิทธิ์  เจ้าของ   กลุ่ม     อายุ
d  /var/www/example.com/sessions       0700  www-data  www-data  2d
d  /var/www/example.com/cache          0755  www-data  www-data  7d

ตัวจับเวลา systemd-tmpfiles-clean.timer ที่มากับระบบจะลบไฟล์ในโฟลเดอร์เหล่านี้ที่เก่ากว่าอายุที่กำหนดวันละครั้ง ทดสอบทันทีด้วย sudo systemd-tmpfiles --clean แล้วตรวจ df -i อีกครั้ง ถ้าต้นเหตุเป็นอีเมลจาก cron ให้แก้ที่ต้นทาง โดยเติม MAILTO="" บนสุดของ crontab หรือส่งผลลัพธ์ลงไฟล์ล็อกที่หมุนด้วย logrotate

เพิ่มการแจ้งเตือนเมื่อ IUse% เกิน 80% ระบบมอนิเตอร์อย่าง Zabbix หรือ Netdata มีค่า Inode ให้ใช้อยู่แล้ว ถ้าไม่มีระบบมอนิเตอร์ ใช้คำสั่งนี้ใน cron รายชั่วโมงเพื่อเขียนลง syslog

df -i --output=ipcent,target -x tmpfs -x devtmpfs | awk 'NR>1 && $1+0 >= 80 {print "inode warning: " $2 " " $1}' | logger -t inode-check
เช็กลิสต์ป้องกัน Inode เต็ม ทั้งการแจ้งเตือน การล้างไฟล์ตามอายุ และสิ่งที่ไม่ควรทำเมื่อลบไฟล์จำนวนมาก
ล้างตามอายุอัตโนมัติและแจ้งเตือนก่อนเต็ม ดีกว่ามาตามลบหลังเว็บล่ม

ขั้นตอนที่ 6: เพิ่มจำนวน Inode เมื่องานต้องการไฟล์เล็กจำนวนมากจริง

ถ้าไฟล์จำนวนมากเป็นข้อมูลจริง เช่น อีเมลแบบ Maildir หรือรูปภาพย่อยหลายล้านรูป การลบไม่ใช่ทางออก ext4 เพิ่ม Inode ให้ระบบไฟล์เดิมโดยตรงไม่ได้ แต่มีสามทางเลือก

  1. ขยายดิสก์เดิม: เมื่อขยาย ext4 ด้วย resize2fs จำนวน Inode เพิ่มขึ้นตามสัดส่วนพื้นที่ใหม่ ดูขั้นตอนได้ที่ คู่มือขยาย Partition บน Linux
  2. เพิ่มดิสก์ใหม่สำหรับข้อมูลชุดนั้น แล้วฟอร์แมตให้มี Inode หนาแน่นขึ้น เช่น sudo mkfs.ext4 -i 4096 /dev/vdb1 คือสร้าง Inode หนึ่งตัวต่อพื้นที่ 4 KB แทนค่าเริ่มต้น 16 KB
  3. ใช้ XFS กับดิสก์ข้อมูลใหม่ ซึ่งจัดสรร Inode แบบยืดหยุ่น

คำสั่ง mkfs ลบข้อมูลทั้งหมดบนพาร์ทิชันนั้น ใช้กับดิสก์ใหม่ที่ว่างเท่านั้น และตรวจชื่ออุปกรณ์ด้วย lsblk ทุกครั้งก่อนกด Enter ตัวเลือกของ mkfs.ext4 ทั้งหมดอยู่ในเอกสาร mke2fs(8)

ปัญหาที่พบบ่อยเกี่ยวกับ Inode

ลบไฟล์ไปแล้ว แต่ df -i ยังไม่ลดลง เพราะอะไร?

ถ้ายังมีโปรเซสเปิดไฟล์นั้นค้างอยู่ Inode จะยังไม่ถูกคืนจนกว่าโปรเซสจะปิดไฟล์ ตรวจด้วย sudo lsof +L1 แล้วรีสตาร์ตบริการที่ถือไฟล์ไว้ อีกกรณีคือ find ยังลบไม่เสร็จ การลบหลายล้านไฟล์อาจใช้เวลาเป็นชั่วโมง

Inode เต็มทำให้เว็บล่มได้อย่างไร?

ทุกการสร้างไฟล์ใหม่ต้องใช้ Inode เมื่อหมด PHP เขียน session ไม่ได้ ผู้ใช้ล็อกอินไม่ติด ฐานข้อมูลสร้างไฟล์ชั่วคราวไม่ได้ และบริการบางตัวเขียน PID หรือ socket ไม่ได้จนเริ่มทำงานไม่ขึ้น อาการจึงดูเหมือนดิสก์เต็มทุกอย่าง

ควรตั้งจำนวน Inode เท่าไรตอนสร้างดิสก์ใหม่?

ประเมินจากขนาดไฟล์เฉลี่ยของข้อมูลชุดนั้น ถ้าไฟล์เฉลี่ยเล็กกว่า 16 KB ค่าเริ่มต้นของ ext4 จะหมด Inode ก่อนพื้นที่ ให้ใช้ -i ที่ใกล้ขนาดไฟล์เฉลี่ย หรือกำหนดจำนวนตรง ๆ ด้วย -N ระวังว่า Inode ทุกตัวกินพื้นที่ดิสก์ล่วงหน้า การตั้งหนาแน่นเกินจำเป็นจึงเสียพื้นที่

Inode ของ /tmp หรือ /dev/shm เต็มแก้อย่างไร?

ถ้า df แสดงว่าเป็น tmpfs จำนวน Inode ขึ้นกับ RAM และตัวเลือก nr_inodes ตอน mount ให้หาแอปที่สร้างไฟล์ชั่วคราวไม่ลบแล้วแก้ที่แอป การรีบูตจะล้าง tmpfs แต่ปัญหาจะกลับมาถ้าไม่แก้ต้นเหตุ

หากต้องการให้ทีมงานช่วยหาต้นเหตุ ย้ายข้อมูลไปดิสก์ใหม่ หรือวางแผนพื้นที่จัดเก็บให้รองรับไฟล์จำนวนมาก ติดต่อทีมงาน THAI DATA CLOUD ได้ และดูตัวเลือกเครื่องพร้อมดิสก์เพิ่มได้ที่หน้า Cloud Linux Server

อ่านเพิ่มเติมเกี่ยวกับ Inode

แชร์FacebookXLINELinkedIn

มีคำถามเรื่องบริการ? ติดต่อทีมงาน