nginx默认轮询不感知后端状态,openresty通过balancer_by_lua_block实现智能轮询:动态读取节点、结合请求特征路由、主动健康检查、平滑加权调度及日志闭环反馈。

直接用 Nginx 默认轮询做不到“智能”,它只是按顺序发请求,不看后端响应快慢、健康状态或业务特征。OpenResty 的价值在于用 Lua 把轮询过程接管过来,在每次转发前做实时判断——这才是智能轮询的起点。
用 balancer_by_lua_block 替代静态调度
Nginx 原生 upstream 只能配死的 server 列表,而 OpenResty 允许你在 balancer_by_lua_block 阶段完全控制选哪个后端:
- 不再依赖 upstream 块里的 server 行,可以动态读取 Redis、Consul 或本地 shared_dict 中的节点列表
- 每次请求进来时,Lua 脚本计算目标 peer,调用 balancer.set_current_peer(host, port) 显式指定
- 可结合请求头(如 X-User-Type)、URI 路径、参数等做条件路由,比如 /admin 接口固定打到高配节点
让轮询真正“感知后端状态”
默认轮询对后端宕机或变慢毫无反应,除非配置了 max_fails + fail_timeout(被动摘除)。OpenResty 支持主动探测+实时反馈:
- 用 ngx.timer.every 启动后台健康检查,定期调用后端 /health 接口
- 把异常节点标记为 down,并存入 shared_dict,后续 balancer_by_lua_block 中跳过该节点
- 恢复逻辑可设为“连续 2 次成功才启用”,避免网络抖动导致误判
实现平滑加权轮询(SWRR)
原生 weight 参数只影响长期比例,可能连续把 3 个请求都发给高权值节点。OpenResty 可实现数学意义上更均匀的分配:
- 维护每个节点的 current_weight 和 effective_weight
- 每轮将所有节点 current_weight += weight,选出最大者,再减去总权重
- 状态存在 shared_dict,跨 worker 进程共享,保证全局一致性
- 效果是权重 3:1 → 实际分发序列为 A,A,B,A,A,B…,而非 A,A,A,B
结合日志做闭环反馈
真正的智能还体现在“学得会”:把实际转发结果反哺调度策略:
- 在 log_by_lua_block 中提取 upstream_status、upstream_response_time 等字段
- 聚合延迟 P95、5xx 比例等指标,推送到 Prometheus 或写入 Redis
- 当某节点平均延迟突增,下一轮调度自动降低其权重;若错误率回落,再逐步恢复
不复杂但容易忽略:所有 Lua 逻辑必须控制执行时间,避免阻塞 worker。高频探测建议用 timer.at 替代 every,计算密集型操作后加 ngx.sleep(0) 让出协程。











