一、LVS核心理论

LVS 全称 Linux Virtual Server,是 Linux 内核层实现的高性能、高可用负载均衡集群技术

1 LVS概念

LVS: Linux Virtual Server,负载调度器,内核集成,阿里的四层 SLB(Server LoadBalance) 是基于 LVS+keepalived 实现。

下面为LVS的官方网站:

1.1 LVS相关术语

  • VS:Virtual Server,虚拟服务器,即 LVS 负载调度器
  • RS:Real Server,真实服务器,后端实际执行业务处理的主机
  • VIP:Virtual Server IP,虚拟 IP,集群对外暴露、供客户端访问的 IP
  • DIP:Director Server IP,调度器内网 IP,用于调度器与后端服务器通信
  • RIP:Real Server IP,真实服务器 IP,后端业务服务器的内网地址
  • CIP:Client IP,客户端 IP,发起请求的用户端 IP 地址

1.2 LVS结构

LVS集群分三层结构:

  • 负载调度器(Load Blancer):

    • 作为整个 LVS 集群的对外前端节点,负责将客户端请求分发至多台 LB 服务器上处理,客户端视角下只会感知到一个统一 IP,该 IP 通常称为虚拟 IP(VIP)
  • 服务器池(Server Pool):

    • 实际处理客户端请求的服务器集群,一般为 Web 服务器,也可部署 FTP、MAIL、DNS 等服务。
  • 共享存储(Shared Stord):

    • 为服务器池提供共享存储区域,便于集群内所有服务器保持内容一致,对外提供相同服务。

2 LVS集群

集群:同一个业务系统,部署在多台服务器上,集群中,每一台服务器实现的功能没有差别,数据 和代码都是一样的

2.1 类型

  • LVS-NAT:基于 DNAT 实现,修改请求报文的目标 IP,支持多目标 IP 映射
  • LVS-DR:直接路由模式,通过改写报文的目标 MAC 地址实现转发
  • LVS-TUN:IP 隧道模式,在原始 IP 报文外新增一层 IP 首部封装
  • LVS-FullNAT:同时修改请求报文的源 IP目标 IP,支持跨网段调度

2.2 LVS-NAT

  • 本质:是多目标 IP 的 DNAT,通过将请求报文中的目标地址和目标端口,修改为选中 RS 的 RIP 及端口,实现流量转发。

  • 原理图

img

  • 流程

    客户端请求到达 LVS 调度器(Director)后,调度器会修改请求报文的目标 IP 为真实服务器 IP(RIP),并将目标端口改为真实服务器对应端口,再将报文转发至后端真实服务器(Real Server);
    真实服务器处理完成后,将响应报文回传给调度器,最终由调度器将报文转发给客户端。

  • 特性

    1. RIP 与 DIP 须在同一 IP 网络,推荐使用私网地址;RS 网关需指向 DIP。
    2. 通过修改报文目标 IP实现转发,无需改写 MAC 地址,VIP 与 RIP 可不在同一网段
    3. 请求报文与响应报文都必须经过 调度器 转发, 调度器 容易成为系统瓶颈。
    4. 支持端口映射,可修改请求报文的目标端口。
    5. VS 必须是 Linux 系统,RS 可以是任意操作系统。

2.3 LVS-DR

  • 本质:工作在数据链路层(二层)的负载均衡,仅改写请求报文的目标 MAC 地址实现转发,IP 与端口全程保持不变

  • 原理图

img

  • 流程

    客户端请求抵达 LVS 调度器(Director)后,调度器仅修改报文目标 MAC 为后端选中 RealServer 的 MAC源 IP(客户端 IP)、目标 IP(VIP)全程保持不变,再将报文转发至 RealServer;

    RealServer 因本地已配置 VIP,会正常处理请求,响应报文可直接返回给客户端(同网段直连,跨网段则通过网关转发),无需再经过 Director。

  • 特性

    1. 前端路由需将所有目标为 VIP 的报文,统一转发至 Director Server。
    2. RealServer(RS)与 Director Server 需至少一块网卡处于同一物理网络
    3. 仅请求报文经由 Director 转发,响应报文由 RS 直接返回客户端,性能极高。
    4. 所有 RealServer 上均需配置 VIP 地址。

二、LVS基础实验

1 LVS-NAT模式

笔记时间:2026-1-20

1.1 环境图

1.2 配置过程

  • VS
1
2
3
4
5
6
7
8
[root@vsnode ~]# vmset.sh vsnode eth0 172.25.254.100 
[root@vsnode ~]# vmset.sh vsnode eth1 192.168.0.100 vsnode nogateway

[root@vsnode ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 172.25.254.2 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
  • RS1
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@vsnode ~]# vmset.sh RS1 eth0 192.168.0.10 192.168.0.100

[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


[root@RS1 ~]# dnf install httpd -y --disablerepo=docker,epel
[root@RS1 ~]# systemctl enable --now httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[root@RS1 ~]# echo 192.168.0.10 --- RS1 > /var/www/html/index.html
  • RS2
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@vsnode ~]# vmset.sh RS2 eth0 192.168.0.20 192.168.0.100

[root@RS2 ~]# 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


[root@RS2 ~]# dnf install httpd -y --disablerepo=docker,epel
[root@RS2 ~]# systemctl enable --now httpd
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service →
[root@RS2 ~]# echo 192.168.0.20 --- RS1 > /var/www/html/index.html

1.3 实验验证

1
2
3
4
5
# VSnode中
[root@vsnode ~]# curl 192.168.0.10
192.168.0.10 --- RS1
[root@vsnode ~]# curl 192.168.0.20
192.168.0.20 --- RS2

2 LVS-DR

笔记时间:2026-1-22

2.1 环境图

2.2 配置过程

  • Router
1
2
3
4
5
6
7
8
9
10
11
12
13
[root@router ~]# vmset.sh router eth0 172.25.254.100
[root@router ~]# vmset.sh router eth1 192.168.0.100 nogateway

[root@router ~]# dnf install ipvsadm -y
[root@router ~]# systemctl disable --now ipvsadm.service
[root@router ~]# ipvsadm -C

[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@router ~]# iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 172.25.254.100
  • VS调度器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
[root@vsnode ~]# vmset.sh vsnode eth0 192.168.0.50 192.168.0.100


[root@vsnode ~]# cd /etc/NetworkManager/system-connections/
[root@vsnode system-connections]# cp -p eth0.nmconnection lo.nmconnection
[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

[root@vsnode system-connections]# nmcli connection reload
[root@vsnode system-connections]# nmcli connection up lo
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/8)

[root@vsnode ~]# 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


[root@vsnode ~]# 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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:2c:93:ef brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 192.168.0.50/24 brd 192.168.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::ee1f:f906:ed7:7719/64 scope link noprefixroute
valid_lft forever preferred_lft forever

  • Client
1
2
3
4
5
6
7
8
9
10
[root@client ~]# vmset.sh client eth0 172.25.254.99

[root@client ~]# ping 192.168.0.200 -c 2
PING 192.168.0.200 (192.168.0.200) 56(84) 比特的数据。
64 比特,来自 192.168.0.200: icmp_seq=1 ttl=128 时间=0.841 毫秒
64 比特,来自 192.168.0.200: icmp_seq=2 ttl=128 时间=0.691 毫秒

--- 192.168.0.200 ping 统计 ---
已发送 2 个包, 已接收 2 个包, 0% packet loss, time 1031ms
rtt min/avg/max/mdev = 0.691/0.766/0.841/0.075 ms
  • RS1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
[root@RS1 ~]# vmset.sh RS1 eth0 192.168.0.10 192.168.0.100
eth0 正在使用!!!
成功删除连接 "eth0" (7ba00b1d-8cdd-30da-91ad-bb83ed4f7474)。
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/6)

=====网卡详细信息====
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:75:27:4f brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 192.168.0.10/24 brd 192.168.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::d364:aca6:84cb:34d7/64 scope link tentative noprefixroute
valid_lft forever preferred_lft forever
====路由表====
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
====主机名====
RS1

[root@RS1 ~]# cd /etc/NetworkManager/system-connections/
[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

[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
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:c4:c1:29 brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 192.168.0.10/24 brd 192.168.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::d364:aca6:84cb:34d7/64 scope link noprefixroute
valid_lft forever preferred_lft forever

# arp 禁止响应
[root@RS1 ~]# vim arp.sh
#!/bin/bash
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 执行成功
[root@RS1 ~]# bash arp.sh
  • RS2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[root@RS2 ~]#  vmset.sh RS2 eth0 192.168.0.20 192.168.0.100
eth0 正在使用!!!
成功删除连接 "eth0" (7ba00b1d-8cdd-30da-91ad-bb83ed4f7474)。

连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/6)

=====网卡详细信息====
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:30:97:ac brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 192.168.0.20/24 brd 192.168.0.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::d364:aca6:84cb:34d7/64 scope link tentative noprefixroute
valid_lft forever preferred_lft forever
====路由表====
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
====主机名====
RS2


[root@RS2 ~]# cd /etc/NetworkManager/system-connections/
[root@RS2 system-connections]# cp -p eth0.nmconnection lo.nmconnection
[root@RS2 system-connections]# vim lo.nmconnection
[connection]
id=lo
type=loopback
interface-name=lo

[ethernet]

[ipv4]
method=manual
address1=127.0.0.1/8
address2=192.168.0.200/32

[root@RS2 system-connections]# nmcli connection reload
[root@RS2 system-connections]# nmcli connection up lo
连接已成功激活(D-Bus 活动路径:/org/freedesktop/NetworkManager/ActiveConnection/8)

# arp 禁止响应
[root@RS1 ~]# vim arp.sh
#!/bin/bash
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 执行成功
[root@RS1 ~]# bash arp.sh

2.3 两种策略

  1. 利用火墙标记解决轮询错误

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    # 在rs主机中同时开始http和https两种协议
    [root@RS1 ~]# dnf install ipvsadm -y
    [root@RS1 ~]# dnf install mod_ssl -y
    [root@RS1 ~]# systemctl disable --now ipvsadm.service
    [root@RS1 ~]# ipvsadm -C
    [root@RS1 ~]# systemctl restart httpd

    # 在vsnode中添加https的轮询策略
    [root@vsnode ~]# dnf install ipvsadm -y

    [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.20 -g
    [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:443 -s rr
    [root@vsnode ~]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.10:443 -g
    [root@vsnode ~]# ipvsadm -a -t 192.168.0.200:443 -r 192.168.0.20:443 -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

    # 轮询错误展示

    [root@client ~]# curl 192.168.0.200;curl -k https://192.168.0.200
    192.168.0.10 --- RS1
    192.168.0.10 --- RS1

    # 当上述设定完成后http和https是独立的service,轮询会出现重复问题

    # 解决方案
    # 使用火墙标记访问vip的80和443的所有数据包,设定标记为6666,然后对此标记进行负载
    [root@vsnode ~]# ipvsadm -C
    [root@vsnode ~]# iptables -t mangle -A PREROUTING -d 192.168.0.200 -p tcp -m multiport --dports 80,443 -j MARK --set-mark 6666

    [root@vsnode ~]# ipvsadm -A -f 6666 -s rr
    [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@client ~]# curl 192.168.0.200;curl -k https://192.168.0.200
    192.168.0.20 --- RS2
    192.168.0.10 --- RS1
  2. 利用持久连接实现会话粘滞

    1
    2
    3
    # 利用持久连接实现会话粘滞
    ## 设定ipvs调度策略
    [root@vsnode ~]# ipvsadm -A -f 6666 -s rr -p 1