架构设计

限流系统设计:令牌桶与滑动窗口

2026-08-18 #分布式系统#Redis#限流

理解常见算法的突发能力、精度和分布式实现成本。

登录请求依次经过边缘、租户接口、账号和全局容量限制的分层限流图

图:组合多个限流维度保护系统容量,同时降低共享 IP 与账号锁定误伤;点击查看原图。

核心思路

令牌桶允许有限突发,适合 API 网关;滑动窗口更直观但存储成本更高。限流维度可以是用户、租户、接口或组合键。

落地步骤

返回明确的剩余额度与重试时间。系统过载时限流要与排队、熔断和降级协同。

验证清单

实施后不要只确认“能运行”,还应检查错误率、延迟、资源占用和异常路径。把验证命令、预期结果和回滚方式写进变更记录,后续维护会轻松很多。

小结

好的工程实践不是堆叠工具,而是用清晰边界、可观察结果和可逆变更降低长期成本。先解决最重要的问题,再逐步自动化。

可执行实践

先确定维度、窗口、配额和突发策略。令牌桶适合允许突发,滑动窗口更精确但成本更高;分布式实现用原子脚本或网关能力。

验证与退出条件

返回 429、Retry-After 和剩余额度,演练存储不可用时采用 fail-open 还是 fail-closed。限流与排队、熔断、降级一起压测。

实践场景

以“为公开 API 设置分层限流”为例。实施前先保存当前版本、配置和关键指标基线,写明成功条件与停止条件;涉及生产数据或外部写入时,先在隔离环境验证。

分步实施

在入口按身份和接口执行令牌桶,关键下游再设并发保护;返回明确重试提示,对不同租户设置公平配额。每完成一步都记录可观察结果,不把命令返回零等同于业务正确。

故障演练

测试突发流量、持续超额、分布式节点时钟差和存储不可用,明确限流组件故障时开放还是关闭。演练应使用可清理的测试数据,并验证告警、日志和恢复路径,而不只是确认系统最终又能访问。

观测与回滚

观察拒绝率、下游饱和度与误伤;阈值先灰度,误伤升高立即恢复旧策略。变更单中应写清负责人、观察窗口、阈值和回滚触发器,避免故障发生后再临时争论。

完成后把使用的版本、关键命令、观测窗口和结果写入变更记录。没有验证证据的“已完成”不能作为上线结论。

第二轮实践复核

可复用交付物: 限流决策表、租户配额和降级开关。复用时先固定软件版本、依赖锁文件、测试数据规模和运行环境;文章中的命令包含占位符,必须替换成自己的非生产目标后再执行。

最低验证: 回放突发与持续流量,核对允许量、拒绝量和下游并发上限

执行记录要保存命令、退出码、关键输出、观察窗口和回滚结果。若验证会产生写入,先使用隔离环境或 dry-run;任何失败都不能通过扩大权限、关闭校验或跳过测试来“解决”。

完整实战:登录接口的分层限流

登录限流既要保护服务,也要避免攻击者通过锁定某个账号阻止真实用户登录。单一 IP 限制会误伤公司出口和移动网络,单一账号限制又容易被用来拒绝服务,因此组合多个低基数字段:

层级 示例键 作用 超限后的动作
边缘 IP / 网段 吸收明显洪峰 短时拒绝或挑战
接口 租户 + 路由 保护服务总容量 429 + 合理退避
账号 账号摘要 限制撞库 渐进延迟、二次验证
全局 集群容量 防止依赖雪崩 负载削减、保留关键流量

不要把原始邮箱、手机号作为监控标签或共享存储键;先规范化后使用带密钥的摘要,并限制保留期。

令牌桶的原子状态转换

每个键保存剩余令牌和上次补充时间。一次请求到达时先按经过时间补充,再判断是否足够扣减;读取、计算和写回必须原子完成,否则并发请求会突破限制。伪代码如下:

1
2
3
4
5
6
elapsed = max(0, now - last_refill)
tokens = min(capacity, tokens + elapsed * refill_rate)
if tokens < cost:
reject(retry_after = (cost - tokens) / refill_rate)
else:
accept(tokens = tokens - cost, last_refill = now)

分布式实现需要明确时钟来源、状态分片、热点键和存储故障策略。安全敏感入口通常偏向 fail-closed,但健康检查、内部恢复流量可能需要独立配额,不能在限流存储故障时一起被堵死。

容量与公平性验证

用真实请求成本做权重:一次导出可能等于数十次查询。压测包含稳定流量、突发流量、单热点账号、多 NAT 用户和存储延迟。验收不仅看总 QPS,还看允许率、误伤率、P95 延迟、限流存储错误和不同租户的公平性。

客户端收到 429 后应遵循 Retry-After 并加入抖动;服务端不能让所有客户端在整秒边界同时重试。上线先以只观测模式计算“本应拒绝”的请求,再小比例执行。误伤越线时回退规则或提高容量,不要直接关闭所有保护;保留边缘与全局兜底层。

一手资料

资料与版本边界复核日期:2026-08-22。工具行为可能演进,实施前以锁定版本对应的官方文档为准。

评论
分享

评论