高并发系统的护城河:全链路限流体系的决策与重构

侯乾 Lv4

1. 始于业务场景:当“流量”变成“洪峰”

两周前的季度大促,我们的核心交易链路遭遇了一次“惊魂时刻”。

在零点秒杀开启的瞬间,流量激增至日常峰值的 15 倍。虽然我们预备了自动扩容策略,但数据库连接池在扩容完成前就被打满,紧接着是应用层的线程池耗尽。最终,API 响应时间从平均 50ms 飙升至 3s 以上,前端大量报错,核心服务陷入“雪崩”。

事后复盘,我们意识到单纯依赖“弹性扩容”处理脉冲流量是不现实的——扩容速度永远追不上流量瞬间的爆发速度

我们需要构建一套全链路限流体系。这不仅是技术堆叠,更是一场关于技术选型的精密计算。


2. 架构设计:构建“漏斗型”防御体系

要在高并发下全身而退,单点防御是远远不够的。我们设计了五层漏斗模型,流量从外到内,层层递减。

graph TD
    subgraph Internet ["外部流量洪峰 (100W QPS)"]
        User((用户/黑产))
    end

    subgraph Layer1 ["第一道:接入层 (Nginx)"]
        L1_Action[("物理阻断<br/>Limit Req Zone")]
        style L1_Action fill:#f9f,stroke:#333,stroke-width:2px
    end

    subgraph Layer2 ["第二道:网关层 (Gateway)"]
        L2_Action[("全局整形<br/>Redis + Lua")]
        style L2_Action fill:#ff9,stroke:#333,stroke-width:2px
    end

    subgraph Layer3 ["第三道:应用层 (Service)"]
        L3_Action[("精细化治理<br/>Sentinel")]
        style L3_Action fill:#9f9,stroke:#333,stroke-width:2px
    end

    subgraph Layer4 ["第四道:资源层 (DB)"]
        L4_Action[("最后底线<br/>Druid Pool")]
        style L4_Action fill:#9ff,stroke:#333,stroke-width:2px
    end

    User -->|全量请求| L1_Action
    L1_Action -->|拦截恶意IP<br/>剩余 50W| L2_Action
    L2_Action -->|集群限流<br/>剩余 10W| L3_Action
    L3_Action -->|单机/热点限流<br/>剩余 8W| L4_Action
    L4_Action -->|并发控制| DB[(核心数据库)]

    linkStyle 0,1,2,3,4 stroke-width:2px,fill:none,stroke:green;

但在每一层的工具选型上,我们经历了两场激烈的“路线之争”。


决策一:网关层为何“弃 Sentinel,选 Redis”?

争议焦点:

网关是流量的咽喉,需要控制整个下游服务集群的总 QPS。团队最初提议:“应用层用了 Sentinel,为了技术栈统一,网关层也上 Sentinel 集群模式吧?”

推演分析:

我们对比了两种架构模式:

flowchart TB
    subgraph Sentinel_Cluster ["方案A:Sentinel 集群模式 (太重)"]
        direction TB
        GW1[Gateway 节点]
        GW2[Gateway 节点]
        TS[("❌ Token Server<br/>(独立集群)")]
        GW1 --"1. 网络请求申请令牌"--> TS
        GW2 --"2. 网络请求申请令牌"--> TS
        TS --"3. 返回结果"--> GW1
        style TS fill:#f99,stroke:#333
    end

    subgraph Redis_Lua ["方案B:Redis + Lua (轻量)"]
        direction TB
        GW_A[Gateway 节点]
        GW_B[Gateway 节点]
        Redis[("✅ Redis Infrastructure<br/>(现有设施)")]
        GW_A --"原子计数 (Lua)"--> Redis
        GW_B --"原子计数 (Lua)"--> Redis
        style Redis fill:#9f9,stroke:#333
    end

否决 Sentinel 的理由:

  1. 架构复杂度: 方案 A 需要维护独立的 Token Server。如果它挂了,网关是全放行还是全拒绝?这引入了新的单点风险。
  2. 性能损耗: 网关对延迟(Latency)极度敏感。Sentinel Client 到 Token Server 的网络 RTT 在高并发下是显性成本。

最终决策:Redis + Lua

我们选择了方案 B。Redis 是基础设施标配,无需引入新组件,且 Lua 脚本执行效率极高,完全满足“抗量”需求。


决策二:应用层为何“弃 Guava,选 Sentinel”?

争议焦点:

流量进入微服务内部后。开发同学提出:“Sentinel 太重了,还要搭控制台。为什么不直接用 Guava 的 RateLimiter?JDK 纯原生,一行代码搞定。”

推演分析:

Guava 是工具,Sentinel 是体系。二者的核心差异在于**“运维闭环”**。

sequenceDiagram
    participant Dev as 运维/开发
    participant Config as 配置中心/控制台
    participant App as 应用服务
    participant Traffic as 业务流量

    rect rgb(255, 230, 230)
        note right of Dev: ❌ Guava 模式:硬编码噩梦
        Dev->>App: 1. 修改代码/配置 (QPS 500 -> 1000)
        Dev->>App: 2. 重新编译 & 打包
        Dev->>App: 3. 重启服务 (Service Restart)
        App-->>Traffic: 4. 服务重启期间,流量丢失/报错!
    end

    rect rgb(230, 255, 230)
        note right of Dev: ✅ Sentinel 模式:动态治理
        Traffic->>App: 持续处理业务...
        Dev->>Config: 1. 控制台修改规则 (QPS 500 -> 1000)
        Config->>App: 2. 推送规则 (Push)
        App->>App: 3. 毫秒级热更新生效
        App-->>Traffic: 4. 无损平滑过渡
    end

否决 Guava 的理由:

  1. 黑盒运行(无观测性): 故障发生时,Guava 不会告诉你拒绝了多少请求。看不见的防御等于没有防御。
  2. 硬编码(无动态性): 如上图所示,大促期间调整阈值如果需要重启服务,这在流量洪峰下无异于自杀。

最终决策:Sentinel

我们看重 Sentinel 的可视化控制台和动态配置能力(集成 Nacos)。即使性能损耗略高于 Guava,但换来了宝贵的“上帝视角”和“热更新能力”。


3. 数据闭环:从“猜测”到“验证”

全链路限流体系上线后,我们在预发环境进行了 50,000 QPS 的全链路压测(Stress Test)。

优化前数据:

  • API 成功率:65%
  • P99 耗时:2800ms
  • 数据库 CPU:98%(接近死锁)

优化后数据:

  1. 网关层(Redis):精准拦截了超出集群容量的 20,000 QPS,保护了下游。
  2. 应用层(Sentinel):通过动态调整热点参数规则,成功压制了“爆款商品”的单点击穿。
  3. 最终结果
    • API 成功率(未被限流用户):99.99%
    • P99 耗时:45ms
    • 数据库 CPU:稳定在 60% 左右。

4. 复盘与展望:没有完美的架构

回顾这次重构,最核心的经验不在于代码本身,而在于**“因地制宜”的技术选型**:

  • 在网关层,我们追求**“快与全局”**,所以放弃了笨重的 Sentinel 集群模式,选择了轻量的 Redis。
  • 在应用层,我们追求**“可控与多变”**,所以放弃了简陋的 Guava,选择了强大的 Sentinel。

架构师的价值,不仅仅是知道有哪些工具,更在于知道在什么场景下,坚决地对某些工具说“不”。

  • Title: 高并发系统的护城河:全链路限流体系的决策与重构
  • Author: 侯乾
  • Created at : 2022-10-11 20:26:00
  • Updated at : 2022-10-11 20:26:00
  • Link: http://houqian.github.io/2022/10/11/高并发系统的护城河:全链路限流体系的决策与重构/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments