Memory Ballooning và KSM trên KVM/Proxmox: Tối ưu RAM để chạy nhiều máy ảo hơn

Virtualization tutorial - IT technology blog
Virtualization tutorial - IT technology blog

Cùng một con server 32GB RAM — người ta chạy được 10–15 máy ảo, mình chỉ được 5–6 cái trước khi hệ thống bắt đầu ì ạch. Lý do? Thường nằm ở hai thứ bị bỏ qua: Memory BallooningKSM (Kernel Same-page Merging).

Mình chạy homelab với Proxmox VE quản lý 12 VM và container — playground để test mọi thứ trước khi đưa lên production. Ban đầu phân bổ RAM kiểu truyền thống: mỗi VM đặt cứng 2GB hoặc 4GB rồi thôi. Kết quả là server 32GB lúc nào cũng báo dùng 28–30GB dù phần lớn VM đang… ngủ. Sau khi bật KSM và cấu hình balloon driver đúng cách, con số đó giảm xuống còn 18–20GB trong giờ thấp điểm — tiết kiệm gần 10GB chỉ bằng cấu hình phần mềm.

Vấn đề với cách phân bổ RAM cứng nhắc

Hầu hết tutorial dạy bạn tạo VM với RAM cố định — ví dụ 4GB. Nghĩa là hypervisor luôn luôn giữ 4GB thực cho VM đó, dù VM đang idle với chỉ 800MB thực sự dùng.

Nhận ra chuyện này sau khi chạy free -h trên từng VM lúc 3 giờ sáng — hầu hết chỉ dùng 20–30% RAM được cấp. Lãng phí hoàn toàn.

Ba hướng để giải quyết:

  • Cấp RAM thấp cố định: Ít lãng phí nhưng VM thiếu RAM khi tải cao → crash hoặc swap nặng
  • Memory Ballooning: Phân bổ động — VM lấy thêm khi cần, trả về khi rảnh
  • KSM: Kernel gộp các trang RAM trùng nhau giữa nhiều VM → tiết kiệm vật lý

Hai cái sau không loại trừ nhau. Dùng cả hai mới là tối ưu thật sự.

Memory Ballooning hoạt động như thế nào?

Hình dung thế này: Hypervisor cài vào VM một driver đặc biệt gọi là balloon driver. Khi host cần lấy lại RAM, nó ra lệnh cho balloon driver phồng lên — driver chiếm RAM trong guest để host dùng cho VM khác. Khi VM cần nhiều hơn, balloon xả ra.

Điểm mạnh nhất: VM không bị kill, không crash. Nó chỉ chậm hơn một chút trong lúc balloon đang điều chỉnh — thường vài giây, không đáng kể với workload nhẹ.

Nhưng cũng có mặt trái:

  • Guest OS phải cài balloon driver (VirtIO balloon trên Linux, virtio-win trên Windows)
  • Nếu balloon lấy quá nhiều RAM, guest bắt đầu swap — mình đã từng khiến một VM Ubuntu swap liên tục vì set min_balloon quá thấp xuống 256MB
  • Không hợp với ứng dụng cần RAM latency thấp (database production, Redis cache)

KSM — Kernel Same-page Merging

KSM là tính năng của Linux kernel, không phụ thuộc vào guest OS — bật một lần trên host, tất cả VM đều hưởng lợi. Cơ chế: kernel quét RAM định kỳ, tìm các trang nhớ có nội dung giống hệt nhau (dù thuộc về các tiến trình hoặc VM khác nhau), rồi merge thành một trang vật lý duy nhất với copy-on-write.

Hiệu quả nhất khi chạy nhiều VM cùng OS — ví dụ 8 VM Ubuntu 22.04 đều có kernel, libc, systemd giống nhau trong RAM. KSM nhận ra và gộp lại, tiết kiệm hàng GB.

Sau khi bật KSM trên host Proxmox, đây là cách kiểm tra xem đang tiết kiệm bao nhiêu:

# Kiểm tra KSM hiện tại
cat /sys/kernel/mm/ksm/pages_shared
cat /sys/kernel/mm/ksm/pages_sharing

# pages_shared: số trang vật lý thực (sau khi merge)
# pages_sharing: số trang được share (tiết kiệm = sharing - shared)

Trên homelab của mình, pages_sharing dao động 180.000–250.000 trang — tương đương 700MB–1GB RAM tiết kiệm được, chỉ từ việc bật một tính năng có sẵn trong kernel.

So sánh: nên dùng cái nào?

Tiêu chí Memory Ballooning KSM
Cần sửa guest? Có (cài driver) Không
Overhead CPU Thấp Trung bình (quét RAM định kỳ)
Hiệu quả Cao khi VM idle Cao khi nhiều VM cùng OS
Rủi ro Guest swap nếu cấu hình sai CPU tăng khi merge nhiều
Phù hợp Homelab, dev/test Mọi môi trường nhiều VM

Câu trả lời thực dụng: Bật KSM luôn — không có lý do gì để tắt. Memory Ballooning thì chọn lọc hơn: VM dev/test/CI thì bật thoải mái, VM chạy database hay Redis production thì cấp RAM cố định, không balloon.

Cấu hình KSM trên Proxmox / KVM Host

KSM có sẵn trong kernel, chỉ cần bật và chỉnh vài thông số:

# Bật KSM
echo 1 > /sys/kernel/mm/ksm/run

# Tăng tần suất quét (mặc định 200ms, giảm xuống 50ms cho homelab)
echo 50 > /sys/kernel/mm/ksm/sleep_millisecs

# Số trang quét mỗi lần (mặc định 100, tăng lên cho server nhiều RAM)
echo 300 > /sys/kernel/mm/ksm/pages_to_scan

Những thay đổi trên mất sau reboot. Để tồn tại lâu dài, dùng systemd service — sạch hơn rc.local:

cat > /etc/systemd/system/ksm-tune.service << 'EOF'
[Unit]
Description=KSM tuning
After=network.target

[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo 1 > /sys/kernel/mm/ksm/run; echo 50 > /sys/kernel/mm/ksm/sleep_millisecs; echo 300 > /sys/kernel/mm/ksm/pages_to_scan'
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
EOF

systemctl enable --now ksm-tune.service

Cấu hình Memory Ballooning trên Proxmox

Proxmox hỗ trợ balloon driver qua giao diện web. Trong VM settings, tab Memory, có ba thông số cần quan tâm:

  • Memory (MiB): RAM tối đa VM có thể dùng
  • Minimum memory: RAM tối thiểu — host không được lấy xuống dưới mức này
  • Ballooning Device: checkbox bật/tắt

Hoặc thao tác qua qm nhanh hơn:

# Xem cấu hình RAM của VM 101
qm config 101 | grep -E 'memory|balloon'

# Đặt max 4GB, min 512MB, bật balloon
qm set 101 --memory 4096 --balloon 512

# Tắt balloon (cấp RAM cố định)
qm set 101 --balloon 0

Sau khi bật, kiểm tra balloon driver đang chạy trong guest Linux:

# Trong guest VM
lsmod | grep balloon
# Kết quả mong đợi: virtio_balloon ...

# Nếu chưa có, load module thủ công
modprobe virtio_balloon

# Tự động load khi boot
echo 'virtio_balloon' >> /etc/modules

Monitoring — Biết được đang tiết kiệm bao nhiêu

Script một dòng để theo dõi KSM realtime trên Proxmox host:

watch -n 5 'echo "=== KSM Stats ==="; \
  echo "Running: $(cat /sys/kernel/mm/ksm/run)"; \
  shared=$(cat /sys/kernel/mm/ksm/pages_shared); \
  sharing=$(cat /sys/kernel/mm/ksm/pages_sharing); \
  saved=$(( (sharing - shared) * 4 / 1024 )); \
  echo "Pages shared: $shared | Pages sharing: $sharing"; \
  echo "RAM saved: ~${saved} MB"'

Đừng lo nếu con số ban đầu nhỏ. KSM cần 20–30 phút sau khi tất cả VM boot để quét hết RAM và merge đủ. Mình thường thấy mức tiết kiệm ổn định ở 800MB–1.2GB sau khoảng nửa tiếng.

Những lỗi hay gặp và cách tránh

1. VM bị OOM killer dù còn balloon headroom: Xảy ra khi minimum memory set quá thấp và host đang dưới pressure cao. Đặt minimum ít nhất 40–50% max memory cho VM production — với VM 4GB thì minimum nên là 1.5–2GB.

2. KSM ăn CPU bất thường: Thường gặp khi pages_to_scan quá cao mà VM đang write nhiều (database). KSM liên tục merge rồi unmerge do copy-on-write. Tăng sleep_millisecs lên 100–200ms là xong.

3. Windows VM không balloon: Phải cài VirtIO drivers từ ISO của Proxmox (virtio-win). Vào Device Manager trong guest, tìm thiết bị chưa có driver và cài VirtIO Balloon từ ISO.

# Tải ISO VirtIO drivers cho Windows guests
wget https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
# Đặt vào /var/lib/vz/template/iso/ trên Proxmox

Kết quả thực tế

Trước khi cấu hình, 12 VM ngốn đều đặn 26GB/32GB RAM. Sau khi bật KSM và balloon (8 VM dev/test balloon xuống 512MB minimum, 4 VM production giữ cố định), mức sử dụng lúc idle giảm xuống 17–18GB. Thừa ra gần 9GB — đủ để spin thêm 3–4 VM test mà không lo gì.

Quan trọng hơn: không VM nào crash hay bị ảnh hưởng performance đáng kể. Chìa khóa là phân biệt rõ VM nào cần balloon, VM nào không — đừng áp dụng đại trà cho tất cả, đặc biệt là những gì đang chạy workload I/O nặng.

Share: