第一部分:LVS多端口轮询问题及解决方案
一、问题描述
1.1 场景
在LVS-DR模式下,同一个VIP(192.168.0.200)上同时运行HTTP(80端口) 和 HTTPS(443端口) 两个服务,后端有RS1(192.168.0.10)和RS2(192.168.0.20)两台真实服务器。
1.2 错误配置
如果按照常规方式,分别独立配置80和443的轮询规则:
# 配置80端口的轮询
[root@vsnode ~]# ipvsadm -A -t 192.168.0.200:80 -s rr
[root@vsnode ~]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.10 -g
[root@vsnode ~]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.20 -g
# 配置443端口的轮询
[root@vsnode ~]# ipvsadm -A -t 192.168.0.200:443 -s rr
[root@vsnode ~]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.10 -g
[root@vsnode ~]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.20 -g
查看规则:
[root@vsnode ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.0.200:80 rr
-> 192.168.0.10:80 Route 1 0 0
-> 192.168.0.20:80 Route 1 0 0
TCP 192.168.0.200:443 rr
-> 192.168.0.10:443 Route 1 0 0
-> 192.168.0.20:443 Route 1 0 0
此时80和443是两条完全独立的IPVS服务。
1.3 问题复现
客户端测试:
[root@client ~]# curl http://192.168.0.200; curl -k https://192.168.0.200
RS2 - 192.168.0.20 ← HTTP请求去了RS2
RS2 - 192.168.0.20 ← HTTPS请求也去了RS2
期望结果:HTTP和HTTPS应该交替分配到不同RS(如HTTP→RS2,HTTPS→RS1)。
实际结果:两次都去了同一台RS2,轮询没有交替。
1.4 原因分析
80和443端口的轮询计数器都独立运行
客户端连续访问:
请求1(HTTP 80)→ 80端口轮询 → 选中RS2
请求2(HTTPS 443)→ 443端口轮询 → 从头开始 → 可能又选中RS2
本质原因:80和443是两条独立的IPVS规则,各自的轮询计数器独立维护,彼此没有关联。
二、解决方案:防火墙标记(FWM)
2.1 核心原理
用iptables给80和443端口的流量打上同一个标记,然后在IPVS中创建基于这个标记的集群服务,而不是基于具体端口。
2.2 完整实验步骤
1、RS上开启HTTPS服务
# RS1和RS2都要执行
[root@RS1 ~]# dnf install httpd mod_ssl -y
[root@RS1 ~]# systemctl restart httpd
# 验证两个端口
[root@RS1 ~]# curl http://localhost
RS1 - 192.168.0.10
[root@RS1 ~]# curl -k https://localhost
RS1 - 192.168.0.10
验证结果:HTTP和HTTPS都返回正确内容,两个服务正常。
2、清空原有错误规则
[root@vsnode ~]# ipvsadm -C
3、用iptables打防火墙标记
[root@vsnode ~]# iptables -t mangle -A PREROUTING \
-d 192.168.0.200 -p tcp \
-m multiport --dports 80,443 \
-j MARK --set-mark 6666
|-------------------------------------|------------------|
| -t mangle | 在路由前链上添加规则 |
| -A PREROUTING | 在路由前链上添加规则 |
| -d 192.168.0.200 | 目标IP为VIP |
| -p tcp -m multiport --dports 80,443 | 匹配TCP协议的80和443端口 |
| -j MARK --set-mark 6666 | 打上标记6666 |
查看标记规则
[root@vsnode ~]# iptables -t mangle -L -n
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
MARK tcp -- 0.0.0.0/0 192.168.0.200 multiport dports 80,443 MARK set 0x1a0a
注:0x1a0a是6666的十六进制表示。
4、基于防火墙标记创建IPVS服务
# 创建基于标记6666的集群服务
[root@vsnode ~]# ipvsadm -A -f 6666 -s rr
# 添加后端RS(注意:不需要指定端口)
[root@vsnode ~]# ipvsadm -a -f 6666 -r 192.168.0.10 -g
[root@vsnode ~]# ipvsadm -a -f 6666 -r 192.168.0.20 -g
# 查看规则
[root@vsnode ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
FWM 6666 rr ← 基于防火墙标记!
-> 192.168.0.10:0 Route 1 0 0
-> 192.168.0.20:0 Route 1 0 0
RS的端口显示为0(匹配标记的所有端口流量)
FWM 6666 r r替了之前的 TCP 192.168.0.200:80 rr
5、验证------轮询恢复正常
[root@client ~]# curl http://192.168.0.200; curl -k https://192.168.0.200
RS2 - 192.168.0.20 ← HTTP去了RS2
RS1 - 192.168.0.10 ← HTTPS去了RS1
[root@client ~]# curl http://192.168.0.200; curl -k https://192.168.0.200
RS2 - 192.168.0.20 ← HTTP去了RS2
RS1 - 192.168.0.10 ← HTTPS去了RS1
HTTP和HTTPS请求被交替分发到不同的RS,轮询恢复正常。
三、防火墙标记原理总结
统一打标计
MARK=6666HTTP请求 :80
iptables mangle表HTTPS请求 :443
IPVS调度器<br/>-f 6666 -s rrRS1RS2
解决的问题:将多端口的流量合并到同一个IPVS集群服务,避免独立调度导致的轮询错乱。
适用场景:同一VIP上多端口服务需要协同调度(如80+443、多协议服务等)。
第二部分:LVS会话粘滞问题及解决方案
一、问题描述
1.1 什么是会话粘滞?
在负载均衡集群中,一个用户的会话需要多次请求完成(如登录→加入购物车→提交订单→支付)。如果每次请求被分发到不同RS,会导致Session丢失:
用户登录 ------》 请求1 ------> RS1(登录成功Session保存在RS1上)
用户下单 ------》 请求2 ------> RS2(没有Session需要重新登录)
1.2 会话粘滞(Session Stickiness)
指将同一个客户端的所有请求都定向到同一台RS,保证会话状态不中断。
二、解决方案一:持久连接(Persistence) 推荐
2.1 原理
IPVS在内存中创建一个持久连接模板,记录"客户端IP → RS"的映射关系。在超时时间内,同一源IP的所有请求都发往同一台RS。
客户端A ------ 请求1 ------ IPVS记录(客户端A>RS1) ------ RS1
客户端A ------ 请求2 ------ IPVS查表(客户端A>RS1) ------ RS1
客户端A ------ 请求3 ------ IPVS查表(客户端A>RS1) ------ RS1
2.2 完整实验步骤
1、创建带持久连接的IPVS服务
基于上一部分的防火墙标记服务,添加持久连接参数 -p:
# -p 1 表示持久超时时间为1秒(实验演示用)
[root@vsnode ~]# ipvsadm -A -f 6666 -s rr -p 1
# 添加后端RS
[root@vsnode ~]# ipvsadm -a -f 6666 -r 192.168.0.10 -g
[root@vsnode ~]# ipvsadm -a -f 6666 -r 192.168.0.20 -g
# 查看规则
[root@vsnode ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
FWM 6666 rr persistent 1 ← 关键!持久连接已开启
-> 192.168.0.10:0 Route 1 0 0
-> 192.168.0.20:0 Route 1 0 0

注意Flags列出现了persistent 1,表示持久连接已开启,超时时间为1秒。
说明 -p 1表示1秒超时,生产环境建议 -p
300(5分钟)~ -p3600(1小时)。实验用1秒是因为连续curl在1秒内完成,可以看到效果。
2、测试会话粘滞效果
[root@client ~]# curl http://192.168.0.200
RS1 - 192.168.0.10 #第1次RS1
[root@client ~]# curl http://192.168.0.200
RS1 - 192.168.0.10 #第2次RS1
[root@client ~]# curl http://192.168.0.200
RS1 - 192.168.0.10 #第3次RS1
**会话粘滞生效,**连续3次请求都去了同一台RS(RS1)。
3、观察持久连接模板表
在VS上开启另一个终端,使用监控命令:
[root@vsnode ~]# watch -n 1 ipvsadm -Lnc
输出示例:
IPVS connection entries
pro expire state source virtual destination
TCP 01:56 FIN_WAIT 172.25.254.99:42420 192.168.0.200:80 192.168.0.20:80
IP 00:57 ASSURED 172.25.254.99:0 0.26.10:0 192.168.0.20:0
TCP 01:54 FIN_WAIT 172.25.254.99:46216 192.168.0.200:80 192.168.0.20:80
TCP 01:55 FIN_WAIT 172.25.254.99:46222 192.168.0.200:80 192.168.0.20:80
第2行协议为IP(不是TCP/UDP),state为ASSURED,是持久连接模板!
| 字段 | 说明 |
|---|---|
| IP | 持久连接模板标识(非真实连接) |
| expire 00:57 | 剩余超时时间(57秒后模板过期) |
| state ASSURED | 已确认的持久连接 |
| source 172.25.254.99:0 | 客户端IP,端口为0表示所有端口 |
| destination 192.168.0.20:0 | 绑定的目标RS |
只要这个模板存在,该客户端的所有请求都会被定向到 192.168.0.20。
2.3 持久连接的超时时间
# 创建时指定超时时间
ipvsadm -A -f 6666 -s wlc -p 300 # 5分钟超时
# 修改已有服务的超时时间
ipvsadm -E -f 6666 -s wlc -p 3600 # 改为1小时
# 注意:如果创建时设了持久连接,修改时需要重新指定 -p
| 超时设置 | 说明 | 适用场景 |
|---|---|---|
| -p 0 | 关闭持久连接 | 不需要会话保持 |
| -p 1~-p 60 | 几秒到1分钟 | 测试效果 |
| -p 300 | 5分钟 | 短会话场景 |
| -p 1800 | 30分钟 | 一般Web应用 |
| -p 3600 | 1小时 | 较长会话的场景 |
注意:超时时间不宜过长,否则会导致负载严重不均------明明有空闲RS,但客户端还被绑死在原来的RS上。
三、解决方案二:SH算法(源地址哈希)
3.1 原理
SH算法对客户端IP做哈希计算,天然具有会话保持特性,不过相同源IP的请求永远去同一台RS。
[root@vsnode ~]# ipvsadm -A -t 192.168.0.200:80 -s sh
[root@vsnode ~]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.10 -g
[root@vsnode ~]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.20 -g
3.2 SH算法特点
| 优点 | 缺点 |
|---|---|
| 配置简单,无超时概念 | 哈希不一定均匀,可能负载不均 |
| 不需要额外参数 | 不适用于代理场景(IP经常变化) |
四、方案对比与选择
| 方案 | 优点 | 缺点 |
|---|---|---|
| 持久连接(-p) | 灵活,可与任何算法配合 | 超时时间内无法重新均衡 |
| SH算法 | 配置简单,无需超时概念 | 哈希不均匀时负载不均 |
| 持久连接+SH | 双重保障,最稳定 | 配置复杂一点 |
ipvsadm命令速查
集群服务管理
| 操作 | 命令 |
|---|---|
| 添加TCP集群服务 | ipvsadm -A -t VIP:PORT -s 算法 -p 超时 |
| 添加防火墙标记服务 | ipvsadm -A -f 标记 -s 算法 -p 超时 |
| 修改集群服务 | ipvsadm -E -t VIP:PORT -s 新算法 |
| 删除集群服务 | ipvsadm -D -t VIP:PORT |
| 清空所有规则 | ipvsadm -C |
RS节点管理
| 操作 | 命令 |
|---|---|
| 添加RS(DR模式) | ipvsadm -a -t VIP:PORT -r RIP -g -w 权重 |
| 添加RS(NAT模式) | ipvsadm -a -t VIP:PORT -r RIP -m -w 权重 |
| 添加RS(TUN模式) | ipvsadm -a -t VIP:PORT -r RIP -i -w 权重 |
| 修改RS | ipvsadm -e -t VIP:PORT -r RIP -w 新权重 |
| 删除RS | ipvsadm -d -t VIP:PORT -r RIP |
查看与监控
| 操作 | 命令 | 说明 |
|---|---|---|
| 查看规则 | ipvsadm -Ln | 查看当前所有规则 |
| 查看连接表 | ipvsadm -Lnc | 查看连接跟踪和持久模板 |
| 实时监控规则 | watch -n 1 ipvsadm -Ln | 每秒刷新 |
| 实时监控连接 | watch -n 1 ipvsadm -Lnc | 每秒刷新 |
| 查看速率 | ipvsadm -Ln --rate | CPS/InPPS/OutPPS等 |
规则持久化
# 方式一:保存到自定义文件
ipvsadm-save > /mnt/ipvs.rule
ipvsadm-restore < /mnt/ipvs.rule
# 方式二:保存到系统配置文件(开机自启)
ipvsadm-save > /etc/sysconfig/ipvsadm
systemctl enable --now ipvsadm.service