1. 限流基础:为什么需要限流?
1.1 限流的本质与必要性
在微服务架构中,限流(Rate Limiting) 是一种通过控制单位时间内请求量的方式,保护系统不被突发流量冲垮的核心手段。没有限流的系统,就像没有保险丝的电路——一旦电流(流量)超过线路(服务)的承载能力,整条线路就会烧毁。
核心观点:限流不是限制业务增长,而是为系统提供“可控的退化”能力。当流量超过阈值时,系统主动拒绝部分请求,确保核心功能仍能正常响应,避免雪崩式崩溃。
1.2 限流在微服务中的核心作用
限流在微服务体系中承担着多重关键角色,下表总结了其四大核心作用:
| 核心作用 | 说明 | 典型场景 |
|---|---|---|
| 防止资源耗尽 | 限制 CPU、内存、数据库连接池、线程池等有限资源的过度使用 | 秒杀活动、热点新闻推送 |
| 保障服务质量 | 避免因高负载导致响应时间(RT)急剧上升,维持尾延迟(Tail Latency)在可接受范围 | API 网关、实时推荐服务 |
| 公平分配资源 | 在多租户系统中,确保每个租户或调用方获得公平的配额 | 开放平台 API、SaaS 服务 |
| 成本控制 | 按流量付费的云服务中,限流可防止意外的高额账单 | 第三方 API 调用、日志采集 |
1.3 常见限流场景
限流并非只存在于网关层,它在微服务的各个层级都有应用。以下是三种最常见的场景:
- 网关层限流(入口限流): 在 API Gateway 或反向代理(如 Nginx、Kong)处对全局流量进行整形,是最外层的防护屏障。通常基于 IP、用户 ID、URL 路径等维度进行限流。
- 服务层限流(业务限流): 在具体微服务内部,针对特定接口或方法进行限流。例如,订单服务的“创建订单”接口与“查询订单”接口可以设置不同的限流阈值。
- 资源层限流(基础设施限流): 针对数据库连接池、Redis 连接、消息队列等底层资源进行限流。当资源池耗尽时,直接拒绝上游请求,避免阻塞蔓延。
实战建议:在 Go 微服务中,推荐采用“网关层 + 服务层”双层限流策略。网关层做粗粒度限流(如 QPS 1000),服务层做细粒度限流(如核心接口 QPS 100,非核心接口 QPS 20),形成纵深防御。
1.4 限流与尾延迟的关系
限流与尾延迟(Tail Latency) 之间存在直接关联。当系统负载超过其最佳吞吐点时,请求的响应时间会急剧增加,尤其是 P99(99% 分位)延迟会显著恶化。限流通过主动拒绝超量请求,将系统负载控制在“膝盖点”以下,从而稳定尾延迟。
下图展示了限流如何保护系统,避免进入“过载-延迟飙升-超时重试-更严重过载”的恶性循环:
1.5 限流的核心指标与术语
在深入限流算法之前,需要先掌握以下关键指标:
| 指标 | 定义 | 常见单位 | 说明 |
|---|---|---|---|
| QPS | 每秒查询数(Queries Per Second) | req/s | 最常用的限流指标,衡量系统吞吐能力 |
| TPS | 每秒事务数(Transactions Per Second) | tps | 通常用于数据库或包含多个步骤的业务操作 |
| 并发数 | 系统同时处理的请求数量 | 个 | 与 QPS 和响应时间相关:QPS = 并发数 / 平均响应时间 |
| 令牌桶容量 | 令牌桶算法中允许的最大突发请求量 | 个 | 控制短时间内的流量尖峰 |
| 漏桶速率 | 漏桶算法中恒定的处理速率 | req/s | 严格平滑流量,不允许突发 |
1.6 限流与熔断、降级的区别
限流常与熔断(Circuit Breaker)和降级(Degradation)一起讨论,三者共同构成微服务的稳定性三板斧。下表清晰区分了三者的定位:
| 机制 | 触发条件 | 动作 | 恢复方式 | 典型工具 |
|---|---|---|---|---|
| 限流 | 请求量超过预设阈值 | 直接拒绝新请求(返回 429 Too Many Requests) | 流量回落到阈值以下后自动恢复 | golang.org/x/time/rate、Sentinel |
| 熔断 | 错误率或延迟超过阈值(如 50% 请求失败) | 快速失败,不再调用下游服务 | 经过冷却时间后,尝试半开探测 | hystrix-go、resilience4j |
| 降级 | 系统资源紧张或依赖服务不可用 | 返回降级结果(如缓存数据、默认值) | 手动或自动恢复 | 自定义 fallback 逻辑 |
常见误区:限流不能替代熔断。限流是“事前”预防,熔断是“事中”保护。当限流未能完全阻止过载时,熔断作为第二道防线,防止故障扩散。在实际 Go 微服务项目中,建议同时配置限流和熔断策略。