1. 限流基础概念
1.1 什么是限流
限流(Rate Limiting / Throttling)是一种通过控制单位时间内允许通过的请求数量、并发连接数或数据传输量,来保护系统不被突发流量冲垮的防护手段。其核心思想是:宁可拒绝部分请求,也不让整个系统崩溃。
限流的本质:在系统容量与用户请求之间插入一个可控的“阀门”,确保系统运行在安全水位线以内。
限流的常见控制维度包括:
- QPS 限流:每秒允许通过的请求数(如 1000 req/s)
- 并发限流:同时处理中的请求数上限(如 200 个并发)
- 速率限流:数据传输速率(如 10 MB/s)
- 连接数限流:同时建立的连接数上限(如 5000 个 TCP 连接)
1.2 为什么需要限流
在分布式系统中,限流不是可选项,而是保障系统稳定性的必备手段。以下是限流要解决的核心问题:
| 问题场景 | 风险描述 | 限流的作用 |
|---|---|---|
| 突发流量 | 秒杀、热点事件、爬虫攻击导致流量瞬间飙升 10x~100x | 削峰填谷,将超出处理能力的请求挡在门外 |
| 资源耗尽 | 数据库连接池、线程池、内存被占满,导致 OOM 或死锁 | 控制并发数,防止资源被过度消耗 |
| 级联故障 | 一个服务过载导致响应变慢,上游调用方堆积,最终雪崩 | 快速失败,避免故障扩散到整个调用链 |
| 成本控制 | 云资源按量计费,无限制的流量会导致巨额账单 | 按预算设定流量上限,防止成本失控 |
| 公平使用 | 某个恶意或异常客户端占用全部资源,影响正常用户 | 按用户/IP/API 进行配额隔离,保障多租户公平 |
实践建议:在 Go 微服务架构中,限流应部署在网关层(如 Envoy、Kong)和业务层(如中间件)两个层级,形成“双层防护”。网关层拦截大部分异常流量,业务层处理更精细的配额控制。
1.3 限流 vs 熔断 vs 降级
这三个概念经常被混淆,但它们解决的问题、触发条件和处理方式有本质区别。下表从多个维度进行对比:
| 对比维度 | 限流(Rate Limiting) | 熔断(Circuit Breaker) | 降级(Degradation) |
|---|---|---|---|
| 核心目标 | 预防过载,主动拒绝 | 快速失败,防止级联 | 牺牲非核心,保住核心 |
| 触发条件 | 请求速率/并发超过阈值 | 错误率/延迟超过阈值(被动检测) | 资源不足或人工决策 |
| 作用位置 | 调用方或服务入口 | 调用方(客户端侧) | 服务提供方(服务端侧) |
| 状态变化 | 持续生效,阈值恢复后自动解除 | Closed → Open → Half-Open 三态切换 | 通常手动或定时恢复 |
| 对调用方影响 | 请求被直接拒绝(429) | 请求快速失败或走 fallback | 返回降级结果(如缓存、默认值) |
| 典型实现 | 令牌桶、漏桶、滑动窗口 | Hystrix、Resilience4j、Google SRE 熔断 | 开关配置、动态路由、功能裁剪 |
1.4 限流在 Go 中的典型应用场景
在 Go 生态中,限流通常出现在以下位置:
- HTTP 服务中间件:基于
net/http或 Gin/Echo 框架,对每个路由或全局进行 QPS 限流。 - gRPC 拦截器:在服务端或客户端拦截器中对 RPC 调用进行并发数或速率限制。
- 消息队列消费端:控制消费者从 Kafka/RabbitMQ 拉取消息的速率,防止消费过快压垮下游。
- 数据库连接池:限制同时执行的 SQL 查询数量,避免数据库连接耗尽。
- 第三方 API 调用:对出站 HTTP 请求进行限流,遵守外部服务的调用配额。
常见误区:限流不是万能的。如果系统已经过载,限流只能阻止情况恶化,不能恢复已损坏的状态。限流必须与熔断、降级、重试、超时控制等策略组合使用,才能构建健壮的分布式系统。
1.5 限流的核心指标
在设计和评估限流方案时,需要关注以下关键指标:
| 指标 | 定义 | 典型值 |
|---|---|---|
| QPS 阈值 | 每秒允许通过的最大请求数 | 1000 / 5000 / 10000 |
| 并发阈值 | 同时处理中的最大请求数 | 200 / 500 / 1000 |
| 拒绝率 | 被限流拒绝的请求占总请求的比例 | < 5% 为正常,> 20% 需扩容 |
| 响应时间 | 限流决策本身的延迟开销 | < 1ms(本地限流),< 5ms(分布式限流) |
| 公平性 | 不同客户端是否获得均等的通过机会 | 按 IP/用户/API 进行配额隔离 |