目录
Keepalived + LVS + Nginx 实现 高可用 + 负载均衡
Keepalived
Keepalived 是什么(高可用)
Keepalived 是一个用于实现 高可用 性(High Availability, HA)的服务,是一款基于 VRRP 协议的高可用软件,常用于主备切换和虚拟IP漂移,在服务故障时自动实现故障转移。
Keepalived 的核心功能
功能 | 说明 |
---|---|
VRRP | Virtual Router Redundancy Protocol,实现主备切换,保障VIP持续可用 |
健康检查(check) | 定时检测真实服务(如 Nginx、LVS、MySQL)是否存活 |
VIP 漂移 | 将一个虚拟 IP 绑定到当前健康的主节点上,故障时自动转移到备节点 |
结合 LVS | 通常与 LVS(Linux Virtual Server)一起部署,提供高可用负载均衡 |
安装 Keepalived
sudo apt-get update
sudo apt-get install -y keepalived
查看是否安装成功
keepalived -v
开启开机自启动:
sudo systemctl enable keepalived
Keepalived 常用命令
开启开机自启动:sudo systemctl enable keepalived
禁用开机自启动:sudo systemctl disable keepalived
开启服务:sudo systemctl start keepalived
关闭服务:sudo systemctl stop keepalived
重启服务:sudo systemctl restart keepalived
查看状态:sudo systemctl status keepalived
编辑配置文件
sudo vim /etc/keepalived/keepalived.conf
配置文件参数说明
## 全局配置,用于日志、调试、邮件通知等目的
global_defs {
## router_id 是 Keepalived 的 全局标识符
router_id LVS_DEVEL
}
# 定义一个 VRRP 实例,VI_1 是自定义的实例名称,每一个实例代表一个高可用虚拟路由组。
vrrp_instance VI_1 {
## 指定该节点的初始角色,MASTER:主节点,正常情况下负责绑定虚拟IP(VIP)。BACKUP:备用节点,在主节点不可用时接管 VIP。
# Keepalived 自动通过优先级判断主备,不是硬编码的主备,所以这个只是初始角色。
state MASTER
## 指定绑定 VIP 的网络接口(网卡名),例如 eth0、ens33、enp0s3 等。使用 ip a 查看当前系统的网卡名。
interface ens33
## 虚拟路由器的 ID,用于识别一个 VRRP 实例的组。所有参与该 VRRP 实例(主备)的服务器必须一致。范围:0~255,确保不同服务之间不要冲突。
virtual_router_id 51
## 指定该节点的优先级。数字越大,优先级越高。主节点应配置较高的值(如 100),备用节点配置较低(如 90)。当优先级高的节点恢复时,会自动抢占 VIP
priority 100
## 指定 VRRP 广播间隔时间(秒)。主节点每隔指定的秒发送一次心跳包,默认是 1 秒,一般无需修改
advert_int 1
## 禁用抢占
# nopreempt # 即使此节点优先级更高也不抢占 MASTER
## 延迟抢占 VIP
# 主节点恢复后,希望它稳定运行一段时间再接管 VIP,防止主节点频繁重启时反复抢占,导致服务中断
# nopreempt 和 preempt_delay 不能同时使用。如果两者都写了,以 nopreempt 为准
# preempt_delay 10 # 恢复后等待10秒才尝试抢占 MASTER
## 状态通知脚本(可选)
# notify_master "/path/to/script" # 成为 MASTER 时执行脚本
# notify_backup "/path/to/script" # 成为 BACKUP 时执行脚本
# notify_fault "/path/to/script" # 出现故障时执行脚本
# notify "/path/to/script" # 所有状态变更时都执行的统一脚本
## 本机实际 IP 地址(作为 VRRP 包发送源 IP)
unicast_src_ip 192.168.189.135
## 用于将 Keepalived 的 VRRP 心跳通信改为“单播”(Unicast)模式。不配置的话默认的是“组播”(Multicast)模式。云服务器(如阿里云、腾讯云)中,出于安全限制,组播通常被禁用或不可用。
unicast_peer {
192.168.189.136
192.168.189.137
}
## 用于设置主备之间的认证信息
authentication {
## 认证类型,一般用 PASS(明文密码)
auth_type PASS
## 认证密码(主备节点必须保持一致)
auth_pass 123456
}
## 指定一个或多个虚拟IP(VIP)。VIP 是客户端访问的目标地址,当主节点故障,VIP 会自动漂移到备节点
virtual_ipaddress {
192.168.189.100 # 虚拟IP 1,例如用于 web 服务A
192.168.189.101 # 虚拟IP 2,例如用于 web 服务B
192.168.189.102 # 虚拟IP 3,例如用于 mysql 服务
# 把 VIP 绑定到本机的 loopback 网卡(lo),LVS 的时候使用(只在Master节点生效,所以不推荐使用,推荐使用命令的方式)
# 192.168.189.100/32 dev lo scope host
}
}
配置文件实操
- 主节点:192.168.189.135,优先级为 100
- 备节点:192.168.189.136,优先级为 90
- 第三节点:192.168.189.137,优先级为 80
这些参数必须在所有节点一致:vrrp_instance、virtual_router_id、advert_int、authentication、virtual_ipaddress
1. 主节点(192.168.189.135)配置
sudo vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
unicast_src_ip 192.168.189.135
unicast_peer {
192.168.189.136
192.168.189.137
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.189.100
}
}
重启 keepalived
sudo systemctl restart keepalived
2. 备节点(192.168.189.136)配置
sudo vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
unicast_src_ip 192.168.189.136
unicast_peer {
192.168.189.135
192.168.189.137
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.189.100
}
}
重启 keepalived
sudo systemctl restart keepalived
3. 第三节点(192.168.189.137)配置
sudo vim /etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 80
advert_int 1
unicast_src_ip 192.168.189.137
unicast_peer {
192.168.189.135
192.168.189.136
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.189.100
}
}
重启 keepalived
sudo systemctl restart keepalived
测试是否配置成功
测试步骤:查看VIP在哪个节点上?发现在主节点上,把主节点关闭后,发现VIP漂移到备用节点上了
1. 在主节点(192.168.189.135)运行:
ip a | grep 192.168.189.100
输入如下内容,表示 VIP 被绑定到此节点
inet 192.168.189.100/32 scope global ens33
2. 关闭主节点的 Keepalived 服务:
sudo systemctl stop keepalived
3. 在备节点(192.168.189.136)运行:
ip a | grep 192.168.189.100
VIP 会自动漂移到备节点。
开启 keepalived 日志
(所有节点都要执行)
1. 配置 rsyslog 接收 Keepalived 日志
sudo vim /etc/rsyslog.d/keepalived.conf
文件内容如下:
local0.* /var/log/keepalived.log
重启 rsyslog 服务
sudo systemctl restart rsyslog
2. 执行命令
sudo keepalived --log-console --log-detail --log-facility=local0
重启 Keepalived 服务
sudo systemctl restart keepalived
3. 查看日志
tail -500f /var/log/keepalived.log
LVS
LVS 是什么(负载均衡)
LVS(Linux Virtual Server)是一个运行在 Linux 内核中的负载均衡器,它可以将大量的请求分发到多台后端服务器上,实现网站或服务的 Linux 内核级负载均衡。
LVS 的特点
特性 | 说明 |
---|---|
高性能 | 内核级处理,效率非常高,适合大规模并发 |
稳定可靠 | 运行在 Linux 内核中,成熟稳定 |
支持多种调度算法 | 如轮询(RR)、最少连接(LC)、加权等 |
透明性高 | 客户端无需感知后端服务器变化 |
扩展性强 | 可轻松添加或移除后端服务器 |
LVS 的负载均衡算法
算法名 | 全称 | 说明 |
---|---|---|
rr | Round Robin | 轮询,每台服务器轮流处理请求,适用于服务器性能差不多的情况。 |
wrr | Weighted Round Robin | 加权轮询,根据服务器权重分配请求,权重大者分配更多请求。 |
lc | Least Connection | 最少连接数优先,当前连接最少的服务器优先接收新请求。 |
wlc | Weighted Least Connection | 加权最少连接,在连接数基础上再加权,适用于连接时长差异较大的情况。 |
lblc | Locality-Based Least Connection | 基于本地性和最少连接数,适用于缓存服务器,提高命中率。 |
lblcr | Locality-Based Least Connection with Replication | 类似于 lblc,但支持多个复制服务器。 |
dh | Destination Hashing | 目的地址哈希,将请求根据目标 IP 哈希分配,适合源地址多样化场景。 |
sh | Source Hashing | 源地址哈希,将同一客户端的请求始终发往同一后端,适用于会话保持。 |
LVS 负载均衡的转发工作模式
模式 | 简介 | 优点 | 缺点或要求 |
---|---|---|---|
NAT | LVS 作为网关,所有流量都经过 LVS,再转发给后端 | 配置简单 | LVS 成为瓶颈,占用带宽 |
DR(Direct Routing) | 请求从 LVS 发出,但响应由后端服务器直接返回客户端 | 性能高,响应快 | 需要所有机器在同一网段,后端需绑定 VIP(不响应 ARP) |
TUN(IP隧道) | LVS 和后端服务器可以跨网段 | 跨地域部署可用 | 后端服务器需支持 IP 隧道 |
安装 LVS
sudo apt-get update
sudo apt-get install -y ipvsadm
编辑配置文件
sudo vim /etc/keepalived/keepalived.conf
配置文件参数说明
LVS 一般和 keepalived 搭配使用,LVS 配置写在 keepalived 的配置文件中
## 全局配置,用于日志、调试、邮件通知等目的
global_defs {
## router_id 是 Keepalived 的 全局标识符
router_id LVS_DEVEL
}
## 定义一个 LVS 虚拟服务(VIP + 端口),192.168.189.100 是虚拟 IP(VIP),80 是端口。
virtual_server 192.168.189.100 80 {
## 每 5 秒执行一次健康检查。值越小,检测频率越高,发现异常越快,但系统负担也会稍高。
delay_loop 5
## 指定使用什么 负载均衡算法
lb_algo wrr
## 指定负载均衡的转发工作模式
lb_kind DR
## 设置客户端 IP 的掩码,用于判定哪些请求来自“同一个客户端子网”。nat_mask 255.255.255.0 表示 LVS 只看客户端 IP 地址的前 24 位(即 a.b.c.*),这意味着来自同一个子网(如 192.168.1.x)的所有客户端请求会被认为是来自同一客户端,并会被转发到同一个 real server。例如:如果两个客户端 IP 分别是 192.168.1.10 和 192.168.1.20,它们被认为来自同一个子网。LVS 会将它们的请求始终转发到同一个后端 real server(在持久连接有效时间内,即 persistence_timeout)。
nat_mask 255.255.255.0
## 保持客户端连接的会话粘性,单位是秒,同一客户端在 60 秒内的请求都发送到同一台后端服务器。
persistence_timeout 60
## 该虚拟服务处理的是 TCP 协议的请求(如 HTTP、HTTPS、MySQL等)
protocol TCP
## 定义一台真实后端服务器,监听 IP 为 192.168.189.135,端口 80。
real_server 192.168.189.135 80 {
## 权重为 3(配合上面的 wrr 算法使用),3:表示这个服务接收3个请求
weight 3
## 健康检查(TCP 方式)
TCP_CHECK {
## 每次 TCP 连接检测最多等待 3 秒,3秒后就连接超时
connect_timeout 3
## 最多尝试连接 3 次
nb_get_retry 3
## 重试前延迟时间,每次失败后等待 2 秒再重试
delay_before_retry 2
## 检查端口(默认是 real_server 的端口)
connect_port 80
}
}
## 定义一台真实后端服务器,监听 IP 为 192.168.189.136,端口 80。
real_server 192.168.189.136 80 {
## 权重为 2(配合上面的 wrr 算法使用),2:表示这个服务接收2个请求
weight 2
TCP_CHECK {
connect_timeout 3
nb_get_retry 3
delay_before_retry 2
connect_port 80
}
}
## 定义一台真实后端服务器,监听 IP 为 192.168.189.137,端口 8080。
real_server 192.168.189.137 8080 {
weight 1
# 健康检查(HTTP GET 请求)
HTTP_GET {
url {
## 检查的路径,例如 /healthz,你需要在该服务器上部署这个路径返回 200,例如:GET http://<real_server_ip>:80/healthz
path /healthz
## 响应体的 MD5 值,匹配这个 hash 才算健康,防止假回包。d41d8cd98f00b204e9800998ecf8427e:是空字符串("")的 MD5 值,即后端什么也不返回时的 MD5 值,这个值可以自定义
digest d41d8cd98f00b204e9800998ecf8427e
}
## 每次 TCP 连接检测最多等待 3 秒,3秒后就连接超时
connect_timeout 3
## GET 请求失败后重试次数
nb_get_retry 3
## 重试前延迟时间,每次失败后等待 2 秒再重试
delay_before_retry 2
## 请求的端口
connect_port 8080
}
}
}
HTTP_GET 健康检查 Restful API 示例:
1. 定义一个 get 接口
@RestController
public class HealthCheckController {
@GetMapping("/healthz")
public String healthCheck() {
return "AAABBBCCC";
}
}
2. 计算返回值的 MD5(用于 digest)
现在后端返回的是 "AAABBBCCC",你可以在 Linux 或 macOS 终端中执行:
echo -n "AAABBBCCC" | md5sum
输出:6207b5df5796e963410d3bc4b6a4218b -
把这个值配置在 HTTP_GET 健康检查的 digest 属性中,如下:
HTTP_GET {
url {
path /healthz
digest 6207b5df5796e963410d3bc4b6a4218b
}
......
}
LVS 状态同步
查看状态是否同步
ipvsadm -L --daemon
显示如下:(syncid=0:表示当前的节点没有设置同步ID或没有正常启动连接同步守护进程)
master sync daemon (mcast=ens33, syncid=0, maxlen=1472, group=224.0.0.81, port=8848, ttl=1)
Master 节点开启同步(ens33是实际的物理网络接口名称,不是 lo。同一集群中的 syncid 1 要设置一致)
ipvsadm --start-daemon master --mcast-interface=ens33 --syncid 1
Backup 节点开启同步
ipvsadm --start-daemon backup --mcast-interface=ens33 --syncid 1
Master 节点关闭同步
ipvsadm --stop-daemon master
Backup 节点关闭同步
ipvsadm --stop-daemon backup
Keepalived + LVS + Nginx 实现 高可用 + 负载均衡
- 主节点:192.168.189.135,优先级为 100
- 备节点:192.168.189.136,优先级为 90
- 第三节点:192.168.189.137,优先级为 80
1. 主节点(192.168.189.135)配置
sudo vim /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_NODE1
}
vrrp_instance VI_1 {
state MASTER
interface ens33
virtual_router_id 51
priority 100
advert_int 1
unicast_src_ip 192.168.189.135
unicast_peer {
192.168.189.136
192.168.189.137
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.189.100
}
}
virtual_server 192.168.189.100 80 {
delay_loop 5
lb_algo rr
lb_kind DR
nat_mask 255.255.255.0
persistence_timeout 60
protocol TCP
real_server 192.168.189.135 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.189.136 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.189.137 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
}
重启 keepalived
sudo systemctl restart keepalived
2. 备节点(192.168.189.136)配置
sudo vim /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_NODE2
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 90
advert_int 1
unicast_src_ip 192.168.189.136
unicast_peer {
192.168.189.135
192.168.189.137
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.189.100
}
}
virtual_server 192.168.189.100 80 {
delay_loop 5
lb_algo rr
lb_kind DR
nat_mask 255.255.255.0
persistence_timeout 60
protocol TCP
real_server 192.168.189.135 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.189.136 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.189.137 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
}
重启 keepalived
sudo systemctl restart keepalived
3. 备节点(192.168.189.137)配置
sudo vim /etc/keepalived/keepalived.conf
global_defs {
router_id LVS_NODE3
}
vrrp_instance VI_1 {
state BACKUP
interface ens33
virtual_router_id 51
priority 80
advert_int 1
unicast_src_ip 192.168.189.137
unicast_peer {
192.168.189.135
192.168.189.136
}
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.189.100
}
}
virtual_server 192.168.189.100 80 {
delay_loop 5
lb_algo rr
lb_kind DR
nat_mask 255.255.255.0
persistence_timeout 60
protocol TCP
real_server 192.168.189.135 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.189.136 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
real_server 192.168.189.137 80 {
weight 1
TCP_CHECK {
connect_timeout 5
nb_get_retry 3
delay_before_retry 3
}
}
}
重启 keepalived
sudo systemctl restart keepalived
# 如果想要测试负载均衡时即时看到效果,就先去掉这2个属性 nat_mask、persistence_timeout
所有节点都配置完成后,使用 ipvsadm 查看当前的 LVS 配置
sudo ipvsadm -L -n
显示如下内容,表示 LVS 配置成功
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.189.100:80 rr persistent 60
-> 192.168.189.135:80 Route 1 3 0
-> 192.168.189.136:80 Route 1 3 0
-> 192.168.189.137:80 Route 1 3 0
参数说明:
TCP 192.168.189.100:80 rr
部分 含义 TCP
LVS 监听的是 TCP 协议(也可能是 UDP) 192.168.189.100:80
虚拟 IP 和端口,表示用户访问的目标(VIP:Port) rr
负载均衡算法,这里是 round-robin
(轮询调度)-> 192.168.189.135:80 Route 1 3 0
字段位置 字段含义 说明 ->
后端 Real Server 表示这是一个转发目标(后端服务器) 192.168.189.135:80
Real Server IP 和端口 LVS 将请求转发到这里 Route
转发方式 这里是 DR 模式(直接路由) 1
权重 (weight) 表示调度器给此 Real Server 分配的权重 3
活跃连接数 (active conn) 当前连接到此 Real Server 的客户端连接数 0
不活跃连接数 (inactive conn) 表示已完成但仍保持连接的 TCP 会话(如等待关闭) 如果你看到多个后端的活跃连接数一致(比如每台都是 3),说明 LVS 负载均衡配置是生效的。
4. 把 VIP 绑定到本机的 loopback 网卡(lo),(在所有节点上执行)
注意:DR 模式下 VIP 一定是绑定在 lo 上,并加上 /32。(192.168.189.100 ip 已经在 ens33 网卡上了,现在再绑定到 lo 上会出现 ARP 冲突问题,等会我们要解决这个问题)
使用 ip a 命令可以查看每个网卡上绑定的 ip
方式一:(临时的,不推荐)
sudo ip addr add 192.168.189.100/32 dev lo
参数说明:
ip addr add 添加一个 IP 地址 192.168.189.100/32 要添加的 IP 地址, /32
表示只有这一个 IP(子网掩码是255.255.255.255
)dev lo 添加到 lo
网卡上,也就是本机的回环接口
命令执行完成后,显示如下内容,lo 下出现了 192.168.189.100,但是 ens33 之前就存在 192.168.189.100,这样就参数了 ARP 冲突。
启用本地回环网卡 lo
接口(默认应该就是开启状态):
sudo ip link set lo up
方式二:(永久的,推荐)
创建一个新的 systemd 服务文件
sudo vim /etc/systemd/system/vip-setup.service
在文件中添加如下内容:
[Unit]
Description=Setup VIP on lo interface
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/sbin/ip addr add 192.168.189.100/32 dev lo
[Install]
WantedBy=multi-user.target
启动服务、开机自启动
sudo systemctl daemon-reload
sudo systemctl enable vip-setup.service
sudo systemctl start vip-setup.service
5. 处理 ARP 冲突问题(在所有节点上执行)
arp_ignore=1:表示只对目标是本地地址的 ARP 请求进行响应,即只有当请求目标是该机器的某个接口时,才会响应 ARP 请求。
arp_announce=2:表示选择具有最优 IP 地址的接口来回应 ARP 请求,通常避免 lo 上的 IP 与其他真实网卡的 IP 冲突。
all:所有的网络接口(包括 lo、eth0、ens33 等)默认 ARP 策略(全局)
创建配置文件(永久生效的方式)
sudo vim /etc/sysctl.d/99-lvs.conf
文件内容如下:
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
重新加载所有 sysctl 配置,包括你刚才创建的 99-lvs.conf
sudo sysctl --system
查看配置是否生效
cat /proc/sys/net/ipv4/conf/lo/arp_ignore
cat /proc/sys/net/ipv4/conf/lo/arp_announce
cat /proc/sys/net/ipv4/conf/all/arp_ignore
cat /proc/sys/net/ipv4/conf/all/arp_announce
6. 配置 Nginx
在所有节点上配置Nginx实例,配置一个普通的可以访问静态页面的80端口(因为我们上面配置文件 real_server 监听的是 80 端口)地址即可。
Nginx 示例配置请查看:Nginx配置
7. 测试 Keepalived + LVS + Nginx 实现 高可用 + 负载均衡
浏览器访问:http://192.168.189.100,可以看到,流量负载到每一台机器上面了,达到了负载均衡的目的。
当我们停掉 2 台机器的时候,发现还有 1 台机器在正常运行,达到了高可用的目的。
注意,节点切换为 Master 的过程中通常会出现短暂的服务不可达现象。这是一主架构的正常现象,因为VIP迁移、ARP 广播、LVS 的连接状态,它们的切换都要时间。想要解决这个问题,使用多主架构(多主热备)的方式即可(当然也会产生其他问题),什么是多主架构:每台服务器既是自己 VIP 的 MASTER,又是其它 VIP 的 BACKUP,这样实现多个 VIP,同时负载均衡、互为备份。。。配置太多了,这里就不再配置了,实际工作中百分之90的加工作5年的程序员不是在大厂都用不上。用到的自行搜索一下吧很简单的,本文就到这里了。