系统设计RateLimiter速率限制systemdesign面试

系统设计 Deep Dive:设计速率限制器(Rate Limiter)

系统设计深度解析:设计速率限制器(Rate Limiter)。涵盖令牌桶、漏桶算法、分布式限流策略与Redis实现方案,还原真实系统设计面试的完整思考过程与面试官追问方向。

Sam · · 10 分钟阅读

面试官真实提问

“请设计一个 Rate Limiter(速率限制器),用于限制 API 的请求频率。比如每个用户每分钟最多 60 次请求。”

“如何扩展到分布式环境?如果有 100 台服务器,如何确保全局限流准确?”

这道题在 Google、Meta、Amazon 的面试中频繁出现,通常考察候选人对算法选择分布式系统设计的理解。


需求澄清清单

功能需求

Must-have:

  • ✓ 限制用户/IP 的请求频率
  • ✓ 支持多种限流粒度(每秒、每分钟、每天)
  • ✓ 超出限制时返回 429 Too Many Requests

Nice-to-have:

  • 多级限流(全局、租户级、用户级)
  • 动态调整限流配额
  • 限流统计与告警

规模估算

指标估算值
API 服务器100 台
总 QPS100 万
唯一用户1000 万
限流规则数10 万(不同用户/租户不同配额)

非功能需求

  • 延迟: 限流检查 < 5ms(不能成为瓶颈)
  • 可用性: 99.99%(限流失败应该允许请求通过,而不是拒绝)
  • 准确性: 分布式环境下 ±5% 误差可接受

第 1 步:高层设计

┌─────────┐
│ 客户端   │
└────┬────┘

┌────▼───────────┐
│ API Gateway    │  限流中间件
└────┬───────────┘

   ┌─┴─┐
┌──▼──┐ ┌──▼──┐
│ API │ │ API │  Node A / B
│ A   │ │ B   │
└──┬──┘ └──┬──┘
     └──┬──┘
     ┌──▼──────┐
     │ Redis   │  限流状态存储
     │ Cluster │
     └─────────┘

核心组件:

  • API Gateway:统一的限流入口,拦截所有请求
  • API Server:业务逻辑处理
  • Redis Cluster:存储限流计数状态,支持原子操作

第 2 步:核心组件设计

★ 限流算法对比(核心考点)

1. 固定窗口计数器(Fixed Window Counter)

时间轴:  |--- 窗口 1 (0:00-0:01) ---|--- 窗口 2 (0:01-0:02) ---|
请求数:      60/60                        1/60

[注意] 问题:窗口边界突发流量
      窗口 1 末尾 60 次 + 窗口 2 开头 60 次 = 1 秒内 120 次

优点: 实现简单,内存占用低 缺点: 窗口边界突刺问题

2. 滑动窗口计数器(Sliding Window Counter)

时间轴:
│── 0:00 (20次) ├── 0:01 (25次) ├── 0:02 (15次) ──│

当前滑动窗口 = 0:01 + 0:02 = 25 + 15 = 40/60

(加权求和,解决固定窗口边界突刺问题)

将固定窗口细分为多个小桶,滑动窗口 = 当前桶 + 前 N 个桶的加权求和

优点: 解决了固定窗口的边界突刺问题 缺点: 内存占用中等,实现复杂度稍高

3. 令牌桶算法(Token Bucket)

┌─────────────────────────┐
│     令牌桶               │
│  容量: 6                 │
│  当前: ●●●○○○            │
│  (●=令牌, ○=空位)        │
└─────────┬───────────────┘
          │ 请求到达,消耗 1 个令牌

┌─────────────────────────┐
│  剩余: ●●○○○○            │
│  (2 个令牌)              │
└─────────────────────────┘

令牌以固定速率生成,桶满时丢弃多余令牌

优点: 允许突发流量(桶内令牌),实现复杂度适中 缺点: 需要维护令牌生成逻辑

4. 漏桶算法(Leaky Bucket)

请求进入: ●●●●●


┌──────────────┐
│    漏桶       │  ●●●○○○
│  固定速率流出  │
└──────┬───────┘


  固定速率处理

(不支持突发流量,平滑输出)

优点: 平滑流量,实现简单 缺点: 不支持突发流量


[对比] 算法对比

算法实现复杂度精度突发支持内存占用适用场景
固定窗口低(边界突刺)简单计数
滑动窗口★★部分支持平滑限流
令牌桶★★API 限流
漏桶★★流量整形

[重点] 推荐方案:滑动窗口 + 令牌桶组合

滑动窗口控制长时间窗口(如每分钟),令牌桶控制短时间突发(如每秒)。


API 设计

# 限流响应头
X-RateLimit-Limit: 60        # 限流配额
X-RateLimit-Remaining: 45    # 剩余请求数
X-RateLimit-Reset: 1651785600 # 重置时间戳

# 超出限制
HTTP 429 Too Many Requests
{
  "error": "rate_limit_exceeded",
  "retry_after": 30  # 秒
}

限流层级设计

全局限流 ──→ 租户级限流 ──→ 用户级限流 ──→ IP 级限流
(保护系统)   (按租户配额)   (按用户配额)   (防滥用)

四层限流,从上到下越来越精细

第 3 步:扩展性与优化

[重点] 分布式限流方案

方案 1:集中式(Redis)

  • 所有服务器共享 Redis 计数
  • ✓ 精确
  • ✗ Redis 成为瓶颈,单点故障

方案 2:本地 + 协同(推荐)

  • 每台服务器维护本地计数器
  • 定期同步到 Redis 做全局校验
  • ✓ 低延迟、高可用
  • [注意] 有短暂的不精确期
┌── 本地限流 ────────────────┐
│                            │
│  本地计数器                │
│  5ms 内响应                │
│       │                    │
│       ├──→ 允许 → 业务逻辑  │
│                            │
└────────┬───────────────────┘
         │ 异步

┌── Redis 全局限流 ──────────┐
│                            │
│  Redis 计数器              │
│       │                    │
│       ├──→ 超限 → 记录日志 + 告警 │
│                            │
└────────────────────────────┘

容量估算

指标计算结果
Redis 内存1000 万用户 × 100 字节1GB
QPS100 万请求/秒每节点 ~17 万 QPS
Redis 集群3 主 3 从6 个节点

[问答] 面试官常问 Trade-offs 与实战问答

[问] Q1:你选择了哪种限流算法?为什么?

候选人回答:

“我选择了滑动窗口 + 令牌桶的组合方案。滑动窗口控制长时间窗口(如每分钟 60 次),避免固定窗口的边界突刺问题。令牌桶控制短时间突发(如每秒 10 次),允许用户有一定的突发能力。这种组合既保证了精度,又兼顾了用户体验。”

面试官追问:

“如果只用固定窗口会怎样?”

候选人回答:

“固定窗口在窗口边界会出现突刺问题。比如用户可能在 0:00-0:01 发送 60 次请求,然后在 0:01-0:02 又发送 60 次,导致 1 秒内实际发送了 120 次请求。滑动窗口通过加权平均解决了这个问题。“


[问] Q2:分布式环境下如何保证限流准确性?

候选人回答:

“我采用本地计数 + Redis 异步校验的方案。每台服务器维护本地计数器,快速判断是否超限。同时异步将计数同步到 Redis,由 Redis 做全局校验。这样即使 Redis 暂时不可用,本地限流仍然生效,只是精度会有短暂下降。”

面试官追问:

“如果 Redis 宕机了怎么办?”

候选人回答:

“限流器本身应该 fail-open。如果 Redis 宕机,允许所有请求通过,但本地限流仍然生效。同时触发告警,运维团队紧急修复。限流的目的是保护系统,而不是拒绝服务。“


[问] Q3:如何处理热点用户的限流?

候选人回答:

“对于热点用户(比如大 V 的 API 调用),我会采用多级限流策略。第一级是本地限流,快速失败。第二级是 Redis 限流,精确控制。第三级是全局限流,防止单个用户占满所有资源。同时会监控异常模式,自动触发防护规则。”

面试官追问:

“如果用户投诉限流太严格怎么办?”

候选人回答:

“提供动态限流配额。对于付费用户或重要客户,可以临时提高配额。同时提供限流统计 API,让用户了解当前的使用情况。“


[问] Q4:限流器本身成为瓶颈了怎么办?

候选人回答:

“限流器应该尽可能轻量。我采用本地计数 + Redis 异步校验的方案,限流检查在 5ms 内完成。如果 Redis 成为瓶颈,可以增加 Redis 节点,或者采用本地限流为主、Redis 为辅的策略。”

面试官追问:

“如果本地限流不够精确怎么办?”

候选人回答:

“本地限流的精度取决于同步频率。如果同步频率高(如每秒),精度就高。对于大多数场景,±5% 的误差是可以接受的。如果需要更高精度,可以增加同步频率,或者采用分布式共识算法。“


[问] Q5:如何实现多级限流?

候选人回答:

全局限流保护系统整体,租户级限流保护多租户隔离,用户级限流保护单个用户,IP 级限流防止滥用。每一级都有独立的计数器和阈值。请求通过所有层级才能被处理,任何一层超限都被拒绝。”

面试官追问:

“如果某一层级限流太严格怎么办?”

候选人回答:

“提供动态调整机制。监控系统负载,自动调整限流阈值。同时提供手动覆盖,允许运维团队临时调整限流策略。“


进阶扩展方向

  • 动态限流: 根据系统负载自动调整配额
  • 配额管理: 付费用户更高配额
  • 分布式协调: 基于 Redisson 的分布式锁
  • 可视化监控: 实时限流仪表盘

[注意] 常见踩坑点

#踩坑点解决方案
1时钟不同步:分布式服务器时间不一致用 NTP 或单调时钟
2Redis 单点故障:限流器本身成为单点Redis Cluster + fail-open
3内存泄漏:不过期清理限流 key设置 TTL + 定期清理
4精确到毫秒:不需要这么精确秒级足够,降低 Redis 压力

总结

Rate Limiter 设计考察:

能力考察点
算法选择4 种限流算法的适用场景和 trade-offs
分布式设计如何在多台服务器间协调限流状态
降级策略限流器故障时的容错处理
性能优化5ms 内完成限流检查的要求

[重点] 面试提示: 先讲清楚 4 种算法的差异,然后选择一个推荐方案深入。面试官通常会追问”如果 Redis 宕机了怎么办”,准备好 fail-open 的降级策略。


推荐阅读


💡 需要面试辅导?

如果你对准备技术面试感到迷茫,或者想要个性化的面试指导和简历优化,欢迎联系 Interview Coach Pro 获取一对一辅导服务。

👉 联系我们 获取专属面试准备方案

准备好拿下下一次面试了吗?

获取针对你的目标岗位和公司的个性化辅导方案。

联系我们