Vấn đề
Đây là một vấn đề đau đầu kinh điển của quản trị viên hệ thống: công cụ giám sát cảnh báo rằng ổ đĩa đã đạt 100% dung lượng. Bạn tìm thấy một file log khổng lồ 80GB, xóa nó bằng lệnh rm và đợi cảnh báo biến mất. Nhưng không. Mặc dù file đã biến mất, df -h vẫn khẳng định ổ đĩa đã đầy, trong khi du -sh lại cho thấy còn nhiều dung lượng trống.
Sự sai lệch này xảy ra vì Linux xử lý các file khác với một số hệ điều hành khác. Nếu một tiến trình vẫn đang ghi vào một file khi bạn xóa nó, dung lượng sẽ không được thu hồi ngay lập tức. Bạn sẽ gặp phải các file "ma" (ghost files) tiêu tốn dung lượng nhưng không xuất hiện trong bất kỳ danh sách thư mục nào.
TL;DR: Cách khắc phục nhanh
Nếu bạn cần thu hồi dung lượng ngay bây giờ mà không cần khởi động lại:
- Tìm tiến trình đang giữ file đã xóa:
sudo lsof +L1 - Khởi động lại dịch vụ được liệt kê trong kết quả trả về.
- Nếu bạn không thể dừng dịch vụ, hãy làm rỗng (truncate) file descriptor:
: > /proc/PID/fd/FD_NUMBER
Tại sao dung lượng vẫn bị khóa
Trong hệ thống file Linux, một file chỉ thực sự bị xóa hoàn toàn khi đáp ứng hai điều kiện:
- Số lượng liên kết (link count) bằng 0 (không còn tên file nào trỏ đến dữ liệu).
- Không có tiến trình hoạt động nào có file descriptor đang mở trỏ đến nó.
Khi bạn chạy rm, bạn xóa liên kết, nhưng không nhất thiết phải đóng file. Nếu Nginx, một cơ sở dữ liệu hoặc một ứng dụng Java tùy chỉnh vẫn đang mở file đó, kernel sẽ giữ các khối dữ liệu (data blocks) được dự phòng. df kiểm tra tổng số khối đã sử dụng của hệ thống file, vì vậy nó vẫn thấy 80GB đó đang bị chiếm dụng.
Các bước xử lý sự cố chi tiết
1. Xác minh sự sai lệch
Bắt đầu bằng cách xác nhận rằng hệ thống file và cấu trúc thư mục không thống nhất về dung lượng sử dụng. Chạy lệnh:
df -h
Sau đó, kiểm tra kích thước thực tế của các file hiện có, loại trừ các hệ thống file ảo:
sudo du -sh / --exclude=/proc --exclude=/sys --exclude=/dev
Nếu df báo cáo đã sử dụng 100GB nhưng du chỉ tìm thấy 20GB, chắc chắn bạn đang có các file descriptor mở đang giữ lại dữ liệu đã xóa.
2. Tìm các file "ma"
Tiện ích lsof (List Open Files) là trợ thủ đắc lực nhất ở đây. Sử dụng cờ +L1 để tìm cụ thể các file có số lượng liên kết nhỏ hơn 1 (các file đã bị xóa):
sudo lsof +L1
Tập trung vào cột SIZE để tìm những "kẻ chiếm dụng" lớn nhất. Kết quả thường trông như thế này:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NLINK NODE NAME
nginx 4567 root 3w REG 253,1 80GB 0 99887 /var/log/nginx/access.log (đã xóa)
Trong ví dụ thực tế này, Nginx (PID 4567) đang mở một file 80GB trên file descriptor 3.
3. Cách khắc phục tiêu chuẩn: Khởi động lại dịch vụ
Cách tiếp cận sạch nhất là khởi động lại ứng dụng. Điều này buộc nó phải đóng tất cả các file descriptor và cho phép kernel cuối cùng giải phóng các khối đĩa.
sudo systemctl restart nginx
Nếu tiến trình là một script độc lập, bạn có thể cần phải chấm dứt nó theo cách thủ công:
sudo kill -15 4567
4. Cách khắc phục chuyên nghiệp: Làm rỗng file mà không làm gián đoạn dịch vụ
Đôi khi bạn không thể khởi động lại dịch vụ, chẳng hạn như cơ sở dữ liệu đang chạy thực tế (production) hoặc máy chủ web có lưu lượng truy cập cao. Trong những trường hợp này, bạn có thể "làm rỗng" file thông qua hệ thống file /proc mà không cần dừng tiến trình.
Sử dụng PID (4567) và FD (3) từ bước trước, hãy chạy:
sudo bash -c ': > /proc/4567/fd/3'
Lệnh này gửi một tín hiệu rỗng đến file descriptor cụ thể. Nó ngay lập tức thu nhỏ file trên đĩa xuống còn 0 byte. Tiến trình vẫn hoạt động và file descriptor vẫn hợp lệ, nhưng dung lượng ổ đĩa của bạn sẽ quay trở lại ngay lập tức.
Cách ngăn chặn vấn đề này tái diễn
Việc xóa thủ công các file log đang hoạt động là nguyên nhân chính gây ra vấn đề này. Để giữ cho ổ đĩa của bạn luôn ổn định, hãy thực hiện các thói quen sau:
- Cấu hình logrotate: Đảm bảo tất cả các log được quản lý bởi
logrotate. Nó sử dụng các tín hiệu nhưSIGHUPđể yêu cầu ứng dụng đóng các log cũ và bắt đầu các log mới một cách an toàn. - Không bao giờ 'rm' một log đang hoạt động: Nếu bạn phải xóa nội dung file log theo cách thủ công, đừng xóa file đó. Thay vào đó hãy làm rỗng (truncate) nó:
/var/log/heavy-app.log
Việc này sẽ xóa sạch nội dung nhưng giữ nguyên trình xử lý file (file handle), ngăn chặn hoàn toàn vấn đề "file ma".
- **Giám sát sự sai lệch:** Thiết lập một kiểm tra so sánh kết quả của `df` và `du` để phát hiện các rò rỉ này trước khi chúng gây ra sự cố khẩn cấp.

