基于 VRRP 协议的高可用解决方案 | 版本 2.3.x | 双节点主备 + 多实例架构
一、什么是 Keepalived
1.1 概述
Keepalived 是一个基于 VRRP(Virtual Router Redundancy Protocol,虚拟路由冗余协议) 实现的高可用(HA)软件。它的核心使命是:通过在多台服务器之间共享一个虚拟 IP(VIP),当主节点故障时自动将 VIP 漂移到备用节点,从而保证服务的连续性。
Keepalived 最初是为 LVS(Linux Virtual Server)负载均衡器设计的高可用守护进程,但因其轻量、可靠、配置简单,现已被广泛用于各种需要 IP 高可用的场景。它通过 VRRP 协议实现 IP 故障转移,通过健康检查脚本实现对后端服务的存活检测。

1.2 核心功能
| VRRP 协议实现 | |
| VIP 故障转移 | |
| 健康检查 | |
| LVS 集成 | |
| 多实例支持 | |
| 通知机制 | |
| SMTP 告警 | |
| SNMP 支持 | |
| IPv4/IPv6 双栈 |
1.3 适用场景
| Nginx/HAProxy 高可用 | |
| LVS 负载均衡高可用 | |
| MySQL/MariaDB 高可用 | |
| 网关 / 路由器高可用 | |
| K8s MetalLB 替代 | |
| Redis / RabbitMQ / Kafka VIP |
1.4 与竞品对比
1.5 为什么选择 Keepalived
- 极轻量:
纯 C 语言编写,内存占用通常 < 50MB,CPU 开销可忽略不计 - 零依赖:
不依赖共享存储、不依赖第三方协调服务(如 ZooKeeper/etcd),两节点即可工作 - 毫秒级切换:
在优化的配置下,故障检测+VIP 漂移可在 1-3 秒内完成 - 成熟稳定:
发展超过 20 年,被全球数百万生产环境验证 - 配置简单:
一个 keepalived.conf 文件即可完成全部配置,学习成本极低
📌 Keepalived 的核心定位
Keepalived 解决的是 IP 层面的高可用,即 VIP 的故障转移。它不负责数据同步(如文件/数据库/缓存同步),数据层面的高可用需要配合其他方案(如 Rsync/DRBD/主从复制)实现。
二、基本原理与架构
2.1 VRRP 协议核心原理
VRRP(Virtual Router Redundancy Protocol) 是 IETF 标准协议(RFC 3768),核心思想是将多台物理路由器组成一个虚拟路由器,对外暴露一个虚拟 IP(VIP)和虚拟 MAC 地址。虚拟路由器内部通过选举产生一台 Master,由 Master 实际处理发往 VIP 的流量。
核心概念表:
| VRRP 实例(Instance) | |
| 虚拟路由器 ID(VRID) | |
| 虚拟 IP(VIP) | |
| 虚拟 MAC 地址 | 00-00-5E-00-01-{VRID}(VRRPv2),Master 响应该 MAC 的 ARP 请求 |
| Priority(优先级) | |
| Advertisement_Interval | |
| Preempt(抢占模式) | |
| Gratuitous ARP |
2.2 VRRP 状态机
每个 VRRP 实例中的节点处于以下三种状态之一:
🔵 MASTER 状态:
持有 VIP 和虚拟 MAC 地址 响应发往 VIP 的 ARP 请求 定期(每 Advert_Int)向 224.0.0.18 组播 VRRP 通告 执行健康检查脚本
🟡 BACKUP 状态:
不持有 VIP 持续监听 VRRP 组播通告 执行健康检查脚本(为接管做准备) 超过 Master_Down_Interval(3×Advert_Int + skew_time)无通告 → 发起选举
🔴 INIT 状态:
启动时的过渡状态,等待事件触发进入 BACKUP
2.3 选举流程
所有节点以 BACKUP 状态启动,等待 Master 通告 超时未收到通告 → 节点将自己的 Priority 与收到的通告中的 Priority 比较 本机 Priority 最高 → 切换到 MASTER 状态,发送 Gratuitous ARP,开始发送 VRRP 通告 收到更高 Priority 节点的通告 → 退回到 BACKUP 状态 如果开启了 Preempt(抢占模式),高 Priority 节点恢复后会自动夺回 Master 健康检查脚本失败 → Priority 降低(track_script 减分),可能触发主备切换
2.4 健康检查机制
Keepalived 支持多种健康检查器,用于检测后端服务的存活状态:
| TCP_CHECK | ||
| HTTP_GET | ||
| SSL_GET | ||
| MISC_CHECK | ||
| SMTP_CHECK | ||
| DNS_CHECK |
2.5 Keepalived 内部架构
┌─────────────────────────────────────────────────────────┐│ Keepalived Core ││ (主进程 + 子进程 fork) │└──────┬────────────────┬──────────────────┬──────────────┘│ │ │┌────▼─────┐ ┌─────▼──────┐ ┌──────▼──────┐│ VRRP │ │ Health │ │ System ││ Stack │ │ Checkers │ │ Services │├──────────┤ ├────────────┤ ├─────────────┤│VRRPv2/v3 │ │TCP_CHECK │ │IPVS Wrapper ││状态机 │ │HTTP_GET │ │SMTP 告警 ││通告收发 │ │SSL_GET │ │SNMP Agent ││GARP发送 │ │MISC_CHECK │ │Notify 脚本 │└────┬─────┘ └─────┬──────┘ └──────┬──────┘│ │ │└────────────────┼──────────────────┘│┌────────────────▼──────────────────┐│ Linux Kernel ││ Netlink / Raw Socket / IPVS ││ IP管理 · ARP表 · 路由表 · Netfilter│└────────────────┬──────────────────┘│┌────────────────▼──────────────────┐│ 物理网络接口 (eth0 / bond0) ││ VRRP 组播 224.0.0.18 或单播通信 │└───────────────────────────────────┘
2.6 故障切换流程(Nginx + Keepalived 典型场景)
Master 节点 Nginx 进程崩溃后的完整切换时序:
| T+0s | |
| T+2s | chk_nginx 检测失败(检测间隔 2s) |
| T+2s | |
| T+2s | |
| T+2s | |
| T+2s | |
| T+3s | |
| T+3s |
⚠️ 故障切换时间分析
总切换时间 = 健康检查间隔 + 通告超时检测时间(3×Advert_Int + skew_time)+ 抢占处理时间。优化后通常可控制在 1-3 秒。如需更快(毫秒级),需要使用 BFD(双向转发检测)等方案。
三、服务部署详细步骤
3.1 集群规划
| MASTER | |||||
| BACKUP | |||||
| 192.168.1.100 |
3.2 环境准备(所有节点)
Step 1: 系统依赖安装
# CentOS / Rocky Linux / RHELyum install -y gcc make autoconf automake openssl-devel libnl3-devel \net-snmp-devel libnfnetlink-devel ipset-devel iptables-devel \pkgconfig curl wget vim net-tools# Ubuntu / Debianapt-get install -y build-essential autoconf automake libssl-dev \libnl-3-dev libnl-genl-3-dev libsnmp-dev libnfnetlink-dev \pkg-config curl wget vim net-tools
Step 2: 关闭 SELinux(或正确配置策略)
# 临时关闭setenforce 0# 永久关闭sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config# 或者保持 SELinux 开启并配置策略(推荐):# setsebool -P keepalived_use_nfs 1
Step 3: 配置防火墙规则
# VRRP 使用协议号 112(非端口),需要放行 VRRP 协议firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'firewall-cmd --reload# 或者使用 iptablesiptables -A INPUT -p vrrp -j ACCEPTiptables-save > /etc/sysconfig/iptables
Step 4: 内核参数优化
cat >> /etc/sysctl.conf << 'EOF'# -------------------- Keepalived 网络优化 --------------------# 允许绑定非本地 IP 地址(VIP 绑定需要)net.ipv4.ip_nonlocal_bind = 1# 开启 IP 转发(作为网关/LVS 时需要)net.ipv4.ip_forward = 1# ARP 相关优化net.ipv4.conf.all.arp_ignore = 1net.ipv4.conf.all.arp_announce = 2net.ipv4.conf.all.arp_filter = 0# 接收所有组播包(VRRP 组播通信需要)net.ipv4.conf.all.rp_filter = 0net.ipv4.conf.default.rp_filter = 0# TCP 优化net.core.somaxconn = 65535net.ipv4.tcp_max_syn_backlog = 65535net.core.netdev_max_backlog = 65535EOFsysctl -p
3.3 安装方式一:YUM/DNF 安装(推荐生产环境)
# CentOS 7/8 / Rocky Linux 8/9yum install -y keepalived# 或者从 EPEL 仓库安装最新版yum install -y epel-releaseyum install -y keepalived# 验证安装keepalived --version# Keepalived v2.2.8 (02/26,2024)# 备份默认配置cp /etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf.bak
3.4 安装方式二:源码编译安装
# 下载源码cd /usr/local/srcwget https://keepalived.org/software/keepalived-2.3.1.tar.gztar -xzf keepalived-2.3.1.tar.gzcd keepalived-2.3.1# 配置编译选项./configure --prefix=/usr/local/keepalived \--sysconfdir=/etc \--with-init=systemd \--enable-snmp \--enable-snmp-rfc \--enable-dbus \--enable-json# 编译安装make -jMAINPIDRestart=on-failureRestartSec=10sKillMode=process[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reload# 验证安装keepalived --version
3.5 安装方式三:Docker 容器化部署
# 拉取镜像(使用 osixia/keepalived 或自行构建)docker pull osixia/keepalived:2.3.0# 创建配置目录mkdir -p /opt/keepalived/conf# 编写 keepalived.conf(内容见 3.6 节)# 启动容器 - Node 1 (MASTER)docker run -d --name keepalived \--restart=always \--net=host \--cap-add=NET_ADMIN \--cap-add=NET_BROADCAST \--cap-add=NET_RAW \-v /opt/keepalived/conf/keepalived.conf:/usr/local/etc/keepalived/keepalived.conf:ro \osixia/keepalived:2.3.0
💡 安装方式选择建议
- 生产环境:
推荐 YUM/DNF 安装,版本稳定且与系统集成好 - 需要最新功能:
源码编译安装,可自定义模块和编译选项 - 容器化场景:
Docker 部署,但必须使用 --net=host模式- K8s 场景:
建议使用 MetalLB(Layer2 模式底层就是 VRRP),而非直接容器化 Keepalived
3.6 主配置文件 keepalived.conf 详解(Node 1 — MASTER)
################################################################################ Keepalived 主配置文件 — Node 1 (MASTER)# 路径: /etc/keepalived/keepalived.conf###############################################################################! Configuration File for keepalived# ========================= 全局定义 =========================global_defs {# 邮件告警通知(可选)notification_email {ops@example.com # 接收告警的邮箱admin@example.com}notification_email_from keepalived@node01.example.comsmtp_server 127.0.0.1 # 本地 SMTP 服务器smtp_connect_timeout 30router_id KA-NODE01 # 标识本机,建议用主机名,全局唯一vrrp_skip_check_adv_addr # 跳过检查 VRRP 通告中的源地址# vrrp_strict # 严格模式(开启后会添加 iptables 规则,慎用)vrrp_garp_interval 0 # 免费 ARP 发送间隔(0=无间隔)vrrp_gna_interval 0 # 免费 NA(IPv6)发送间隔vrrp_mcast_group4 224.0.0.18 # VRRP IPv4 组播地址(默认值)vrrp_iptables # 自动添加 iptables 放行规则(可选)script_user root # 执行脚本的用户enable_script_security # 启用脚本安全检查# enable_traps # 启用 SNMP traps(需 --enable-snmp 编译)}# ========================= 健康检查脚本 =========================vrrp_script chk_nginx {script "/etc/keepalived/scripts/chk_nginx.sh" # 检查脚本路径interval 2 # 检测间隔(秒)timeout 3 # 脚本执行超时(秒)rise 2 # 连续成功 N 次认为恢复fall 3 # 连续失败 N 次判定故障weight -30 # 失败后降低的优先级(减分模式)}vrrp_script chk_app_port {script "/etc/keepalived/scripts/chk_port.sh 8080"interval 5timeout 3rise 2fall 3weight -20}# ========================= VRRP 实例 =========================vrrp_instance VI_1 {state MASTER # 初始状态:MASTER 或 BACKUPinterface eth0 # 绑定网卡virtual_router_id 51 # VRRP 实例 ID (1-255),同一实例必须相同priority 100 # 优先级 (0-255),MASTER 应设最高advert_int 1 # VRRP 通告间隔(秒),默认为 1# ===== 认证配置 =====authentication {auth_type PASS # PASS(简单密码)或 AH(IPSec 认证头)auth_pass KEEPALIVED@2024 # 最长 8 字符的密码}# ===== 虚拟 IP =====virtual_ipaddress {192.168.1.100/24 dev eth0 label eth0:vip1# 多个 VIP 示例:# 192.168.1.101/24 dev eth0 label eth0:vip2# 2001:db8::100/64 dev eth0 # IPv6 VIP}# ===== 关联健康检查 =====track_script {chk_nginx # 引用上面定义的 vrrp_scriptchk_app_port}# ===== 状态切换通知脚本 =====notify_master "/etc/keepalived/scripts/notify.sh MASTER"notify_backup "/etc/keepalived/scripts/notify.sh BACKUP"notify_fault "/etc/keepalived/scripts/notify.sh FAULT"notify_stop "/etc/keepalived/scripts/notify.sh STOP"# ===== 抢占模式 =====preempt_delay 60 # 抢占延迟(秒),恢复后等待 N 秒再抢占# 不抢占则使用: nopreempt# ===== 单播模式(用于不支持组播的网络)=====# unicast_src_ip 192.168.1.11# unicast_peer {# 192.168.1.12# }# ===== 不依赖接口的跟踪(VIP 存活检测增强)=====# use_vmac # 使用虚拟 MAC 地址# vmac_xmit_base # 基于物理接口发送 VMAC 流量}
3.7 Node 2 — BACKUP 节点配置
Node 2 与 Node 1 的差异仅在于三个参数:
global_defs {router_id KA-NODE02 # 🔴 改为本机标识# ... 其余与 Node 1 相同 ...}vrrp_instance VI_1 {state BACKUP # 🔴 改为 BACKUPinterface eth0virtual_router_id 51priority 90 # 🔴 改为 90(低于 Master 的 100)advert_int 1authentication {auth_type PASSauth_pass KEEPALIVED@2024}virtual_ipaddress {192.168.1.100/24 dev eth0 label eth0:vip1}track_script {chk_nginxchk_app_port}notify_master "/etc/keepalived/scripts/notify.sh MASTER"notify_backup "/etc/keepalived/scripts/notify.sh BACKUP"notify_fault "/etc/keepalived/scripts/notify.sh FAULT"notify_stop "/etc/keepalived/scripts/notify.sh STOP"}
3.8 健康检查脚本示例
Nginx 进程检测脚本
# /etc/keepalived/scripts/chk_nginx.sh#!/bin/bash# 检测 nginx 进程是否存在if systemctl is-active --quiet nginx; thenexit 0 # 正常else# 尝试重启一次systemctl restart nginx 2>/dev/nullsleep 1if systemctl is-active --quiet nginx; thenexit 0elseexit 1 # 失败fifi
TCP 端口检测脚本
# /etc/keepalived/scripts/chk_port.sh#!/bin/bash# 用法: chk_port.sh <端口号>PORT=HOST/? -eq 0 ]; thenexit 0elseexit 1fi
状态通知脚本
# /etc/keepalived/scripts/notify.sh#!/bin/bash# 用法: notify.sh <STATE>STATE=(hostname)mkdir -p /var/log/keepalivedcase "(date'+%Y-%m-%d %H:%M:%S') [VIP" >> (date '+%Y-%m-%d %H:%M:%S') [LOGFILE# 可选:停止后端服务避免双主# systemctl stop nginx;;FAULT)echo "HOSTNAME] FAULT state entered">>(date'+%Y-%m-%d %H:%M:%S') [LOGFILE;;esacexit 0
设置脚本权限
chmod 755 /etc/keepalived/scripts/*.shchown root:root /etc/keepalived/scripts/*.sh
3.9 启动与验证
# ==== 1. 启动 Keepalived(两个节点分别执行)====systemctl start keepalivedsystemctl enable keepalived# 查看状态systemctl status keepalived# ==== 2. 验证 VIP 绑定 ====# 在 Node 1 (MASTER) 上查看 VIP 是否已绑定ip addr show eth0# 应能看到: inet 192.168.1.100/24 scope global secondary eth0:vip1# ==== 3. 验证 ARP 表 ====# 从客户端 ping VIPping -c 4 192.168.1.100# 查看 ARP 表,确认 VIP 对应的 MACarp -a | grep 192.168.1.100# VRRPv2 时虚拟 MAC 格式: 00:00:5e:00:01:33 (33 = VRID 51 的十六进制)# ==== 4. 查看日志 ====journalctl -u keepalived -f# 或者tail -f /var/log/messages | grep -i keepalived# ==== 5. 故障切换测试 ====# 在 Node 1 (MASTER) 上手动停止 Keepalivedsystemctl stop keepalived# 在 Node 2 (BACKUP) 上立即查看 VIP 是否已接管ip addr show eth0# 应能看到: inet 192.168.1.100/24 scope global secondary eth0:vip1# 查看日志确认切换journalctl -u keepalived --since "1 min ago" | grep -E "MASTER|BACKUP"# 恢复 Node 1systemctl start keepalived# 由于设置了 preempt_delay 60,Node 1 将在 60 秒后抢回 Master
3.10 双主(Active-Active)模式配置
双主模式下,两台机器互为热备,各自承载不同的 VIP 组,充分利用两台机器的资源。
################################################################################ 双主模式配置 — Node 1###############################################################################global_defs {router_id KA-NODE01}# ===== VIP 组 1: Node1 为 Master, Node2 为 Backup =====vrrp_instance VI_NGINX_A {state MASTERinterface eth0virtual_router_id 51priority 100advert_int 1authentication {auth_type PASSauth_pass VIP_A_PWD}virtual_ipaddress {192.168.1.100/24 dev eth0 label eth0:nginx_a}track_script {chk_nginx}}# ===== VIP 组 2: Node1 为 Backup, Node2 为 Master =====vrrp_instance VI_NGINX_B {state BACKUPinterface eth0virtual_router_id 52 # 🔴 不同 VRIDpriority 90 # 🔴 较低优先级advert_int 1authentication {auth_type PASSauth_pass VIP_B_PWD # 🔴 不同密码更安全}virtual_ipaddress {192.168.1.101/24 dev eth0 label eth0:nginx_b}track_script {chk_nginx}}
Node 2 的配置与 Node 1 互换 state 和 priority 即可。DNS 轮询或上游 LB 将流量分发到两个 VIP,任一节点故障时,另一节点接管全部流量。
3.11 单播模式配置(不支持组播的网络环境)
📌 何时使用单播模式
公有云环境(AWS/Azure/阿里云/腾讯云等)通常不支持 VRRP 组播报文(224.0.0.18)。此时需要改用单播模式,通过已知的对端 IP 直连发送 VRRP 通告。
# Node 1 单播模式配置vrrp_instance VI_1 {state MASTERinterface eth0virtual_router_id 51priority 100advert_int 1# ===== 单播模式 =====unicast_src_ip 192.168.1.11 # 本机 IPunicast_peer {192.168.1.12 # 对端 IP(可多个)}authentication {auth_type PASSauth_pass KEEPALIVED@2024}virtual_ipaddress {192.168.1.100/24 dev eth0}track_script {chk_nginx}}# Node 2 的 unicast_src_ip 改为 192.168.1.12# unicast_peer 改为 192.168.1.11
四、集群监控
4.1 Keepalived 日志监控
# 查看 Keepalived 实时日志journalctl -u keepalived -f# 过滤关键事件journalctl -u keepalived | grep -E "MASTER|BACKUP|FAULT|Entering|Transition"# 查看 VRRP 状态变化grep -i "vrrp" /var/log/messages | tail -50
4.2 SNMP 监控集成
Keepalived 内置 SNMP Agent(需编译时开启 --enable-snmp),支持通过 SNMP 协议查询 VRRP 实例状态。
# keepalived.conf 中启用 SNMPglobal_defs {enable_traps # 启用 SNMP trapsenable_snmp_vrrp # 启用 VRRP SNMP MIBenable_snmp_checker # 启用 Checker SNMP MIBenable_snmp_rfc # 启用 RFC 标准 MIBenable_snmp_rfcv2 # 启用 RFCv2 MIBenable_snmp_rfcv3 # 启用 RFCv3 MIBsnmp_socket udp:127.0.0.1:161}# 安装 SNMP 工具进行查询测试yum install -y net-snmp-utils# 查询 Keepalived MIBsnmpwalk -v2c -c public localhost KEEPALIVED-MIB::vrrpInstanceTable
4.3 Prometheus + Grafana 监控方案
方案一:使用 keepalived-exporter(推荐)
# 下载 keepalived-exportercd /optwget https://github.com/cafebazaar/keepalived-exporter/releases/download/v1.5.0/keepalived-exporter-1.5.0.linux-amd64.tar.gztar -xzf keepalived-exporter-1.5.0.linux-amd64.tar.gzmv keepalived-exporter-1.5.0.linux-amd64 /opt/keepalived-exporter# 创建 systemd 服务cat > /etc/systemd/system/keepalived-exporter.service << 'EOF'[Unit]Description=Keepalived Prometheus ExporterAfter=network.target keepalived.service[Service]Type=simpleUser=nobodyExecStart=/opt/keepalived-exporter/keepalived-exporter \--web.listen-address=:9165 \--keepalived.pid-file=/var/run/keepalived.pid \--keepalived.stats-file=/tmp/keepalived.stats \--keepalived.json-file=/tmp/keepalived.jsonRestart=on-failureRestartSec=5s[Install]WantedBy=multi-user.targetEOFsystemctl daemon-reloadsystemctl enable --now keepalived-exporter
方案二:自建监控脚本(Prometheus textfile 格式)
#!/bin/bash# /etc/keepalived/scripts/monitor.sh# 通过 crontab 定时执行,输出 Prometheus textfile 格式指标METRICS_FILE="/var/lib/node_exporter/textfile_collector/keepalived.prom"VIP="192.168.1.100"VRRP_STATE=2 # 0=INIT, 1=BACKUP, 2=MASTER, 3=FAULTif ip addr show | grep -q "(pgrep -f"keepalived"|head-1)if [ -z "(dirname METRICS_FILE << EOF# HELP keepalived_vrrp_state VRRP instance state (0=INIT,1=BACKUP,2=MASTER,3=FAULT)# TYPE keepalived_vrrp_state gaugekeepalived_vrrp_state{instance="VI_1",vip="(hostname)"} ( [ -n "labels.instance }})"description: "节点 {{ labels.cluster }})"description: "集群 {{ labels.cluster }})"description: "集群 {{ labels.cluster }} 在 1 小时内发生 {{ labels.instance }} 的健康检查脚本连续失败超过 1 分钟"# ===== P2 — 一般告警 =====- alert: KeepalivedHighVRRPAdvertLossexpr: rate(keepalived_vrrp_advert_lost_total[5m]) > 0.1for: 5mlabels:severity: warningpriority: P2annotations:summary: "VRRP 通告丢包率偏高"description: "节点 {{ labels.instance }} 当前状态为 {{ (cat /var/run/keepalived.pid)发送 SIGHUP 信号触发配置重载kill -USR1 $(cat /var/run/keepalived.pid)将统计数据写入 /tmp/keepalived.statskill -USR2 $(cat /var/run/keepalived.pid)将数据写入 /tmp/keepalived.dataarping -I eth0 -c 3 192.168.1.100发送 ARP 查询,确认 VIP 对应的 MAC 地址5.2 日志管理# 创建专用日志目录mkdir -p /var/log/keepalived# 配置 rsyslog 将 Keepalived 日志输出到单独文件cat > /etc/rsyslog.d/keepalived.conf << 'EOF'# Keepalived 日志单独存储local0.* /var/log/keepalived/keepalived.log& stopEOFsystemctl restart rsyslog# 在 keepalived.conf 中指定 syslog 设施:# 启动时使用: keepalived -S 0# 配置 logrotatecat > /etc/logrotate.d/keepalived << 'EOF'/var/log/keepalived/*.log {dailyrotate 30missingoknotifemptycompressdelaycompresscopytruncatedateextdateformat .%Y%m%dpostrotate/bin/kill -HUP (date +%Y%m%d_%H%M%S)"mkdir -p BACKUP_DIR/# 备份脚本文件cp -r /etc/keepalived/scripts {BACKUP_DIR}.tar.gz -C BACKUP_DIR)BACKUP_DIR)rm -rf {BACKUP_DIR}.tar.gz"# 添加到 crontab(每天凌晨 2 点)# 0 2 * * * /opt/scripts/backup_keepalived.sh5.4 故障切换测试流程测试项操作预期结果手动主备切换在 Master 上 systemctl stop keepalivedVIP 在 3s 内漂移到 Backup模拟服务故障在 Master 上 systemctl stop nginx健康检查失败 → Priority 降低 → VIP 漂移模拟网络中断在 Master 上 iptables -A OUTPUT -p vrrp -j DROPBackup 检测到无通告 → 抢占 Master恢复测试恢复 Master 服务/网络Preempt 模式:VIP 自动回到 Master;NoPreempt:保持在 Backup压力测试在主备切换期间持续访问 VIP 服务丢包数应 < 3 秒流量(约 TCP 重传即可恢复)脑裂恢复测试模拟网络分区后恢复Priority 较高的节点应恢复为主5.5 滚动升级流程确认 Backup 节点状态正常,可以接管 VIP在 Master 节点执行:systemctl stop keepalived,VIP 漂移到 Backup验证 Backup 已成功接管 VIP 且服务正常升级 Master 节点的 Keepalived(或系统/内核)重启 Master 节点(如需要),然后:systemctl start keepalived等待 preempt_delay 时间后,验证 VIP 回到原 Master重复步骤 1-6,升级 Backup 节点5.6 常见故障排查故障现象可能原因排查步骤双主(脑裂)两台节点都是 MASTERVRRP 组播不通;单播配置错误;防火墙/交换机策略阻挡① tcpdump -i eth0 vrrp 检查是否收到对端通告② 检查 iptables/安全组是否放行协议号 112③ 检查交换机是否支持组播/IGMP Snooping 配置④ 确认 unicast_peer 配置正确VIP 频繁漂移网络抖动;健康检查太敏感;VRRP 通告超时① 检查网络延迟和丢包率(ping -f)② 增大 advert_int(如 1s→2s)③ 增加健康检查的 rise/fall 次数④ 检查健康检查脚本是否有偶发性失败VIP 无法绑定VIP 已被占用;ip_nonlocal_bind 未开启① ip addr show 确认 VIP 未被其他进程占用② 检查 sysctl net.ipv4.ip_nonlocal_bind = 1③ 检查 SELinux 是否阻止Keepalived 无法启动配置语法错误;依赖的网卡不存在① keepalived -t -f /etc/keepalived/keepalived.conf 检查语法② 确认 interface 指定的网卡名称正确③ 查看 journalctl -u keepalived 错误日志健康检查脚本不执行脚本权限问题;enable_script_security 限制;脚本路径错误① ls -la /etc/keepalived/scripts/ 确认脚本有执行权限② 检查 script_user 配置③ 手动执行脚本测试并查看退出码5.7 运维注意事项配置文件修改后务必使用 keepalived -t 检查语法,再用 systemctl reload 热加载不要使用 kill -9 杀掉 keepalived 进程,这会导致 VIP 无法正常释放健康检查脚本的 timeout 值必须小于 (interval × fall) + advert_int × 4,否则可能导致状态不一致如果使用 notify_master 启动服务,确保 notify_backup 会停止服务,避免双主时服务冲突定期(至少每季度)执行一次故障切换演练,验证 VIP 漂移和服务恢复流程监控 VRRP 实例状态变化频率,频繁切换通常是网络问题的信号在公有云环境务必使用单播模式,并确认安全组放行了 VRRP 协议(协议号 112)Keepalived 的 auth_pass 最多 8 字符,这只是基本的防误配机制,不是安全加密vrrp_strict 模式会自动添加 iptables 规则,可能会干扰已有的防火墙配置多网卡场景下,确保 VRRP 通告走正确的接口,避免跨网卡通信延迟六、安全配置6.1 VRRP 通信安全安全措施说明配置方法VRRP 认证防止未授权节点加入 VRRP 组authentication { auth_type PASS; auth_pass <密码>; }注意:PASS 模式密码明文传输,最长 8 字符;AH 模式需要内核支持单播模式不使用组播,避免组播流量被监听unicast_src_ip + unicast_peer 配置(见 3.11 节)防火墙限制只允许已知对端的 VRRP 通信见 6.2 节MAC 地址过滤交换机端口安全,只允许特定 MAC 发送 VRRP交换机配置 port-security6.2 防火墙精细化配置# ===== iptables 配置 =====# 仅允许来自已知对端节点的 VRRP 协议iptables -A INPUT -p vrrp -s 192.168.1.12 -j ACCEPTiptables -A INPUT -p vrrp -j DROPiptables -A OUTPUT -p vrrp -d 224.0.0.18 -j ACCEPT# 单播模式iptables -A OUTPUT -p vrrp -d 192.168.1.12 -j ACCEPT# 保存规则iptables-save > /etc/sysconfig/iptables# ===== firewalld 配置 =====# 添加 rich rule 限制 VRRP 只允许特定来源firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.12" protocol value="vrrp" accept'firewall-cmd --permanent --add-rich-rule='rule family="ipv4" protocol value="vrrp" drop'firewall-cmd --reload6.3 脚本安全# keepalived.conf 中启用脚本安全global_defs {enable_script_security # 启用脚本安全检查script_user keepalived_scr # 使用专用非 root 用户执行脚本# 注意:VIP 绑定仍需要 root 权限,这里仅影响 vrrp_script 和 notify 脚本}# 创建专用脚本用户useradd -r -s /sbin/nologin -M keepalived_scr# 脚本权限最小化chown root:keepalived_scr /etc/keepalived/scripts/*.shchmod 750 /etc/keepalived/scripts/*.sh# 限制脚本可执行的操作(SELinux 策略)# semanage fcontext -a -t keepalived_unconfined_script_t "/etc/keepalived/scripts(/.*)?"6.4 SELinux 策略配置# 如果必须开启 SELinux,配置正确的策略# 查看 AVC 拒绝记录ausearch -m avc -ts recent | grep keepalived# 创建自定义策略模块grep keepalived /var/log/audit/audit.log | audit2allow -M keepalived_customsemodule -i keepalived_custom.pp# 常用布尔值setsebool -P keepalived_use_nfs 1setsebool -P daemons_use_tty 16.5 Docker 容器安全# Docker 运行时的安全最佳实践docker run -d --name keepalived \--restart=always \--net=host \--cap-add=NET_ADMIN \--cap-add=NET_BROADCAST \--cap-add=NET_RAW \--cap-drop=ALL \ # 丢弃所有其他能力--security-opt=no-new-privileges \ # 禁止提权--read-only \ # 根文件系统只读-v /opt/keepalived/conf/keepalived.conf:/usr/local/etc/keepalived/keepalived.conf:ro \-v /opt/keepalived/scripts:/scripts:ro \osixia/keepalived:2.3.06.6 安全检查清单 VRRP 认证密码已配置且不是默认值 防火墙规则限制了 VRRP 通信的源 IP(仅允许集群内节点) 公网环境使用单播模式而非组播模式 健康检查脚本使用最小权限运行(enable_script_security + script_user) 脚本文件权限为 750 或更严格,属主为 root notify 脚本中不包含硬编码的密码或密钥 SELinux 处于 enforcing 模式(如开启)且策略配置正确 Keepalived 版本保持更新,定期关注 CVE 公告 管理网口(SSH)与业务网口分离,VIP 不要绑定到管理网口 SMTP 告警使用 TLS 加密(如启用邮件通知) SNMP community 字符串不是 public/private 默认值(如启用 SNMP) Docker 容器使用 --cap-drop=ALL 和 --read-only 加固七、集群调优7.1 VRRP 协议参数调优参数默认值建议值说明advert_int1 秒1-3 秒Master 发送 VRRP 通告的间隔。减小可加快故障检测,但会增加 CPU 和网络开销preempt_delay0(立即)30-120 秒抢占延迟,等待网络和服务稳定后再切换,避免抖动vrrp_garp_interval00.001(1ms)免费 ARP 发送间隔,设为 0 可能导致部分交换机丢弃 ARPvrrp_garp_repeat55-10状态切换后发送免费 ARP 的次数,确保所有交换机更新 MAC 表vrrp_version22(IPv4)或 3(IPv6)VRRPv3 支持更快的通告间隔(厘秒级)和 IPv6# 优化后的 VRRP 实例配置示例vrrp_instance VI_1 {state MASTERinterface eth0virtual_router_id 51priority 100advert_int 1 # 1 秒足够,生产环境不建议 < 0.5 秒preempt_delay 60 # 等待 60 秒再抢占,避免抖动# 优化 GARP 参数vrrp_garp_interval 0.01 # 10ms 间隔发送 GARPvrrp_garp_repeat 10 # 发送 10 次# 使用 VRRPv3(支持更快的故障检测)# vrrp_version 3# 注意:VRRPv3 和 VRRPv2 节点不能混用authentication {auth_type PASSauth_pass KEEPALIVED@2024}virtual_ipaddress {192.168.1.100/24 dev eth0 label eth0:vip1}track_script {chk_nginx}}7.2 健康检查参数调优# 高灵敏度健康检查(适用于关键服务)vrrp_script chk_nginx {script "/etc/keepalived/scripts/chk_nginx.sh"interval 1 # 每秒检查timeout 2 # 2 秒超时rise 1 # 1 次成功即恢复(快速恢复)fall 2 # 2 次失败即判定故障(快速检测)weight -30}# 低灵敏度健康检查(适用于容忍瞬时故障的服务)vrrp_script chk_db {script "/etc/keepalived/scripts/chk_db.sh"interval 5 # 5 秒检查一次timeout 5 # 5 秒超时rise 3 # 连续 3 次成功才认为恢复fall 5 # 连续 5 次失败才判定故障weight -20}# 设置 weight 的技巧:# weight 值必须是整数,绝对值通常设为 (Master Priority - Backup Priority) + 安全余量# 例如 Priority(MASTER)=100, Priority(BACKUP)=90# weight 应 ≥ 100 - 90 + 1 = 11,设 -30 可确保足够触发切换7.3 网络层调优内核网络参数优化cat >> /etc/sysctl.conf << 'EOF'# -------------------- Keepalived 网络性能优化 --------------------# 允许绑定本地 IP(VIP 需要)net.ipv4.ip_nonlocal_bind = 1# IP 转发(网关模式需要)net.ipv4.ip_forward = 1# ARP 优化 — 避免不必要的 ARP 响应# ignore=1: 只在请求的目标 IP 在入接口上时才回复# announce=2: 使用最佳本地地址(非接口主 IP 不回复)net.ipv4.conf.all.arp_ignore = 1net.ipv4.conf.all.arp_announce = 2net.ipv4.conf.default.arp_ignore = 1net.ipv4.conf.default.arp_announce = 2# 反向路径过滤 — 组播通信需要关闭net.ipv4.conf.all.rp_filter = 0net.ipv4.conf.default.rp_filter = 0# 组播相关net.ipv4.conf.all.mc_forwarding = 1net.ipv4.conf.default.mc_forwarding = 1# IGMP 相关(如果网络中有 IGMP Snooping 交换机)net.ipv4.neigh.default.gc_thresh1 = 1024net.ipv4.neigh.default.gc_thresh2 = 2048net.ipv4.neigh.default.gc_thresh3 = 4096# 网络队列和缓冲net.core.somaxconn = 65535net.core.netdev_max_backlog = 65535net.ipv4.tcp_max_syn_backlog = 65535# TCP KeepAlive(适用于后端长连接)net.ipv4.tcp_keepalive_time = 300net.ipv4.tcp_keepalive_intvl = 30net.ipv4.tcp_keepalive_probes = 3EOFsysctl -p网卡中断亲和性(多核 CPU 优化)# 将网卡中断绑定到独立的 CPU 核心,减少干扰# 查看网卡中断cat /proc/interrupts | grep eth0# 设置中断亲和性(将 eth0 的所有中断绑定到 CPU 0-1)echo 3 > /proc/irq/1}'|tr-d' ')/smp_affinity# 使用 irqbalance 自动优化systemctl enable --now irqbalance7.4 多实例架构优化当同一台机器上运行多个 VRRP 实例时,需要注意以下问题:优化点说明VRID 规划同一局域网中的所有 VRRP 实例必须使用不同的 VRID(1-255),避免冲突优先级分层不同实例的 Master 应该分布在不同物理节点上,实现负载均衡通告间隔多实例时适当增大 advert_int(如 2-3s),减轻 CPU 和网络负担GARP 发送多实例切换时,使用 GARP 分组(vrrp_garp_master_delay),避免 GARP 风暴健康检查复用多个实例共享相同的健康检查脚本,减少重复开销7.5 脚本性能优化#!/bin/bash# 高性能健康检查脚本示例# 原则:最小化执行时间、避免 fork 子进程、使用 bash 内置功能chk_port() {local host="{2:-80}"local timeout="timeoutbash-c"echo >/dev/tcp/port"2>/dev/null}chk_process() {local proc_name="proc_name" > /dev/null 2>&1}chk_http() {local url="{2:-3}"# curl 使用 --max-time 限制总时间curl -sf --max-time url" > /dev/null 2>&1}# 组合检查if chk_process "nginx" && chk_port "127.0.0.1" "80"; thenexit 0elseexit 1fi7.6 消除脑裂(Split-Brain)的额外保护#!/bin/bash# /etc/keepalived/scripts/anti_split_brain.sh# 在 notify_master 中调用,通过额外手段确认是否有双主VIP="192.168.1.100"PEER_IP="192.168.1.12"LOGFILE="/var/log/keepalived/split_brain.log"# 方法 1: 通过 SSH 检查对端是否也持有 VIPif ssh -o ConnectTimeout=2 -o StrictHostKeyChecking=no VIP'" 2>/dev/null; thenecho "VIP! Taking corrective action...">>VIP|grep-q"reply from (date) [SPLIT-BRAIN] Peer LOGFILEexit 1fiecho "LOGFILEexit 07.7 生产环境调优# ===== 推荐的生产环境 keepalived.conf 调优参数汇总 =====global_defs {router_id KA-NODE01vrrp_skip_check_adv_addrvrrp_garp_interval 0.01vrrp_garp_repeat 10vrrp_mcast_group4 224.0.0.18script_user rootenable_script_security}vrrp_script chk_nginx {script "/etc/keepalived/scripts/chk_nginx.sh"interval 2timeout 3rise 2fall 3weight -30}vrrp_instance VI_1 {state MASTERinterface eth0virtual_router_id 51priority 100advert_int 1preempt_delay 60authentication {auth_type PASSauth_pass KEEPALIVED@2024}virtual_ipaddress {192.168.1.100/24 dev eth0 label eth0:vip1}track_script {chk_nginx}notify_master "/etc/keepalived/scripts/notify.sh MASTER"notify_backup "/etc/keepalived/scripts/notify.sh BACKUP"notify_fault "/etc/keepalived/scripts/notify.sh FAULT"notify_stop "/etc/keepalived/scripts/notify.sh STOP"}7.8 性能基准参考场景节点数VIP 数量故障切换时间CPU 使用率内存占用标准 Nginx HA211-3 秒<0.1%<20MB双主模式241-3 秒<0.2%<30MBLVS + Keepalived221-3 秒<0.5%<40MB多实例(10+ VIP)2101-5 秒<1%<50MB
夜雨聆风