Website đột ngột chậm, lúc vào được lúc không, MariaDB tự tắt giữa đêm. Đây là triệu chứng quen thuộc của VPS thiếu tài nguyên. Bài này giúp bạn tạo swap làm lớp đệm cho RAM, biết dùng các công cụ cơ bản để xem CPU, RAM, ổ đĩa, đọc log hệ thống và lần ra nguyên nhân web chậm theo một trình tự rõ ràng.

Bạn cần chuẩn bị:

  • VPS Ubuntu 22.04 hoặc 24.04, có user sudo.
  • Website chạy Nginx, PHP-FPM, MariaDB (các lệnh tương tự với Apache hoặc MySQL).
  • Ít nhất vài GB ổ đĩa trống nếu muốn tạo swap.

Bước 1: Kiểm tra swap hiện có

free -h
swapon --show

Nếu dòng Swap: toàn số 0 và swapon --show không in gì, VPS chưa có swap. Nhiều image cloud không tạo swap sẵn.

Lưu ý: một số nền tảng ảo hóa dạng container (như OpenVZ, LXC) không cho phép tạo swap trong VPS. Lệnh systemd-detect-virt cho biết loại ảo hóa.

Bước 2: Tạo swap file 2 GB

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
swapon --show

Quyền 600 là bắt buộc, để user thường không đọc được dữ liệu RAM bị đẩy ra swap. Nếu fallocate báo lỗi (một số hệ thống file không hỗ trợ), dùng lệnh thay thế:

sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress

Để swap tự bật sau khi khởi động lại, thêm vào /etc/fstab:

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Bước 3: Chỉnh swappiness

vm.swappiness điều chỉnh mức kernel sẵn sàng đẩy dữ liệu ra swap. Mặc định là 60. Với máy chủ web, giá trị thấp hơn giúp giữ dữ liệu trong RAM lâu hơn.

cat /proc/sys/vm/swappiness
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swap.conf
sudo sysctl --system
cat /proc/sys/vm/swappiness

Bước 4: Xem tổng quan bằng htop

sudo apt install -y htop
htop

Những gì cần nhìn:

Chỉ sốVị tríDấu hiệu có vấn đề
CPUThanh từng nhân phía trênĐầy liên tục
Mem, SwpThanh bộ nhớMem đầy và Swp tăng dần
Load averageGóc phải trênCao hơn số nhân CPU kéo dài
Tiến trìnhDanh sách bên dướiMột tiến trình chiếm phần lớn CPU hoặc RAM

Nhấn F6 để sắp xếp theo PERCENT_CPU hoặc PERCENT_MEM, nhấn q để thoát. Số nhân CPU xem bằng nproc.

Nếu CPU không cao nhưng load vẫn cao, có thể máy đang chờ ổ đĩa. Xem cột wa (I/O wait) trong lệnh:

vmstat 2 5

Bước 5: Kiểm tra ổ đĩa

Ổ đĩa đầy khiến MariaDB dừng ghi, PHP không tạo được session, Nginx không ghi log. Kiểm tra cả dung lượng và inode:

df -h
df -i

Tìm thư mục chiếm nhiều chỗ:

sudo du -xh --max-depth=1 / 2>/dev/null | sort -rh | head -n 15
sudo du -sh /var/log/* | sort -rh | head

Thủ phạm hay gặp: log lớn, bản sao lưu cũ, cache plugin, journal của systemd. Giới hạn dung lượng journal:

journalctl --disk-usage
sudo journalctl --vacuum-size=200M

Bước 6: Đọc log bằng journalctl

journalctl đọc log của systemd. Vài lệnh hữu ích:

# Lỗi từ lần khởi động hiện tại
journalctl -p err -b

# Log của từng dịch vụ trong 1 giờ qua
journalctl -u nginx --since "1 hour ago"
journalctl -u php8.3-fpm --since today
journalctl -u mariadb -n 100

# Theo dõi trực tiếp
journalctl -u php8.3-fpm -f

Kiểm tra tiến trình có bị kernel tắt vì hết RAM (OOM killer) không:

journalctl -k | grep -i -E 'out of memory|oom-kill'

Nếu thấy Killed process ... (mariadbd) hoặc (php-fpm8.3), VPS đã thiếu RAM thật sự. Ngoài journal, Nginx ghi log riêng tại /var/log/nginx/error.log.

Bước 7: Kiểm tra PHP-FPM có đủ worker không

Khi mọi worker PHP-FPM đều bận, yêu cầu mới phải chờ, web chậm dù CPU không cao. Tìm cảnh báo trong log:

sudo grep -i 'max_children' /var/log/php8.3-fpm.log

Nếu có dòng server reached pm.max_children setting, cần điều chỉnh pool tại /etc/php/8.3/fpm/pool.d/www.conf. Trước hết, đo RAM trung bình mỗi worker:

ps -C php-fpm8.3 -o rss= | awk '{s+=$1; n++} END {if (n) print n " worker, TB " int(s/n/1024) " MB"}'

Ước lượng pm.max_children bằng (RAM dành cho PHP) chia (RAM mỗi worker). Ví dụ còn 1 GB cho PHP, mỗi worker khoảng 60 MB thì đặt khoảng 15. Đặt quá cao sẽ gây OOM.

pm = dynamic
pm.max_children = 15
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

Bật slow log để biết script nào chạy lâu:

request_slowlog_timeout = 5s
slowlog = /var/log/php8.3-fpm-slow.log
sudo systemctl reload php8.3-fpm

Bước 8: Tìm truy vấn chậm và truy cập bất thường

Xem truy vấn đang chạy trong MariaDB:

sudo mariadb -e "SHOW FULL PROCESSLIST;"

Xem IP truy cập nhiều nhất trong access log, giúp phát hiện bot cào dữ liệu hoặc tấn công dò mật khẩu:

sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

Nếu một IP gọi /wp-login.php hay /xmlrpc.php hàng nghìn lần, chặn bằng sudo ufw deny from 198.51.100.7 hoặc cấu hình fail2ban, Cloudflare.

Kiểm tra lại

  • free -h hiện swap 2 GB, sau khi reboot vẫn còn.
  • cat /proc/sys/vm/swappiness trả về 10.
  • df -h phân vùng gốc còn trống trên 15 đến 20%.
  • Log PHP-FPM không còn cảnh báo max_children sau vài ngày.
  • journalctl -k | grep -i oom không có dòng mới.

Lỗi thường gặp và cách xử lý

swapon: /swapfile: insecure permissions

Quyền file chưa đúng. Chạy sudo chmod 600 /swapfile rồi bật lại.

swapon: Invalid argument

File tạo bằng fallocate trên hệ thống file không hỗ trợ. Xóa file, tạo lại bằng dd. Nếu vẫn lỗi, nền tảng VPS có thể không cho phép swap.

Ổ đĩa báo còn trống nhưng không ghi được

Hết inode do quá nhiều file nhỏ (session, cache). Xem df -i, tìm thư mục có nhiều file bằng sudo find /var -xdev -type f | cut -d/ -f2-4 | sort | uniq -c | sort -rn | head.

Đã xóa file log lớn mà dung lượng không giảm

Tiến trình vẫn giữ file đang mở. Tìm bằng sudo lsof +L1, rồi restart dịch vụ tương ứng. Lần sau nên làm rỗng file bằng sudo truncate -s 0 tenfile.log thay vì xóa.