Nginx如何实现熔断(原理+图解+案例)

高并发场景

Nginx 作为高性能的 Web 服务器、和反向代理。

在高并发环境下常用于流量控制,以保障系统稳定性。

Nginx如何实现熔断(原理+图解+案例)-mikechen

Nginx 常被用于实现限流(rate limiting)与熔断(circuit breaking)机制,以保护后端服务并平滑流量峰值。

比如:某金融服务在检测到,后端风控服务错误率持续上升时。

Nginx(openresty Lua)将该服务标记为熔断,直接返回降级默认结果并异步告警。

同时周期性探测后端恢复情况,熔断解除后逐步放流以验证稳定性,避免一次性流量回潮导致再次故障。

 

Nginx实现熔断

当后端服务出现错误率升高或响应延迟显著增加时,主动阻断或降级对该服务的请求以避免雪崩式故障。

Nginx 本身并不内置完整的熔断器逻辑,但可通过 Lua 脚本、外部熔断服务或 API 网关实现熔断策略。

Nginx如何实现熔断(原理+图解+案例)-mikechen

比如:基于错误率、失败次数或响应时间的阈值判断,以及短路、半开、恢复检测等状态机。

lua_shared_dict cb_metrics 10m;

server {
    listen 80;
    server_name api.example.com;

    location /api/report/ {
        access_by_lua_block {
            local dict = ngx.shared.cb_metrics
            local state = dict:get("report_state") or "closed"
            local open_until = dict:get("report_open_until") or 0
            local now = ngx.now()

            -- 打开状态且未到恢复时间:直接熔断
            if state == "open" and now < open_until then
                ngx.status = 503
                ngx.say('{"code":503,"msg":"report service temporarily unavailable"}')
                return ngx.exit(ngx.HTTP_OK)
            end
        }

        proxy_pass http://upstream_report;

        log_by_lua_block {
            local dict = ngx.shared.cb_metrics
            local key_err = "report_err"
            local key_total = "report_total"

            -- 累计窗口内统计
            dict:incr(key_total, 1, 0)

            local status = ngx.status
            local cost = ngx.now() - ngx.req.start_time()

            if status >= 500 or cost > 2 then  -- 错误或耗时>2s
                dict:incr(key_err, 1, 0)
            end

            local total = dict:get(key_total)
            local err = dict:get(key_err)

            if total and total >= 50 then
                local err_rate = err / total
                -- 错误率 > 50% 触发熔断,打开 30 秒
                if err_rate > 0.5 then
                    dict:set("report_state", "open")
                    dict:set("report_open_until", ngx.now() + 30)
                else
                    dict:set("report_state", "closed")
                end
                -- 窗口滚动重置
                dict:set(key_total, 0)
                dict:set(key_err, 0)
            end
        }
    }
}

当 /api/report/ 在窗口内错误率过高或超时过多时,将其熔断 30 秒。

在熔断窗口内,Nginx 直接 503 或返回自定义 JSON,无需再把流量压到下游。

mikechen睿哥

10年+一线大厂架构实战经验,操盘多个亿级大厂核心项目,就职于阿里、淘宝等一线大厂。

评论交流
    说说你的看法