ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

负载均衡核心原理与Nginx/HAProxy实战:从流量分发到高可用架构

负载均衡核心原理与Nginx/HAProxy实战:从流量分发到高可用架构 很多人第一次接触“负载均衡”这个词脑子里跳出来的第一反应就是这不就是多买几台服务器把请求分开处理嘛。听起来确实简单就像餐厅客人多了多开几个窗口一样。但真到了生产环境你会发现事情远没有这么简单——多加一台服务器之后流量该怎么分某台服务器悄悄挂了请求还会继续往它那边发吗同一个用户刚登录完下一次请求却被分到了另一台机器Session 丢了怎么办如果只是“加服务器”就能解决问题那互联网公司就不需要专门养一个负责负载均衡和网关的团队了。这篇文章想跟你认真聊一聊负载均衡它到底解决了什么问题核心原理是什么调度算法怎么选四层和七层有什么区别以及如何用 Nginx 和 HAProxy 快速搭出一套可用的负载均衡环境。文章会从概念讲到配置再讲验证和排查尽量让新手也能照着做同时让有经验的读者也能有所收获。1. 负载均衡真正要解决的三个问题如果只给负载均衡下一个定义那就是把一组客户端请求按照某种策略分发到多台后端服务器上从而提高系统的整体处理能力、可用性和稳定性。但这不是重点重点是它到底解决了什么原本让你头疼的问题。第一个问题单点压力。一台服务器的处理能力是有上限的。无论是 CPU、内存、带宽还是数据库连接数总有一个指标会先到瓶颈。当并发请求超过阈值后响应时间会快速恶化甚至直接拒绝服务。负载均衡把流量分散到多台服务器让每一台机器都工作在合理水位这是最直观的价值。第二个问题单点故障。一台服务器如果宕机了整个应用就不可用了。即便你做了 RAID 磁盘阵列、做了系统备份、做了数据定期快照机器硬件故障、机房网络抖动、操作系统内核异常这些问题依然无法完全避免。负载均衡配合健康检查机制会自动把故障节点摘除把流量导到其他正常节点。用户几乎感知不到后端发生了什么。第三个问题弹性伸缩。互联网业务的流量不是恒定的。上午十点和晚上八点的访问量可能差好几倍大促、活动、热点事件带来的流量峰值可能是平时的几十倍。如果按照峰值去采购服务器平时大部分算力都在闲置如果按均值采购峰值一来就会被打垮。负载均衡让你可以随时增加或减少后端节点扩容时直接把新服务器加进集群即可缩容时摘除节点即可整个过程对调用方透明。所以“负载均衡不就是加台服务器”这句话只看到了表面。加服务器解决的是容量问题负载均衡解决的是在有多台服务器之后怎么把流量安全、稳定、可控地分出去的问题。没有负载均衡服务器加得越多管理成本和故障风险反而越高。2. 核心概念与工作原理负载均衡体系里有几个概念会反复出现先把它们理清楚。2.1 负载均衡器负载均衡器是流量的“总入口”所有外部请求先到达这里再由它转发给后端服务器。它可以是一台专门的硬件设备比如 F5 BIG-IP也可以是运行在普通服务器上的软件比如 Nginx、HAProxy、LVS还可以是云平台提供的托管服务比如阿里云的 SLB、腾讯云的 CLB。负载均衡器本身应该是无状态的它只负责转发不负责保存业务数据。2.2 后端服务器池后端服务器池就是真正处理业务请求的一组服务器也叫真实服务器组。负载均衡器会维护一张后端节点列表根据调度算法从列表里选一台服务器然后把请求转发过去。在云环境里这些节点通常是云服务器 ECS在自建机房它们就是物理机或虚拟机。2.3 虚拟服务地址对外提供服务的统一入口地址通常是一个虚拟 IPVIP。客户端只需要访问这个地址不需要关心背后到底有多少台服务器、这些服务器在哪个机房、IP 是什么。对于客户端来说后端是一个黑盒它只知道访问 VIP 就能获得服务。2.4 健康检查这是负载均衡最容易忽略、却最关键的能力。如果某一台后端服务器已经宕机或者应用进程挂掉了负载均衡器必须能发现并且不把新请求转发过去。常见做法是定时向后端节点发送探测请求比如 TCP 端口探测、HTTP 接口探测连续失败 N 次后标记为异常连续成功 M 次后再恢复。2.5 会话保持HTTP 协议本身是无状态的但业务往往有状态。用户登录后产生的 Session 在服务器 A 上如果下一次请求被转发到服务器 BB 上找不到这个 Session用户就会被踢回登录页。会话保持就是为了解决这个问题把同一个用户的请求尽可能固定到同一台后端节点上。2.6 四层与七层负载均衡这是面试常考题也是选型时必须搞清楚的问题。类型工作层级转发依据典型代表性能能力四层负载均衡传输层基于 IP 和端口IP TCP/UDP 端口LVS、HAProxyTCP 模式、云 SLB 四层极高转发延迟低不解析应用层协议无法做域名、URL 路由七层负载均衡应用层基于 HTTP 等协议内容URL、域名、Header、Cookie 等Nginx、HAProxyHTTP 模式、云 SLB 七层相对四层略低可以做更精细的路由支持 SSL 卸载、缓存、重写等从架构发展来看很多大型系统会在不同层级同时使用两种负载均衡最外层用四层做流量接入和分发负责扛大流量内部再用七层做业务路由比如按域名或 URL 转发到不同的微服务集群。3. 调度算法流量是怎么分出去的负载均衡器拿到一个请求后究竟该把它给谁这个决策规则就是调度算法。不同算法有不同适用场景没有绝对的好坏只有合不合适。3.1 轮询与加权轮询轮询是最基础的算法请求轮流分给后端节点A → B → C → A → B → C。如果后端服务器配置一样权重一样轮询能保证流量均匀。加权轮询则给每台服务器设置一个权重比如新买的机器性能好权重设为 3旧机器设为 1那么新机器分到的请求大约是旧机器的三倍。3.2 最小连接数负载均衡器会记录每台后端节点的当前连接数每次把请求分给连接数最少的节点。这种算法适合请求处理时间差异比较大的场景。如果一个请求要处理 5 秒另一个只要 10 毫秒按照轮询硬分处理慢的那台会不断堆积请求而最小连接数可以动态避开繁忙节点。3.3 IP HASH 与一致性哈希IP HASH 根据客户端 IP 计算哈希值同一个 IP 的请求总是落在同一台后端节点上。这种算法可以天然实现会话保持但缺点是如果节点数量变化大量请求会被重新映射。一致性哈希则是将节点和请求都映射到同一个哈希环上节点增减时只会影响环上很小范围内的请求更适用于缓存类服务。3.4 调度算法选型建议场景推荐算法原因后端服务器配置相同请求处理时间接近轮询简单可靠流量均匀服务器性能不一致加权轮询按性能比例分配流量请求处理时间差异大最小连接数避免请求堆积到慢节点有 Session 保存需求未做 Session 共享IP HASH同 IP 落到同节点缓存类、状态类服务一致性哈希节点变化影响范围小4. 负载均衡在真实架构中的位置负载均衡不是一个孤立组件它往往贯穿整个请求链路。理解它在架构里的位置才能明白不同层的负载均衡分别解决什么问题。在典型的分层架构中最外层是 DNS 解析然后是负载均衡器再往后是应用服务器集群最后是数据库、缓存和消息队列。DNS 本身也可以做最简单的负载均衡也就是一个域名解析到多个 IP浏览器随机选一个访问。这种方式实现简单但粒度太粗——DNS 服务器不知道哪台后端机器挂了也不会根据负载情况动态调整解析结果。真正意义上的负载均衡要更精细。云上架构最常用的是云负载均衡实例绑定多台 ECS对公网暴露一个 VIP再通过 HTTP 监听器把请求转发到后端的 Tomcat、Spring Boot、Nginx 或容器服务里。如果是 Kubernetes 环境Service 的 LoadBalancer 类型和 Ingress 控制器也在承担不同层级的负载均衡职责。自建机房的老牌方案则更倾向于 LVS Nginx 的组合LVS 在最前面做四层转发扛住海量并发Nginx 在后端做七层路由、SSL 卸载和静态资源处理。再往后应用服务之间如果有相互调用还会通过 RPC 框架自带的负载均衡能力做服务发现和流量分配比如 Dubbo、Spring Cloud LoadBalancer这就是更上一层的客户端负载均衡了。从“加服务器”往上走你会发现真正拉开系统吞吐量的恰恰是这套从 DNS 到四层、七层再到服务间的流量调度体系。5. 实操使用 Nginx 搭建七层负载均衡Nginx 是目前使用最广泛的七层负载均衡软件之一它既能当 Web 服务器也能做反向代理和负载均衡。下面用一个最小示例演示如何把请求分发到两台后端服务上。5.1 环境准备本文的操作在 Linux 环境下演示你可以在云服务器或本地虚拟机中完成。需要准备一台安装了 CentOS 7/8、Ubuntu 20.04/22.04 等系统的服务器作为负载均衡节点。两台后端服务节点可以用真实服务器也可以在本地用不同端口模拟。Nginx 版本建议使用官方主线版本或系统仓库版本版本不是关键配置思路是通用的。如果你的系统没有安装 NginxCentOS 使用下面命令安装sudo yum install -y nginxUbuntu 使用下面命令sudo apt update sudo apt install -y nginx检查安装是否成功nginx -v出现版本号即说明安装成功。5.2 修改 Nginx 配置Nginx 的主配置文件位于/etc/nginx/nginx.conf也可以在/etc/nginx/conf.d/下新增独立配置文件。推荐使用独立文件的方式避免改动主配置带来风险。这里新增一个配置# 文件路径/etc/nginx/conf.d/load_balance.conf upstream backend_servers { server 192.168.1.101:8080 weight1 max_fails2 fail_timeout10s; server 192.168.1.102:8080 weight1 max_fails2 fail_timeout10s; } server { listen 80; server_name demo.example.com; location / { proxy_pass http://backend_servers; 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; } }这段配置的核心是upstream块。它定义了一个名为backend_servers的后端服务器组里面有两台后端节点。weight1表示权重相同max_fails2表示如果连续失败 2 次将该节点标记为不可用fail_timeout10s表示在 10 秒内统计失败次数并且节点被标记为不可用后经过 10 秒再重新探测。server块则是定义 Nginx 监听 80 端口当请求的域名匹配demo.example.com时把请求反向代理到backend_servers这个服务器组。注意proxy_set_header这几行它们把客户端真实 IP 和原始协议信息传递给后端否则后端日志里看到的全是 Nginx 的 IP排查问题时会非常痛苦。5.3 检查并重载配置修改完配置后一定要先检查语法再重新加载配置。这一点很重要生产环境中因为配置错误直接重启 Nginx 导致服务中断的例子非常多。nginx -t看到syntax is ok和test is successful后执行nginx -s reloadreload会平滑地重新加载配置不中断已有连接。5.4 模拟后端服务验证为了验证负载均衡是否生效可以在两台后端节点上用简单的 HTTP 服务来测试。假设后端节点 IP 分别为 192.168.1.101 和 192.168.1.102端口都是 8080它们分别返回不同的标识。在两台后端节点上分别执行# 节点 1 while true; do echo -e HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 7\n\nNode-101 | nc -l -p 8080; done# 节点 2 while true; do echo -e HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 7\n\nNode-102 | nc -l -p 8080; done然后在负载均衡节点上多次请求curl http://127.0.0.1/连续执行几次如果看到输出在Node-101和Node-102之间交替出现说明轮询生效了。6. 实操使用 HAProxy 搭建四层负载均衡有些场景下你并不需要解析 HTTP 协议只想基于 TCP 做流量分发比如转发 MySQL、Redis、MQ 等中间件流量。这时 HAProxy 是一个很好的选择它在四层转发性能和稳定性上都表现优秀。6.1 安装 HAProxyCentOS 安装命令sudo yum install -y haproxyUbuntu 安装命令sudo apt install -y haproxy查看版本haproxy -v6.2 配置 TCP 负载均衡HAProxy 的主配置位于/etc/haproxy/haproxy.cfg。修改配置前建议先备份原文件cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak下面是一个把 TCP 流量分发到两台 Redis 节点的示例# 文件路径/etc/haproxy/haproxy.cfg global log /dev/log local0 maxconn 4096 user haproxy group haproxy daemon defaults log global mode tcp option tcplog option dontlognull retries 3 timeout connect 5000 timeout client 50000 timeout server 50000 frontend redis_front bind *:6379 default_backend redis_backend backend redis_backend balance roundrobin server redis1 192.168.1.201:6379 check inter 3s fall 3 rise 2 server redis2 192.168.1.202:6379 check inter 3s fall 3 rise 2这里的mode tcp表示 HAProxy 工作在四层不解析应用层协议直接转发原始 TCP 流量。frontend redis_front定义了外部入口监听所有网卡的 6379 端口。backend redis_backend定义后端节点池balance roundrobin表示采用轮询算法。check表示启用健康检查inter 3s表示每 3 秒探测一次fall 3表示连续 3 次失败后标记为下线rise 2表示连续 2 次成功后再恢复上线。6.3 启动并验证systemctl restart haproxy systemctl status haproxy确认状态为active (running)后用 Redis 客户端连接负载均衡入口进行验证redis-cli -h 127.0.0.1 -p 6379 ping返回PONG说明转发成功。为了确认流量确实分发到了两台后端可以分别在 redis1 和 redis2 上查看连接情况或者观察 HAProxy 的统计页面这个我们在下一节说明。6.4 开启 HAProxy 监控页面HAProxy 内置了一个监控页面可以通过网页查看后端节点的健康状态和连接数。在haproxy.cfg的defaults或单独listen中添加listen stats bind *:8888 mode http stats enable stats uri /stats stats realm HAProxy\ Statistics stats auth admin:admin123 stats refresh 5s保存并重载配置haproxy -c -f /etc/haproxy/haproxy.cfg systemctl reload haproxy浏览器访问http://负载均衡节点IP:8888/stats输入用户名admin、密码admin123就能看到两台 Redis 后端节点的状态、连接数、健康检查结果等实时数据。这个页面在排障时非常有用。7. 运行结果与效果验证配置写好了服务也启动了接下来要验证负载均衡真的按预期工作并且能正确应对故障。7.1 验证流量分发对于 Nginx 七层负载均衡可以通过循环请求观察返回内容来验证轮询效果for i in {1..10}; do curl -s http://127.0.0.1/; echo; done预期输出会在后端两个节点之间交替。如果始终只能访问到某一个节点说明另一个节点没有进入可用状态首先检查后端服务是否正常监听端口以及负载均衡器到后端节点之间的网络是否连通。7.2 验证健康检查模拟后端故障是最重要的验证手段。把某一台后端节点上的服务停掉比如在节点 1 上停止刚才的 netcat 进程然后在负载均衡节点上继续循环请求curl -s http://127.0.0.1/这时所有请求应该都被转发到节点 2不会出现请求失败。再把节点 1 服务恢复一段时间后流量应该自动恢复到两台节点。这里真正的价值在于故障切换是由负载均衡器自动完成的不需要人工修改任何配置。这也就是“加一台服务器”之外负载均衡带来的稳定性收益。7.3 验证会话保持如果使用ip_hash算法同一个客户端 IP 的请求会固定落在同一台后端节点上。在 Nginx 配置upstream中修改upstream backend_servers { ip_hash; server 192.168.1.101:8080; server 192.168.1.102:8080; }重载后再次请求你会发现所有请求都落在了同一台节点上。这在 Session 没有外置到 Redis/数据库的场景下非常有用。8. 常见问题与排查思路负载均衡在实际使用中会遇到各种问题我把最常见的几种整理成了一张排查表方便你对照处理。问题现象可能原因排查方式解决方案后端日志中拿不到客户端真实 IP未设置 X-Forwarded-For 等 Header检查 Nginx 配置中 proxy_set_header 字段补充 X-Real-IP、X-Forwarded-For 配置后端改为读取对应 Header某个节点始终没有流量节点被健康检查标记为故障查看健康检查状态、检查节点端口是否监听、应用是否存活排查后端应用和网络恢复服务后等待自动拉回部分用户登录状态丢失未配置会话保持或 Session 未共享检查负载均衡算法和 Session 存储位置短期用 ip_hash 解决长期建议 Session 外置到 Redis负载均衡器自身 CPU 飙升并发超出单机处理能力或 TLS 频繁握手查看监控指标、分析访问日志扩展为多级负载均衡或启用 SSL 会话复用、升级硬件出现请求超时后端响应慢或超时时间配置过短查看后端应用访问日志和压测报告适当增大 timeout检查后端应用是否存在慢查询、死锁配置重载后服务中断配置语法错误导致重启失败先执行 nginx -t / haproxy -c 检查语法始终先检查语法再 reload保留上一版可用配置后端节点频繁被摘除又恢复健康检查路径设置错误或健康检查频率过高查看负载均衡日志和节点应用日志正确配置健康检查接口适当调整失败/成功阈值加权轮询不符合预期权重配置不合理或节点性能差异过大查看后端节点处理能力和负载情况基于压测数据调整权重这里特别提醒一点排查问题时要先分清楚“入口通不通”和“后端通不通”。入口不通检查负载均衡器的监听端口和防火墙后端不通检查后端服务的监听状态和负载均衡器到后端的网络链路。不要一上来就怀疑配置先看链路再看配置效率会高很多。9. 最佳实践与工程建议如果要把负载均衡真正用好在生产环境有几个原则值得坚持。9.1 配置管理要谨慎所有变更都遵循“先备份 → 改配置 → 语法检查 → 灰度加载 → 观察日志 → 稳定后全量生效”的流程。很多线上事故并非功能设计有问题而是变更时图省事跳过了检查步骤。在修改 Nginx 时nginx -t只需要一秒值得养成习惯。也可以用版本管理工具保存配置回滚时能快速切换到上一版本。9.2 健康检查要讲究不要简单地依赖 TCP 端口探测因为端口通并不代表应用可用。比如 Tomcat 可能端口还在监听但线程池已经打满此时请求进来依然会超时。更可靠的做法是通过健康检查接口反馈应用真实状态例如/actuator/health或自定义的/health接口接口内部检查依赖的基础设施数据库连接、缓存连接、磁盘空间等再以 HTTP 状态码告知负载均衡器。健康检查的频率也不要太低3 秒一次比较常见具体频率需要和业务容忍度做平衡。9.3 会话状态尽量外置不要在应用本地保存 Session而是统一放到 Redis 等外部存储应用节点保持无状态。这样即使任意一台服务器宕机、即使负载均衡器把请求分到任意节点都能拿到同一份会话数据。真正做到无状态之后扩容缩容才不受约束负载均衡的弹性价值才能真正发挥出来。9.4 日志和监控不可缺失负载均衡器是流量的咽喉必须监控它的连接数、转发延迟、后端节点健康状态、错误率等指标。至少要做到有统一的日志采集日志里能追踪到客户端 IP、转发的后端节点、响应状态码有基础告警当某台后端节点频繁被摘除或整体错误率升高时能及时通知到人。没有监控的负载均衡出问题时就像在黑暗里找东西。9.5 容量规划要留余量负载均衡器本身也有处理上限。一台 Nginx 能扛住数万并发但 TLS 握手、URL 路由、日志写入都会消耗资源。线上建议让负载均衡器的峰值负载不超过其能力的 50% 到 60%留出一半余量给突发流量和故障转移场景。如果单机负载均衡器成为瓶颈优先考虑云平台自带的负载均衡服务或者使用 LVS Nginx 的多级架构。9.6 安全边界要清晰负载均衡器是公网进入内网的第一道关口必须收敛暴露面。管理端口不要对公网开放尽量只允许运维网段访问。如果负载均衡器需要对外提供 HTTPS 服务证书管理要规范并配置合理的 TLS 版本。同时防止后端节点被公网直接访问后端只允许负载均衡器的 IP 访问这样可以避免绕过负载均衡直接打到后端的风险。文中使用 HAProxy 监控页时设置的密码只是一个示例生产环境应当使用强密码并限制访问来源不要直接暴露在公网。关于负载均衡的核心问题其实可以归纳成一句话它解决的不是“服务器不够用”而是“有了多台服务器之后怎么让它们像一个整体一样对外提供稳定、高可用的服务”。理解了这一点再看各种算法和配置思路就会清晰很多。下一步建议你亲手做一次实验准备两台后端服务用一个负载均衡器把流量分出去然后手动停掉其中一台观察请求是否自动切换、恢复后是否自动收回。这个过程会把健康检查、调度算法、会话保持的概念全部串起来比看十篇文章都管用。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表