Kinh nghiệm Live Migration KVM/Proxmox không downtime: Tách Dedicated Network, nén ZSTD và dùng Post-copy

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

1. Cơn ác mộng khi di chuyển máy ảo: Treo ở 95% và nghẽn toàn bộ cluster

Tình huống này hẳn nhiều anh em Sysadmin từng nếm trải. Một server vật lý chạy cụm PostgreSQL production hoặc web app thương mại điện tử cần thay thanh RAM lỗi. Bạn tự tin click Live Migration từ Node A sang Node B, đinh ninh dịch vụ vẫn chạy mượt mà.

Nhưng đời không như mơ. Tiến trình migration bò đến 95% rồi đứng chôn chân. Thủ phạm là do ứng dụng ghi dữ liệu vào RAM nhanh hơn tốc độ card mạng đẩy qua host mới (hiện tượng không hội tụ).

Họa vô đơn chí, luồng dữ liệu RAM nuốt trọn băng thông cổng mạng dùng chung. Hậu quả là gói tin nội bộ rớt liên tục. Nhân viên mất kết nối CRM. Khách hàng bên ngoài lập tức nhận lỗi 504 Gateway Timeout.

Ngay cả ở cụm lab nhỏ với 12 VM Proxmox của mình, bài toán này cũng từng xuất hiện. Mỗi khi migrate một VM Redis hay PostgreSQL có tần suất ghi 150–200 MB/s qua cổng 1Gbps, mạng cluster nghẽn cứng ngắc. Muốn hệ thống ổn định trên production, chúng ta buộc phải xử lý tận gốc vấn đề này.

2. Bản chất kỹ thuật: Vì sao Live Migration thất bại?

Hình dung đơn giản: Live Migration giống như việc bạn chuyển đồ sang nhà mới trong khi ở nhà cũ, người thân vẫn liên tục mua sắm đồ mới về.

Vòng lặp Pre-copy và Dirty Memory

Theo mặc định, KVM/QEMU và Proxmox VE áp dụng cơ chế Pre-copy Migration theo 3 bước:

  1. Giai đoạn 1 (Initial Copy): Chép toàn bộ dung lượng RAM của VM từ Node A sang Node B trong lúc VM vẫn phục vụ request.
  2. Giai đoạn lặp (Iterative Phase): Khi đang chép, VM liên tục sinh ra các vùng nhớ bị sửa đổi (gọi là Dirty Pages). KVM gom các trang bẩn này để gửi tiếp sang Node B. Quá trình lặp lại qua nhiều vòng.
  3. Giai đoạn chuyển giao (Cutover): Khi lượng Dirty Pages còn lại đủ nhỏ, KVM pause VM trên Node A trong khoảng 50–100ms, đẩy nốt vài MB cuối cùng và start VM bên Node B.

Sự cố xảy ra khi Tốc độ ghi RAM (Dirty Rate) > Tốc độ truyền tải mạng (Network Bandwidth). KVM rơi vào vòng lặp vô tận. Băng thông cạn kiệt, switch quá tải và tiến trình không bao giờ về đích.

Xung đột đường truyền (Network Contention)

Nếu để traffic migration đi chung card mạng với Traffic ứng dụng và cụm Corosync (Heartbeat), rủi ro còn tồi tệ hơn. Khi luồng migration chiếm 100% dung lượng link vật lý, Corosync bị timeout. Cluster ngỡ rằng node đã chết nên lập tức kích hoạt cơ chế Fencing (tự reboot máy chủ). Một đợt bảo trì nhỏ bỗng chốc biến thành thảm họa sập toàn bộ hệ thống.

3. Hai giải pháp tình thế thường dùng (và hạn chế)

Cách 1: Giới hạn tốc độ migration (Rate Limiting)

Phương án nhanh nhất là bóp băng thông truyền migration để cứu đường mạng chung:

# Giới hạn tốc độ migration xuống tối đa 50 MB/s trên KVM
virsh migrate-setspeed <vm_name> 50

Điểm trừ: Cách này giữ an toàn cho mạng nội bộ nhưng kéo dài thời gian migrate. Với VM có tốc độ ghi RAM cao, việc bóp băng thông chắc chắn khiến migration thất bại hoàn toàn.

Cách 2: Giảm chu kỳ CPU máy ảo (Auto-Converge)

Khi nhận thấy số vòng lặp không giảm, hypervisor sẽ bóp bớt chu kỳ xử lý (vCPU throttle) của VM để ép nó ghi ít RAM hơn.

# Bật tính năng auto-converge trên KVM qua virsh
virsh migrate --live --auto-converge <vm_name> qemu+ssh://10.10.10.2/system

Điểm trừ: vCPU bị bóp từ 20% đến tận 80%. Ứng dụng bên trong (đặc biệt là Database) sẽ phản hồi cực kỳ chậm, gây ảnh hưởng trực tiếp đến người dùng.

4. Bộ giải pháp chuẩn: Dedicated Network, nén dữ liệu và Post-copy

Để đạt mục tiêu di chuyển an toàn, 0 downtime và không ảnh hưởng dịch vụ, đây là kiến trúc chuẩn nên triển khai:

Bước 1: Tách riêng Dedicated Migration Network (Khuyến nghị 10Gbps+)

Hãy dành riêng một card mạng vật lý (hoặc bond 2 cổng độc lập) chỉ phục vụ việc chuyển dữ liệu giữa các node.

Giả sử bạn có 2 node với subnet riêng 10.10.10.0/24 trên card eth1:

  • Node A: 10.10.10.1/24
  • Node B: 10.10.10.2/24

Trên Proxmox VE, bạn cấu hình trực tiếp qua GUI hoặc chỉnh file /etc/pve/datacenter.cfg:

# Khai báo dải mạng riêng cho migration trong file datacenter.cfg
migration: type=secure,network=10.10.10.0/24

Với KVM thuần (libvirt), chỉ định rõ IP migration endpoint:

# Thực hiện live migration trỏ thẳng vào IP dedicated network
virsh migrate --live --verbose \
  --migrateuri tcp://10.10.10.2:49152 \
  my-production-vm qemu+ssh://10.10.10.2/system

Bước 2: Bật nén luồng dữ liệu (ZSTD Compression)

Nén bộ nhớ trước khi đẩy qua mạng giúp giảm từ 30% đến 60% dung lượng thực tế. Tính năng này phát huy tác dụng cực tốt với các VM chứa nhiều RAM rỗng hoặc cache lặp.

Trên Proxmox VE, truy cập Datacenter -> Options -> Migration Settings, chuyển kiểu nén sang ZSTD để cân bằng tối ưu giữa tải CPU và tốc độ nén.

Bước 3: Dùng Post-copy cứu cánh cho các VM tải nặng

Nếu gặp các database có tần suất ghi liên tục (như MySQL, PostgreSQL, Redis) khiến Pre-copy không thể dứt điểm, Post-copy là giải pháp dứt điểm.

Khác với Pre-copy, Post-copy hoạt động như sau:

  1. Chạy Pre-copy một phần dữ liệu cơ bản.
  2. Nếu không hội tụ, hypervisor tạm dừng VM trên Node A và kích hoạt ngay VM bên Node B (downtime chuyển đổi chỉ khoảng vài chục mili-giây).
  3. VM bắt đầu chạy luôn trên Node B. Khi cần đọc trang RAM nào chưa kịp chuyển, Node B sẽ kích hoạt Userfaultfd (Page Fault) qua mạng để kéo trang đó từ Node A sang tức thì.
  4. Node A tiếp tục stream nốt phần RAM còn lại dưới nền cho đến khi xong 100%.

Cách thực hiện trên KVM/libvirt:

# 1. Bắt đầu live migration kèm cờ cho phép post-copy
virsh migrate --live --postcopy --verbose my-database-vm qemu+ssh://10.10.10.2/system

# 2. Sau vài chục giây nếu thấy vòng lặp kéo dài, kích hoạt post-copy ngay:
virsh migrate-postcopy my-database-vm

Việc kết hợp đường mạng Dedicated 10Gbps, thuật toán nén ZSTD và kỹ thuật Post-copy giúp bạn tự tin di chuyển bất kỳ máy ảo dung lượng lớn nào mà không lo sập mạng hay gián đoạn dịch vụ.

Share: