负载均衡原理:Nginx、LVS、DNS轮询,算法对比与选型
负载均衡这东西,说白了就是把流量分散到多台服务器上。你想想看,单点扛不住的时候怎么办?加机器。但加完机器,谁来分发请求?这就是负载均衡要解决的问题。
我最早接触大规模负载均衡,是在一个日活千万级的电商项目里。当时流量一上来,单台应用服务器直接打满,CPU报警。我们紧急上了Nginx做反向代理,才把流量扛住。后来随着规模扩大,又引入了LVS和DNS轮询。这三种方案各有各的战场,我分别讲讲。
三种核心负载均衡方案
1. DNS轮询
DNS轮询是最简单的方式。你在DNS服务器里为同一个域名配多个A记录,客户端解析时会随机拿到一个IP。这个方案优点是无成本,配置简单。但缺点也很明显:客户端会缓存DNS结果,流量分配不均匀;而且DNS服务器不知道后端服务器的健康状态,挂了照样发请求。
我曾经遇到过一个线上事故:某次扩容后,我改了DNS记录,想着流量能慢慢切过去。结果客户端缓存了旧的IP,新加的机器一直没流量。后来才知道,TTL设太长了,很多客户端根本不重新解析。从那以后,我调整重要业务的DNS TTL到60秒,并且配合健康检查一起用。
2. Nginx反向代理
Nginx是我最常用的七层负载均衡器。它工作在应用层,可以理解HTTP报文,实现更精细的路由,比如按URL、按Cookie、按Header分发。配置起来也直观:
upstream backend {
# 加权轮询
server 10.0.1.1:8080 weight=3;
server 10.0.1.2:8080 weight=2;
server 10.0.1.3:8080 backup; # 备用节点
keepalive 32;
}
server {
listen 80;
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Nginx还内置健康检查、连接超时、重试机制。我个人习惯在生产环境用 max_fails=3 fail_timeout=30s 来标记故障节点,避免频繁切换。
避坑指南:Nginx的keepalive连接数不要设太大,不然上游连接池会占用过多文件描述符。我记得有一次线上Nginx的 worker_connections 没调大,结果并发上来后直接报“too many open files”。
3. LVS(Linux Virtual Server)
LVS工作在四层(传输层),比Nginx更快。它直接在内核空间做包转发,不解析应用层协议,所以吞吐量极高。LVS有三种工作模式:
| 模式 | 转发方式 | 性能 | 典型场景 |
|---|---|---|---|
| NAT模式 | 修改目标IP和端口 | 中等 | 中小规模,后端服务器可私有IP |
| TUN模式 | IP隧道封装 | 高 | 跨机房、后端有公网IP |
| DR模式 | 直接修改MAC地址 | 最高 | 同机房高性能场景,后端必须配置VIP |
我参与过的那个日活千万项目,最外层就是LVS/DR模式,直接扛住百万级并发。后端挂了两台Nginx做七层转发,再往后是应用服务器。这个分层架构,我画了一张图:
负载均衡算法对比
不管是Nginx还是LVS,内部都有一组调度算法。选对算法,直接影响系统吞吐和响应时间。我整理了一张常用算法的对比表:
| 算法 | 特点 | 适用场景 | 常见实现 |
|---|---|---|---|
| 轮询 (Round Robin) | 按顺序轮流,权重可调 | 服务器配置均匀、请求处理时间相近 | Nginx upstream、LVS rr |
| 最少连接 (Least Connections) | 动态分配给当前连接数最少的节点 | 长连接、请求处理时间差异大 | Nginx least_conn、LVS lc |
| IP哈希 (IP Hash) | 根据客户端IP哈希,保证同一IP固定发到同一台服务器 | 需要会话保持(Session Stickiness) | Nginx ip_hash、LVS sh |
| URL哈希 | 根据请求路径或参数做哈希 | 缓存命中优化、API网关路由 | Nginx hash指令 |
| 加权轮询 (Weighted RR) | 按权重分配比例,适合异构服务器 | 服务器性能不同时 | Nginx weight参数、LVS wrr |
| 最少响应时间 | 选择响应时间最短的节点 | 需要低延迟的业务 | Nginx 商业版、第三方模块 |
选型建议:
- 业务场景简单、服务器性能一致 → 轮询就行,配置最低。
- 请求处理时间差异大 → 最少连接,能自动均衡实时负载。
- 需要会话保持 → IP哈希,但要小心源IP变化导致负载不均。我有个项目用了哈希,结果某个运营商出口IP特别集中,导致一台服务器被压垮。
- 七层路由(按域名、路径分发) → Nginx;纯四层加速 → LVS。
实战选型流程
接下来我分享一套我自己总结的选型流程。你不必死记硬背,理解思路就好。
- 看吞吐量:如果预估并发连接数超过10万,优先考虑LVS/DR。Nginx单机在普通硬件上能扛到几万并发,再高就需要多实例或前置LVS。
- 看协议:HTTP/HTTPS/WebSocket业务用Nginx可以灵活路由;TCP/UDP业务用LVS更好。DNS轮询只适合入口层简单分流。
- 看需求:需要灰度发布、蓝绿部署、A/B测试?必须用七层负载均衡(Nginx)。只需要简单的流量分发?用LVS或DNS轮询就够了。
- 看运维:团队如果熟悉Nginx配置,可以全栈用Nginx+ keepalived做高可用。如果对内核调优有经验,LVS可以发挥极致性能。
我曾经踩过一个坑:有个项目直接用LVS做七层业务分发,结果后端应用需要获取客户端真实IP。LVS/DR模式下后端看到的源IP是LVS的IP,必须通过TOA模块或者proxy protocol才能透传。当时没注意,后来查日志全是一个IP,排查问题花了半天。所以选型时一定要考虑网络拓扑对业务的影响。
小结
负载均衡选型没有银弹。DNS轮询简单但粗糙,LVS高效但底层,Nginx灵活但吃性能。在实际项目中,我通常把它们组合使用:最外层DNS轮询做多机房或多云分发,中间用LVS做四层流量接入,内部用Nginx做七层路由。三层各司其职,这才是我认为比较完善的架构。