Thông báo disk full trên VPS thường xuất hiện dưới nhiều dạng: website trả lỗi vì không ghi được file upload, database không tạo được temporary table, Docker không tạo container mới hoặc SSH bắt đầu phản hồi chậm. Đừng vội xóa ngẫu nhiên trong /var/log hay /home. Trước tiên cần phân biệt filesystem hết block, hết inode, một process vẫn giữ file đã xóa, hay một thư mục log tăng bất thường.
Bài viết này xây dựng một quy trình chẩn đoán an toàn trên Ubuntu và Linux nói chung. Bạn sẽ bắt đầu với df, kiểm tra inode, dùng du và find để khoanh vùng file lớn, xem journal systemd, xử lý file đã xóa nhưng còn được process mở, rồi mới đưa ra phương án dọn dẹp có kiểm soát. Mục tiêu là khôi phục dịch vụ mà không phá dữ liệu production.
1. Disk full trên Linux thực sự nghĩa là gì?
Một filesystem có thể gặp hai loại cạn kiệt chính. Loại đầu tiên là block storage đã dùng gần hết dung lượng byte. Loại thứ hai là inode đã hết dù vẫn còn vài gigabyte trống; trường hợp này thường xảy ra khi có hàng triệu file nhỏ, cache hoặc session. Hai tình huống cho triệu chứng gần giống nhau nhưng cách kiểm tra và xử lý khác nhau.
Manual GNU df mô tả df là công cụ báo dung lượng của filesystem chứa một file hoặc của tất cả filesystem đang mount. Tùy chọn -h hiển thị dạng dễ đọc, còn -i chuyển sang thống kê inode thay vì block usage. Đây là lý do không nên chỉ chạy df -h rồi kết luận nguyên nhân.[1]
df báo dung lượng khả dụng của filesystem chứa file; tùy chọn -i hiển thị thông tin inode thay vì block usage.Tóm lược từ GNU df(1) manual.[1]
2. Bước đầu tiên: chụp hiện trạng trước khi xóa
Trong incident, hãy ghi lại thời điểm, hostname, filesystem gặp vấn đề và trạng thái dịch vụ. Nếu có monitoring, lưu alert hoặc ảnh chụp trước khi thao tác. Không chạy lệnh xóa hàng loạt khi chưa biết thư mục nào đang chiếm dung lượng, vì một lệnh rm sai có thể biến sự cố đầy đĩa thành mất dữ liệu.
date -Is
hostnamectl --static 2>/dev/null || hostname
uptime
sudo df -hT
sudo df -ih
lsblk -f
findmnt -Ddf -hT giúp nhìn cả loại filesystem, còn df -ih cho biết inode đã dùng bao nhiêu phần trăm. Nếu một mount đạt 100% dung lượng nhưng inode còn thấp, hãy tập trung tìm file lớn. Nếu inode đạt 100%, hãy tìm thư mục có quá nhiều file nhỏ thay vì chỉ tìm file vài gigabyte.
3. Đọc df để phân biệt block và inode
Lệnh nền tảng là df -h. Tham số -h dùng đơn vị dễ đọc và phù hợp khi kiểm tra nhanh; -T thêm filesystem type; -x có thể giới hạn filesystem local. Khi cần xác định một đường dẫn cụ thể nằm trên mount nào, truyền chính đường dẫn đó cho df.
df -h /
df -h /var/lib/mysql
df -T /var/lib/docker
df -ih /
df -h --output=source,fstype,size,used,avail,pcent,targetMột lỗi phổ biến là nhìn thấy /dev/mapper hoặc /dev/nvme0n1p1 đã đầy rồi đi kiểm tra toàn bộ thư mục mà không để ý /mnt, /proc hoặc volume Docker có thể là filesystem khác. Bài cài Ubuntu Server tối giản trên VPS có thể dùng làm checklist nền để ghi rõ các mount point của máy ngay sau khi cài.
4. Khoanh vùng thư mục lớn bằng du
GNU du ước lượng dung lượng file và thư mục theo cách đệ quy. Tùy chọn --max-depth giới hạn độ sâu, --one-file-system không đi qua filesystem khác và --exclude loại trừ pattern. Khi chẩn đoán, bắt đầu ở root với độ sâu thấp rồi đi sâu dần; tránh chạy du -ah / trên máy lớn nếu chưa hiểu tác động I/O.
sudo du -xhd1 / 2>/dev/null | sort -h
sudo du -xhd1 /var 2>/dev/null | sort -h
sudo du -xhd1 /var/log 2>/dev/null | sort -h
sudo du -xhd1 /home 2>/dev/null | sort -hNếu output cho thấy /var/lib, /var/log hoặc /home nổi bật, hãy chuyển sang thư mục đó. Dùng -x để không cộng nhầm dữ liệu từ mount con và dùng sort -h để các dòng lớn nằm ở cuối. Manual du xác nhận --max-depth chỉ in tổng của thư mục ở số tầng cho phép, rất hữu ích để tạo từng lớp điều tra thay vì quét một lần quá rộng.[2]
5. Tìm file lớn nhưng không xóa mù
Sau khi biết thư mục lớn, find giúp lọc các file theo kích thước, loại file và thời gian sửa. Hãy ưu tiên liệt kê trước, xác minh owner/process/ngữ cảnh sau đó mới xóa hoặc archive. Đặc biệt không xóa file database, file upload của người dùng hoặc file backup chỉ vì chúng đứng đầu danh sách.
sudo find /var -xdev -type f -size +500M -printf '%s %p\n' 2>/dev/null | sort -n | tail -30
sudo find /home -xdev -type f -size +1G -printf '%s %TY-%Tm-%Td %p\n' 2>/dev/null | sort -n | tail -30
sudo find /var/log -xdev -type f -printf '%s %p\n' 2>/dev/null | sort -n | tail -30Kết quả size dạng byte dễ sort chính xác hơn output đã format. Trước khi xử lý, hãy dùng file, stat và ls -lh để biết file là log, archive, database dump hay dữ liệu ứng dụng. Với backup, nên kiểm tra retention và nơi lưu bản sao trước khi xóa bản cũ.
6. Khi inode đầy: tìm hàng triệu file nhỏ
Nếu df -i cho thấy IUse% gần 100%, vấn đề không nhất thiết nằm ở file lớn. Các thư mục session, cache, queue failed, mail spool, thumbnail hoặc thư mục build có thể tạo rất nhiều file nhỏ. Dùng số lượng entry theo từng thư mục để khoanh vùng, sau đó xem ứng dụng nào tạo ra chúng.
sudo du --inodes -xhd1 / 2>/dev/null | sort -h
sudo du --inodes -xhd1 /var 2>/dev/null | sort -h
sudo find /var -xdev -type f -printf '%h\n' 2>/dev/null | sort | uniq -c | sort -n | tail -30Không dùng rm -rf với một glob chưa được kiểm tra. Nếu là cache có thể tái tạo, dùng công cụ quản lý của ứng dụng hoặc xóa theo batch nhỏ. Nếu là session hoặc queue, cần xác nhận TTL, trạng thái job và khả năng ảnh hưởng tới người dùng đang đăng nhập.
7. Log systemd và journal chiếm dung lượng
Journal có thể tăng nhanh khi service crash loop hoặc ứng dụng ghi quá nhiều stdout/stderr. Trước tiên hãy xem tổng dung lượng journal và xác định service nào phát sinh log. Không nên xóa toàn bộ journal ngay lúc incident vì log là bằng chứng để tìm nguyên nhân.
sudo journalctl --disk-usage
sudo journalctl --list-boots
sudo journalctl -p warning..alert -b --no-pager
sudo journalctl -u myapp.service --since '2 hours ago' --no-pagerjournalctl hỗ trợ vacuum theo size, thời gian hoặc số file. Điểm quan trọng trong manual là vacuum chỉ tác động archived journal; active journal có thể vẫn còn. Kết hợp --rotate trước vacuum nếu cần đưa phần log active vào archive rồi mới dọn theo retention.[5]
sudo journalctl --rotate
sudo journalctl --vacuum-time=14d
sudo journalctl --vacuum-size=1G
sudo journalctl --disk-usageChọn retention theo yêu cầu điều tra và compliance, không chọn một con số tùy tiện. Nếu log tăng lại ngay sau vacuum, nguyên nhân thường là service đang lỗi lặp, log level quá verbose hoặc một request path tạo exception liên tục. Hãy sửa nguồn phát sinh trước khi tăng tần suất dọn.
8. File đã xóa nhưng dung lượng chưa trở lại
Một trường hợp gây nhầm là file đã bị unlink nhưng process vẫn mở file descriptor. df vẫn báo block đã dùng, trong khi du không còn thấy file đó. Đây là lý do kết quả df và du đôi khi lệch lớn. Dùng lsof để tìm deleted-open files, xác định process rồi restart hoặc reload đúng dịch vụ theo runbook.
sudo lsof +L1
sudo lsof -nP | grep '(deleted)'
sudo systemctl status myapp.service --no-pager
sudo systemctl restart myapp.serviceKhông kill process database hoặc process quan trọng chỉ vì thấy chữ deleted. Hãy đọc command line, PID, user, file descriptor và service owner. Với log, cách đúng thường là để logrotate hoặc ứng dụng reopen file; restart có kiểm soát chỉ là phương án khôi phục khi bạn đã biết tác động.
9. Các cách giải phóng dung lượng an toàn hơn
Thứ tự ưu tiên nên là: xóa file tạm có thể tái tạo; rotate log theo chính sách; archive backup đã xác minh; dọn package cache bằng package manager; giảm artifact build cũ; sau đó mới xem xét thay đổi storage. Mỗi bước cần có điều kiện dừng và ghi nhận trước-sau bằng df -h, df -i và df -h đường dẫn liên quan.
sudo apt-get clean
sudo journalctl --rotate
sudo journalctl --vacuum-time=14d
sudo du -xhd1 /var/cache 2>/dev/null | sort -h
sudo df -hT
sudo df -ihapt-get clean chỉ phù hợp khi bạn hiểu chính sách cache của máy; không thay thế cho việc tìm thư mục ứng dụng. Không dùng truncate hoặc rm lên file database, socket, lock hay file đang được ứng dụng ghi nếu chưa có hướng dẫn của hệ thống đó.
10. Khi disk full làm dịch vụ không khởi động
Sau khi giải phóng một lượng dung lượng nhỏ, đừng mặc định sự cố đã xong. Kiểm tra inode, thử tạo file tạm trong filesystem liên quan, xem status các service và đọc log theo thời gian xảy ra lỗi. Một số ứng dụng cần restart để đóng file descriptor, rebuild temporary state hoặc mở lại log.
df -h /var
df -ih /var
test -w /var/lib/myapp && echo writable
sudo systemctl --failed
sudo systemctl status nginx php8.3-fpm --no-pager
sudo journalctl -b -p err..alert --no-pagerNếu chạy Laravel, hãy xem cả storage, cache, queue và thư mục log của application. Liên kết Laravel storage link và quyền thư mục hữu ích khi sự cố disk đi kèm lỗi ghi file hoặc ảnh không hiển thị; quyền đúng không thể bù cho filesystem đã đầy, nhưng hai lỗi thường xuất hiện cùng lúc trong production.
11. Checklist xử lý Linux disk full
- Ghi thời điểm, hostname, filesystem và triệu chứng trước khi dọn dữ liệu.
- Chạy df -hT và df -ih để phân biệt block usage với inode usage.
- Dùng du -xhd1 theo từng tầng, không quét và xóa toàn bộ root một cách mù quáng.
- Dùng find để liệt kê file lớn, sau đó xác minh loại file, owner, retention và backup.
- Kiểm tra journalctl --disk-usage, service crash loop và logrotate trước khi vacuum.
- Dùng lsof để kiểm tra file deleted nhưng process vẫn mở.
- Sau khi dọn, kiểm tra khả năng ghi, service failed, queue và endpoint thực tế.
- Ghi lại nguyên nhân gốc, ngưỡng cảnh báo và kế hoạch mở rộng storage hoặc retention.
12. Kết luận
Xử lý disk full tốt không phải là tìm một lệnh xóa nhanh mà là quy trình phân biệt đúng loại cạn kiệt, giữ bằng chứng và dọn theo chính sách. df cho biết filesystem, df -i cho biết inode, du và find giúp khoanh vùng, journalctl giúp xử lý log, còn lsof giải thích trường hợp file đã xóa nhưng dung lượng vẫn bị giữ.
Hãy biến các lệnh trên thành runbook có owner, ngưỡng cảnh báo và thời gian retention cụ thể. Khi VPS có nhiều dịch vụ, việc ghi lại mount point, thư mục dữ liệu và cách rollback dọn dẹp sẽ giúp bạn phục hồi nhanh mà không biến một cảnh báo dung lượng thành sự cố dữ liệu.