Cách Xử Lý Lỗi ‘Disk Full’ và Quản Lý Dung Lượng Đĩa trên Linux

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Khi Đĩa Đầy Lúc 2 Giờ Sáng

Bạn nhận cảnh báo lúc nửa đêm: ứng dụng web đang báo lỗi 500. SSH vào, thứ đầu tiên bạn thấy là No space left on device. Database không ghi được. Nginx không tạo được file tạm. Mọi thứ đổ vỡ — vì ai đó (có thể là một tiến trình log chạy lỗi, có thể là chính bạn) đã làm đầy đĩa.

Tôi đã trải qua điều đó — 3 giờ sáng, tay gõ phím liên tục, nguyền rủa một tiến trình mình không hề biết đang chạy. Ba năm và hàng chục VPS sau đó, giờ tôi đã cài disk monitoring trên mỗi server mới trước khi làm bất cứ thứ gì khác. Nhưng khi cảnh báo đã kêu, đây là những gì thực sự hiệu quả.

Hiểu Nguyên Nhân Tại Sao Đĩa Bị Đầy

Trước khi vội vàng rm -rf mọi thứ, cần hiểu cái gì thực sự ngốn dung lượng đĩa trên Linux server. Những thủ phạm quen thuộc:

  • File log — Log ứng dụng, log hệ thống và journal file cứ tăng mãi không có giới hạn
  • Docker — Image không dùng, container đã dừng và volume dangling tích tụ âm thầm
  • Cache package — apt/yum giữ lại các gói cũ sau khi cập nhật
  • File tạm — Một số ứng dụng ghi vào /tmp hoặc /var/tmp mà không bao giờ dọn dẹp
  • Database dump và backup — Các file backup cũ mà không ai xóa
  • Core dump — Một tiến trình crash có thể dump hàng gigabyte bộ nhớ ra đĩa

Đây là cạm bẫy thường gặp: df báo đĩa đầy, nhưng du không tìm thấy file nào chiếm chỗ. Thường là do file đã bị xóa nhưng vẫn đang được một tiến trình giữ mở — inode vẫn còn sống, dung lượng vẫn bị chiếm. Không giải phóng được cho đến khi tiến trình đó đóng file handle lại. Bẫy cổ điển.

Các Lệnh Cơ Bản Bạn Cần Biết

Kiểm Tra Tổng Quan Dung Lượng Đĩa

# Xem tổng quan dung lượng đĩa dạng dễ đọc
df -h

# Tập trung vào một filesystem cụ thể
df -h /var

Tìm Thứ Gì Đang Chiếm Dung Lượng

# Xem dung lượng cấp cao nhất trong /var, sắp xếp theo kích thước
du -sh /var/* 2>/dev/null | sort -rh | head -20

# Đi sâu hơn
du -sh /var/log/* 2>/dev/null | sort -rh | head -10

Flag sort -rh sắp xếp kích thước dạng dễ đọc một cách chính xác — 1.2G xếp trên 900M. Bỏ -h đi là bạn sẽ nhận được kết quả sắp xếp loạn, tốn công tìm kiếm nhầm thư mục trong khi đĩa vẫn đầy.

Tìm Trực Tiếp File Lớn

# Tìm file lớn hơn 100MB trên toàn hệ thống
find / -xdev -type f -size +100M 2>/dev/null | sort -k5 -rn

# Phiên bản dễ đọc hơn với kích thước
find / -xdev -type f -size +100M -exec du -sh {} \; 2>/dev/null | sort -rh

Flag -xdev giữ việc tìm kiếm trong filesystem hiện tại và không vượt qua mount point — hữu ích khi bạn muốn chỉ tìm trên / mà không vô tình đi vào NFS mount.

Thực Hành: Thu Hồi Dung Lượng Nhanh Chóng

1. Dọn Dẹp Journal Log

Trên các distro dùng systemd (Ubuntu, Debian, CentOS 7+, AlmaLinux), journald có thể âm thầm đạt tới 2–5GB trên server bận rộn. Bạn sẽ không để ý đến khi đĩa đã hết.

# Kiểm tra journal đang dùng bao nhiêu dung lượng
journalctl --disk-usage

# Chỉ giữ lại 200MB log gần nhất
journalctl --vacuum-size=200M

# Hoặc chỉ giữ log trong 2 tuần gần nhất
journalctl --vacuum-time=2weeks

Giới hạn vĩnh viễn trong /etc/systemd/journald.conf:

SystemMaxUse=500M
SystemKeepFree=1G

Sau đó restart journald: systemctl restart systemd-journald

2. Truncate (Không Phải Xóa) File Log Đang Hoạt Động

Nếu một tiến trình đang giữ file log mở, xóa file sẽ không giải phóng dung lượng — inode vẫn còn sống. Truncate mới có tác dụng:

# Truncate an toàn file log đang được ghi
> /var/log/nginx/access.log

# Cách tương đương dùng lệnh truncate
truncate -s 0 /var/log/nginx/error.log

Để xử lý vấn đề file đã xóa nhưng vẫn đang được giữ mở, tìm tiến trình đang giữ handle:

# Tìm tiến trình đang giữ file đã bị xóa
lsof | grep '(deleted)'

Restart tiến trình đó sẽ giải phóng handle và thực sự giải phóng dung lượng.

3. Dọn Dẹp Các Artifact của Docker

Trên các server chạy Docker, đây thường là nơi thu hồi được nhiều nhất:

# Xem Docker đang dùng bao nhiêu dung lượng
docker system df

# Xóa container đã dừng, network không dùng, image dangling, build cache
docker system prune

# Cũng xóa volume không dùng (cẩn thận — kiểm tra kỹ trước!)
docker system prune --volumes

# Chỉ xóa image dangling
docker image prune

# Xóa tất cả image không được container nào dùng
docker image prune -a

Tôi đã thu hồi được 20–40GB chỉ với một lệnh docker system prune -a trên các build server không được dọn dẹp trong nhiều tháng. Chỉ cần đảm bảo không có container nào đang dùng các image bạn sắp xóa.

4. Dọn Cache Package Manager

# Debian/Ubuntu
apt clean          # Xóa các gói .deb đã cache
apt autoremove     # Xóa các gói mồ côi

# RHEL/CentOS/AlmaLinux
yum clean all
dnf clean all

Trên một Ubuntu server vừa được cập nhật, chỉ riêng apt clean có thể thu hồi 500MB–1GB. Không quá ấn tượng, nhưng dung lượng trống là dung lượng trống — và chỉ mất hai giây.

5. Tìm và Xử Lý Core Dump

# Kiểm tra core dump
ls -lh /var/lib/systemd/coredump/

# Dọn sạch
coredumpctl list
rm /var/lib/systemd/coredump/*

# Hoặc tắt hoàn toàn core dump trong /etc/security/limits.conf
# * hard core 0

6. Kiểm Tra Mức Dùng Inode

Đôi khi df -h cho thấy vẫn còn nhiều dung lượng nhưng write vẫn bị lỗi. Thủ phạm thường là inode, không phải byte:

df -i

# Hiển thị % sử dụng inode trên từng filesystem
# Nếu Use% là 100%, bạn đã hết inode

Hàng triệu file nhỏ có thể làm cạn kiệt bảng inode từ lâu trước khi hết byte đĩa. Hàng đợi mailer, PHP session file và cache ứng dụng là những thủ phạm quen thuộc. Tìm thư mục nào là thủ phạm:

# Tìm thư mục chứa nhiều file nhất
for i in /var/*; do echo $(find $i -type f 2>/dev/null | wc -l) $i; done | sort -rn | head -10

Thiết Lập Monitoring Để Phát Hiện Sớm

Bài học thực sự từ mọi sự cố đĩa đầy không phải là “làm thế nào để sửa” — mà là “tại sao tôi không biết sớm hơn”. Một cron job đơn giản cảnh báo ở mức 80% chỉ tốn 10 phút thiết lập và có thể giúp bạn tránh khỏi đúng tình huống này:

#!/bin/bash
# /usr/local/bin/disk-check.sh
THRESHOLD=80
USAGE=$(df / | awk 'NR==2 {print $5}' | tr -d '%')

if [ "$USAGE" -ge "$THRESHOLD" ]; then
  echo "CẢNH BÁO: Dung lượng đĩa trên $(hostname) đạt ${USAGE}%" | \
    mail -s "Cảnh báo Đĩa: $(hostname)" [email protected]
fi
# Thêm vào crontab để kiểm tra mỗi giờ
crontab -e
# Thêm: 0 * * * * /usr/local/bin/disk-check.sh

Với nhiều server, Netdata, Prometheus + Grafana, hoặc Zabbix agent xử lý disk monitoring ở quy mô lớn. Chỉ một VPS? Script cron ở trên là đủ rồi. Dùng ngay đi.

Checklist Khi Bạn Đang Trong Tình Huống Khẩn Cấp

Khi chuông báo động đang kêu và bạn cần dung lượng ngay bây giờ, hãy thực hiện theo thứ tự này:

  1. Chạy df -h để xác nhận filesystem nào đang đầy
  2. Chạy du -sh /var/* | sort -rh | head -20 để tìm thư mục lớn nhất
  3. Kiểm tra file đã xóa nhưng vẫn đang mở: lsof | grep deleted
  4. Truncate hoặc rotate file log lớn nhất đang hoạt động
  5. Chạy journalctl --vacuum-size=200M
  6. Nếu có Docker: docker system prune
  7. Chạy apt clean hoặc dnf clean all
  8. Kiểm tra inode: df -i

Chỉ các bước 2–5 thôi thường đã đủ để lấy lại dung lượng và ổn định hệ thống. Sau đó bạn có thể thở phào, điều tra nguyên nhân gốc rễ và xử lý đúng cách.

Ngăn Sự Cố Lần Sau

Mọi cuộc khủng hoảng đĩa đầy tôi từng thấy đều theo cùng một kịch bản: thứ gì đó tăng không kiểm soát trong nhiều tuần, không ai để ý, rồi mọi thứ vỡ vụn cùng lúc. Dọn dẹp một lần không giải quyết được vấn đề. Thay đổi vĩnh viễn mới giải quyết:

  • Cấu hình logrotate cho tất cả log ứng dụng — kiểm tra /etc/logrotate.d/ để xem cấu hình hiện có và thêm những cái còn thiếu
  • Đặt SystemMaxUse trong cấu hình journald
  • Chạy docker system prune hàng tuần qua cron trên build/CI server
  • Thêm disk usage vào hệ thống monitoring của bạn — dù dùng gì, hãy đảm bảo nó cảnh báo bạn ở mức 80%
  • Xem lại chính sách lưu trữ backup — để backup cũ trên cùng đĩa với ứng dụng là thảm họa chực chờ xảy ra

Quản lý dung lượng đĩa không hào nhoáng gì. Nhưng 30 phút thiết lập hôm nay sẽ giúp bạn tránh khỏi một trận chiến lúc 2 giờ sáng sáu tháng sau. Tin tôi đi.

Share: