virtual_server是Keepalived向内核IPVS提交的虚拟服务规则,用于在传输层(TCP/UDP)转发流量;它不是独立服务,不解析HTTP内容,需与vrrp_instance协同实现VIP漂移和健康检查。

Keepalived 本身不直接处理四层负载分发,而是通过 virtual_server 配置块调用 Linux 内核的 IPVS(即 LVS)模块,在传输层(TCP/UDP)完成流量转发。要实现四层协议高可用,必须同时满足两个条件:VIP 能自动漂移(靠 VRRP),后端真实服务器能被健康检查并动态剔除(靠 Check 模块)。关键不在“写 virtual_server”,而在于它与 VRRP 实例协同工作、与 IPVS 内核联动。
virtual_server 是什么,不是什么
它不是独立服务,而是 Keepalived 向内核 IPVS 提交的一条“虚拟服务规则”。配置中指定的 VIP:Port(如 192.168.1.100:80)会被加载为 IPVS 的一条 virtual server 条目;real_server 则对应 IPVS 中的 real server 节点。Keepalived 不转发数据包,只管理规则生命周期和节点状态。
- 必须确保系统已启用 IPVS 内核模块:
modprobe ip_vs,且lsmod | grep ip_vs可见加载 - virtual_server 的 VIP 必须与 vrrp_instance 中定义的 VIP 完全一致,否则 IPVS 规则绑定失败
- 不支持 HTTP 内容解析或重写——这是七层行为,超出 virtual_server 能力范围
四层高可用的核心配置结构
一个可用的四层高可用配置,需包含 vrrp_instance + virtual_server 两大部分,且部署在主备两台机器上(仅 state 和 priority 不同):
- vrrp_instance:定义 VIP 漂移逻辑(interface、virtual_router_id、priority、advert_int、authentication)
- virtual_server:定义该 VIP:Port 下的负载策略(delay_loop、lb_algo、lb_kind、persistence_timeout、protocol)
- real_server:每个 real_server 块内必须含 weight 和健康检查(TCP_CHECK / HTTP_GET / SSL_GET / SCRIPT_CHECK)
例如监听 192.168.1.100:3306(MySQL)的典型片段:
virtual_server 192.168.1.100 3306 {delay_loop 6
lb_algo wrr
lb_kind DR
persistence_timeout 50
protocol TCP
real_server 192.168.1.201 3306 {
weight 100
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.1.202 3306 {
weight 100
TCP_CHECK { ... }
}
}
保障四层协议高可用的关键细节
仅配置语法正确远远不够,以下三点决定是否真正“高可用”:
- VIP 与 real_server 网络可达性:若使用 DR 模式,所有 real_server 必须与 LB 节点同网段,且配置好 ARP 抑制(arp_ignore/arp_announce);NAT 模式则需确认 LB 节点开启 IP 转发和 SNAT
- 健康检查必须匹配四层语义:对 MySQL、Redis、Kafka 等非 HTTP 服务,禁用 HTTP_GET,改用 TCP_CHECK;connect_timeout 建议设为 1–3 秒,避免误判
- 主备切换时 IPVS 规则同步:Keepalived 在 master 上升时自动加载 virtual_server 规则,在 backup 上升时自动清空——这依赖于 keepalived 进程启停时对 IPVS 的增删操作,不可手动干预
验证四层高可用是否生效
不要只看 VIP 是否 ping 通,要分层验证:
- 查 VIP 是否绑定:
ip addr show看 eth0 是否含192.168.1.100/32 - 查 IPVS 规则是否加载:
ipvsadm -Ln应显示 Virtual Server 及 Real Server 列表 - 查后端节点状态:
ipvsadm -Ln --stats中 ActiveConn/InActConn 是否有流量,且故障节点应显示为Weight = 0 - 模拟故障:停掉一台 real_server 的 MySQL,观察 6 秒后(delay_loop)其 weight 是否变为 0,客户端连接是否自动切到另一台










