Go限流熔断与服务治理工程开发与部署实践 - 第2节
2.1 什么是限流
限流(Rate Limiting)是一种通过控制单位时间内允许通过的请求数量,来保护系统不被突发流量冲垮的防护手段。它本质上是对系统入口或关键路径施加一个“流量阀门”,确保后端资源(CPU、内存、数据库连接、下游服务)始终工作在安全水位以下。
核心思想:与其让系统在过载时崩溃,不如在入口处主动拒绝一部分请求,保证大部分请求仍能获得正常响应。
限流在微服务架构中通常部署在以下位置:
- 网关层:全局流量整形,如 Nginx、Kong、APISIX
- 服务入口:每个微服务实例的 HTTP/RPC 接口
- 中间件客户端:数据库连接池、消息队列生产端
- 业务关键路径:秒杀、下单、支付等核心链路
| 维度 | 说明 | 典型阈值 |
|---|---|---|
| QPS(每秒请求数) | 按请求数量限流 | 1000 req/s |
| 并发数 | 按同时处理中的请求数限流 | 200 并发 |
| 带宽 | 按网络吞吐量限流 | 100 Mbps |
| CPU/内存水位 | 按系统资源使用率自适应限流 | CPU > 80% |
2.2 常见限流算法原理对比
业界主流限流算法有四种:固定窗口计数器、滑动窗口计数器、漏桶算法、令牌桶算法。下面逐一拆解其原理、优缺点和适用场景。
2.2.1 固定窗口计数器
将时间划分为固定的窗口(如 1 秒),每个窗口内维护一个计数器。请求到达时计数器加 1,若计数器超过阈值则拒绝;窗口结束时计数器归零。
临界突变问题:假设阈值 100 req/s,若第 1 秒最后 100ms 内通过 100 个请求,第 2 秒前 100ms 内又通过 100 个请求,则实际 200ms 内通过了 200 个请求,远超阈值。这是固定窗口最严重的缺陷。
2.2.2 滑动窗口计数器
将固定窗口细分为多个小格子(如 1 秒拆成 10 个 100ms 格子),每次请求到来时统计当前时间往前推一个完整窗口内的所有格子计数之和。滑动窗口通过更细的粒度平滑了流量,临界突变问题大幅缓解。
| 对比项 | 固定窗口 | 滑动窗口 |
|---|---|---|
| 实现复杂度 | 低(1 个计数器) | 中(环形数组 + 滑动指针) |
| 临界突变 | 严重 | 基本消除(格子越细越平滑) |
| 内存开销 | O(1) | O(格子数) |
| 适用场景 | 对突发不敏感的低频接口 | 大部分通用场景 |
2.2.3 漏桶算法
漏桶算法将请求比作水,系统是一个底部有孔的固定容量桶。水以恒定速率从桶底漏出(处理请求),桶满时新水溢出(拒绝请求)。漏桶强制输出速率恒定,无论入口流量如何波动。
2.2.4 令牌桶算法
令牌桶算法以固定速率向桶中放入令牌,每个请求需要从桶中获取一个或多个令牌才能被处理。桶有最大容量,令牌超过容量则丢弃。当桶中令牌不足时请求被拒绝或等待。
2.3 四种算法综合对比
| 算法 | 输出速率 | 突发能力 | 实现复杂度 | 内存开销 | 适用场景 |
|---|---|---|---|---|---|
| 固定窗口计数器 | 不保证 | 有(但导致临界突变) | ★☆☆☆☆ | O(1) | 低频接口、监控告警 |
| 滑动窗口计数器 | 较平滑 | 有限(取决于格子数) | ★★☆☆☆ | O(N) | 通用场景、API 限流 |
| 漏桶算法 | 严格恒定 | 无(桶容量仅缓冲) | ★★★☆☆ | O(1) | 保护下游脆弱系统、数据库写入 |
| 令牌桶算法 | 平均恒定 | 允许突发 | ★★★☆☆ | O(1) | Web 服务、微服务网关(最常用) |
2.4 Go 语言中的限流实践选型
在 Go 生态中,不同算法有对应的成熟实现:
- 令牌桶:
golang.org/x/time/rate— Go 官方扩展库,基于令牌桶实现,支持Allow()、Wait()、Reserve()三种模式 - 漏桶:
github.com/uber-go/ratelimit— Uber 开源漏桶实现,适合需要严格恒定速率的场景 - 滑动窗口:
github.com/zeromicro/go-zero/core/limit— go-zero 框架内置滑动窗口限流器 - 自适应限流:
github.com/alibaba/sentinel-golang— 阿里开源,支持 CPU/内存/并发数自适应
课程选型建议:本骨架工程默认采用
① 官方维护,零外部依赖;
② 支持突发流量,符合互联网业务特征;
③ 接口简洁,易于集成到中间件和业务代码中。
golang.org/x/time/rate(令牌桶)作为核心限流组件,原因如下:① 官方维护,零外部依赖;
② 支持突发流量,符合互联网业务特征;
③ 接口简洁,易于集成到中间件和业务代码中。
2.5 限流与熔断的关系
限流和熔断是系统防护的“双保险”,但职责不同:
| 维度 | 限流 | 熔断 |
|---|---|---|
| 触发条件 | 流量超过预设阈值 | 错误率/延迟超过阈值 |
| 作用位置 | 入口/上游 | 调用链路/下游 |
| 恢复方式 | 流量下降后自动恢复 | 半开探测 + 超时重置 |
| 目标 | 防止系统过载 | 防止故障扩散 |
| 典型实现 | 令牌桶、漏桶 | 断路器模式(Hystrix、Resilience4j) |