1. 负载均衡概述:为什么需要它

1.1 单机服务的瓶颈

在互联网早期,一台服务器足以支撑一个网站。随着用户量增长,单机面临以下问题:

问题表现后果
性能瓶颈CPU、内存、磁盘 I/O、网络带宽达到上限响应变慢,超时增多
单点故障服务器宕机、网卡故障、机房断电服务完全不可用
扩展困难垂直扩容(加 CPU / 内存)成本高且有上限无法应对流量洪峰

负载均衡(Load Balancing) 的核心思想是:将大量并发请求分散到多台后端服务器上,使每台机器只处理一部分流量,从而提升整体吞吐能力、降低单点风险。

1.2 负载均衡要解决的三件事

                    ┌─────────────────┐
   客户端请求 ──────►│   负载均衡器     │
                    │  (Director/LB)  │
                    └────────┬────────┘
                             │
              ┌──────────────┼──────────────┐
              ▼              ▼              ▼
         ┌─────────┐   ┌─────────┐   ┌─────────┐
         │ Real 1  │   │ Real 2  │   │ Real 3  │
         └─────────┘   └─────────┘   └─────────┘
  1. 分发(Distribution):按某种算法将请求分配到后端节点
  2. 高可用(High Availability):某节点故障时自动剔除、流量转移
  3. 扩展(Scalability):可动态增删后端节点,水平扩展

1.3 百亿级流量下的负载均衡

在大型互联网场景(如电商大促、春晚红包),负载均衡处于流量入口的第一道关卡

  • 接入层:DNS → CDN → 四层 LB(LVS/F5)→ 七层 LB(Nginx/HAProxy)→ 应用集群
  • 性能要求:四层 LB 需支持百万级并发连接、极低延迟
  • 可靠性要求:LB 本身不能成为单点,必须主备 / 集群化

四层负载均衡(如 LVS)因工作在内核态,适合超高并发、低延迟场景;七层负载均衡(如 Nginx)因能解析 HTTP,适合路由、缓存、SSL 终结等应用层逻辑。


2. 四层与七层负载均衡:本质区别与选型

2.1 OSI 模型回顾

┌──────────────────────────────────────────────────────────────┐
│  七层  Application   HTTP、HTTPS、FTP、SMTP、DNS ...          │
│  六层  Presentation  加密、压缩、编码转换                      │
│  五层  Session       会话管理                                 │
│  四层  Transport     TCP、UDP(端口、连接)  ◄── 四层 LB 工作于此 │
│  三层  Network       IP 路由                                 │
│  二层  Data Link     MAC 地址                                │
│  一层  Physical      物理传输                                 │
└──────────────────────────────────────────────────────────────┘
  • 四层负载均衡(L4):基于 IP + 端口 转发,不解析应用层协议内容
  • 七层负载均衡(L7):基于 HTTP Header、URL、Cookie 等应用层信息路由

2.2 核心对比

维度四层(L4)七层(L7)
工作层级传输层(TCP/UDP)应用层(HTTP/HTTPS)
转发依据IP、端口URL、Header、Cookie、Host
性能极高(内核转发)较高(需解析协议)
灵活性低,无法按 URL 分流高,可灰度、A/B 测试
典型工具LVS、F5、Nginx streamNginx、HAProxy、Traefik
SSL 终结一般不支持(需透传)支持
真实 IP需额外机制(TOA/Proxy Protocol)可通过 X-Forwarded-For 传递
适用协议任意 TCP/UDP主要是 HTTP/HTTPS

2.3 数据包流转对比

四层 LB 转发示意:

Client                    L4 LB                    Backend
  │                         │                         │
  │──── SYN (CIP:Cport ──► VIP:Vport) ────────────────►│
  │                         │  修改目标 IP:Port        │
  │                         │─────────────────────────►│ RIP:Rport
  │◄─── 响应 ◄──────────────│◄─────────────────────────│

七层 LB 转发示意:

Client                    L7 LB                    Backend
  │                         │                         │
  │──── GET /api/user HTTP/1.1 ─────────────────────►│
  │                         │  解析 Host/URI           │
  │                         │  选择 upstream           │
  │                         │──── 新 TCP 连接 ────────►│
  │                         │  可修改 Header           │
  │◄─── HTTP Response ◄─────│◄─────────────────────────│

2.4 工作中如何选择四 / 七层

选四层(LVS / Nginx stream)当:

  • 流量极大,追求极致性能(百万 QPS 级)
  • 协议非 HTTP(MySQL、Redis、MQ、gRPC over TCP)
  • 只需按 IP:Port 分发,无需 URL 路由
  • 作为入口第一层,后面再接七层

选七层(Nginx / HAProxy HTTP)当:

  • 需要按 URL、域名、Header 路由
  • 需要 SSL 卸载、缓存、限流、WAF
  • 需要灰度发布、A/B 测试
  • Web/API 服务为主

典型生产架构(推荐):

Internet → LVS(四层) → Nginx集群(七层) → 应用服务器
              ↑              ↑
         超高并发入口      灵活路由+SSL+缓存

3. LVS 是什么:架构与核心组件

3.1 LVS 简介

LVS(Linux Virtual Server) 是由章文嵩博士主导开发的开源负载均衡解决方案,集成在 Linux 内核中,通过 IPVS(IP Virtual Server) 模块实现四层负载均衡。

特点:

  • 内核级转发:数据包在内核空间完成调度,性能接近硬件 LB
  • 高并发:可支持数十万并发连接
  • 多种工作模式:NAT、DR、TUN、FullNAT
  • 丰富调度算法:rr、wrr、lc、wlc、sh、dh 等
  • 开源免费:无授权费用

3.2 LVS 架构组成

┌─────────────────────────────────────────────────────────────┐
│                      LVS 集群架构                            │
│                                                             │
│   Client ──► Director Server (负载调度器)                    │
│              ├── VIP: 虚拟 IP,对外服务地址                   │
│              ├── DIP: Director IP,与 RS 通信                │
│              └── IPVS 内核模块 + ipvsadm 管理工具            │
│                         │                                   │
│              ┌──────────┼──────────┐                        │
│              ▼          ▼          ▼                        │
│         Real Server  Real Server  Real Server               │
│         RIP1:Port    RIP2:Port    RIP3:Port                 │
└─────────────────────────────────────────────────────────────┘
组件全称说明
Director负载调度器运行 IPVS,接收请求并转发到 RS
Real Server (RS)真实服务器实际处理业务的后端节点
VIPVirtual IP对外提供的虚拟 IP,客户端访问地址
DIPDirector IPDirector 与 RS 通信用的 IP
RIPReal IPRS 的真实 IP
IPVSIP Virtual ServerLinux 内核模块,实现负载均衡
ipvsadm用户态管理工具配置 IPVS 规则

3.3 为何需要 LVS

与 Nginx、HAProxy 等用户态代理相比,LVS 的优势:

  1. 性能:内核转发,无用户态 / 内核态频繁切换,单机可支撑百万连接
  2. 稳定:久经大规模生产验证(阿里、百度、腾讯等)
  3. 低开销:Director 只做调度,不终止连接(DR/TUN 模式)
  4. 适配广:支持 TCP、UDP、SCTP 等

适用场景:

  • 大型网站 / Web 服务入口
  • 邮件、DNS、FTP 等 TCP 服务
  • MySQL/Redis 等数据库读负载(只读副本)
  • 游戏服务器、长连接服务

3.4 LVS 与 Keepalived 的关系

  • LVS:负责负载均衡调度
  • Keepalived:负责 VIP 漂移、健康检查、Director 高可用(VRRP 协议)

二者常配合使用:Keepalived 管理 VIP 和 RS 健康状态,并调用 ipvsadm 或内置 IPVS 配置实现 LB。


4. LVS 工作模型详解:NAT、DR、TUN、FullNAT

LVS 有四种工作模式,差异在于请求与响应的数据包路径

4.1 NAT 模式

原理: Director 修改数据包的目标 IP(DNAT),RS 响应时修改源 IP(SNAT),请求和响应都经过 Director

Client ──► Director(VIP) ──DNAT──► RS(RIP)
Client ◄── Director(VIP) ◄──SNAT── RS(RIP)
项目说明
Director必须开启 ip_forward,通常是 RS 的默认网关
RS 网络可以是私有 IP,与 Director 同网段或跨网段
RS 网关必须指向 Director 的 DIP
优点RS 可使用任意操作系统,RS 可出公网
缺点Director 易成瓶颈,扩展 RS 数量受限(约 10~20 台)

4.2 DR 模式(Direct Routing,最常用)

原理: Director 只修改目标 MAC 地址,将包转发给 RS;RS 响应时直接回 Client,不经过 Director。

Client ──► Director(VIP) ──改MAC──► RS(有VIP在lo上)
Client ◄────────────────────────── RS 直接响应
项目说明
要求Director 与 RS 必须在同一物理网段(L2)
RS 配置lo 上绑定 VIP;抑制 ARP 应答
优点性能最高,Director 压力小,可扩展大量 RS
缺点要求 L2 互通,配置稍复杂

4.3 TUN 模式(IP Tunneling)

原理: Director 将请求包封装在 IP 隧道中发给 RS;RS 解封装后处理,响应直接回 Client。

Client ──► Director ──IPIP隧道──► RS(有VIP在tunl0上)
Client ◄────────────────────────── RS 直接响应
项目说明
要求RS 支持 IPIP 隧道
优点RS 可跨网段、跨地域
缺点有隧道封装开销,MTU 需调整

4.4 FullNAT 模式

原理: 同时修改源 IP 和目标 IP,RS 无需配置 VIP,也无需与 Director 同网段。

Client ──► Director: 改 src=DIP, dst=RIP ──► RS
Client ◄── Director: 改 src=VIP, dst=CIP ◄── RS
项目说明
优点RS 无需 VIP,无 ARP 问题,跨网段灵活
缺点需内核支持(阿里开源 patch),响应仍过 Director

4.5 四种模式对比总结

模式请求路径响应路径性能复杂度生产常用度
NAT过 Director过 Director★★★
DR过 Director直连 Client★★★★★
TUN过 Director(隧道)直连 Client中高★★
FullNAT过 Director过 Director★★★★

选型建议:

  • 同机房、Web/DB 读负载 → DR
  • 小规模、RS 需出公网 → NAT
  • 跨机房、跨地域 → TUN 或 FullNAT
  • 云环境、RS 无 VIP 需求 → FullNAT

5. ipvsadm:LVS 集群管理命令全解

5.1 安装与内核模块

# CentOS/RHEL
yum install -y ipvsadm

# Ubuntu/Debian
apt install -y ipvsadm

# 加载 IPVS 内核模块
modprobe ip_vs
modprobe ip_vs_rr      # 调度算法模块
modprobe ip_vs_wrr
modprobe ip_vs_sh
modprobe ip_vs_wlc

# 开机自动加载
cat >> /etc/modules-load.d/ipvs.conf << 'EOF'
ip_vs
ip_vs_rr
ip_vs_wrr
ip_vs_sh
ip_vs_wlc
nf_conntrack
EOF

# 查看是否加载成功
lsmod | grep ip_vs

5.2 ipvsadm 命令结构

ipvsadm [选项] [虚拟服务] [真实服务器]

# 常用选项
-A  添加虚拟服务
-a  添加真实服务器
-t  TCP 服务
-u  UDP 服务
-s  指定调度算法
-r  指定 Real Server
-g  DR 模式 (Gateway)
-m  NAT 模式 (Masquerade)
-i  TUN 模式
-w  权重
-p  持久连接超时(秒)
-d  删除
-D  删除虚拟服务
-E  编辑虚拟服务
-e  编辑 RS
-L  列出规则
-l  列出规则(简写)
-C  清空所有规则
-S  保存规则
-R  恢复规则
-Z  清零计数器
--stats   统计信息
--rate    速率信息
-n  数字形式显示 IP/端口

5.3 常用配置示例

添加虚拟服务 + RS(DR 模式)
# 在 Director 上绑定 VIP
ip addr add 192.168.1.100/32 dev eth0

# 添加 TCP 80 端口的虚拟服务,使用 wlc 算法
ipvsadm -A -t 192.168.1.100:80 -s wlc

# 添加 RS(-g 表示 DR 模式)
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -g -w 1
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -g -w 2
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.13:80 -g -w 1

# 查看规则
ipvsadm -Ln
NAT 模式
ipvsadm -A -t 192.168.1.100:80 -s rr
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -m -w 1
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -m -w 1
持久连接(会话保持)
# 同一客户端 300 秒内固定到同一 RS
ipvsadm -A -t 192.168.1.100:80 -s rr -p 300
删除与清空
# 删除单个 RS
ipvsadm -d -t 192.168.1.100:80 -r 192.168.1.11:80

# 删除整个虚拟服务
ipvsadm -D -t 192.168.1.100:80

# 清空所有规则
ipvsadm -C

5.4 规则持久化

# 保存
ipvsadm-save > /etc/sysconfig/ipvsadm

# 或使用
service ipvsadm save

# 恢复
ipvsadm-restore < /etc/sysconfig/ipvsadm

5.5 查看统计与监控

# 列出规则及连接数、包数
ipvsadm -Ln --stats

# 速率信息
ipvsadm -Ln --rate

# 持续监控(类似 top)
watch -n 1 'ipvsadm -Ln --stats'

输出示例解读:

TCP  192.168.1.100:80 wlc
  -> 192.168.1.11:80    Masq    1    0    0
  -> 192.168.1.12:80    Masq    2    0    0
  • 第一列:协议与 VIP:Port
  • 第二列:调度算法
  • -> 后:RIP:Port、模式、权重、当前连接数、包数、字节数

6. LVS-NAT 模型:原理、架构与完整实操

6.1 NAT 模型原理深入

NAT 模式下,Director 充当 RS 的网关,对数据包做两次地址转换:

  1. 入向(DNAT)CIP:Cport → VIP:Vport 变为 CIP:Cport → RIP:Rport
  2. 出向(SNAT)RIP:Rport → CIP:Cport 变为 VIP:Vport → CIP:Cport

Client 认为始终在与 VIP 通信,不知道 RS 的存在。

6.2 NAT 架构与 IP 规划

                    Internet
                        │
                        │ 访问 VIP: 192.168.1.100:80
                        ▼
              ┌─────────────────────┐
              │   Director (LB)     │
              │   eth0: 192.168.1.10│ ◄── DIP(内网)
              │   eth0: 192.168.1.100│ ◄── VIP(可与 DIP 同网卡)
              │   ip_forward = 1    │
              └──────────┬──────────┘
                         │ 内网 192.168.1.0/24
              ┌──────────┼──────────┐
              ▼          ▼          ▼
         RS1: 192.168.1.11   RS2: 192.168.1.12
         GW: 192.168.1.10    GW: 192.168.1.10
         运行 Nginx/Apache  运行 Nginx/Apache
角色主机名IP说明
Directorlvs-nat192.168.1.10 (DIP), 192.168.1.100 (VIP)负载调度器
RS1web1192.168.1.11网关 192.168.1.10
RS2web2192.168.1.12网关 192.168.1.10
Clientclient192.168.1.200测试客户端

6.3 Director 配置步骤

# ========== Director (192.168.1.10) ==========

# 1. 开启 IP 转发
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl -p

# 2. 配置 VIP(若与 DIP 同网卡)
ip addr add 192.168.1.100/32 dev eth0

# 3. 安装 ipvsadm
yum install -y ipvsadm

# 4. 清除旧规则
ipvsadm -C

# 5. 添加虚拟服务(NAT 模式 -m)
ipvsadm -A -t 192.168.1.100:80 -s wrr

# 6. 添加 RS
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -m -w 1
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -m -w 2

# 7. 验证
ipvsadm -Ln

6.4 Real Server 配置步骤

# ========== RS1 (192.168.1.11) & RS2 (192.168.1.12) ==========

# 1. 设置默认网关为 Director 的 DIP
ip route del default
ip route add default via 192.168.1.10

# 永久生效(CentOS)
cat > /etc/sysconfig/network-scripts/ifcfg-eth0 << 'EOF'
DEVICE=eth0
BOOTPROTO=static
IPADDR=192.168.1.11
NETMASK=255.255.255.0
GATEWAY=192.168.1.10
ONBOOT=yes
EOF

# 2. 安装并启动 Web 服务(用于区分 RS)
yum install -y nginx
echo "RS1 - 192.168.1.11" > /usr/share/nginx/html/index.html
systemctl start nginx && systemctl enable nginx

# RS2 同理,页面内容改为 RS2

注意: RS 上不要配置 VIP,也不要在 lo 上绑 VIP(那是 DR 模式的做法)。

6.5 测试与验证

# ========== Client (192.168.1.200) ==========

# 1. 访问 VIP
curl http://192.168.1.100

# 2. 多次请求,观察轮询(wrr 下 RS2 权重 2,应获得更多请求)
for i in {1..10}; do curl -s http://192.168.1.100; echo; done

# 3. 在 Director 查看连接统计
ipvsadm -Ln --stats

# 4. 在 RS 上抓包验证
tcpdump -i eth0 host 192.168.1.200 -nn
# 应看到来自 Client IP 的请求(非 VIP)

6.6 NAT 模式常见问题

问题原因解决
Client 无法访问 VIPDirector 未绑 VIP 或防火墙拦截检查 ip addr、iptables
RS 能收到包但无响应RS 网关未指向 Director检查 ip route
响应无法回到 ClientDirector 未开 ip_forwardsysctl net.ipv4.ip_forward
连接超时RS 路由错误,响应未经过 DirectorRS 网关必须是 DIP
Director 性能瓶颈所有流量双向往返考虑 DR 模式或增加 Director

7. LVS-DR 模型:原理、架构与 Shell 自动化

7.1 DR 模型原理深入

DR(Direct Routing)模式下:

  1. Client 请求 CIP → VIP,到达 Director
  2. Director 根据调度算法选择 RS,只修改二层 MAC,将包转发给 RS
  3. RS 的 lo 接口上配置了 VIP,因此认为该包是发给自己的
  4. RS 处理完毕,直接以 VIP 为源 IP 响应 Client(不经过 Director)

关键:Director 与 RS 必须在同一广播域(同一 VLAN / 交换机)

7.2 ARP 问题与抑制

若 RS 也配置了 VIP,可能引发 ARP 冲突:交换机 / Client 的 ARP 表可能把 VIP 解析到 RS 的 MAC,导致 Client 绕过 Director 直接访问 RS,破坏负载均衡。

解决方案:在 RS 上抑制 ARP

# 抑制 ARP 应答:lo 上的 VIP 不响应 ARP 请求
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce

# 抑制 eth0 对 VIP 的 ARP 应答
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

arp_ignore 取值:

含义
0任意网络接口收到 ARP 请求,只要目标 IP 在本机,就响应
1仅当目标 IP 配置在收到请求的接口上时才响应

arp_announce 取值:

含义
0使用任意本地地址
1尽量避免不在同一子网的地址
2优先使用与目标在同一子网的地址

7.3 DR 架构与 IP 规划

                    Internet
                        │
                        ▼
              ┌─────────────────────┐
              │   Director (LB)     │
              │   eth0: 192.168.1.10│
              │   VIP: 192.168.1.100│ (绑在 eth0)
              └──────────┬──────────┘
                         │ 同一 L2 网段 192.168.1.0/24
              ┌──────────┼──────────┐
              ▼          ▼          ▼
         RS1: 192.168.1.11   RS2: 192.168.1.12
         lo:0 VIP/32         lo:0 VIP/32
         网关: 192.168.1.1    网关: 192.168.1.1 (真实网关,非 Director)
角色IPVIP 位置网关
Director192.168.1.10eth0: 192.168.1.100/32192.168.1.1
RS1192.168.1.11lo:0: 192.168.1.100/32192.168.1.1
RS2192.168.1.12lo:0: 192.168.1.100/32192.168.1.1

7.4 Director 配置

# ========== Director ==========
ip addr add 192.168.1.100/32 dev eth0

ipvsadm -C
ipvsadm -A -t 192.168.1.100:80 -s wlc
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.11:80 -g -w 1
ipvsadm -a -t 192.168.1.100:80 -r 192.168.1.12:80 -g -w 1

ipvsadm -Ln

7.5 Real Server 配置

# ========== RS1 / RS2 ==========

VIP=192.168.1.100

# 1. lo 上绑定 VIP
ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP up

# 2. 抑制 ARP
cat >> /etc/sysctl.conf << 'EOF'
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
EOF
sysctl -p

# 3. 网关指向真实网关(不是 Director!)
# GATEWAY=192.168.1.1

# 4. 启动 Web 服务
yum install -y nginx
echo "DR-RS1" > /usr/share/nginx/html/index.html
systemctl start nginx

7.6 Shell 脚本自动化配置 LVS-DR

Director 端脚本 lvs-director.sh
#!/bin/bash
# LVS-DR Director 配置脚本
# 用法: ./lvs-director.sh start|stop|status

VIP=192.168.1.100
PORT=80
RS_SERVERS=(
    "192.168.1.11:80:1"
    "192.168.1.12:80:1"
    "192.168.1.13:80:2"
)
SCHEDULER=wlc
IFACE=eth0

start() {
    echo "[Director] 启动 LVS-DR..."
    
    # 加载内核模块
    modprobe ip_vs
    modprobe ip_vs_wlc
    
    # 绑定 VIP
    if ! ip addr show dev $IFACE | grep -q "$VIP"; then
        ip addr add ${VIP}/32 dev $IFACE
        echo "[Director] VIP $VIP 已绑定到 $IFACE"
    fi
    
    # 清除旧规则
    ipvsadm -C
    
    # 添加虚拟服务
    ipvsadm -A -t ${VIP}:${PORT} -s $SCHEDULER
    
    # 添加 RS
    for rs in "${RS_SERVERS[@]}"; do
        IFS=':' read -r rip rport weight <<< "$rs"
        ipvsadm -a -t ${VIP}:${PORT} -r ${rip}:${rport} -g -w $weight
        echo "[Director] 添加 RS: ${rip}:${rport} weight=$weight"
    done
    
    echo "[Director] LVS-DR 启动完成"
    ipvsadm -Ln
}

stop() {
    echo "[Director] 停止 LVS-DR..."
    ipvsadm -C
    ip addr del ${VIP}/32 dev $IFACE 2>/dev/null
    echo "[Director] 已停止"
}

status() {
    echo "=== VIP 状态 ==="
    ip addr show dev $IFACE | grep $VIP
    echo "=== IPVS 规则 ==="
    ipvsadm -Ln --stats
}

case "$1" in
    start)  start ;;
    stop)   stop ;;
    status) status ;;
    *)      echo "用法: $0 {start|stop|status}"; exit 1 ;;
esac
Real Server 端脚本 lvs-rs.sh
#!/bin/bash
# LVS-DR Real Server 配置脚本
# 用法: ./lvs-rs.sh start|stop

VIP=192.168.1.100
IFACE=lo:0

start() {
    echo "[RS] 配置 LVS-DR Real Server..."
    
    # 绑定 VIP 到 lo
    ifconfig $IFACE $VIP netmask 255.255.255.255 broadcast $VIP up
    
    # ARP 抑制
    cat > /etc/sysctl.d/99-lvs-rs.conf << 'EOF'
net.ipv4.conf.lo.arp_ignore = 1
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
EOF
    sysctl -p /etc/sysctl.d/99-lvs-rs.conf
    
    echo "[RS] VIP $VIP 已绑定到 $IFACE,ARP 已抑制"
}

stop() {
    ifconfig $IFACE down 2>/dev/null
    echo "[RS] 已停止"
}

case "$1" in
    start) start ;;
    stop)  stop ;;
    *)     echo "用法: $0 {start|stop}"; exit 1 ;;
esac

7.7 DR 模式测试验证

# Client 多次访问
for i in {1..20}; do curl -s http://192.168.1.100; done

# Director 上查看(应有 InPkts 增加,OutPkts 较少,因响应不经过 Director)
ipvsadm -Ln --stats

# RS 上抓包:应看到目标 MAC 是 RS 的 MAC,目标 IP 是 VIP
tcpdump -i eth0 -nn host 192.168.1.100

# RS 上验证响应源 IP 是 VIP
tcpdump -i eth0 -nn src 192.168.1.100 and host <Client_IP>

8. Keepalived + LVS:高可用架构实战

8.1 LVS 高可用问题

单机 Director 存在单点故障

  • Director 宕机 → VIP 不可用 → 整个集群瘫痪
  • Director 网卡故障 → 同上
  • 维护重启 → 服务中断

解决思路: 部署主备两台 Director,通过 VRRP 协议共享 VIP,Master 故障时 Backup 接管 VIP 和 IPVS 规则。

8.2 Keepalived 简介

Keepalived 基于 VRRP(Virtual Router Redundancy Protocol),提供:

  • VIP 漂移:Master 持 VIP,Backup 监听;Master 故障时 Backup 升主
  • 健康检查:检测 RS 和后端服务,故障 RS 自动剔除
  • IPVS 集成:可直接在配置文件中定义 LVS 规则,无需手动 ipvsadm

8.3 高可用架构

                    Internet
                        │
                        ▼
              VIP: 192.168.1.100 (漂移)
                        │
         ┌──────────────┴──────────────┐
         ▼                             ▼
   Director-M (Master)          Director-B (Backup)
   192.168.1.10                  192.168.1.20
   Keepalived: MASTER            Keepalived: BACKUP
   持有 VIP                      监听 VRRP,待命
         │                             │
         └──────────────┬──────────────┘
                        ▼
              RS1 / RS2 / RS3 (LVS-DR)

8.4 安装 Keepalived

yum install -y keepalived
# 或
apt install -y keepalived

8.5 Master 配置 /etc/keepalived/keepalived.conf

! Configuration File for keepalived

global_defs {
    router_id LVS_MASTER
    vrrp_skip_check_adv_addr
}

# LVS 健康检查脚本(可选)
vrrp_script check_lvs {
    script "/etc/keepalived/check_lvs.sh"
    interval 3
    weight -20
    fall 2
    rise 2
}

# VRRP 实例:负责 VIP 漂移
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51          # 同一集群必须相同,范围 1-255
    priority 100                  # Master 优先级高
    advert_int 1                  # VRRP 通告间隔(秒)
    
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    
    virtual_ipaddress {
        192.168.1.100/32 dev eth0
    }
    
    track_script {
        check_lvs
    }
}

# 虚拟服务器:LVS 规则
virtual_server 192.168.1.100 80 {
    delay_loop 6
    lb_algo wlc
    lb_kind DR                    # NAT 模式改为 NAT
    protocol TCP
    
    real_server 192.168.1.11 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            connect_port 80
            nb_get_retry 3
            delay_before_retry 3
        }
    }
    
    real_server 192.168.1.12 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            connect_port 80
            nb_get_retry 3
            delay_before_retry 3
        }
    }
    
    real_server 192.168.1.13 80 {
        weight 2
        TCP_CHECK {
            connect_timeout 3
            connect_port 80
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

8.6 Backup 配置

global_defs {
    router_id LVS_BACKUP
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90                   # 低于 Master
    advert_int 1
    
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    
    virtual_ipaddress {
        192.168.1.100/32 dev eth0
    }
}

virtual_server 192.168.1.100 80 {
    delay_loop 6
    lb_algo wlc
    lb_kind DR
    protocol TCP
    
    real_server 192.168.1.11 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            connect_port 80
        }
    }
    
    real_server 192.168.1.12 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            connect_port 80
        }
    }
}

8.7 健康检查脚本

# /etc/keepalived/check_lvs.sh
#!/bin/bash
# 检查 IPVS 模块和规则是否存在
if ! ipvsadm -Ln | grep -q "192.168.1.100:80"; then
    exit 1
fi
exit 0
chmod +x /etc/keepalived/check_lvs.sh

8.8 启动与故障切换测试

# Master 和 Backup 都执行
systemctl enable keepalived
systemctl start keepalived

# 查看 VIP(应只在 Master 上)
ip addr show eth0 | grep 192.168.1.100

# 查看 IPVS 规则
ipvsadm -Ln

# 模拟 Master 故障
systemctl stop keepalived   # 在 Master 上执行

# 在 Backup 上验证 VIP 已漂移
ip addr show eth0 | grep 192.168.1.100

# Client 访问应无感知(短暂中断 1~3 秒)
curl http://192.168.1.100

8.9 脑裂问题与预防

脑裂: 两台 Director 同时认为自己是 Master,都绑定 VIP,导致 ARP 混乱。

预防措施:

  1. 使用 vrrp_script 检测本机服务,异常时降低 priority
  2. 开启 vrrp_strict(新版本默认)
  3. 使用 unicast_src_ip / unicast_peer 单播 VRRP,减少广播干扰
  4. 防火墙放行 VRRP(协议号 112)和组播 224.0.0.18

9. LVS 调度算法深度解析

LVS 提供多种调度算法,分为静态动态两类。

9.1 静态调度算法

rr(Round Robin,轮询)
  • 原理:依次将请求分配给每个 RS
  • 适用:RS 性能相近、请求处理时间接近
  • 示例:3 台 RS,请求顺序 1→2→3→1→2→3...
wrr(Weighted Round Robin,加权轮询)
  • 原理:按权重比例分配,权重高的 RS 获得更多请求
  • 适用:RS 性能不同(如 4 核 vs 8 核)
  • 示例:RS1 (w=1), RS2 (w=2) → 比例约 1:2
sh(Source Hashing,源地址哈希)
  • 原理:根据客户端源 IP 哈希,同一 IP 固定到同一 RS
  • 适用:需要会话保持,且无 cookie 的场景
  • 缺点:RS 数量变化时,大量会话重新映射
dh(Destination Hashing,目标地址哈希)
  • 原理:根据目标 IP 哈希
  • 适用:缓存集群,同一目标 URL 固定到同一缓存节点

9.2 动态调度算法

lc(Least-Connection,最少连接)
  • 原理:将请求分配给当前连接数最少的 RS
  • 适用:请求处理时间差异较大的场景
wlc(Weighted Least-Connection,加权最少连接,默认)
  • 原理调度连接数 = 当前连接数 / 权重,选值最小的 RS
  • 适用:RS 性能不同且请求耗时不同,生产最常用
lblc(Locality-Based Least-Connection)
  • 原理:基于目标 IP 的哈希,在对应 RS 组中选最少连接
  • 适用:分布式缓存
lblcr(Locality-Based Least-Connection with Replication)
  • 原理:lblc 的增强,支持缓存复制到多个节点
sed(Shortest Expected Delay)
  • 原理(C+1)/U,C 为当前连接数,U 为权重,选值最小
  • 适用:请求处理时间接近
nq(Never Queue)
  • 原理:sed 的改进,若有 RS 连接数为 0,直接分配,不排队

9.3 算法对比与选型

算法类型会话保持考虑权重考虑连接数推荐场景
rr静态同构集群、短连接
wrr静态异构集群、短连接
sh静态是 (源 IP)无 cookie 的会话保持
dh静态是 (目标)缓存集群
lc动态长连接、耗时差异大
wlc动态生产默认首选
sed/nq动态优化延迟

9.4 配置示例

# 轮询
ipvsadm -A -t 192.168.1.100:80 -s rr

# 加权轮询
ipvsadm -A -t 192.168.1.100:80 -s wrr

# 源地址哈希(会话保持)
ipvsadm -A -t 192.168.1.100:80 -s sh

# 加权最少连接(推荐)
ipvsadm -A -t 192.168.1.100:80 -s wlc

# 持久连接(与算法配合,单位:秒)
ipvsadm -A -t 192.168.1.100:80 -s wlc -p 300

10. 实战案例:LVS-DR 实现 MySQL 负载均衡

10.1 场景说明

对 MySQL 只读从库 做读负载均衡(写仍走主库),是 LVS 的经典场景之一。

                    应用服务器
                        │
                        │ 读请求
                        ▼
              VIP: 192.168.1.100:3306
                        │
              ┌─────────┴─────────┐
              ▼                   ▼
         MySQL-Slave1        MySQL-Slave2
         192.168.1.21:3306   192.168.1.22:3306

注意: LVS 做 MySQL 负载均衡时:

  • 仅适合负载或无状态连接
  • 写操作、事务、主从复制配置需应用层配合
  • 推荐使用 DR 模式 + sh(源哈希) 或 持久连接,减少连接迁移

10.2 架构与 IP 规划

角色IP说明
Director192.168.1.10VIP: 192.168.1.100
MySQL-S1192.168.1.21从库 1
MySQL-S2192.168.1.22从库 2
App192.168.1.50应用服务器

10.3 Director 配置

# 绑定 VIP
ip addr add 192.168.1.100/32 dev eth0

# MySQL 3306 端口,源哈希保持连接稳定
ipvsadm -C
ipvsadm -A -t 192.168.1.100:3306 -s sh -p 3600

ipvsadm -a -t 192.168.1.100:3306 -r 192.168.1.21:3306 -g -w 1
ipvsadm -a -t 192.168.1.100:3306 -r 192.168.1.22:3306 -g -w 1

ipvsadm -Ln

10.4 MySQL Real Server 配置

# ========== 两台 MySQL 从库 ==========

VIP=192.168.1.100

# 1. lo 绑定 VIP
ifconfig lo:0 $VIP netmask 255.255.255.255 up

# 2. ARP 抑制
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

# 3. 确保 MySQL 监听 0.0.0.0:3306
# my.cnf: bind-address = 0.0.0.0
systemctl start mysqld

10.5 Keepalived 健康检查(MySQL)

virtual_server 192.168.1.100 3306 {
    delay_loop 6
    lb_algo sh
    lb_kind DR
    persistence_timeout 3600
    protocol TCP
    
    real_server 192.168.1.21 3306 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            connect_port 3306
            nb_get_retry 3
            delay_before_retry 3
        }
    }
    
    real_server 192.168.1.22 3306 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            connect_port 3306
        }
    }
}

10.6 验证

# 应用端连接 VIP
mysql -h 192.168.1.100 -P 3306 -u readonly -p -e "SELECT @@hostname, @@server_id;"

# 多次执行,观察是否分配到不同从库(sh 算法下同一 Client IP 固定同一从库)
for i in {1..5}; do
    mysql -h 192.168.1.100 -u readonly -p'password' -e "SELECT @@hostname;" 2>/dev/null
done

# Director 统计
ipvsadm -Ln --stats

10.7 MySQL 负载均衡注意事项

  1. 主从延迟:读从库可能读到旧数据,需业务容忍或读主
  2. 连接池:应用连接池应对 VIP,而非单个 RS IP
  3. 故障切换:Keepalived TCP_CHECK 只能检测端口,建议配合 mysql_check 脚本
  4. 半同步 / 组复制:与 LVS 无冲突,但拓扑设计需统一规划

11. Nginx 四层负载均衡:原理与配置

11.1 Nginx 四层 vs LVS 四层

维度LVSNginx stream
实现层级内核 IPVS用户态事件驱动
性能极高高(万级~十万级并发)
配置灵活性ipvsadm/Keepalived配置文件,易读易维护
七层能力同一 Nginx 可同时做七层
健康检查需 Keepalived原生支持
SSL 终结不支持stream 可 ssl_preread

结论: 超大规模入口用 LVS;需要灵活配置、与七层统一、中等规模用 Nginx stream。

11.2 安装与 stream 模块

Nginx 1.9.0+ 自带 stream 模块,需编译时启用:

# 检查是否支持
nginx -V 2>&1 | grep stream

# 若无,编译添加
./configure --with-stream --with-stream_ssl_module

11.3 基本四层配置

/etc/nginx/nginx.conf

# 注意:stream 与 http 块同级,都在 main 上下文

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;

events {
    worker_connections 65535;
    use epoll;
}

# ========== 四层负载均衡 ==========
stream {
    # 日志格式
    log_format stream_log '$remote_addr [$time_local] '
                          '$protocol $status $bytes_sent $bytes_received '
                          '$session_time "$upstream_addr" '
                          '"$upstream_bytes_sent" "$upstream_bytes_received"';

    access_log /var/log/nginx/stream-access.log stream_log;

    # 上游服务器组(nginx官方叫法实际上是rs)
    upstream backend_web {
        least_conn;                    # 调度算法
        server 192.168.1.11:80 weight=1 max_fails=3 fail_timeout=30s;
        server 192.168.1.12:80 weight=2 max_fails=3 fail_timeout=30s;
        server 192.168.1.13:80 weight=1 max_fails=3 fail_timeout=30s backup;
    }

    # 监听并转发
    server {
        listen 8080;                   # 监听端口
        proxy_pass backend_web;
        proxy_connect_timeout 5s;
        proxy_timeout 300s;
    }
}

# ========== 七层配置(可选,同一 Nginx) ==========
http {
    upstream web {
        server 192.168.1.11:80;
        server 192.168.1.12:80;
    }
    
    server {
        listen 80;
        location / {
            proxy_pass http://web;
        }
    }
}

11.4 stream 调度算法

指令说明
round_robin默认,轮询
least_conn最少连接
hash $remote_addr consistent源 IP 哈希,一致性哈希
hash $remote_addr$remote_port源 IP + 端口哈希
upstream mysql_backend {
    least_conn;
    hash $remote_addr consistent;   # 与 least_conn 二选一
    server 192.168.1.21:3306;
    server 192.168.1.22:3306;
}

11.5 健康检查与故障转移

upstream backend {
    server 192.168.1.11:80 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:80 max_fails=3 fail_timeout=30s;
    server 192.168.1.13:80 backup;   # 仅当主 RS 全挂时使用
}
  • max_fails:连续失败次数
  • fail_timeout:失败窗口 / 禁用时长
  • backup:备用服务器

Nginx Plus 支持主动健康检查;开源版依赖被动检测(连接失败)。

11.6 测试

nginx -t && systemctl reload nginx

# 测试四层转发
curl http://127.0.0.1:8080

# 查看 stream 日志
tail -f /var/log/nginx/stream-access.log

12. LVS、Nginx、HAProxy 对比

12.1 三者定位

工具层级实现典型场景
LVS四层内核 IPVS超大规模入口、百万并发
Nginx四 + 七层用户态Web 服务、反向代理、静态资源、中小规模 LB
HAProxy四 + 七层用户态专业 LB、TCP/HTTP、精细健康检查

12.2 详细对比

维度LVSNginxHAProxy
性能★★★★★★★★★★★★★
四层能力原生内核stream 模块原生支持
七层能力强大强大
配置方式ipvsadm/Keepalived配置文件配置文件
健康检查需 Keepalived被动 / Plus 主动主动 + 被动
SSL不支持支持支持
会话保持sh、持久连接ip_hash、stickycookie、source
动态上下线需脚本需 reload支持 socket 热更新
日志有限灵活详细
学习成本

12.3 常见问题

Q1:LVS 的 NAT 和 DR 区别?

NAT:Director 做 DNAT+SNAT,请求响应都过 Director,RS 网关指向 Director。
DR:Director 只改 MAC,RS 直接响应 Client,需 lo 绑 VIP 并抑制 ARP,要求 L2 互通。
DR 性能更高,是生产首选。

Q2:为什么 DR 模式 RS 要在 lo 上绑 VIP?

请求包目标 IP 是 VIP,到达 RS 时目标 MAC 是 RS 的 MAC。RS 必须在某个接口上 "拥有"VIP,内核才会接收该包。绑在 lo 上并抑制 ARP,可避免 RS 响应 ARP 导致 VIP 漂移。

Q3:Nginx 和 LVS 都做四层,怎么选?

流量极大(百万级)选 LVS;需要与七层统一、配置灵活、中等并发选 Nginx stream。常见架构是 LVS 做第一层,Nginx 做第二层。

Q4:Keepalived 原理?

基于 VRRP,Master 持 VIP 并发 VRRP 通告,Backup 监听。Master 故障时 Backup 升主接管 VIP。可配合 script 做健康检查,实现 Director 和 RS 的高可用。

Q5:wlc 和 lc 区别?

lc 选连接数最少的 RS;wlc 选 连接数/权重 最小的 RS,考虑 RS 性能差异,是 LVS 默认算法。

Q6:如何防止 LVS 脑裂?

VRRP 优先级、track_script 检测、unicast VRRP、防火墙规范、避免网络分区。


13. Nginx 四层代理 MySQL 实战

13.1 场景

应用通过 Nginx stream 连接 MySQL 从库集群,实现读负载均衡。

13.2 架构

App Server ──► Nginx (192.168.1.10:3306) ──► MySQL-S1 / MySQL-S2

13.3 完整配置

stream {
    log_format mysql_log '$remote_addr [$time_local] $protocol '
                         '$status $bytes_sent $bytes_received '
                         '$session_time "$upstream_addr"';

    access_log /var/log/nginx/mysql-access.log mysql_log;

    upstream mysql_read {
        least_conn;
        server 192.168.1.21:3306 weight=1 max_fails=3 fail_timeout=30s;
        server 192.168.1.22:3306 weight=1 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 3306;
        proxy_pass mysql_read;
        proxy_connect_timeout 10s;
        proxy_timeout 600s;        # MySQL 长连接超时
        proxy_buffer_size 16k;
    }
}

13.4 双端口读写分离(扩展)

stream {
    # 读:从库
    upstream mysql_read {
        least_conn;
        server 192.168.1.21:3306;
        server 192.168.1.22:3306;
    }

    # 写:主库
    upstream mysql_write {
        server 192.168.1.20:3306;
    }

    server {
        listen 3306;
        proxy_pass mysql_read;
    }

    server {
        listen 3307;
        proxy_pass mysql_write;
    }
}

应用配置:读 3306,写 3307

13.5 验证

nginx -t && systemctl reload nginx

mysql -h 192.168.1.10 -P 3306 -u user -p -e "SELECT @@hostname;"

tail -f /var/log/nginx/mysql-access.log

14. 大并发架构:四层 + 七层组合设计

14.1 为何需要 L4 + L7 组合

单一七层 Nginx 在超大规模下:

  • 需解析 HTTP,CPU 开销大于纯四层
  • SSL 终结消耗大
  • 单机连接数有上限

分层架构:

                    Internet
                        │
                        ▼
              ┌─────────────────┐
              │  LVS / F5 (L4)  │  ◄── 第一层:超高并发入口
              │  VIP 漂移 HA     │      内核转发,百万连接
              └────────┬────────┘
                       │
         ┌─────────────┼─────────────┐
         ▼             ▼             ▼
   ┌──────────┐  ┌──────────┐  ┌──────────┐
   │ Nginx L7 │  │ Nginx L7 │  │ Nginx L7 │  ◄── 第二层:七层
   │  SSL     │  │  缓存    │  │  路由    │      URL路由、限流
   └────┬─────┘  └────┬─────┘  └────┬─────┘
        │             │             │
        └─────────────┼─────────────┘
                      ▼
              ┌───────────────┐
              │  应用服务器    │  ◄── 第三层:业务
              └───────────────┘

14.2 仅七层模式(中小规模)

Internet → Nginx (L7) → App Servers

适用:QPS 万级以下,需 URL 路由、SSL、缓存。

14.3 Nginx 四层 + 多 Nginx 七层

Internet → Nginx Stream (L4) → Nginx1/Nginx2/Nginx3 (L7) → App

L4 Nginx 配置:

stream {
    upstream nginx_l7_cluster {
        least_conn;
        server 192.168.1.11:80 weight=1 max_fails=3 fail_timeout=30s;
        server 192.168.1.12:80 weight=1 max_fails=3 fail_timeout=30s;
        server 192.168.1.13:80 weight=1 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 80;
        proxy_pass nginx_l7_cluster;
        proxy_connect_timeout 3s;
        proxy_timeout 300s;
    }
}

L7 Nginx 配置(每台):

http {
    upstream app_backend {
        server 192.168.2.11:8080;
        server 192.168.2.12:8080;
    }

    server {
        listen 80;
        
        location / {
            proxy_pass http://app_backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        
        location /api/ {
            proxy_pass http://app_backend;
        }
        
        location /static/ {
            root /var/www;
            expires 30d;
        }
    }
}

14.4 LVS + Nginx 七层(大规模标准架构)

Internet → LVS(DR) → Nginx×N (L7) → App×N
  • LVS:DR 模式,wlc 算法,Keepalived HA
  • Nginx:SSL 终结、静态资源、反向代理
  • App:无状态,可水平扩展

14.5 性能调优要点

LVS 层:

# 连接跟踪表大小
echo 655360 > /proc/sys/net/ipv4/ip_conntrack_max

# Director 文件描述符
ulimit -n 655350

Nginx 层:

worker_processes auto;
worker_rlimit_nofile 655350;

events {
    worker_connections 65535;
    use epoll;
    multi_accept on;
}

http {
    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    keepalive_timeout 65;
    keepalive_requests 10000;
}

15. 多级代理下的真实客户端 IP 获取

15.1 问题背景

多级代理后,后端应用看到的 $remote_addr 是上一级代理的 IP,而非真实 Client IP。

Client (1.2.3.4) → LVS → Nginx → App
                              App 看到的 remote_addr = Nginx 的 IP

日志、限流、风控、审计都需要真实 IP

15.2 Nginx 相关变量

变量含义
$remote_addr直连 Nginx 的客户端 IP(可能是上一级代理)
$proxy_add_x_forwarded_for追加 X-Forwarded-For 链
$http_x_forwarded_for请求头中的 X-Forwarded-For
$http_x_real_ip请求头中的 X-Real-IP
$realip_remote_addrrealip 模块解析后的真实 IP

15.3 标准传递方式

Nginx 转发时设置 Header:

location / {
    proxy_pass http://backend;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

后端 Nginx 使用 realip 模块还原:

# 信任上游代理 IP 段
set_real_ip_from 192.168.1.0/24;
set_real_ip_from 10.0.0.0/8;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

# 之后 $remote_addr 即为真实 Client IP
log_format main '$remote_addr - $remote_user [$time_local] "$request"';

15.4 多级代理示例

Client → LVS → Nginx1 (L4) → Nginx2 (L7) → App

Nginx1 (L4 stream): 四层无法修改 HTTP Header,真实 IP 需通过 proxy_protocol 或 TOA 模块传递。

Nginx2 (L7) 启用 proxy_protocol:

# Nginx1 stream 发送 proxy_protocol
stream {
    server {
        listen 80;
        proxy_pass 192.168.1.12:80;
        proxy_protocol on;
    }
}

# Nginx2 接收
server {
    listen 80 proxy_protocol;
    set_real_ip_from 192.168.1.11;
    real_ip_header proxy_protocol;
    
    location / {
        proxy_pass http://app;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

15.5 应用层获取真实 IP

Java (Spring):

String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.isEmpty()) {
    ip = request.getHeader("X-Real-IP");
}
if (ip == null || ip.isEmpty()) {
    ip = request.getRemoteAddr();
}
// X-Forwarded-For 可能有多级: "client, proxy1, proxy2"
if (ip != null && ip.contains(",")) {
    ip = ip.split(",")[0].trim();
}

Python (Flask):

from flask import request

def get_client_ip():
    if request.headers.get('X-Forwarded-For'):
        return request.headers['X-Forwarded-For'].split(',')[0].strip()
    return request.headers.get('X-Real-IP', request.remote_addr)

15.6 安全注意

  • X-Forwarded-For 可被客户端伪造,必须配合 set_real_ip_from 只信任已知代理
  • 不要无条件信任 X-Forwarded-For 的第一个 IP
  • 生产环境建议 LVS 层使用 TOA 或在最外层 Nginx 统一注入

16. Nginx 反向代理参数详解

16.1 连接与超时

location / {
    proxy_pass http://backend;
    
    # 与后端建立连接的超时
    proxy_connect_timeout 60s;
    
    # 向后端发送请求的超时
    proxy_send_timeout 60s;
    
    # 从后端读取响应的超时
    proxy_read_timeout 60s;
    
    # 客户端与 Nginx 之间的超时
    send_timeout 60s;
}
参数默认说明
proxy_connect_timeout60s连接后端超时
proxy_send_timeout60s发送请求到后端超时
proxy_read_timeout60s从后端读取响应超时

16.2 Header 传递

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;

# 不传递某些头
proxy_pass_request_headers on;   # 默认 on
proxy_pass_request_body on;        # 默认 on

16.3 缓冲与 Body

proxy_buffering on;                # 默认 on,缓冲后端响应
proxy_buffer_size 4k;              # 响应头缓冲
proxy_buffers 8 4k;                # 响应体缓冲
proxy_busy_buffers_size 8k;

proxy_request_buffering on;        # 请求体缓冲
client_max_body_size 10m;          # 客户端请求体大小限制

关闭缓冲场景: 流式响应、SSE、大文件下载

proxy_buffering off;
proxy_cache off;

16.4 重定向与 URL

# 后端返回 302 时,重写 Location 头
proxy_redirect http://backend:8080/ http://$host/;

# 自动替换
proxy_redirect default;

# URL 路径替换
location /api/ {
    proxy_pass http://backend/v1/;   # /api/foo → /v1/foo
}

proxy_pass 路径规则:

locationproxy_pass请求 URI转发 URI
/api/http://backend//api/user/user
/api/http://backend/api/user/api/user
/api/http://backend/v1//api/user/v1/user

16.5 故障转移与重试

upstream backend {
    server 192.168.1.11:8080 max_fails=3 fail_timeout=30s;
    server 192.168.1.12:8080 max_fails=3 fail_timeout=30s;
}

location / {
    proxy_pass http://backend;
    proxy_next_upstream error timeout http_502 http_503 http_504;
    proxy_next_upstream_tries 3;
    proxy_next_upstream_timeout 10s;
}

16.6 HTTPS 后端

location / {
    proxy_pass https://backend;
    proxy_ssl_verify on;
    proxy_ssl_trusted_certificate /etc/nginx/ca.crt;
    proxy_ssl_server_name on;
    proxy_ssl_name backend.example.com;
}

16.7 WebSocket

location /ws/ {
    proxy_pass http://backend;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_read_timeout 3600s;
}

16.8 常用变量实测

# 调试 location,查看各变量值
location /debug/ {
    default_type text/plain;
    return 200 "
remote_addr: $remote_addr
remote_user: $remote_user
request_uri: $request_uri
uri: $uri
args: $args
host: $host
http_host: $http_host
scheme: $scheme
request_method: $request_method
http_user_agent: $http_user_agent
http_x_forwarded_for: $http_x_forwarded_for
http_x_real_ip: $http_x_real_ip
proxy_add_x_forwarded_for: $proxy_add_x_forwarded_for
";
}

访问 /debug/ 可直观看到各变量在多级代理下的值。


17. 生产最佳实践与故障排查

17.1 架构选型 checklist

  •  预估 QPS、并发连接数、带宽
  •  确定四 / 七层需求(URL 路由?SSL?)
  •  选 LVS / Nginx / HAProxy 组合
  •  Director/LB 高可用(Keepalived 主备)
  •  RS 健康检查与自动剔除
  •  监控:连接数、QPS、延迟、5xx 率
  •  真实 IP 传递方案
  •  灰度与扩容流程

17.2 常见问题排查

现象可能原因排查命令
VIP 无法访问VIP 未绑定、防火墙、ARPip addriptables -Larp -n
部分 RS 无流量权重为 0、被剔除、算法ipvsadm -Ln --stats
DR 模式 RS 收不到包lo 未绑 VIP、ARP 未抑制ip addr show losysctl arp_ignore
NAT 模式无响应RS 网关错误、ip_forward 未开ip routesysctl ip_forward
连接超时后端服务 down、防火墙curltelnettcpdump
脑裂VRRP 配置不一致、网络分区journalctl -u keepalived
502 Bad Gateway后端无响应、upstream 全挂nginx -t, 查 error.log
真实 IP 不对Header 未传或未信任查 $remote_addr, realip 配置

17.3 监控指标

LVS:

# 连接数、包数
ipvsadm -Ln --stats

# 网卡流量
sar -n DEV 1

# 连接跟踪表
cat /proc/net/ip_conntrack | wc -l

Nginx:

# stub_status 模块
location /nginx_status {
    stub_status;
    allow 127.0.0.1;
    deny all;
}

Keepalived:

systemctl status keepalived
journalctl -u keepalived -f

17.4 安全建议

  1. Director 仅开放必要端口,禁止 RS 对 VIP 的 direct 访问(DR 除外 lo)
  2. Keepalived 认证密码强度足够
  3. 限制 set_real_ip_from 信任范围
  4. 定期更新 Nginx、Keepalived 版本
  5. LB 层可配合 DDoS 防护、限流

17.5 总结:技术选型速查

┌─────────────────────────────────────────────────────────────────┐
│                        负载均衡选型速查                           │
├─────────────────────────────────────────────────────────────────┤
│  百万并发、纯四层           → LVS (DR) + Keepalived              │
│  Web 服务、需 SSL/路由      → Nginx (七层)                        │
│  TCP 服务、中等规模         → Nginx stream 或 HAProxy             │
│  MySQL 读负载              → LVS-DR + sh/wlc 或 Nginx stream      │
│  超大入口 + 灵活七层        → LVS (L4) → Nginx (L7) → App         │
│  专业 LB、精细健康检查      → HAProxy                             │
└─────────────────────────────────────────────────────────────────┘

0voice · GitHub

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐