df -h báo phân vùng đã đầy 100%, nhưng cộng hết du lại chỉ thấy vài GB. Hoặc ngược lại: dung lượng còn thênh thang mà hệ thống vẫn kêu hết chỗ trống. Cả hai tình huống đều có nguyên nhân rõ ràng, và đều tra ra được trong vài phút nếu biết nhìn đúng chỗ.
Nhìn toàn cảnh trước
lsblk -f # o dia, phan vung, loai filesystem, diem gan ket
df -hT # dung luong da dung theo tung filesystem
df -h /var/log # filesystem nao dang chua duong dan nay
Bước này quan trọng hơn vẻ ngoài của nó. Rất nhiều lần thứ “đầy” không phải ổ chính mà là một phân vùng nhỏ riêng như /boot — vốn chỉ vài trăm MB và đầy sau dăm lần nâng cấp nhân.
Trong bảng kết quả của df, hãy bỏ qua các dòng tmpfs, devtmpfs, squashfs. Chúng nằm trong bộ nhớ hoặc chỉ đọc, không phải chỗ dữ liệu của bạn.
du: ai đang chiếm chỗ
du -sh /var/* | sort -h # tung thu muc con, sap xep tang dan
du -xh -d 1 / | sort -h # tang tren cung, khong vuot mount
du -sh /var/log/* | sort -h | tail -20
Hai cờ đáng nhớ:
-x— chỉ ở trong một filesystem, không đi lạc sang/proc,/syshay ổ mạng đang gắn.-hcủasort— hiểu hậu tố K, M, G nên sắp xếp đúng. Thiếu nó thì 9M sẽ đứng trên 40G.
Cách làm việc thực tế là đi xuống dần: chạy ở /, nhìn thư mục lớn nhất, chạy tiếp vào trong đó, lặp lại cho tới khi ra thủ phạm. Nếu máy có sẵn ncdu thì nó làm đúng việc này bằng giao diện duyệt được, nhanh hơn nhiều.
Tìm file lớn bất thường
find /var -xdev -type f -size +500M -exec ls -lh {} \;
find / -xdev -type f -printf '%s %p\n' 2>/dev/null | sort -rn | head -20
Thủ phạm quen mặt: log không xoay vòng, file core dump, ảnh máy ảo, gói cài đặt còn trong cache, và file tạm của các job nhập liệu bị đứt giữa chừng.
Còn dung lượng nhưng vẫn hết chỗ: hết inode
Mỗi file, mỗi thư mục, mỗi liên kết tượng trưng đều tiêu một inode. Số inode của hệ thống file ext4 được ấn định ngay lúc định dạng và không tăng được về sau. Một triệu file cấu hình nhỏ xíu vẫn có thể làm cạn inode trong khi biểu đồ dung lượng còn nguyên.
df -i # cot IUse% moi la thu can nhin
df -ih
Nếu IUse% là 100% thì mọi thao tác tạo file mới đều báo lỗi hết chỗ, kể cả khi df -h nói còn trống 40GB. XFS cấp phát inode động nên ít gặp cảnh này hơn, nhưng vẫn nên kiểm tra trước khi kết luận.
Truy thư mục đang giữ quá nhiều file
# Dem file trong tung thu muc con cua /var
for d in /var/*/; do
printf '%8s %s\n' "$(find "$d" -xdev 2>/dev/null | wc -l)" "$d"
done | sort -rn | head
Bản du của GNU coreutils còn có cờ --inodes làm thẳng việc này:
du --inodes -x -d 1 /var | sort -n
Những chỗ hay tích file nhất: /var/spool/ khi hàng đợi mail bị tắc, thư mục session của PHP, cache của ứng dụng không bao giờ dọn, và /tmp trên máy không bật cơ chế dọn tự động.
Khi đã tìm ra, cẩn thận lúc xóa — rm * trong thư mục có hàng trăm nghìn file sẽ báo danh sách tham số quá dài. Dùng find để xóa theo lô và theo tuổi:
find /var/lib/ungdung/cache -xdev -type f -mtime +30 -delete
File đã xóa nhưng tiến trình còn giữ
Đây là nguyên nhân kinh điển của việc df và du không khớp nhau. Khi bạn xóa một file đang được một tiến trình mở, tên của nó biến mất khỏi thư mục nhưng inode và toàn bộ khối dữ liệu vẫn tồn tại cho tới khi tiến trình đó đóng file lại hoặc kết thúc.
Kết quả: du đi theo cây thư mục nên không còn thấy file đâu, còn df hỏi thẳng hệ thống file nên vẫn đếm đủ. Chênh lệch hàng chục GB là chuyện bình thường sau khi ai đó rm một file log khổng lồ mà không khởi động lại dịch vụ.
sudo lsof +L1 # file co so lien ket = 0 nhung dang mo
sudo lsof -nP | grep '(deleted)'
Cột SIZE cho biết đang mất bao nhiêu, cột PID và COMMAND chỉ ra ai đang giữ. Cách chữa sạch sẽ là khởi động lại dịch vụ đó:
sudo systemctl restart nginx
Nếu chưa thể dừng dịch vụ, có cách lấy lại chỗ ngay bằng cách cắt file qua thư mục /proc — mỗi file đang mở đều có một liên kết ở đó theo số thứ tự của mô tả file:
sudo ls -l /proc/1234/fd | grep deleted
sudo truncate -s 0 /proc/1234/fd/3
Dữ liệu trong file mất ngay lập tức, nên chỉ làm việc này với file log. Và bài học dài hạn: đừng rm file log, hãy để logrotate lo, vì nó biết báo cho dịch vụ mở lại file sau khi xoay vòng.
Phần dung lượng dành riêng cho root
Hệ thống file họ ext dành sẵn một tỷ lệ khối đĩa mà chỉ root mới ghi được — mặc định là 5%. Mục đích là để dịch vụ hệ thống và chính người quản trị còn chỗ xoay xở khi ổ đầy. Hệ quả là ứng dụng chạy dưới tài khoản thường sẽ báo hết chỗ trong khi df vẫn thấy còn vài phần trăm.
sudo tune2fs -l /dev/sda1 | grep -i 'reserved'
sudo tune2fs -m 1 /dev/sda1 # ha xuong 1%
Trên ổ dữ liệu dung lượng lớn, 5% là con số rất đáng kể và hạ xuống 1% là hợp lý. Nhưng với phân vùng chứa / thì đừng đưa về 0 — đó chính là tấm đệm giúp bạn còn đăng nhập được vào máy để dọn dẹp.
File bị che bởi điểm gắn kết
Một trường hợp hiếm nhưng khó chịu: ai đó ghi dữ liệu vào /mnt/dulieu lúc ổ chưa được gắn vào đó. Sau khi gắn ổ, những file cũ bị che khuất — không nhìn thấy, không xóa được bằng đường dẫn thường, nhưng vẫn chiếm chỗ trên hệ thống file gốc.
sudo mkdir -p /mnt/goc
sudo mount --bind / /mnt/goc
sudo du -sh /mnt/goc/mnt/dulieu # phan bi che, neu co
sudo umount /mnt/goc
Thứ tự kiểm tra khi ổ báo đầy
df -hT— xác định đúng filesystem nào đầy, đừng đoán.df -i— loại trừ khả năng hết inode trước khi đi tìm file lớn.du -xh -d 1lần xuống từ thư mục gốc của filesystem đó.- Nếu
dunhỏ hơndfnhiều —lsof +L1, gần như chắc chắn là file đã xóa còn bị giữ. - Nếu vẫn không khớp — kiểm tra phần dành riêng cho root và file bị che dưới điểm gắn kết.
Đừng đợi tới lúc ổ đầy mới chạy những lệnh này. Đặt một cảnh báo ở mức 80% cho cả dung lượng lẫn inode, cấu hình logrotate cho mọi ứng dụng tự ghi log, và mỗi tháng dành năm phút chạy du -xh -d 1 / để biết máy mình đang béo lên ở chỗ nào.
