引言
在现代IT架构中,高可用性(High Availability)已成为系统设计的核心要求。当负载均衡器(Load Balancer)作为关键流量入口时,其单点故障可能导致整个服务不可用。本篇文章将深入探讨如何使用Keepalived实现虚拟IP(VIP)在负载均衡器之间的自动漂移,构建真正的高可用架构。
keepalived核心概念
什么是Keepalived?
Keepalived是一个基于VRRP(Virtual Router Redundancy Protocol)协议的高可用解决方案,主要用于Linux环境。它通过虚拟IP(VIP)地址的漂移实现服务的高可用性,同时提供负载均衡和健康检查功能。
VRRP协议简介
VRRP协议(虚拟路由协议)允许一组路由器(或服务器)协同工作,形成一个虚拟路由器。这个虚拟路由器拥有自己的虚拟IP地址,客户端只需要与这个虚拟IP通信,而实际的数据转发由Master节点处理。当Master节点故障时,Backup节点会自动接管VIP,实现无缝切换。
VIP作用
- 统一集群访问控制入口,简化客户端配置
- 实现自动故障转移,提高系统可用性
- 支持无缝维护切换,减少服务中断时间
- 隐藏后端复杂性,客户端无需知道后端有多少台服务器
双LB+keepalived高可用架构
客户端请求
↓
虚拟IP (VIP): 10.0.0.50
主LB节点: 10.0.0.51 (Master)(正常时)
备LB节点: 10.0.0.52 (Backup)(故障时)
↓
后端真实服务器集群
10.0.0.101
10.0.0.102
10.0.0.103
10.0.0.104
keepalived+lb配置及操作
keepalived+lb安装
# CentOS/RHEL
yum install -y keepalived nginx
# Ubuntu/Debian
apt-get update
apt-get install -y keepalived nginx
nginx负载均衡配置
vim /etc/nginx/nginx.conf #将以下内容添加至http区域
http {
upstream backend {
server 10.0.0.101:80;
server 10.0.0.102:80;
server 10.0.0.103:80;
server 10.0.0.104:80;
}
server {
listen 80;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
}
#启动nginx并设置为自启动
systemctl enable --now nginx
主节点配置(/etc/keepalived/keepalived.conf)
! Configuration File for keepalived
global_defs {
router_id lb01 # 标识本节点的名称,同一集群中需唯一
}
# 定义脚本检查,这里检查Nginx进程
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh" #执行脚本检查
interval 2 # 每2秒检查一次
weight -30 # 健康检查失败时,优先级减少30
fall 2 # 连续2次失败才认为是真的失败
rise 1 # 成功1次就认为恢复
}
vrrp_instance VI_1 {
state MASTER # 初始状态,MASTER/BACKUP
interface eth0 # 绑定VIP的网络接口
virtual_router_id 51 # 虚拟路由ID,同一集群中必须一致(0-255)
priority 100 # 初始优先级,MASTER应高于BACKUP
# 主备同步的认证信息
authentication {
auth_type PASS
auth_pass 123456 # 密码,主备必须一致
}
# 虚拟IP配置
virtual_ipaddress {
10.0.0.50/24 dev eth0 label eth0:0
#也可直接简单配置
#10.0.0.50/24
#可以配置多个VIP
#10.0.0.60/24 dev eth0 label eth0:1
}
#健康检查脚本引用
track_script {
chk_nginx
}
# 抢占模式配置
# preempt # 开启抢占(默认开启)
# nopreempt # 关闭抢占
preempt_delay 10 # 抢占延迟10秒,避免频繁切换
# 日志配置
log_file /var/log/keepalived.log
log_info
}
备节点配置
! Configuration File for keepalived
global_defs {
router_id lb02 # 标识本节点的名称,同一集群中需唯一
}
vrrp_script chk_nginx {
script "/etc/keepalived/check_nginx.sh"
interval 2
weight -30
fall 2
rise 1
}
vrrp_instance VI_1 {
state BACKUP # 初始状态为BACKUP
interface eth0
virtual_router_id 51
priority 90 # 初始优先级低于MASTER
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
10.0.0.50/24
}
track_script {
chk_nginx
}
preempt_delay 10
log_file /var/log/keepalived.log
log_info
}
健康检查脚本 (/etc/keepalived/check_nginx.sh)
#!/bin/bash
# 简单的健康检查,返回0表示成功,非0表示失败
# 检查Nginx进程
if ! pgrep -x "nginx" > /dev/null 2>&1; then
echo "Nginx进程不存在"
exit 1
fi
#!逻辑"非"操作
#如果pgrep找到进程(返回0),!会使其变为非0(假)
#如果pgrep没找到进程(返回非0),!会使其变为0(真)
# > /dev/null 2>&1 让命令静默执行,不产生任何输出
# 检查本地HTTP服务
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 2 http://localhost/ 2>/dev/null || echo "000")
#curl localhost 相当于是curl 本机回环地址127.0.0.1 的80端口,而nginx默认监听 0.0.0.0的80端口,这就意味着curl 本机上的任何ip的80端口都是可以验证nginx进程是否正常。
#使用localhost或者127.0.0.1可以确保我们检查的是本机,而不受网络配置(如防火墙、路由等)的影响。但是使用宿主机的IP地址(10.0.0.51)进行curl,会经过网络栈,可能会受到本机防火墙规则的影响。如果本机防火墙阻止了来自外部(甚至包括本机)的访问,那么curl 10.0.0.51可能会失败,但nginx实际上可能是正常的。
#因此,在健康检查脚本中,使用localhost(127.0.0.1)是更安全的选择,因为它不经过网络,直接通过环回接口,可以排除网络配置的问题。
# 判断是否成功状态码
if [[ "$HTTP_CODE" =~ ^(200|301|302|304)$ ]]; then
exit 0 # 成功
else
echo "HTTP服务异常,状态码: $HTTP_CODE"
exit 1 # 失败
fi
#脚本执行流程
开始执行
↓
检查Nginx进程是否存在?
↓
├── 不存在 → 输出错误 → 退出(1)
↓
存在 → 继续
↓
尝试获取HTTP状态码
↓
├── 成功获取 → 得到具体状态码(200/404/500等)
├── 失败获取 → 得到"000"
↓
判断状态码是否在[200, 301, 302, 304]中?
↓
├── 是 → 退出(0) → Keepalived认为健康
↓
否 → 输出错误信息 → 退出(1) → Keepalived认为不健康
#添加执行权限
chmod +x /etc/keepalived/check_nginx.sh
测试与验证
1. 启动服务并查看vip绑定状态
# 启动服务
systemctl start keepalived
systemctl enable keepalived
#systemctl enable --now keepalived
# 查看状态
systemctl status keepalived
# 查看VIP绑定情况
ip addr show eth0
# 输出应包含:
# inet 10.0.0.51brd 10.0.0.255 scope global eth0
# inet 10.0.0.51/24 scope global secondary eth0:0
#或者使用hostname -I 应有显示vip 10.0.0.50
2. 模拟故障转移测试
# 在主节点上停止keepalived
systemctl stop keepalived
# 在备节点上检查VIP是否漂移
ip addr show eth0
#或者使用hostname -I
# 观察日志
tail -f /var/log/keepalived.log
3. 网络连通性测试
# 从客户端ping VIP
ping 10.0.0.50
# 使用curl测试
curl -I http://10.0.0.50
4. 自动恢复测试
# 重启主节点的keepalived
systemctl start keepalived
# VIP应该自动回到主节点(如果preempt模式启用)
Keepalived权重调整的VIP漂移机制详解
权重调整的工作原理
权重调整是Keepalived内置的、最优雅的VIP漂移机制。它不是直接停止服务,而是通过动态调整优先级来触发VRRP协议的标准选举过程。
核心概念
1. 优先级(priority)
- 每个Keepalived节点都有一个优先级(0-255)
- 优先级高的节点会成为MASTER
- 默认:MASTER=100,BACKUP=90
2. 权重(weight)
- 健康检查脚本可以动态调整优先级
weight值可以是正数或负数- 脚本返回0(成功):优先级 + weight值
- 脚本返回非0(失败):优先级 - weight值
3. 选举机制
- 所有节点定期广播自己的优先级
- 最高优先级的节点自动成为MASTER
- MASTER节点绑定VIP
权重调整流程详解
初始状态
节点A (10.0.0.51):
- 状态: MASTER
- 初始优先级: 100
- 配置: weight -30
节点B (10.0.0.52):
- 状态: BACKUP
- 初始优先级: 90
- 配置: weight -30
VIP: 10.0.0.50 绑定在节点A
步骤1:健康检查正常时
节点A:
- 健康检查脚本: 返回0 (成功)
- 实际优先级: 100 + 0 = 100 # weight只在失败时生效
- 状态: MASTER
节点B:
- 健康检查脚本: 返回0 (成功)
- 实际优先级: 90 + 0 = 90
- 状态: BACKUP
结果: 节点A保持MASTER,持有VIP
步骤2:节点A健康检查失败
节点A:
- 健康检查脚本: 返回1 (失败)
- 实际优先级: 100 - 30 = 70 # weight -30生效
- 状态: MASTER -> 降级
节点B:
- 健康检查脚本: 返回0 (成功)
- 实际优先级: 90 + 0 = 90
- 状态: BACKUP -> 发现自己的优先级(90) > 节点A的优先级(70)
VRRP协议触发选举:
1. 节点B发现自己的优先级更高
2. 节点B广播"我要成为MASTER"
3. 节点A收到消息,同意节点B成为MASTER
4. 节点A释放VIP,切换为BACKUP状态
5. 节点B绑定VIP,切换为MASTER状态
结果: VIP自动漂移到节点B,无需手动停止任何服务
步骤3:节点A恢复健康
节点A:
- 健康检查脚本: 返回0 (成功)
- 实际优先级: 100 + 0 = 100 # 恢复原始优先级
- 状态: BACKUP -> 发现自己的优先级(100) > 节点B的优先级(90)
节点B:
- 健康检查脚本: 返回0 (成功)
- 实际优先级: 90 + 0 = 90
- 状态: MASTER
抢占模式(preempt)决定是否切回:
1. 如果开启抢占(默认): 节点A重新成为MASTER,VIP切回
2. 如果关闭抢占(nopreempt): 节点B保持MASTER,除非它故障