侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1824 篇文章
  • 累计收到 0 条评论

设计支持动态策略的分布式限流系统

2025-12-11 / 0 评论 / 3 阅读

题目

设计支持动态策略的分布式限流系统

信息

  • 类型:问答
  • 难度:⭐⭐⭐

考点

分布式一致性, 限流算法选择, 高并发优化, 容错设计, 动态策略管理

快速回答

核心设计要点:

  • 采用分层令牌桶架构:本地桶+全局Redis集群
  • 使用Redis+Lua保证原子计数和滑动窗口限流
  • 动态策略加载:ZooKeeper监听配置变更+本地缓存
  • 容错机制:降级本地限流 + 熔断策略
  • 性能优化:本地预取令牌 + 异步刷新
## 解析

1. 系统核心需求

在分布式电商系统中,需实现:
• 支持每秒 50 万+请求的限流
• 动态调整策略(如秒杀时临时提额)
• 毫秒级响应延迟
• 99.99% 可用性

2. 架构设计

+----------------+     +-----------------+
|  Client App    |     |  Config Manager |
|  (Local Bucket)|---->|  (ZooKeeper)    |
+-------+--------+     +--------+--------+
        |                       |
        |  Async Refresh        | Policy Update
+-------v--------+     +--------v--------+
|  Redis Cluster |<----|  Control Plane  |
|  (Global Count)|     |  (Dashboard API)|
+----------------+     +-----------------+

3. 关键技术实现

3.1 限流算法组合

  • 本地层:令牌桶算法(应对突发流量)
    // Java 伪代码
    class LocalTokenBucket {
      long lastRefillTime;
      int currentTokens;
      int capacity;
    
      synchronized boolean tryAcquire() {
        refillTokens(); // 按固定速率补充
        if (currentTokens > 0) {
          currentTokens--;
          return true;
        }
        return false;
      }
    }
  • 全局层:滑动窗口计数(精确控制)
    -- Redis Lua 脚本
    local key = KEYS[1]        -- 限流键(如 user:123)
    local limit = tonumber(ARGV[1]) -- 阈值
    local window = tonumber(ARGV[2]) -- 时间窗(秒)
    local now = tonumber(ARGV[3])   -- 当前时间戳
    
    -- 清除过期记录
    redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
    
    -- 获取当前计数
    local count = redis.call('ZCARD', key)
    
    if count < limit then
      redis.call('ZADD', key, now, now) -- 添加新请求
      redis.call('EXPIRE', key, window) -- 设置过期
      return 1 -- 允许访问
    end
    return 0 -- 拒绝请求

3.2 动态策略管理

// ZooKeeper 监听示例
public class PolicyWatcher implements Watcher {
  void process(WatchedEvent event) {
    if (event.getType() == EventType.NodeDataChanged) {
      loadNewPolicy(event.getPath()); // 重载本地策略
    }
  }
}

3.3 容错设计

  • 降级模式:Redis 故障时切换本地限流
  • 熔断机制:连续超时自动切到本地桶
  • 过载保护:基于系统负载动态调整阈值

4. 最佳实践

  • 分层过滤:先本地桶再全局计数,减少Redis压力
  • 批量预取:每次从Redis获取一批令牌本地缓存
  • 热点分离:对高频用户(如黄牛)使用独立Redis分片
  • 监控指标:实时采集 QPS、拒绝率、延迟百分位

5. 常见错误

  • 时间同步问题:使用Redis时间避免时钟漂移
  • 竞争条件:必须用Lua保证原子操作
  • 策略雪崩:配置变更时逐步滚动更新
  • 内存泄漏:ZADD需配合EXPIRE设置TTL

6. 扩展知识

  • 自适应限流:结合CPU/负载动态调整(如TCP BBR算法)
  • 机器学习应用:基于历史流量预测配额
  • 服务网格集成:通过Envoy Filter实现基础设施层限流
  • 配额银行模式:允许用户借用未来配额(需偿还机制)