openresty可通过动态限流与熔断保护后端:基于滑动窗口统计p95耗时和错误率调整rate/burst,用resty.limit.req动态创建限流器,并实现关闭→打开→半开三层熔断状态。

OpenResty 可以基于实时响应时间动态调整限流阈值,并结合熔断逻辑保护后端服务。核心思路是:当接口变慢时自动收紧流量,响应恢复后再逐步放开;若持续超时或失败,则触发熔断,快速失败并返回兜底内容。
用 resty.limit.req 实现响应时间感知的限流
标准的 resty.limit.req 本身不直接读取响应时间,但可通过 Lua 在请求生命周期中采集耗时,并据此重建限流器实例。
- 在
log_by_lua*阶段记录本次请求耗时:ngx.ctx.start_time = ngx.now()(放在access_by_lua*或rewrite_by_lua*开头),然后在log_by_lua_block中计算:local cost = ngx.now() - (ngx.ctx.start_time or ngx.now()) - 将耗时作为因子参与限流参数计算,例如:
若平均耗时 ≤ 100ms,允许 100r/s;耗时升至 300ms,自动降为 30r/s;超过 500ms 则设为 10r/s - 每次请求都调用
limit_req.new("my_store", rate, burst)动态生成新限流器(注意:共享字典名需固定,rate/burst 值可变);实际生产中建议缓存最近几个档位的 lim 实例,避免高频新建开销
通过共享字典 + 时间窗口统计响应质量
仅靠单次耗时不稳,应聚合滑动窗口内的成功率与 P95 耗时,再决策是否调整限流或熔断。
- 使用
lua_shared_dict resp_stats 10m;存储每个 upstream 的统计信息,key 如"upstream:api_v1" - 每完成一次后端调用(无论成功/失败/超时),在
log_by_lua中更新:
— 成功请求数、总耗时、失败次数、超时次数
— 使用ngx.shared.resp_stats.incr()和set()维护带过期时间的窗口(如 60 秒) - 在
access_by_lua阶段读取该窗口数据,若 P95 > 400ms 或错误率 > 20%,则临时启用更严限流策略(如 rate 减半、burst 设为 0)
实现三层状态熔断器(关闭 → 打开 → 半开)
熔断逻辑不依赖外部组件,纯 OpenResty 内存实现,低延迟且可靠。
- 定义共享字典
lua_shared_dict circuit_breaker 5m;,每个 upstream 对应一个 key,值为 JSON 字符串:{"state":"closed","fail_count":0,"last_fail_ts":1747123456,"half_open_at":0} - 请求前检查状态:
— 若为open,直接return ngx.exit(503)或返回预设兜底响应
— 若为half_open,只放行固定数量(如 3 个)请求做试探,其余拒绝 - 请求结束后更新状态:
— 成功:重置计数,状态切回closed
— 失败(超时/5xx):fail_count++,若连续失败 ≥ 5 次且间隔 open,并设置half_open_at = now + 30
— 进入half_open后,首次成功即切回closed;若试探失败,延长熔断时间
组合限流与熔断的典型流程
二者不是互斥,而是分层协作:限流控制入口流量密度,熔断应对后端异常。推荐部署顺序为「限流 → 熔断检查 → 代理转发」。
- 先执行动态限流判断,过滤掉明显过载请求
- 再查熔断状态,若已打开则跳过真实转发,直出 fallback
- 转发后,在
log_by_lua中同步更新响应指标和熔断状态 - 兜底内容可由
content_by_lua_block渲染 JSON 或静态 HTML,避免依赖下游










