Skip to content

Keepalived-脑裂

什么是脑裂?

在高可用(HA)系统中,当主备节点之间的心跳线断开时,双方无法检测到对方状态,均认为自身是主节点,导致系统分裂为两个独立部分。此时:

  • 双方可能同时抢占共享资源(如VIP),造成服务冲突。
  • 若涉及有状态服务(如数据库),可能导致数据损坏(如双写冲突)

脑裂产生的原因

  1. 网络问题

    • 心跳线故障(断线、老化、网卡/交换机故障)。
    • 防火墙阻挡VRRP协议(如未放行组播地址 224.0.0.18)。
    • 网卡配置错误或IP冲突。
  2. 配置错误

    • 主备节点 virtual_router_id 不一致。
    • 心跳间隔(advert_int)或超时时间设置不合理。
  3. 其他因素

    • 仲裁节点故障(若使用第三方仲裁)。
    • Keepalived软件Bug或资源竞争。

脑裂的解决方案

冗余心跳线路

  • 同时使用以太网和串行电缆,避免单点故障。

配置优化

  • 确保主备节点 virtual_router_idauth_pass 一致。
  • 启用非抢占模式(nopreempt),避免主节点恢复后重新抢占VIP。

第三方仲裁

通过脚本定期检测网关或参考IP,若无法连通则自动降级或重启Keepalived:

bash
#!/bin/bash
# 双检测仲裁脚本(业务端口+网关)
VIP="192.168.1.100"
GATEWAY="192.168.1.1"
PORT=80                              # 业务服务端口
FAIL_COUNT_THRESHOLD=3
LOG_FILE="/var/log/keepalived_arbiter.log"

check_service() {
    # 检测本地业务端口是否活跃
    if ! nc -z localhost $PORT &>/dev/null; then
        return 1
    fi
    return 0
}

check_gateway() {
    if ! ping -c 2 -W 3 $GATEWAY &>/dev/null; then
        return 1
    fi
    return 0
}

LOG_FILE="/var/log/check_nginx.log"
function log() {
  local level="${2:-INFO}" # 默认日志级别
  echo "[$(date '+%F %T')] [$level] $1" | tee -a "$LOG_FILE"
}

if ip addr show eth0 | grep -q $VIP; then
    FAIL_COUNT=0
    while [ $FAIL_COUNT -lt $FAIL_COUNT_THRESHOLD ]; do
        if ! check_gateway || ! check_service; then
            FAIL_COUNT=$((FAIL_COUNT + 1))
            log "检测失败: 网关或端口不可达 (次数: $FAIL_COUNT)" "ERROR"
        else
            break
        fi
        sleep 5
    done

    if [ $FAIL_COUNT -ge $FAIL_COUNT_THRESHOLD ]; then
        log "仲裁生效: 停止Keepalived"
        systemctl stop keepalived
    fi
fi