高可用入门:keepalived 双机热备与 VIP 漂移

「高可用」听起来很高级,最基础的实现其实就是一个虚拟 IP 在两台机器之间漂移。理解这个,就理解了大部分 HA 方案的原理。

一、VIP 是什么

两台服务器各有自己的真实 IP(比如 .10 和 .11),再共同持有一个虚拟 IP(VIP).100。

bash
node1  192.168.1.10   (MASTER)
node2  192.168.1.11   (BACKUP)
VIP    192.168.1.100  ← 对外服务的地址,飘在其中一台上

用户只访问 .100。谁持有 VIP,流量就到谁那里。MASTER 挂了,BACKUP 自动接管。

二、VRRP 协议

keepalived 用的是 VRRP:

  • 节点间互相发心跳(组播,协议号 112);
  • 每个节点有优先级,高的成为 MASTER;
  • MASTER 定期广播,BACKUP 收不到就认为它挂了,自己顶上。
bash
# 抓 VRRP 包看心跳
sudo tcpdump -i eth0 vrrp

三、最小配置

bash
sudo apt install -y keepalived

MASTER 节点 /etc/keepalived/keepalived.conf

nginx
global_defs {
    router_id LVS_01
    script_user root
    enable_script_security
}

# 健康检查脚本:检测本机 Nginx 是否活着
vrrp_script chk_nginx {
    script "/etc/keepalived/check_nginx.sh"
    interval 2
    weight -20
    fall 2
    rise 1
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51        # 同一组必须一致,0-255
    priority 100                # MASTER 高一些
    advert_int 1                # 心跳间隔秒

    authentication {
        auth_type PASS
        auth_pass 1111
    }

    virtual_ipaddress {
        192.168.1.100/24 dev eth0
    }

    track_script {
        chk_nginx
    }
}

BACKUP 节点:只有三处不同

nginx
    router_id LVS_02
    state BACKUP
    priority 90                 # 比 MASTER 低

健康检查脚本:

bash
# /etc/keepalived/check_nginx.sh
#!/usr/bin/env bash
if ! pgrep -x nginx > /dev/null; then
    systemctl start nginx
    sleep 2
    if ! pgrep -x nginx > /dev/null; then
        exit 1      # 起不来,让 VIP 漂走
    fi
fi
exit 0
bash
chmod +x /etc/keepalived/check_nginx.sh
sudo systemctl enable --now keepalived

# 看 VIP 在谁身上
ip a | grep 192.168.1.100

四、测试故障切换

bash
# 在 BACKUP 上盯日志
sudo journalctl -u keepalived -f

# 停掉 MASTER 的 nginx
sudo systemctl stop nginx
# 2 秒后应该看到 VIP 漂到 BACKUP

# 或者直接停 keepalived / 关机
sudo systemctl stop keepalived

五、抢占与非抢占

模式配置行为
抢占(默认)state MASTERMASTER 恢复后抢回 VIP
非抢占nopreempt + 双 BACKUP当前持有者继续持有,不来回切
nginx
vrrp_instance VI_1 {
    state BACKUP        # 两边都设 BACKUP
    nopreempt           # 不抢占
    priority 100
}

生产环境推荐非抢占。抢占会造成一次额外的抖动,如果 MASTER 反复出问题,VIP 会来回漂,服务反而更不稳定。

六、脑裂(Split Brain)

心跳线断了但两台都活着 → 两台都认为自己是 MASTER → 都持有 VIP → 网络冲突。

防范措施:

  1. 双心跳链路(网络 + 串口/第二条网线);
  2. 监控告警:检测到两台都持有 VIP 立刻报警;
  3. unicast_src_ip / unicast_peer 替代组播(云环境组播常被禁):
nginx
    unicast_src_ip 192.168.1.10
    unicast_peer {
        192.168.1.11
    }
  1. 脚本里加「能否访问网关」的判断,防止自己网络断了还抢 VIP。

七、云环境要注意

平台说明
阿里云不支持普通 VRRP,需用「高可用虚拟 IP」产品
腾讯云类似,要用「HAVIP」
AWS用 Elastic IP + 脚本切换,或直接用 ELB
自建/机房/VMwareVRRP 正常可用

大多数云平台禁用了组播和 ARP 欺骗,keepalived 直接跑不生效。云上更简单的做法是用云厂商的负载均衡器,把两台机器挂到后面。

八、还有别的方案吗

方案层级特点
keepalived + VIP网络层简单,切换快
云负载均衡平台层最省事,但要花钱
Nginx/HAProxy 多节点 + DNS 轮询应用层简单但切换慢(受 TTL 影响)
Pacemaker + Corosync集群层功能强,复杂

九、个人项目要不要做

我的真实看法:基本不需要。

理由:

  • 单点故障的概率远低于「配置错误导致故障」的概率;
  • 两台机器的成本翻倍,运维复杂度也翻倍;
  • 静态站挂 CDN 后,源站短暂不可用影响很小;
  • 真要高可用,用云负载均衡 + 两台后端,比自己搞 keepalived 省心。

值得做的场景:

  • 有明确的可用性要求(比如对外的 API 服务);
  • 已经有两台机器在跑;
  • 想练手(那就练,反正也不贵)。
bash
# 如果只是为了「机器挂了能自动恢复」,更简单的办法是:
# systemd Restart=always + 云厂商的自动重启/告警

高可用的本质是消除单点。先想清楚单点在哪——很多时候瓶颈不在服务器,而在你只有一份没备份的数据。