09-反向代理与负载均衡微服务多节点分发、会话保持、轮询策略一、正向代理 vs 反向代理先搞清楚你在代理谁很多人一上来就搞混这两个概念我们用一句话区分正向代理代理的是客户端。客户端知道自己要访问谁但让代理服务器替你去访问。典型场景——翻墙、公司内网通过代理上网。反向代理代理的是服务端。客户端不知道真实服务器是谁只跟代理打交道。典型场景——Nginx、CDN。打个比方正向代理是你找了个跑腿小哥帮你去排队买奶茶你知道买哪家跑腿替你去反向代理是你走进一家餐厅点餐后厨哪个厨师做你不知道前台帮你分配。对于我们的无人售货柜系统来说用户打开小程序下单请求打到 NginxNginx 把请求转发给后端的 SpringBoot 微服务集群——这就是反向代理。用户根本不知道后面有几台服务器。二、upstream 模块负载均衡的核心Nginx 的负载均衡靠upstream模块实现本质上就是定义一个后端服务器池然后 Nginx 按照一定策略把请求分发到池子里的机器上。基础语法如下upstream vending_backend { server 192.168.1.101:8080; server 192.168.1.102:8080; server 192.168.1.103:8080; } server { listen 80; server_name api.vending.com; location / { proxy_pass http://vending_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; } }这段配置的含义定义了3台后端服务器所有访问api.vending.com的请求都会被 Nginx 分发到这3台机器上。proxy_set_header那几行很重要——不加的话后端拿到的 IP 永远是 Nginx 的 IP日志排查和风控都会出问题。三、负载均衡策略5种姿势总有一款适合你1. 轮询Round Robin——默认策略upstream vending_backend { server 192.168.1.101:8080; server 192.168.1.102:8080; server 192.168.1.103:8080; }按顺序一个个来请求1给101请求2给102请求3给103请求4又给101……简单粗暴适合后端服务器配置完全一样的场景。2. 权重Weightupstream vending_backend { server 192.168.1.101:8080 weight3; server 192.168.1.102:8080 weight1; server 192.168.1.103:8080 weight1; }101机器配置高比如32核64G另外两台配置低8核16G那就给101分配更高的权重。按3:1:1的比例分配请求让性能强的机器多干活。3. ip_hash ——会话保持的利器upstream vending_backend { ip_hash; server 192.168.1.101:8080; server 192.168.1.102:8080; server 192.168.1.103:8080; }根据客户端IP做hash计算同一个IP的请求永远落到同一台机器上。这解决了Session共享的问题——用户的购物车数据存在某台机器的本地Session里如果下次请求被分到另一台机器购物车就空了。4. least_conn ——最少连接优先upstream vending_backend { least_conn; server 192.168.1.101:8080; server 192.168.1.102:8080; server 192.168.1.103:8080; }谁的连接数少就把请求给谁适合请求处理时间差异较大的场景。比如有些请求要查大表有些只是返回个缓存轮询就不太合理了。5. fair第三方模块upstream vending_backend { fair; server 192.168.1.101:8080; server 192.168.1.102:8080; }按响应时间分配响应快的多分点。需要安装nginx-upstream-fair模块不是内置的。四、健康检查挂了就别往那发了Nginx 内置的被动健康检查upstream vending_backend { server 192.168.1.101:8080 max_fails3 fail_timeout30s; server 192.168.1.102:8080 max_fails3 fail_timeout30s; server 192.168.1.103:8080 max_fails3 fail_timeout30s; }max_fails3在fail_timeout时间内失败3次标记为不可用fail_timeout30s标记不可用后30秒内不再往这台机器发请求30秒后再试被动检查的缺点是要等真实请求失败了才会摘掉节点。如果想主动探测需要用nginx_upstream_check_module或者商业版 Nginx Plus 的health_check指令。五、会话保持方案对比方案原理优点缺点ip_hashIP哈希固定后端配置简单客户端IP变化切换WiFi/4G会失效sticky cookie在Cookie中植入后端标识不受IP变化影响需要客户端支持CookieRedis共享SessionSession统一存Redis最彻底的方案需要改代码增加Redis依赖推荐方案生产环境用 Redis 共享Session Nginx负载均衡的组合最稳妥。如果不想改代码ip_hash 是最快上线的方案。六、无人售货柜微服务负载均衡实战实际项目中的完整配置# 订单服务集群 upstream order_service { server 192.168.1.101:8080 weight2 max_fails3 fail_timeout30s; server 192.168.1.102:8080 weight2 max_fails3 fail_timeout30s; server 192.168.1.103:8080 weight1 max_fails3 fail_timeout30s backup; } # 设备管理服务集群 upstream device_service { ip_hash; server 192.168.1.201:8081 max_fails3 fail_timeout30s; server 192.168.1.202:8081 max_fails3 fail_timeout30s; } server { listen 443 ssl; server_name api.vending.com; ssl_certificate /etc/nginx/ssl/vending.pem; ssl_certificate_key /etc/nginx/ssl/vending.key; # 订单接口 location /api/order/ { proxy_pass http://order_service; 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_connect_timeout 5s; proxy_read_timeout 30s; proxy_send_timeout 10s; } # 设备管理接口 location /api/device/ { proxy_pass http://device_service; 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 /health { access_log off; return 200 ok\n; } }几个关键点说明backup参数103服务器标记为备用节点正常情况下不参与负载只有101和102都挂了才启用。适合用低配机器做兜底。设备服务用ip_hash售货柜设备通过MQTT长连接上报状态同一台设备的请求最好固定到同一后端避免Session/连接状态在不同节点间迁移。超时配置proxy_connect_timeout 5s表示连接后端超时5秒就判定失败避免用户等太久。proxy_read_timeout 30s给后端足够的处理时间订单涉及支付回调可能慢一点。access_log off健康检查接口关掉日志否则监控探针每秒请求一次日志文件会爆炸。七、负载均衡效果验证部署完成后用ab压测工具验证分发效果# 发送1000个请求并发10ab-n1000-c10http://api.vending.com/api/order/list然后看各台后端服务器的访问日志# 在每台后端机器上执行tail-f/var/log/nginx/access.log|wc-l如果是轮询策略每台机器的请求量应该大致均等约333次。如果权重是2:2:1那比例应该是40%:40%:20%。负载均衡不是配置完就完事了持续监控各节点的请求量和响应时间根据实际情况调整权重和策略才是运维的真功夫。