High Availability với Keepalived trên Linux: Virtual IP và Tự động hóa Failover

Linux tutorial - IT technology blog
Linux tutorial - IT technology blog

Chiến lược High Availability: Keepalived so với Pacemaker và DNS Failover

Đó là lúc 2:15 sáng ngày thứ Ba khi chuông PagerDuty reo lên. Một lỗi kernel panic đã làm treo hoàn toàn proxy Nginx chính, làm rớt 1.200 kết nối đang hoạt động và khiến toàn bộ lưu lượng truy cập rơi vào vô định. Vào thời điểm ấy, cơ chế tự động failover tạo nên sự khác biệt hoàn toàn: nó quyết định liệu bạn xử lý xong sự cố trong vòng 5 giây hay phải mất 2 giờ tiếp theo để gồng mình giải quyết hàng loạt ticket của khách hàng. Các đội ngũ vận hành production thường lựa chọn giữa 3 phương pháp:

  • Keepalived (VRRP – Virtual Router Redundancy Protocol): Hai hoặc nhiều node cùng chia sẻ một floating Virtual IP (VIP) duy nhất. Một node đóng vai trò MASTER và phản hồi các yêu cầu ARP. Trong khi đó, node BACKUP sẽ theo dõi các gói tin VRRP multicast heartbeat định kỳ mỗi 1.000 ms. Nếu các heartbeat này dừng lại hoặc health check tùy chỉnh thất bại, node backup sẽ tiếp quản VIP ngay lập tức.
  • Pacemaker + Corosync: Bộ giải pháp clustering hạng nặng được thiết kế cho các mô hình tài nguyên phức tạp, thiết bị lưu trữ dạng khối dùng chung (DRBD) và cơ chế cô lập node STONITH. Bộ công cụ này điều phối failover cho nhiều dịch vụ có trạng thái (stateful) trên hàng chục máy chủ.
  • DNS-Based Failover: Các probe giám sát tổng hợp từ bên ngoài theo dõi tình trạng endpoint và cập nhật lại bản ghi DNS A/AAAA qua API mỗi khi origin server bị offline.

Ưu và nhược điểm: Lựa chọn lớp Failover phù hợp

Các quyết định kiến trúc luôn đi kèm với những đánh đổi rõ rệt khi từng mili-giây đều mang tính quyết định:

  • Keepalived
    • Ưu điểm: Cực kỳ nhẹ. Tiêu tốn chưa tới 15MB RAM và lượng tài nguyên CPU không đáng kể. Quá trình failover diễn ra chỉ trong 1 đến 2 giây ở Layer 3/4 mà không cần cấu hình lại phía client, cùng file cấu hình gọn gàng, dễ đọc.
    • Nhược điểm: Cả hai node phải nằm trong cùng một broadcast domain Layer 2 (cùng VLAN hoặc subnet), trừ khi bạn cấu hình unicast peer tường minh. Ngoài ra, công cụ này không hỗ trợ điều phối mặc định cho các dịch vụ phụ thuộc đa tầng.
  • Pacemaker + Corosync
    • Ưu điểm: Hỗ trợ cluster active-active, kiểm soát thứ tự khởi động chặt chẽ, khóa lưu trữ dùng chung và cơ chế hardware fencing giúp triệt tiêu hoàn toàn hiện tượng split-brain.
    • Nhược điểm: Cực kỳ phức tạp để làm quen và tiêu tốn nhiều bộ nhớ. Chỉ một lỗi cấu hình nhỏ trong topology fencing cũng có thể khiến máy chủ của bạn rơi vào vòng lặp khởi động lại vô tận.
  • DNS Failover
    • Ưu điểm: Hoạt động trên phạm vi toàn cầu qua nhiều nền tảng đám mây, khu vực và hệ thống mạng định tuyến khác nhau mà không bị giới hạn bởi subnet.
    • Nhược điểm: Bị ảnh hưởng nặng nề bởi bộ nhớ đệm (caching) của DNS resolver phía client. Ngay cả khi đặt TTL 30 giây, các resolver của ISP phía trên thường bỏ qua thời hạn này. Lưu lượng truy cập có thể vẫn tiếp tục đổ về IP đã chết suốt 10 đến 15 phút.

Mô hình khuyến nghị: Cặp Active-Passive với Floating VIP

Đối với reverse proxy và load balancer như HAProxy hay Nginx, mô hình active-passive với Keepalived là lựa chọn tối ưu nhất. Trên một cụm thử nghiệm gồm hai máy ảo Ubuntu 22.04 (2 vCPU, 4GB RAM), mô hình này đã xử lý failover trọn vẹn chỉ trong 1,4 giây. Quan trọng hơn, nó đạt được điều đó mà không gây ra những cơn đau đầu về quản lý trạng thái phân tán vốn có ở các bộ clustering phức tạp hơn.

Mô hình triển khai production của chúng tôi hướng tới topology chuẩn sau:

  • Virtual IP (Floating VIP): 192.168.10.100
  • Node 1 (Primary – MASTER): 192.168.10.11 trên interface eth0
  • Node 2 (Secondary – BACKUP): 192.168.10.12 trên interface eth0
  • Workload: Nginx lắng nghe trên port 80 và 443 ở cả hai node

Hướng dẫn triển khai: Xây dựng cụm High Availability

Bước 1: Cho phép Non-Local IP Binding

Theo mặc định, Linux kernel ngăn các tiến trình bind vào socket trên những địa chỉ IP chưa được gán cho bất kỳ interface đang hoạt động nào. Vì floating VIP chỉ nằm trên một máy chủ tại một thời điểm nhất định, node phụ sẽ không thể khởi động Nginx khi boot hệ thống nếu thiếu tùy chỉnh này.

Chạy các lệnh sau trên cả hai Node 1 và Node 2:

echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee -a /etc/sysctl.d/99-keepalived.conf
sudo sysctl --system

Bước 2: Cài đặt Keepalived

Cài đặt gói Keepalived bằng trình quản lý gói mặc định của bản phân phối bạn đang dùng:

# Trên Ubuntu / Debian
sudo apt update && sudo apt install -y keepalived

# Trên RHEL / AlmaLinux / Rocky Linux 9
sudo dnf install -y keepalived

Bước 3: Tạo script Health Check cho ứng dụng

Tuyệt đối không nên chỉ phụ thuộc vào heartbeat ở tầng mạng. Một máy chủ vẫn có thể gửi các gói tin VRRP bình thường trong khi dịch vụ web bên dưới đã bị treo do worker deadlock không thể phục hồi. Chúng ta cần một script health check để xác nhận Nginx phản hồi các request cục bộ với status code hợp lệ trong vòng 2 giây.

Triển khai file /usr/local/bin/check_service.sh trên cả hai node:

sudo tee /usr/local/bin/check_service.sh << 'EOF'
#!/usr/bin/env bash
set -euo pipefail

# Kiểm tra HTTP endpoint cục bộ với timeout nghiêm ngặt 2 giây
if curl -sf --max-time 2 http://127.0.0.1:80/ > /dev/null; then
    exit 0
else
    exit 1
fi
EOF

sudo chmod 755 /usr/local/bin/check_service.sh

Bước 4: Cấu hình Node chính (MASTER)

Trên Node 1 (192.168.10.11), tiến hành tạo file cấu hình chính cho daemon. Chúng ta thiết lập độ ưu tiên ban đầu (priority) là 101 và gán trọng số âm -30 cho script health check. Nếu 2 lần kiểm tra liên tiếp thất bại, độ ưu tiên thực tế của Node 1 sẽ giảm từ 101 xuống 71, thấp hơn mức ưu tiên cơ sở 90 của Node 2.

sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
    router_id lb-node-01
    script_user root
    enable_script_security
}

vrrp_script chk_web {
    script "/usr/local/bin/check_service.sh"
    interval 2
    weight -30
    fall 2
    rise 2
}

vrrp_instance VI_PROD {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 101
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass VrrpS3cur3Key
    }

    virtual_ipaddress {
        192.168.10.100/24 dev eth0 label eth0:vip
    }

    track_script {
        chk_web
    }
}
EOF

Bước 5: Cấu hình Node phụ (BACKUP)

Chuyển sang Node 2 (192.168.10.12). Lưu ý cấu hình tại đây sử dụng state BACKUP và đặt độ ưu tiên cơ sở là 90:

sudo tee /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
    router_id lb-node-02
    script_user root
    enable_script_security
}

vrrp_script chk_web {
    script "/usr/local/bin/check_service.sh"
    interval 2
    weight -30
    fall 2
    rise 2
}

vrrp_instance VI_PROD {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass VrrpS3cur3Key
    }

    virtual_ipaddress {
        192.168.10.100/24 dev eth0 label eth0:vip
    }

    track_script {
        chk_web
    }
}
EOF

Bước 6: Cấu hình Firewall và khởi động dịch vụ

Keepalived điều phối thông qua VRRP (IP protocol 112), chứ không dùng các port TCP hay UDP thông thường. Nếu firewall chặn giao thức này, hai node sẽ không thấy nhau. Mỗi node sẽ tự nhận là master và cùng bind vào VIP, dẫn tới hiện tượng xung đột gói tin split-brain nghiêm trọng.

Mở giao thức này và kích hoạt dịch vụ trên cả hai node:

# UFW (Ubuntu / Debian)
sudo ufw allow in on eth0 proto 112

# Firewalld (RHEL / AlmaLinux)
sudo firewall-cmd --add-protocol=vrrp --permanent
sudo firewall-cmd --reload

# Tải lại cấu hình systemd và khởi chạy daemon
sudo systemctl daemon-reload
sudo systemctl enable --now keepalived

Bước 7: Kiểm tra VIP Binding và thử nghiệm Failover

Kiểm tra cấu hình mạng trên Node 1:

ip addr show dev eth0

Kết quả đầu ra sẽ hiển thị 192.168.10.100/24 bên cạnh IP chính của máy. Kiểm tra trên Node 2 sẽ chỉ thấy 192.168.10.12.

Bây giờ, hãy thử nghiệm cơ chế failover bằng cách dừng web server trên Node 1:

# Trên Node 1
sudo systemctl stop nginx

Trong vòng 4 giây (tương ứng 2 lần health check thất bại cách nhau 2 giây), hãy kiểm tra log trên Node 2:

sudo journalctl -u keepalived -n 25 --no-pager

Bạn sẽ thấy Keepalived chuyển trạng thái Node 2 từ BACKUP sang MASTER, tiếp theo là thông báo gửi các khung gratuitous ARP để cập nhật bảng định tuyến trên upstream switch. Các lệnh kiểm tra HTTP liên tục tới 192.168.10.100 sẽ chỉ ghi nhận 1 đến 2 packet bị rớt trước khi lưu lượng được phục hồi bình thường.

Share: