Sự cố lúc 2 giờ sáng: Khi một tiến trình ‘nuốt trọn’ server
Chuông báo Zabbix réo liên tục lúc 2 giờ sáng. Toàn bộ cụm web trên con VPS CentOS Stream 9 (4 vCPU, 16GB RAM) hoàn toàn mất phản hồi. SSH liên tục báo connection timeout. Chỉ số load average chạm mốc 48.
Phải chật vật qua console cứu hộ của nhà cung cấp, tôi mới gõ được lệnh top. Thủ phạm lộ diện: một worker Python xử lý queue bị rò rỉ bộ nhớ (memory leak). Nó ngốn sạch 14GB RAM. Hậu quả là Linux OOM Killer bị kích hoạt và lập tức ‘trảm’ nhầm MariaDB cùng Nginx.
Để mặc định tài nguyên cho các tiến trình chạy tự do là rủi ro lớn. Từ phiên bản CentOS Stream 9, Red Hat đã chuyển hẳn sang cgroups v2. Khi kết hợp cùng systemd slices, bạn có thể phân vùng và cô lập tài nguyên cho từng nhóm ứng dụng cực kỳ hiệu quả.
3 cách kiểm soát tài nguyên trên Linux
Quản trị viên thường cân nhắc giữa 3 phương án sau:
- Cách 1: Thao tác thủ công qua cgroupfs (Tự tạo thư mục trong
/sys/fs/cgroup/và gán PID bằng tay). - Cách 2: Dùng
ulimithoặc cấu hìnhlimits.conf(Giới hạn ở cấp độ user session). - Cách 3: Sử dụng cgroups v2 kết hợp systemd slices (Kiểm soát trực tiếp theo đơn vị unit service).
Đánh giá ưu nhược điểm từng giải pháp
1. Can thiệp thủ công qua cgroupfs
- Ưu điểm: Chạy độc lập, không phụ thuộc vào init system.
- Nhược điểm: Quá phức tạp để duy trì. Khi tiến trình fork tiến trình con hoặc crash restart, PID thay đổi làm mất cấu hình đã gán.
2. Dùng ulimit (/etc/security/limits.conf)
- Ưu điểm: Tiện lợi cho tài khoản tương tác qua terminal.
- Nhược điểm: Vô tác dụng với các daemon do systemd khởi chạy. Thêm vào đó,
ulimit -vthường ép ứng dụng crash lập tức thay vì điều tiết bộ nhớ mềm dẻo.
3. cgroups v2 kết hợp systemd unit & slices
- Ưu điểm: Sử dụng cây phân cấp đơn nhất (single unified hierarchy) cho cả CPU, Memory và I/O. Tiến trình restart bao nhiêu lần vẫn bị khóa chặt trong nhóm. Bạn dễ dàng gom nhiều service vào một hạn mức chung.
- Nhược điểm: Cú pháp directive mới (ví dụ
MemoryMaxthay choMemoryLimitcũ của cgroups v1).
Vì sao systemd slices + cgroups v2 là lựa chọn tối ưu trên CentOS Stream 9?
CentOS Stream 9 chạy nhân Linux 5.14+ cùng systemd v250+ và kích hoạt sẵn cgroups v2. Cố áp dụng các giải pháp cũ chỉ khiến cấu hình phân mảnh.
Với systemd slices, bạn chia server thành từng lát cắt tài nguyên rõ rệt. Ví dụ: gom toàn bộ worker và cronjob vào background.slice (tối đa 20% CPU, 2GB RAM). 80% CPU và 14GB RAM còn lại được bảo toàn cho system.slice chứa database và web server.
Các bước triển khai thực tế
Bước 1: Kiểm tra trạng thái cgroups v2
Đầu tiên, hãy xác minh hệ thống đang chạy cgroups v2:
# Kiểm tra filesystem cgroup
stat -fc %T /sys/fs/cgroup/
# Output hợp lệ: cgroup2fs
# Xem danh sách controllers đang bật
cat /sys/fs/cgroup/cgroup.controllers
# Output mong đợi: cpuset cpu io memory pids
Bước 2: Tạo slice để cô lập nhóm dịch vụ phụ
Tạo file background-worker.slice để quản lý nhóm tác vụ nền:
sudo nano /etc/systemd/system/background-worker.slice
Khai báo ngưỡng giới hạn:
[Unit]
Description=Slice gioi han tai nguyen cho Background Workers
Before=slices.target
[Slice]
# Gioi han CPU bang 50% cua 1 core
CPUQuota=50%
# Nguong RAM mem: vuot 1GB kernel se tich cuc thu hoi/page-out
MemoryHigh=1G
# Nguong RAM cung: cham 1.5GB thi cgroup OOM Killer se kill tien trinh trong slice
MemoryMax=1.5G
# Gioi han so process de ngan fork bomb
TasksMax=100
Bước 3: Gán Service vào Slice
Giả sử bạn có service data-worker.service. Mở file cấu hình:
sudo systemctl edit --full data-worker.service
Thêm dòng Slice=background-worker.slice vào mục [Service]:
[Unit]
Description=Data Worker Background Service
After=network.target
[Service]
Type=simple
User=workeruser
Slice=background-worker.slice
ExecStart=/usr/bin/python3 /opt/worker/app.py
Restart=always
[Install]
WantedBy=multi-user.target
Nạp lại cấu hình systemd và khởi động dịch vụ:
sudo systemctl daemon-reload
sudo systemctl restart data-worker.service
Bước 4: Giới hạn nhanh cho một service đơn lẻ (Drop-in override)
Nếu chỉ cần khống chế riêng một dịch vụ như Nginx mà không muốn tạo slice, hãy dùng override file:
sudo systemctl edit nginx.service
Thêm các tham số điều tiết:
### Editing /etc/systemd/system/nginx.service.d/override.conf
[Service]
# Cho phep Nginx dung toi da 2 vCPU (200%)
CPUQuota=200%
# Khong che tran bo nho o muc 2GB
MemoryMax=2G
# Trong so uu tien CPU khi bi tranh chap tai nguyen (mac dinh la 100)
CPUWeight=200
Áp dụng thay đổi:
sudo systemctl daemon-reload
sudo systemctl restart nginx
Bước 5: Giám sát và kiểm tra hiệu quả
Quan sát mức tiêu thụ tài nguyên thực tế của từng slice bằng lệnh sau:
systemd-cgtop -m
Để xem chi tiết mức RAM đang chiếm dụng và số lần chạm ngưỡng giới hạn của slice:
# Xem dung luong RAM hien tai
cat /sys/fs/cgroup/background-worker.slice/memory.current
# Xem so lan cham MemoryHigh hoac bi trigger OOM
cat /sys/fs/cgroup/background-worker.slice/memory.events
Chủ động thiết lập ranh giới tài nguyên với cgroups v2 giúp hệ thống vận hành ổn định. Dù tiến trình nền có phát sinh lỗi rò rỉ bộ nhớ, các dịch vụ cốt lõi vẫn luôn được bảo vệ an toàn.

