LVS(Linux Virtual Server)
LVS 全称 Linux Virtual Server ,是 Linux 内核层实现的高性能、高可用的负载均衡集群技术,由章文嵩博士开发,目前是 Linux 内核的标准模块之一。它的核心作用是将前端的请求流量分发到后端多台真实服务器(Real Server)上,从而提升服务的并发处理能力和可用性。
一.实验环境
| 主机名 | 角色 |
|---|---|
| server1 | 调度器(VS) |
| server2 | 真实服务器(RS) |
| server3 | 真实服务器(RS) |
| server4 | 测试机 |
二、LVS运行原理
2.1LVS简介
2.1.1 什么是LVS
| 项目 | 说明 |
|---|---|
| 全称 | Linux Virtual Server(Linux虚拟服务器) |
| 本质 | 负载调度器,集成在Linux内核中 |
| 作者 | 章文嵩(阿里开源贡献者) |
| 典型应用 | 阿里四层SLB(Server Load Balance)基于 LVS + Keepalived 实现 |
| 官网 | http://www.linuxvirtualserver.org/ #### 3.1.2 LVS核心术语 |
| 缩写 | 全称 | 角色说明 |
|---|---|---|
| VS | Virtual Server | 虚拟服务器,负责调度分发请求 |
| RS | Real Server | 真实服务器,负责实际处理业务 |
2.2 LVS集群体系结构
2.2.1 工作原理
客户端请求 → VS(调度器)根据算法选择 → RS(真实服务器)处理响应
核心逻辑 :VS根据请求报文的目标IP、协议、端口 ,通过调度算法挑选合适的RS进行转发。
2.3 LVS核心概念
2.3.1 关键IP地址定义
表格
复制
| 缩写 | 全称 | 说明 | 类比 |
|---|---|---|---|
| CIP | Client IP | 客户端主机的IP | 顾客的住址 |
| VIP | Virtual Server IP | VS外网IP,对外暴露的访问地址 | 门店招牌地址 |
| DIP | Director IP | VS内网IP,连接后端RS的地址 | 店长内部联络号 |
| RIP | Real Server IP | 真实业务主机的IP | 后厨各工位分机 |
2.3.2 数据流向
CIP <--> VIP == DIP <--> RIP
解读:客户端访问VIP,VS将请求转发到某RS的RIP,响应再返回给客户端。 |
2.4 LVS集群的四种工作模式
| 模式 | 全称 | 核心机制 | 使用频率 |
|---|---|---|---|
| lvs-nat | NAT模式 | 修改请求报文的目标IP(DNAT) | ⭐⭐⭐ |
| lvs-dr | 直接路由模式 | 重新封装MAC地址 | ⭐⭐⭐⭐⭐ 最常用 |
| lvs-tun | 隧道模式 | 在原IP报文外新增IP首部 | ⭐⭐ 远距离场景 |
| lvs-fullnat | 全NAT模式 | 同时修改源IP和目标IP | ⭐ 需重新编译内核 |
2.4.1 NAT模式详解
核心特点
| 特性 | 说明 |
|---|---|
| 本质 | 多目标IP的DNAT(目标地址转换) |
| 网络要求 | RIP和DIP必须在同一IP网络 ,使用私网地址 |
| 网关设置 | RS的网关必须指向DIP |
| 流量走向 | 请求和响应都必须经过Director |
| 端口映射 | 支持修改目标端口 |
| 系统要求 | VS必须是Linux,RS可以是任意OS |
数据流转过程(6步)
1. 客户端 → 发送请求 [CIP→VIP:80]
↓
2. VS调度器 → DNAT转换 [目标VIP→RIP:9000]
↓
3. RS处理 → 响应请求 [RIP→CIP]
↓
4. VS调度器 → SNAT转换 [源RIP→VIP:80]
↓
5. VS回传 → 客户端收到响应
↓
6. ⚠️ 瓶颈:所有流量进出都走VS,易成性能瓶颈
内核处理位置
关键位置 :IPVS作用点在 PREROUTING → INPUT 链之间
注意 :iptables的PREROUTING规则会干扰IPVS工作,部署LVS时需清空防火墙策略。

安装httpd
bash
[root@RS1 ~]# systemctl enable httpd --now
Created symlink /etc/systemd/system/multi-user.target.wants/httpd.service → /usr/lib/systemd/system/httpd.service.
[root@RS1 ~]# echo RS1 - 192.168.0.10 > /var/www/html/index.html
[root@RS1 ~]# curl 192.168.0.10
RS1 - 192.168.0.10
[root@RS1 ~]#
开启调度器内核转发
bash
[root@DR ~]# echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf
[root@DR ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@DR ~]#
配置ipvs
bash
[root@DR ~]# dnf install ipvsadm -y
[root@DR ~]# ipvsadm -C
[root@DR ~]# ipvsadm -A -t 172.25.254.100:80 -s wrr
[root@DR ~]# ipvsadm -a -t 172.25.254.100:80 -r 192.168.0.10 -m -w 1
[root@DR ~]# ipvsadm -a -t 172.25.254.100:80 -r 192.168.0.20 -m -w 1
[root@DR ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.25.254.100:80 wrr
-> 192.168.0.10:80 Masq 1 0 0
-> 192.168.0.20:80 Masq 1 0 0
[root@DR ~]# systemctl restart ipvsadm.service
[root@DR ~]# curl 172.25.254.100
RS1 - 192.168.0.10
[root@DR ~]# curl 172.25.254.100
RS2 - 192.168.0.20
[root@DR ~]# curl 172.25.254.100
RS1 - 192.168.0.10
[root@DR ~]# curl 172.25.254.100
RS2 - 192.168.0.20
[root@DR ~]# curl 172.25.254.100
RS1 - 192.168.0.10
[root@DR ~]# curl 172.25.254.100
RS2 - 192.168.0.20
[root@DR ~]# curl 172.25.254.100
RS1 - 192.168.0.10
ipvs持久化
利用自定义文件进行持久化
bash
[root@DR ~]# ipvsadm-save -n
-A -t 172.25.254.100:80 -s wrr
-a -t 172.25.254.100:80 -r 192.168.0.10:80 -m -w 1
-a -t 172.25.254.100:80 -r 192.168.0.20:80 -m -w 1
[root@DR ~]# ipvsadm-save -n > /mnt/ipvs.rule
[root@DR ~]# ipvsadm -C
[root@DR ~]# ipvsadm-restore < /mnt/ipvs.rule
[root@DR ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.25.254.100:80 wrr
-> 192.168.0.10:80 Masq 1 0 0
-> 192.168.0.20:80 Masq 1 0 0
[root@DR ~]#
DR实验实操

实验环境
| 主机名 | ip | vip | 角色 |
|---|---|---|---|
| client | 172.25.254.10 vmware NAT | null | 测试主机 |
| router | NAT-eth0:172.25.254.100,仅主机-eth1:192.168.0.10 | null | 路由器 |
| lvs | 192.168.0.200,GW 192.168.0.10 仅主机 | lo:192.168.0.100 | 调度器 |
| RS1 | 192.168.0.101,GW 192.168.0.10 仅主机 | lo:192.168.0.100 | web服务器1 |
| RS2 | 192.168.0.102, GW 192.168.0.10 仅主机 | lo:192.168.0.100 | web服务器2 |
实验配置
[root@router ~]# 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
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:61:87:fd brd ff:ff:ff:ff:ff:ff
altname enp3s0
altname ens160
inet 172.25.254.100/24 brd 172.25.254.255 scope global noprefixroute eth0
valid_lft forever preferred_lft forever
inet6 fe80::3fa1:87d2:5cf9:b034/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:0c:29:61:87:07 brd ff:ff:ff:ff:ff:ff
altname enp19s0
altname ens224
inet 192.168.0.100/24 brd 192.168.0.255 scope global noprefixroute eth1
valid_lft forever preferred_lft forever
inet6 fe80::e4ac:effc:837f:ec6e/64 scope link tentative noprefixroute
valid_lft forever preferred_lft forever
[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:a2:8c:26 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::3fa1:87d2:5cf9:b034/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@RS2 ~]# 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:46:6d:2b 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::e90:1704:51c8:2b6b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@DR1 ~]# 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:b8:06:d9 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::6355:ed82:1687:35a1/64 scope link noprefixroute
valid_lft forever preferred_lft forever
[root@client ~]# 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
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:a6:62:22 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::e90:1704:51c8:2b6b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
调度器的配置
[root@DR1 ~]# 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 wrr
-> 192.168.0.10:80 Route 1 0 0
-> 192.168.0.20:80 Route 1 0 0
client的配置
[root@client ~]# 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
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:a6:62:22 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::e90:1704:51c8:2b6b/64 scope link noprefixroute
valid_lft forever preferred_lft forever
测试
[root@client ~]# curl 192.168.0.200
RS2 - 192.168.0.20
[root@client ~]# curl 192.168.0.200
RS1 - 192.168.0.10
[root@client ~]# curl 192.168.0.200
RS2 - 192.168.0.20
[root@client ~]# curl 192.168.0.200
RS1 - 192.168.0.10
[root@client ~]# curl 192.168.0.200
RS2 - 192.168.0.20
[root@client ~]# curl 192.168.0.200
RS1 - 192.168.0.10