LVS-负载均衡
LVS 核心概念
LVS 是由章文嵩博士开发的开源负载均衡解决方案,通过将客户端请求分发到多台后端服务器(Real Server),构建高性能、高可用的虚拟服务器集群系统。其核心组件包括:
- 负载均衡器(Director Server):接收客户端请求,通过调度算法分发流量。
- 真实服务器(Real Server, RS):实际处理请求的后端服务器。
- 虚拟 IP(VIP):客户端访问的统一入口地址,由负载均衡器管理。
工作模式详解
LVS 支持三种主流工作模式,适用于不同网络环境和性能需求:
NAT 模式
- 原理:负载均衡器修改请求包的目标 IP 和端口(VIP → RIP),并将响应包源 IP 改回 VIP。双向流量均需经过负载均衡器。
- 特点:
- 支持端口映射(如将外部 80 端口映射到内部 8080)。
- 负载均衡器易成瓶颈(需处理全量流量),适合小型集群(10-20 台)。
- 真实服务器网关必须指向负载均衡器。
DR 模式
- 原理:负载均衡器仅修改请求包的 目标 MAC 地址(指向选定的 RS),响应包由 RS 直接返回客户端(不经过负载均衡器)。
- 特点:
- 高性能(负载均衡器仅处理请求分发),支持百台级服务器。
- 要求负载均衡器与 RS 在同一局域网,且 RS 需配置 VIP 并启用 ARP 抑制(避免地址冲突)。
- 不支持端口映射。
TUN 模式
- 原理:负载均衡器将请求包封装在 IP 隧道中(新增 IP 头),RS 解封后处理请求并直接响应客户端。
- 特点:
- 支持跨网段/异地部署(如云环境多区域集群)。
- RS 需支持 IP 隧道协议(如 Linux IPIP 模块)。
- 运维复杂度较高,适用特定场景。
三种模式对比
| 特性 | NAT 模式 | DR 模式 | TUN 模式 |
|---|---|---|---|
| 性能瓶颈 | 高(全流量经过) | 低(仅请求分发) | 中(隧道封装开销) |
| 网络要求 | 可跨网段 | 必须同一局域网 | 支持跨网段/异地 |
| RS 系统要求 | 无特殊限制 | 需支持 ARP 抑制 | 需支持 IP 隧道协议 |
| 典型应用场景 | 小型内部集群 | 高并发本地集群(如电商) | 分布式/跨地域服务 |
| 端口映射 | 支持 | 不支持 | 不支持 |
调度算法
LVS 根据业务需求选择不同调度策略:
静态算法
- 轮询(RR):依次分配请求至各 RS(性能均衡场景)。
- 加权轮询(WRR):按 RS 权重分配流量(处理能力差异场景)。
- 源 IP 哈希(SH):同一客户端 IP 固定分发至特定 RS(会话保持场景)。
动态算法
- 最少连接(LC):优先选择当前连接数最少的 RS(长连接服务)。
- 加权最少连接(WLC):综合权重与连接数的最优分配(默认推荐算法)。
各IP地址代表的含义
| 缩写 | 全称 | 中文名称 | 角色与含义 |
|---|---|---|---|
| CIP | Client IP | 客户端 IP 地址 | 发起请求的终端用户设备的 IP 地址。 |
| VIP | Virtual IP | 虚拟 IP 地址 | 对外提供服务的 IP 地址。客户端直接访问的这个IP,它通常配置在负载均衡器(LVS Director)和所有Real Server上。 |
| DIP | Director IP | 调度器 IP 地址 | 负载均衡器(LVS Director)与后端服务器通信时使用的内部 IP 地址。 |
| RIP | Real Server IP | 真实服务器 IP 地址 | 后端真正处理请求的应用服务器(如Nginx、Apache)的物理 IP 地址。 |
核心优势
- 高性能:工作在网络四层,无应用层解析开销,吞吐量可达千兆级。
- 高可用:支持与 Keepalived 集成实现双机热备,自动屏蔽故障节点。
- 扩展性:DR/TUN 模式可扩展至上百台服务器,适应业务增长。
- 透明性:客户端与 RS 无需感知集群存在,无缝接入现有架构。
LVS-NAT模式搭建
mermaid
graph TD
subgraph "External Network (VMNET8)"
A[WAN Client<br/>IP: 192.168.148.150]
end
subgraph "LVS Load Balancer"
B[LVS Load Balancer]
B_ens32[ens32: 192.168.148.130]
B_ens33[ens33: 192.168.148.161]
end
subgraph "Internal Network (VMNET1)"
C[Real Server<br/>HTTP Server 1<br/>IP: 192.168.148.131<br/>GW:192.168.148.130]
D[Real Server<br/>HTTP Server 2<br/>IP: 192.168.148.132<br/>GW:192.168.148.130]
E[Real Server<br/>HTTP Server 3<br/>IP: 192.168.148.133<br/>GW:192.168.148.130]
end
A -->|VMNET8| B_ens33
B_ens32 -->|VMNET1| C
B_ens32 -->|VMNET1| D
B_ens32 -->|VMNET1| E
style A fill:#e1f5fe,stroke:#01579b,stroke-width:2px
style B fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
style C fill:#f1f8e9,stroke:#33691e,stroke-width:2px
style D fill:#f1f8e9,stroke:#33691e,stroke-width:2px
style E fill:#f1f8e9,stroke:#33691e,stroke-width:2px环境准备
| IP地址 | 主机 | 操作系统 | 预装软件 |
|---|---|---|---|
| 192.168.148.130;VIP:192.168.159.130 | lvs-server | openEuler-24.03(LTS) | ipvsadm,内核模块ip_vs |
| 192.168.148.131 | lvs-real01 | openEuler-24.03(LTS) | nginx |
| 192.168.148.132 | lvs-real02 | openEuler-24.03(LTS) | nginx |
lvs-server配置
VIP配置
我这里使用的是VMWare增加的虚拟网卡,网卡类型选择的是主机模式主要用于区分开集群内IP段
内核配置
bash
# 开启路由转发功能,因为调度器同时承载着网关的角色
sed -i 's/net.ipv4.ip_forward = 0"/net.ipv4.ip_forward = 1/' /etc/sysctl.conf
sysctl -p
# 加载内核模块ip_vs
modprobe ip_vs
# 查看lp_vs
lsmod |grep ip_vs配置LVS负载池
bash
dnf -y install ipvsadm
# 指定集群的VIP地址(Virtual IP),rr指定轮询调度算法
ipvsadm -A -t 192.168.148.161:80 -s rr
# -m表示NAT模式,-w指定权重值
ipvsadm -a -t 192.168.148.161:80 -r 192.168.148.131:80 -m -w 1
ipvsadm -a -t 192.168.148.161:80 -r 192.168.148.132:80 -m -w 1
# 保存规则
ipvsadm-save -n > /etc/sysconfig/ipvsadm
# 查看规则
ipvsadm -Lreal后端集群配置
安装nginx服务
bash
dnf -y install nginx
hostname -I > /usr/share/nginx/html/index.html网卡配置
LVS后端服务的网卡只需要将网关地址设置成lvs-server的同网段IP地址
bash
vim /etc/sysconfig/network-scripts/ifcfg-ens32
GATEWAY=192.168.148.130
# 重启网卡
systemctl restart NetworkManager
nmcli conn down ens32; nmcli conn up ens32测试
bash
curl 192.168.159.130LVS-RD模式搭建
mermaid
flowchart TD
subgraph Internet[公网 Internet]
Client[客户端 Client<br/>CIP: 访问者IP]
end
Firewall[防火墙]
Switch[核心交换机]
subgraph LVS_Cluster[LVS 负载均衡集群]
VS[负载均衡器 VS<br/>主机名: lvs-server<br/>DIP: 192.168.148.130<br/>管理VIP: 192.168.148.161]
end
subgraph App_Servers[Web 应用服务器池]
RS1[真实服务器 RS-1<br/>主机名: lvs-real01<br/>RIP: 192.168.148.131<br/>绑定隐藏VIP: 192.168.148.161]
RS2[真实服务器 RS-2<br/>主机名: lvs-real02<br/>RIP: 192.168.148.132<br/>绑定隐藏VIP: 192.168.148.161]
end
Client -->|"请求: Client -> VIP(192.168.148.161)"| Firewall
Firewall -->|请求包| Switch
Switch -->|"请求: Client -> VIP(192.168.148.161)"| VS
VS -->|"1. 接收请求<br/>2. 根据调度算法(如: rr/wlc)<br/>选择一台RS (lvs-real01/02)<br/>3. 仅修改目标MAC地址<br/>(源/目的IP、端口不变)"| Switch
Switch -->|"数据帧: 目标MAC为 lvs-real01"| RS1
Switch -->|"数据帧: 目标MAC为 lvs-real02"| RS2
RS1 -->|"响应: VIP(192.168.148.161) -> Client<br/>(直接返回客户端,不经过VS)"| Client
RS2 -->|"响应: VIP(192.168.148.161) -> Client<br/>(直接返回客户端,不经过VS)"| Client
%% 样式
style Internet fill:#f0f8ff
style LVS_Cluster fill:#f0fff0
style App_Servers fill:#fff0f5
style Client fill:#bae1ff
style VS fill:#baffc9
style RS1 fill:#ffdfba
style RS2 fill:#ffdfbaNOTE
这种模式搭建的LVS负载均衡存在弊端,这里搭建的LVS并没有健康检查,如果后端服务节点的服务宕机了,那么LVS依旧会负载,并不会剔除掉有问题的节点,可以使用Keepalived来规避
环境准备
| IP地址 | VIP | 主机 | 操作系统 | 预装软件 |
|---|---|---|---|---|
| 192.168.148.130 | 192.168.148.161 | lvs-server | openEuler-24.03(LTS) | ipvsadm,内核模块ip_vs |
| 192.168.148.131 | 192.168.148.161 | lvs-real01 | openEuler-24.03(LTS) | nginx |
| 192.168.148.132 | 192.168.148.161 | lvs-real02 | openEuler-24.03(LTS) | nginx |
网络拓扑要求
- 所有节点(调度器、Real Server)必须在同一局域网(二层互通),确保 MAC 地址可直达。
- Real Server 的默认网关不可指向调度器,需指向实际路由器(如
192.168.148.1)
调度器配置(lvs-server)
安装 ipvsadm
bash
dnf install ipvsadm -y
systemctl enable --now ipvsadm配置VIP
bash
cat > /etc/sysconfig/network-scripts/ifcfg-ens32:0 << "EOF"
DEVICE=ens32:0
ONBOOT=yes
IPADDR=192.168.148.161
NETMASK=255.255.255.255
EOF
systemctl restart NetworkManager
nmcli conn down ens32;nmcli conn up ens32- NETMASK:子网掩码必须为/32位
ip_vs配置
bash
# 加载内核模块ip_vs
modprobe ip_vs
# 查看lp_vs
lsmod |grep ip_vs内核配置
bash
# 替换为实际网卡名
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.ens32.send_redirects = 0
# 内核配置生效
sysctl -p
# 注解:
# 开启路由转发功能,因为调度器同时承载着网关的角色
# 禁止转发重定向报文
# 禁止默认转发重定向报文
# 禁止ens32网卡转发重定向报文配置LVS负载池
bash
dnf -y install ipvsadm
# 指定集群的VIP地址(Virtual IP),rr指定轮询调度算法
ipvsadm -A -t 192.168.148.161:80 -s rr
# -g表示DR模式,-w指定权重值
ipvsadm -a -t 192.168.148.161:80 -r 192.168.148.131:80 -g -w 1
ipvsadm -a -t 192.168.148.161:80 -r 192.168.148.132:80 -g -w 1
# 保存规则使用 -n参数禁止反向解析,直接保存 IP 地址
ipvsadm-save -n > /etc/sysconfig/ipvsadm
# 查看规则
ipvsadm -Ln
# 清理规则
ipvsadm --clear
# 清空错误规则
ipvsadm -CReal 配置(lvs-real)
后端节点配置一样,后端所有节点都要配置
安装nginx服务
bash
dnf -y install nginx
# Real Server 1
echo "Real Server 1 ($(hostname -I))" > /usr/share/nginx/html/index.html
# Real Server 2
echo "Real Server 2 ($(hostname -I))" > /usr/share/nginx/html/index.html
# 启动服务
nginx配置VIP
bash
cat > /etc/sysconfig/network-scripts/ifcfg-ens32:0 << "EOF"
DEVICE=ens32:0
ONBOOT=yes
IPADDR=192.168.148.161
NETMASK=255.255.255.255
EOF
systemctl restart NetworkManager
nmcli conn down ens32;nmcli conn up ens32内核配置
bash
vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.ens32.send_redirects = 0
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.ens32.arp_ignore = 1
net.ipv4.conf.ens32.arp_announce = 2
# 内核配置生效
sysctl -p
# 注解:
# 开启路由转发功能,因为调度器同时承载着网关的角色
# 禁止转发重定向报文
# 禁止默认转发重定向报文
# 禁止ens32网卡转发重定向报文
# ARP 抑制客户端访问测试
LVS的DR模式在server端请求VIP地址是不会通的,这是正常现象,必须使用客户端请求VIP地址
bash
curl 192.168.148.161Keepalived+LVS 部署
环境准备
| 角色 | IP地址 | VIP | 功能 |
|---|---|---|---|
| LVS主节点 | 192.168.148.130 | 192.168.148.161 | 运行Keepalived MASTER,流量分发 |
| LVS备节点 | 192.168.148.131 | 192.168.148.161 | 运行Keepalived BACKUP |
| Nginx负载均衡 | 192.168.148.132 | 绑定VIP到lo | 负载均衡代理后端Tomcat |
| Nginx负载均衡 | 192.168.148.133 | 绑定VIP到lo | 负载均衡代理后端Tomcat |
| Tomcat | 192.168.148.134 | - | Tomcat管理Java业务 |
| Tomcat | 192.168.148.135 | - | Tomcat管理Java业务 |
核心要求:
- 所有节点时间同步(
chronyd) - 关闭防火墙:
systemctl disable --now firewalld - 禁用SELinux:
setenforce 0 && sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
时间同步
bash
dnf -y install ntpdate
# 日期同步
ntpdate ntp1.aliyun.com通用基础配置(所有节点执行)
加载IPVS内核模块
bash
modprobe ip_vs
echo "ip_vs" >> /etc/modules-load.d/ipvs.conf # 开机自启
lsmod | grep ip_vs # 验证LVS节点配置(主备节点)
内核优化
bash
cat >> /etc/sysctl.conf << EOF
net.ipv4.ip_forward = 1
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.ens32.send_redirects = 0
EOF
sysctl -p安装服务
bash
# ipvsadm用于调试
dnf install -y keepalived ipvsadmKeepalived主节点配置
bash
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
router_id LVS_MASTER # 唯一标识
}
vrrp_instance VI_1 {
state MASTER
interface ens32 # 网卡名(ip a查看)
virtual_router_id 51 # 主备必须一致
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111 # 主备密码一致
}
virtual_ipaddress {
192.168.148.161/32 dev ens32 # VIP绑定
}
# 非抢占模式(防抖动)
nopreempt
# 单播通信(避免VRRP广播风暴)
unicast_src_ip 192.168.148.130 # 本机IP
unicast_peer {
192.168.148.131 # 对端IP
}
}
virtual_server 192.168.148.161 80 {
delay_loop 6
lb_algo wrr # 加权轮询
lb_kind DR # DR模式
#persistence_timeout 30 # 会话保持
protocol TCP
# 真实服务器1(HTTP健康检查)
real_server 192.168.148.132 80 {
weight 1
HTTP_GET {
url {
path /health_check
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 2
}
}
# 真实服务器2(同上)
real_server 192.168.148.133 80 {
weight 1
HTTP_GET {
url {
path /health_check
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 2
}
}
}
EOFKeepalived备节点配置
bash
cat > /etc/keepalived/keepalived.conf << 'EOF'
global_defs {
router_id LVS_BACKUP # 唯一标识
}
vrrp_instance VI_1 {
state BACKUP
interface ens32 # 网卡名(ip a查看)
virtual_router_id 51 # 主备必须一致
priority 90 # 低于主节点
advert_int 1
authentication {
auth_type PASS
auth_pass 1111 # 主备密码一致
}
virtual_ipaddress {
192.168.148.161/32 dev ens32 # VIP绑定
}
# 非抢占模式(防抖动)
nopreempt
# 单播通信(避免VRRP广播风暴)
unicast_src_ip 192.168.148.131 # 本机IP
unicast_peer {
192.168.148.130 # 对端IP
}
}
virtual_server 192.168.148.161 80 {
delay_loop 6
lb_algo wrr # 加权轮询
lb_kind DR # DR模式
persistence_timeout 30 # 会话保持
protocol TCP
# 真实服务器1(HTTP健康检查)
real_server 192.168.148.132 80 {
weight 1
HTTP_GET {
url {
path /health_check
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 2
}
}
# 真实服务器2(同上)
real_server 192.168.148.133 80 {
weight 1
HTTP_GET {
url {
path /health_check
status_code 200
}
connect_timeout 3
retry 3
delay_before_retry 2
}
}
}
EOF启动服务
bash
systemctl enable --now keepalived
# 查看LVS规则
ipvsadm -Ln负载均衡配置
配置VIP
bash
ip addr add 192.168.148.161/32 dev lo
# 持久化(重启后生效)
echo 'ip addr add 192.168.148.161/32 dev lo' >> /etc/rc.local
chmod +x /etc/rc.d/rc.local内核优化
bash
# ARP抑制(关键!)
cat >> /etc/sysctl.conf << EOF
net.ipv4.ip_forward = 1
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
EOF
sysctl -p作用:避免Real Server响应VIP的ARP请求导致IP冲突
配置Nginx负载均衡和健康检查
bash
# health.conf
cat > /etc/nginx/conf.d/www.conf << "EOF"
upstream tomcat_servers {
ip_hash;
server 192.168.148.134:8080 weight=1;
server 192.168.148.134:8080 weight=1;
}
server {
listen 80;
location / {
proxy_pass http://tomcat_servers;
index index.jsp;
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Client-IP $remote_addr;
proxy_set_header X-For $proxy_add_x_forwarded_for;
}
location /health_check {
allow 192.168.148.0/24; # 仅允许LVS网段访问
deny all;
return 200 "OK";
}
}
EOF
nginx -s reload后端Tomcat部署
安装JDK
bash
wget https://download.java.net/java/GA/jdk22.0.1/c7ec1332f7bb44aeba2eb341ae18aca4/8/GPL/openjdk-22.0.1_linux-x64_bin.tar.gz
tar xvf openjdk-22.0.1_linux-x64_bin.tar.gz -C /usr/local/
# 编辑环境变量配置文件
cat >> /etc/profile << "EOF"
export JAVA_HOME=/usr/local/jdk-22.0.1
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib:$CLASSPATH
export JAVA_PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin
export PATH=$PATH:${JAVA_PATH}
EOF
source /etc/profile
# 检测
java -version安装Tomcat
bash
# Tomcat下载:
https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.108/bin/apache-tomcat-9.0.108.tar.gz
# 解压
tar xf apache-tomcat-9.0.108.tar.gz -C /usr/local/
mv /usr/local/apache-tomcat-9.0.108 /usr/local/tomcat
# 可选的操作
echo 'export TOMCAT_HOME=/usr/local/tomcat' >>/etc/profile
source /etc/profile
# 启动程序
/usr/local/tomcat/bin/startup.sh
# 关闭程序
/usr/local/tomcat/bin/shutdown.sh创建测试页面
bash
hostname -I > /usr/local/tomcat/webapps/ROOT/index.jsp健康检查与故障切换验证
模拟节点故障
bash
# 在132上停止Nginx
nginx -s stop主备切换测试
bash
# 停止主节点Keepalived
systemctl stop keepalived验证:
备节点应接管VIP(ip a show ens32),且LVS规则自动同步
