Optimization

Giảm tiêu thụ RAM VPS Linux: các kỹ thuật hiệu quả

VPS 2 GB RAM chạy được vài tuần thì free -m báo còn 80 MB trống, swap đầy, SSH gõ lệnh cũng khựng. Bạn restart lại thì hết, vài hôm sau tái diễn. Vấn đề gần như luôn nằm ở một trong bốn chỗ: service thừa khởi động cùng hệ thống, cache/tuning sai, một process rò rỉ RAM, hoặc bạn đang đọc free sai cách. Bài này đi qua từng bước để giảm tiêu thụ RAM VPS Linux đúng chỗ, kèm lệnh đo và kiểm tra sau mỗi thao tác. Áp dụng cho Ubuntu 24.04 LTS, Debian 12/13 và các distro systemd cùng họ; chỗ nào khác sẽ ghi rõ.

  • Đọc đúng: cột available trong free -h, không phải cột free.
  • Service không dùng thì tắt và mask, không chỉ stop.
  • RAM 1-2 GB nên bật zram trước khi nghĩ đến swap file.
  • Tuning kernel nhỏ giọt; RAM thật do ứng dụng (PHP-FPM, MySQL, Node) quyết định.

Đo đúng trước khi tối ưu

Muốn giảm tiêu thụ RAM VPS Linux thì bước đầu tiên là nhìn đúng số liệu. Linux dùng RAM trống làm page cache, nên cột free thấp là bình thường và vô hại. Con số bạn cần nhìn là available: đó là lượng RAM kernel ước tính cấp được cho ứng dụng mới mà không phải đẩy ra đĩa.

free -h
cat /proc/meminfo | grep -E 'MemTotal|MemAvailable|SwapTotal|SwapFree|Dirty'

Nếu MemAvailable còn trên 15% tổng RAM thì hệ thống chưa thiếu. Lo là khi SwapFree thấp, Dirty cao, hoặc si/so trong vmstat liên tục khác 0.

vmstat 2 5
# cột si (swap in) và so (swap out) phải gần 0 khi hệ thống rảnh

Giờ xem process nào thực sự ăn RAM. Dùng ps_mem thay vì top, vì nó cộng cả shared memory đúng cách, còn top dễ khiến bạn tưởng mọi process đều khổng lồ.

sudo apt install ps_mem -y    # Debian/Ubuntu
sudo ps_mem -s | head -30

Output mong đợi: một bảng xếp hạng theo Private + Swap. Đây là danh sách thật để bạn cắt, đừng đoán.

Tắt service và daemon thừa

Một VPS cài sẵn panel hoặc image mặc định thường chạy hàng chục service bạn hiếm khi dùng: bluetooth, modemmanager, packagekit, snapd, unattended-upgrades bản desktop, avahi. Mỗi cái chỉ vài chục MB, nhưng trên VPS 2 GB thì cộng lại thành 300-500 MB. Câu trả lời trực tiếp: systemctl list-units để soi, rồi mask thứ không cần, vì chỉ stop thì lần sau reboot nó quay lại.

Liệt kê các service đang chạy và RAM ước tính của từng cái:

systemctl list-units --type=service --state=running
systemd-cgtop -m --order=memory     # nhấn q để thoát

Vài cái hay gặp và hầu như luôn tắt được trên VPS server:

sudo systemctl disable --now snapd.service snapd.socket
sudo systemctl disable --now packagekit.service
sudo systemctl disable --now bluetooth.service ModemManager.service
sudo systemctl disable --now avahi-daemon.service avahi-daemon.socket

Với những cái bạn chắc chắn hiếm khi cần kể cả khi bị dependency kéo, dùng mask để chặn cứng:

sudo systemctl mask snapd.service snapd.socket

Verify: chạy lại systemctl list-units --type=service --state=running, danh sách phải ngắn hơn rõ rệt. Kiểm tra tổng RAM đã tiết kiệm:

sudo ps_mem -s | head -20

Lưu ý: trên Debian/Ubuntu mới, snapd có thể là dependency của thứ khác bạn cần. Tắt xong reboot một lần rồi kiểm tra ứng dụng chính còn chạy không, đừng tắt xong để đó.

Zram: nén RAM tốt hơn swap file với VPS 1-2 GB

Nếu VPS ít RAM, zram là thứ đáng bật trước swap file. Zram tạo một block device nằm gọn trong RAM và nén dữ liệu bị đẩy ra đó, hiệu quả với dữ liệu văn bản, cache web, session. Trên VPS 2 GB, một zram 512 MB có thể chứa tới 1-1.5 GB dữ liệu nén, và truy cập nhanh hơn swap trên đĩa NVMe rất nhiều. Đây là kỹ thuật giảm tiêu thụ RAM VPS Linux mà tôi luôn bật đầu tiên.

Cài đặt trên Ubuntu 24.04 / Debian 12 trở lên:

sudo apt install zram-tools -y

Chỉnh cấu hình, đặt kích thước zram bằng 50% RAM và thuật toán nén zstd (tỉ lệ nén tốt, CPU dùng chấp nhận được):

sudo tee /etc/default/zramswap <<'EOF'
ALGO=zstd
PERCENT=50
PRIORITY=100
EOF
sudo systemctl restart zramswap

Verify: zram phải xuất hiện như một swap device có priority cao hơn swap khác:

swapon --show
zramctl
cat /proc/swaps

Output mong đợi: một dòng /dev/zram0 với SIZE bằng nửa RAM, PRIORITY 100. Nếu bạn chạy VPS NVMe có băng thông trong nước tốt, zram vẫn thắng swap đĩa ở độ trễ, vì đơn giản nó không đi qua đĩa.

Cấu hình swap file đúng cách

Zram xử lý RAM nén, nhưng vẫn nên có một swap file nhỏ trên đĩa làm lớp đệm cuối, nhất là khi bạn cài lại OS và snapshot hệ thống. Một file swap 1-2 GB với vm.swappiness thấp giúp tránh OOM killer khi có đợt tải đột biến.

sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Điều quan trọng không kém là hạ độ "sốt sắng" đẩy trang ra swap. Swappiness mặc định 60 quá cao cho server; 10 là điểm cân bằng tôi hay dùng:

sudo sysctl vm.swappiness=10
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.d/99-tuning.conf

Verify: swapon --show phải liệt kê cả zram lẫn /swapfile. Sau một ngày chạy, vmstat 2 5 cột si/so phải gần 0 khi rảnh. Nếu vẫn swap liên tục thì vấn đề không phải swap, mà là ứng dụng đang rò rỉ hoặc cấu hình quá tham, quay lại bước đo.

Kernel tuning: sysctl nhỏ giọt cho đúng chỗ

Nhiều hướng dẫn chỉnh kernel như thể đổi sysctl là giảm được RAM, nhưng thực tế kernel chỉ chiếm vài trăm MB và hầu hết tham số không đụng tới. Có ba nhóm đáng chỉnh trên VPS ít RAM: dirty page, inode/file cache, và overcommit. Tôi để chúng trong một file sysctl riêng để dễ rollback.

sudo tee /etc/sysctl.d/99-memory.conf <<'EOF'
vm.swappiness = 10
vm.vfs_cache_pressure = 50
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.overcommit_memory = 0
vm.min_free_kbytes = 65536
EOF
sudo sysctl --system

Giải thích nhanh: vfs_cache_pressure thấp giữ inode/dentry cache lâu hơn, đỡ phải đọc lại metadata (đổi lấy việc ưu tiên thu hồi cache khi cần); dirty_ratio thấp để kernel ghi xuống đĩa sớm, tránh dồn ứ rồi phải đẩy cả đống ra đĩa một lúc. min_free_kbytes giữ lại một kho dự trữ để hệ thống còn thở được lúc cao điểm.

Verify: sysctl vm.swappiness vm.dirty_ratio phải trả về đúng giá trị. Đừng đặt overcommit_memory=1 trừ khi có ứng dụng cụ thể cần (ví dụ Redis fork lúc RDB), vì nó cho phép cấp phát vượt RAM và dễ giết OOM hơn.

Siết PHP-FPM, MySQL và các app ngốn RAM thật

Đây mới là chỗ quyết định. Trên VPS 2 GB cài LEMP, PHP-FPM và MySQL/MariaDB thường ăn 70% RAM. Giới hạn đúng hai thứ này thường tiết kiệm hơn mọi mẹo kernel cộng lại.

Với PHP-FPM, thủ phạm là pm.max_children đặt quá cao, mỗi child ~40-60 MB. Công thức đơn giản: lấy RAM khả dụng trừ phần cho MySQL rồi chia cho RSS trung bình của một child.

# xem RSS trung bình của một php-fpm child
ps -ylC php-fpm8.3 --sort:rss | awk '{sum+=$8; n++} END {print "avg RSS KB:", sum/n}'

Giả sử còn khoảng 600 MB cho PHP thì pm.max_children = 10 với child ~60 MB là hợp lý. Sửa trong pool config và reload, đừng restart cứng:

sudo sed -i 's/^pm.max_children.*/pm.max_children = 10/' /etc/php/8.3/fpm/pool.d/www.conf
sudo systemctl reload php8.3-fpm

MariaDB/MySQL thì siết buffer pool và connection. Với VPS 2 GB chạy web nhỏ, buffer pool 256 MB và max_connections quanh 30 là đủ; đặt buffer pool 60% RAM như nhiều hướng dẫn rất dễ OOM nếu còn PHP chạy chung.

sudo tee /etc/mysql/mariadb.conf.d/99-small.conf <<'EOF'
[mysqld]
innodb_buffer_pool_size = 256M
max_connections = 30
performance_schema = OFF
EOF
sudo systemctl restart mariadb

Verify: systemctl status mariadb phải active, app kết nối được, và ps_mem -s | head RSS của cả hai dịch vụ giảm rõ. Nếu app báo "too many connections", nâng max_connections lên 50 chứ đừng tắt luôn giới hạn.

Cắt log, cache và snapshot theo định kỳ

Một phần RAM "mất tích" không phải do process mà do tmpfs: /run, /dev/shm, log trong RAM, và các bản cache không được dọn. Trên VPS chạy lâu ngày, /dev/shm đầy do process nào đó ghi mà không xoá, điều này ăn RAM trực tiếp.

df -h /run /dev/shm /tmp
du -sh /dev/shm/* 2>/dev/null | sort -h | tail

Đảm bảo log không phình và được xoay vòng, dùng đúng logrotate; kiểm tra các thư mục tạm và file vụn:

sudo journalctl --vacuum-size=200M
sudo find /tmp -type f -atime +7 -delete

Nếu bạn chạy Docker, container không giới hạn RAM rất dễ ăn hết bộ nhớ. Đặt giới hạn khi chạy:

docker run -m 512m --memory-swap 512m ...

Verify: df -h /dev/shm sau khi dọn phải giảm, và journalctl --disk-usage không vượt ngưỡng bạn đặt. Với VPS chạy nhiều dịch vụ, một chiến lược là chọn gói có RAM cao hơn hoặc dùng VPS Linux NVMe với nhiều RAM để chia tải giữa các app, thay vì cố nhồi tất cả vào một máy 2 GB.

Câu hỏi thường gặp

Vì sao free -m báo hết RAM mà hệ thống vẫn chạy bình thường?

Vì Linux dùng RAM trống làm page cache, và cache được giải phóng ngay khi ứng dụng cần. Cột free thấp không phải vấn đề; cột available mới phản ánh RAM thật dùng được.

Bật zram có làm CPU tăng tải không?

Có, nhưng thường không đáng kể trên vCPU hiện đại, đặc biệt khi chọn thuật toán zstd. Đổi lại bạn được nhiều RAM hiệu dụng hơn và độ trễ thấp hơn swap trên đĩa. Với VPS 2 GB, lợi ích thường lớn hơn chi phí CPU.

Đặt innodb_buffer_pool_size bao nhiêu là đủ?

Với VPS 2 GB chạy PHP-FPM cùng máy, 256 MB là điểm khởi đầu an toàn. Nếu database là workload chính, có thể lên 50-60% RAM nhưng phải theo dõi OOM. Không có con số đúng cho mọi trường hợp, hãy đo rồi tăng dần.

Tắt service bằng stopmask khác gì nhau?

stop chỉ dừng phiên hiện tại, service sẽ quay lại sau reboot. disable ngăn tự khởi động nhưng vẫn có thể bị kéo theo dependency. mask chặn cứng, không gì kéo nó lên được, dùng cho thứ bạn chắc chắn không cần.

VPS 1 GB RAM có chạy được web không?

Chạy được một site tĩnh hoặc WordPress nhẹ với zram và tuning đầy đủ, nhưng rất sát trần. Nếu có database và PHP cùng lúc, nâng lên gói 2 GB hoặc tách database ra máy khác thường rẻ hơn về công sức vận hành.

Khi nào thì nên nâng RAM thay vì tiếp tục tối ưu?

Khi tối ưu đã siết nhưng ứng dụng vẫn swap liên tục và vmstat cho thấy si/so khác 0 thường xuyên. Lúc đó vấn đề là tổng cầu vượt tổng cung, không còn mẹo nào cứu được. Xem bảng giá VPS để cân nhắc nâng gói.

Bài viết liên quan

Lưu ý: Bài viết mang tính tham khảo, tổng hợp kiến thức chung. Mỗi hệ thống, hạ tầng và nhu cầu có đặc thù riêng, nên kiểm thử trong môi trường an toàn và tham vấn kỹ sư trước khi triển khai thực tế.