---
id: case-disk
title: "Disk đầy vì log"
shortTitle: "Disk đầy"
track: cases
trackTitle: "Tình huống vận hành"
order: 3
level: important
status: published
estimatedMinutes: 30
prerequisites:
  - logs-journald
  - logs-files
next: case-secret
reviewedAgainst: 2026-10-12
sources:
  - title: "unlink(2)"
    url: https://man7.org/linux/man-pages/man2/unlink.2.html
  - title: "journalctl"
    url: https://man7.org/linux/man-pages/man1/journalctl.1.html
---

# Disk đầy vì log

Khi đĩa đầy, app không ghi được file, database từ chối checkpoint, và SSH vẫn vào được cho tới lúc đĩa hệ thống cũng đầy nốt. Nếu bạn xóa nhầm một file đang được process mở, `df` sẽ không giảm chút nào.

## Để làm gì

Bạn cần tìm thứ đang chiếm đĩa, giải phóng dung lượng trong khi process vẫn chạy, và chặn lần đầy tiếp theo. Đừng xóa file log đang được process giữ inode, vì dung lượng sẽ không trả về.

## Gồm những gì

- Vì sao `df` và `du` lệch nhau khi file đã bị unlink nhưng vẫn còn mở.
- `journalctl --disk-usage` và `--vacuum-size`.
- Logrotate cần gửi tín hiệu cho process, không chỉ đổi tên file.

Bài không bàn chuyện mua thêm đĩa trên cloud. Đó là quyết định sau khi bạn đã biết thứ gì đang phình ra.

## Dùng khi nào

Log app báo `No space left on device`, hoặc alert đĩa vượt 90%. Nếu user đang mất dịch vụ vì đĩa đầy, việc này được ưu tiên ngang sự cố 502, và phải làm trước khi bạn đi tối ưu query.

Đừng chạy `rm -rf /var/log`. Bạn sẽ mất dấu vết của chính sự cố này, và có thể xóa luôn log mà syslog vẫn đang ghi.

## Kiến thức cốt lõi

`df -h` cho biết dung lượng đã dùng của filesystem. `du -xh /var --max-depth=1` cộng kích thước của những file còn tên trong cây thư mục. Hai số này lệch nhau nhiều khi một process vẫn giữ một file đã bị xóa. Lý do là `unlink` chỉ gỡ tên file; dung lượng chỉ được trả lại khi không còn handle nào mở file đó. Man page `unlink(2)` ghi rõ file chỉ thật sự bị xóa khi link cuối cùng mất và không còn process nào mở nó.

Thứ tự điều tra:

1. Chạy `df -h` để biết filesystem nào đầy. Bước này phải đi đầu, vì bạn không muốn dọn nhầm trên một đĩa khác.
2. Chạy `du` trên filesystem đó để tìm thư mục lớn. Nếu tổng của `du` thấp hơn hẳn `df`, nghi ngay tới file đã xóa nhưng còn mở, và kiểm tra bằng `lsof +L1`.
3. Xem journald đang giữ bao nhiêu bằng `journalctl --disk-usage`.
4. Giải phóng dung lượng bằng cách an toàn nhất có thể, rồi chạy lại `df -h`. Bạn chỉ coi là đã thở được khi `df` thật sự giảm và app ghi được log trở lại.

Với file log đang mở, cách an toàn là thu nhỏ file tại chỗ, hoặc để logrotate dùng copytruncate hay gửi tín hiệu cho process mở lại file. `truncate -s 0 /var/log/app.log` giữ nguyên inode, process tiếp tục ghi vào cùng file, và `df` giảm ngay. Còn nếu `rm` file rồi đợi process chết, `df` cũng giảm nhưng muộn, và file mới có thể không được tạo nếu app không mở lại file.

journald có giới hạn dung lượng riêng. `journalctl --vacuum-size=200M` cắt bớt journal cũ. Hãy thử lệnh này trên máy lab trước, rồi mới dùng trên một máy mà bạn chỉ có đúng một đường SSH vào.

Sau khi đĩa đã có chỗ, hãy tìm vì sao nó đầy: một request lỗi lặp lại và ghi stack trace mỗi lần, log level debug bị quên chưa tắt, hay container không có giới hạn dung lượng log. Sửa tận gốc nguyên nhân, vì xóa log một lần chỉ mua thêm thời gian.

## Lệnh và code mẫu

Chạy trên máy lab hoặc server bạn được phép sửa:

```bash
df -h
sudo du -xh /var --max-depth=1 | sort -h
sudo journalctl --disk-usage
sudo lsof +L1 2>/dev/null | head
```

`lsof +L1` liệt kê những file đã unlink nhưng vẫn còn được mở. Nếu máy không có `lsof`, hãy bỏ qua lệnh này. Đừng cài thêm package lên production giữa lúc sự cố nếu `du` đã chỉ ra được thư mục thủ phạm.

Thu nhỏ một file log trong lab. Đừng đụng vào file hệ thống nếu bạn không chắc:

```bash
mkdir -p /tmp/devops-lab && dd if=/dev/zero of=/tmp/devops-lab/big.log bs=1M count=20 status=none
df -h /tmp
truncate -s 0 /tmp/devops-lab/big.log
df -h /tmp
rm -f /tmp/devops-lab/big.log
```

## Thực hành

1. Tạo file 20 MB rồi `truncate` như trên. `df` phải giảm.
2. Viết một câu giải thích vì sao `rm` một file log đang mở có thể không làm `df` thay đổi.
3. Nếu máy bạn dùng journald, chạy `--disk-usage`. Không vacuum trên máy nào không phải máy lab.

## Kết quả mong đợi

Bạn giải thích được vì sao `df` và `du` lệch nhau. Bạn có một lệnh thu nhỏ file mà không đổi inode.

## Checklist

- [ ] Chạy `df` trước để biết filesystem nào đầy, tránh xóa nhầm trên đĩa khác.
- [ ] Không `rm` file log mà process vẫn đang ghi, nếu bạn cần dung lượng ngay.
- [ ] Vacuum journal có chủ đích, với con số giới hạn cụ thể.
- [ ] Chạy lại `df` sau khi dọn để xác nhận dung lượng đã trả về.
- [ ] Sau sự cố, tắt log debug hoặc đặt giới hạn log cho container.

## Lỗi thường gặp

**Đã xóa log mà app vẫn báo đầy.** Process vẫn giữ file cũ. Hãy `truncate` đúng path mà app đang mở, hoặc restart app sau khi đã có chỗ trống cho file mới. Restart lúc đĩa còn 100% có thể khiến app không tạo lại được file, nên thu nhỏ trước, restart sau.

**Chỉ thêm đĩa.** Tuần sau đĩa lại đầy. Hãy tìm dòng log đang lặp lại, vì một exception nằm trong vòng lặp có thể ghi hàng GB mỗi giờ.

## Nguồn

1. [unlink(2)](https://man7.org/linux/man-pages/man2/unlink.2.html) — dung lượng trả về khi không còn process mở file.
2. [journalctl(1)](https://man7.org/linux/man-pages/man1/journalctl.1.html) — `--disk-usage` và `--vacuum-size`.

## Tiếp theo

[Secret đã lên Git](./04-secret.md)
