LVS(Linux Virtual Server,Linux 虚拟服务器) 是 Linux 内核原生的高性能四层负载均衡方案,由章文嵩博士开发,已集成进 Linux 内核,用于将流量分发到后端服务器集群,提升系统并发与可用性。
一、LVS DR(直接路由)模式(设计调度器,路由器,客户端,后端服务器)
1.调度器初始化配置
bash
# 1. 配置调度器eth0网卡IP为192.168.0.50,主机标识vsnode。norouter:不自动添加默认路由(避免路由冲突)
# 注:vmset.sh是实验环境自定义脚本,等价于ip addr add 192.168.0.50/24 dev eth0
[root@vsnode ~]# vmset.sh eth0 192.168.0.50 vsnode norouter
# 2. 编辑NetworkManager的eth0网卡配置文件(持久化IP/网关配置)
[root@vsnode ~]# vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet #以太网
interface-name=eth0 #绑定网卡
[ipv4]
method=manual
address1==192.168.0.50/24,192.168.0.100
# 3. 进入NetworkManager配置文件目录(存放所有网卡的持久化配置)
[root@vsnode ~]# cd /etc/NetworkManager/system-connections/
# 4. 复制eth0的配置文件为lo.nmconnection(快速生成回环网卡配置模板,-p:保留原文件权限/属性)
# 注:DR模式中调度器需要在lo(回环网卡)绑定VIP,因此需单独配置lo
[root@vsnode system-connections]# cp -p eth0.nmconnection lo.nmconnection
# 5. 编辑lo(回环网卡)配置文件,核心目的:绑定VIP(192.168.0.200)
[root@vsnode system-connections]# vim lo.nmconnection
[connection]
id=lo #回环网卡
type=loopback
interface-name=lo
[ipv4]
method=manual
address1==127.0.0.1/8
address2=192.168.0.200/32
# 6. 重载NetworkManager配置(使修改后的网卡配置生效,无需重启服务)
[root@RS1 system-connections]# nmcli connection reload
[root@RS1 system-connections]# nmcli connection up eth0
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/7)
[root@RS1 system-connections]# nmcli connection up lo
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/8)
#检测
root@vsnode system-connections]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.0.100 0.0.0.0 UG 100 0 0 eth0
192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
[root@vsnode system-connections]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet 192.168.0.200/32 brd 192.168.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:41:e5:8b brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 192.168.0.50/24 brd 192.168.0.255 scope global secondary noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::e40:8975:6b9:fea8/64 scope link noprefixroute
valid_lft forever preferred_lft forever
2.路由器初始化
bash
# 1. 停止ipvsadm服务并禁用开机自启(--now:立即停止)
# 作用:清理旧的LVS调度规则,防止原有配置影响新的路由/NAT设置
[root@router ~]# systemctl disable --now ipvsadm.service
Removed "/etc/systemd/system/multi-user.target.wants/ipvsadm.service".
# 2. 清空所有IPVS(LVS)规则(-C:Clear,清空)
# 作用:彻底重置LVS调度器,删除所有已配置的虚拟服务和后端服务器规则
[root@router ~]# ipvsadm -C
#在路由器中
[root@router ~]# vmset.sh eth0 172.25.254.100 vsnode
[root@router ~]# vmset.sh eth1 192.168.0.100 vsnode noroute、
#设定内核路由功能
# 3.将net.ipv4.ip_forward=1写入/etc/sysctl.conf,实现永久开启IP转发
[root@router ~]# echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf
[root@router ~]# sysctl -p
net.ipv4.ip_forward = 1
#数据转发策略
[root@router ~]# iptables -t nat -A POSTROUTING -o eth1 -j SNAT --to-source 192.168.0.100
[root@vsnode ~]# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 172.25.254.100
3.客户端
bash
# norouter参数:避免脚本自动添加默认路由,后续手动配置网关指向调度器(保证流量走LVS集群)
[root@client ~]# vmset.sh eth0 172.25.254.99 client norouter
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/4)
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:e5:75:af brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 172.25.254.99/24 brd 172.25.254.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fee5:75af/64 scope link tentative noprefixroute
valid_lft forever preferred_lft forever
client
#编辑NetworkManager的eth0网卡配置文件(实现IP/网关/DNS的永久生效)
[root@client ~]# vim /etc/NetworkManager/system-connections/eth0.nmconnection
[connection]
id=eth0
type=ethernet
interface-name=eth0
# 核心作用:客户端所有跨网段流量(如访问192.168.0.200)都会转发到调度器,实现负载均衡
[ipv4]
method=manual
address1=172.25.254.99/24,172.25.254.100
dns=8.8.8.8;
[root@client ~]# nmcli connection reload
[root@client ~]# nmcli connection up eth0
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/5)
[root@client ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.25.254.100 0.0.0.0 UG 100 0 0 eth0
172.25.254.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
#检测
[root@client ~]# ping 192.168.0.200
PING 192.168.0.200 (192.168.0.200) 56(84) 比特的数据。
64 比特,来自 192.168.0.200: icmp_seq=1 ttl=128 时间=1.08 毫秒
4.RS1和RS2
bash
#RS1/RS2
[root@RS1 ~]# vmset.sh eth0 192.168.0.10 RS1 noroute
# 修改eth0网卡的NetworkManager配置,设置默认网关为192.168.0.100(LVS调度器后端IP)
# 核心作用:DR模式下RS1的回包需先指向调度器,确保流量路径正确(客户端→调度器→RS1→调度器→客户端)
[root@RS1 ~]# nmcli connection modify eth0 ipv4.gateway 192.168.0.100
#重载NetworkManager配置(使网关修改生效)
[root@RS1 ~]# nmcli connection reload
[root@RS1 ~]# nmcli connection up eth0
[root@RS1 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.0.100 0.0.0.0 UG 100 0 0 eth0
192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 eth0
#在lo上设定vip
[root@RS1 ~]# cd /etc/NetworkManager/system-connections/
#复制eth0的配置文件为lo.nmconnection
# 作用:无需手动新建lo配置文件,基于eth0的模板修改即可
[root@RS1 system-connections]# cp -p eth0.nmconnection lo.nmconnection
[root@RS1 system-connections]# vim lo.nmconnection
[connection]
id=lo
type=loopback
interface-name=lo
[ethernet]
[ipv4]
address1=127.0.0.1/8
address2=192.168.0.200/32
method=manual
[root@RS1 system-connections]# nmcli connection reload
[root@RS1 system-connections]# nmcli connection up lo
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/6)
[root@RS1 system-connections]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet 192.168.0.200/32 scope global lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
#arp禁止响应
[root@rs1 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@rs1 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@rs1 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@rs1 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
易错点:
- 常见错误:配置 NetworkManager 文件时出现
address1==xxx双等号语法错误,导致 VIP 绑定到 eth0 而非 lo; - 参数持久化:ARP 抑制参数(arp_ignore/arp_announce)当前为临时生效,需写入
/etc/sysctl.conf实现重启不丢失; - 规则补全:需在调度器上添加 LVS 核心规则(
ipvsadm -A -t 192.168.0.200:80 -s rr),才能实现流量分发到 RS1/RS2
二、利用火墙标记解决轮询错误
1.在rs主机中同时开始http和https两种协议
bash
#在RS1和RS2中开启https
# 安装 Apache 的 SSL 模块(mod_ssl 是实现 HTTPS 的核心模块)
[root@RS1+RS2 ~]# dnf install mod_ssl -y
# 重启 httpd 服务,使 mod_ssl 模块生效
[root@RS1+RS2 ~]# systemctl restart httpd
[root@RS1+RS2 ~]# systemctl restart httpd#验证
2.在vsnode中添加https的轮询策略
bash
root@vsnode boot]# ip^Cadm -A -t 192.168.0.200:80 -s rr
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.20 -g
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:80 -r 192.168.0.10 -g
[root@vsnode boot]# ipvsadm -A -t 192.168.0.200:443 -s rr
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.10:443 -g
[root@vsnode boot]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.20:443 -g
[root@vsnode boot]# 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
3.轮询错误展示
bash
[root@client ~]# curl 192.168.0.200;curl -k https://192.168.0.200
RS2 - 192.168.0.20
RS2 - 192.168.0.20
#当上述设定完成后http和https是独立的service,轮询会出现重复问题
#问题原因:HTTP 和 HTTPS 是独立的 LVS 虚拟服务
80 和 443 端口分别创建了独立的 LVS 虚拟服务(192.168.0.200:80 和 192.168.0.200:443),且都使用 rr(轮询)算法。
rr 算法是按虚拟服务独立计数的:80 端口的轮询计数器和 443 端口的计数器互不干扰。
但是同时执行 curl 80端口 + curl 443端口 时,两个请求分别走各自的轮询序列,大概率会命中同一台服务器(比如第一次 80 端口轮询到 RS2,443 端口轮询也刚到 RS2),就出现了重复问题。
#如何解决:使用 persistent(持久连接)特性(适合需要会话粘滞的场景)
[root@vsnode boot]# iptables -t mangle -A PREROUTING -d 192.168.0.200 -p tcp -m multiport --dports 80,443 -j MARK --set-mark 6666
[root@vsnode boot]# ipvsadm -A -f 6666 -s rr
[root@vsnode boot]# ipvadm -a -f 6666 -r 192.168.0.10 -g
[root@vsnode boot]# ipvsadm -a -f 6666 -r 192.168.0.20 -g
#测试:在客户端
[root@client ~]# curl 192.168.0.200;curl -k https://192.168.0.200
RS2 - 192.168.0.20
RS1 - 192.168.0.10