51mee - AI智能招聘平台Logo
模拟面试题目大全招聘中心会员专区

设计一个高并发的API限流系统,用于360安全产品的用户访问控制。请说明限流策略(如滑动窗口、令牌桶)、熔断机制、降级逻辑,并阐述在Golang中如何实现(包括数据结构、并发控制、缓存等),以及分布式场景下的处理方案。

360服务端开发工程师-Golang难度:困难

答案

1) 【一句话结论】:设计高并发API限流系统,核心是结合滑动窗口(精确控制QPS,应对突发流量)与令牌桶(平滑流量,允许短时间超量),搭配熔断(错误率超阈值时快速失败)和降级(服务不可用时降级),在Golang中通过并发安全的数据结构(如环形数组、channel)与分布式缓存(如Redis)实现,分布式场景下通过共享存储保证全局计数一致性。

2) 【原理/概念讲解】:老师口吻解释关键概念:

  • 滑动窗口:类似时间轴上的滑动条,每个时间窗口(如1秒)内统计请求数,当请求数超过阈值时拒绝。类比:超市收银台,每个时间段(1秒)最多接待固定人数(QPS),超过则排队或拒绝。
  • 令牌桶:像水桶装水,按固定速率生成令牌(每秒N个),请求消耗令牌,若桶满则等待。类比:水管接水,流速固定,桶里水满后需要等待。
  • 熔断:当服务错误率超过阈值(如50%),熔断器切换到“断开”状态,后续请求直接失败或降级,避免雪崩。
  • 降级:服务不可用时,返回缓存数据(如Redis缓存的热数据)、降级接口或限流提示,保证核心功能可用。

3) 【对比与适用场景】:

特性滑动窗口(滑动计数)令牌桶(速率限制)
定义基于时间窗口的请求计数,统计当前窗口内的请求数按固定速率生成令牌,请求消耗令牌,桶满则等待
特性精确控制QPS,对突发流量敏感(窗口内计数)平滑流量,允许短时间超量(桶内令牌数)
适用场景需要严格限制QPS,避免突发流量冲击(如API接口)需要平滑流量,允许短时间波动(如用户登录、支付)
注意点窗口大小需平衡精度与延迟(太大延迟,太小计数不准)令牌生成速率需准确计算(否则无法平滑流量)

4) 【示例】:

  • 滑动窗口伪代码:
    type SlidingWindowLimiter struct {
        windowSize int           // 时间窗口数量(秒)
        bucketSize int           // 每个窗口最大请求数
        buckets    []int         // 环形数组存储每个窗口的请求数
        curIndex   int           // 当前窗口索引
        mu         sync.Mutex    // 并发控制
    }
    
    func (l *SlidingWindowLimiter) Allow() bool {
        l.mu.Lock()
        defer l.mu.Unlock()
        l.curIndex = (l.curIndex + 1) % l.windowSize
        if l.buckets[l.curIndex] >= l.bucketSize {
            return false
        }
        l.buckets[l.curIndex]++
        return true
    }
    
  • 令牌桶伪代码:
    type TokenBucketLimiter struct {
        capacity int           // 桶容量(最大令牌数)
        rate     int           // 令牌生成速率(每秒生成令牌数)
        tokens   int           // 当前令牌数
        mu       sync.Mutex    // 并发控制
        ticker   *time.Ticker  // 定时器生成令牌
    }
    
    func (l *TokenBucketLimiter) Allow() bool {
        l.mu.Lock()
        defer l.mu.Unlock()
        l.tokens = min(l.tokens + l.rate, l.capacity)
        if l.tokens > 0 {
            l.tokens--
            return true
        }
        return false
    }
    
  • 分布式计数器(Redis ZADD示例):
    用于滑动窗口的分布式实现,通过Redis的有序集合(ZADD)按时间戳排序,取最近窗口内的请求数,判断是否超过阈值。

5) 【面试口播版答案】:
“面试官您好,设计高并发API限流系统,核心是结合滑动窗口(精确控制QPS,应对突发流量)与令牌桶(平滑流量,允许短时间超量),搭配熔断(错误率超阈值时快速失败)和降级(服务不可用时降级)。在Golang中,滑动窗口用环形数组存储时间窗口的请求数,用互斥锁保护并发,滑动时间窗口时更新计数;令牌桶用定时器按固定速率生成令牌,请求时检查令牌数。熔断机制用状态机(正常/熔断/恢复),用Redis存储状态,错误率超过阈值时切换到熔断状态,后续请求直接失败。分布式场景下,通过Redis的分布式计数器(如ZADD或SETNX+过期时间)保证全局计数一致,避免单点故障。整体策略是:滑动窗口用于精确控制QPS,令牌桶用于平滑流量,熔断防止雪崩,降级保证核心功能可用。”

6) 【追问清单】:

  • 问题1:分布式限流如何保证多个实例的计数一致性?
    回答要点:用Redis的分布式计数器(如SETNX+过期时间或ZADD),通过原子操作(如SETNX)确保只有一个实例能成功更新计数,其他实例等待,避免计数不一致。过期时间管理(如窗口过期时间)防止内存占用。
  • 问题2:熔断的阈值如何动态调整?
    回答要点:根据错误率(如5秒内错误率超过50%),动态调整阈值,比如从50%降到30%,逐步恢复。采用“半开状态”(允许少量请求,观察错误率),避免恢复后立即全开导致雪崩。
  • 问题3:降级策略的具体实现?
    回答要点:服务不可用时,返回缓存数据(如Redis缓存的热数据,避免缓存穿透用布隆过滤器)、降级接口(如返回默认用户信息或限流提示“系统繁忙,请稍后重试”),确保核心功能可用。

7) 【常见坑/雷区】:

  • 坑1:滑动窗口的窗口大小选择不当,导致延迟或计数不准(如窗口过大导致延迟,过小导致计数误差)。
  • 坑2:令牌桶的令牌数量计算错误,导致流量无法平滑(如速率过低,请求积压;速率过高,无法限流)。
  • 坑3:熔断的恢复策略不当,导致服务恢复慢(如错误率下降后,熔断器未及时切换回正常状态)。
  • 坑4:分布式限流时数据不一致,导致部分实例限流失效(如Redis写入失败,计数未更新)。
  • 坑5:降级策略未考虑缓存穿透或雪崩,导致降级后仍影响用户体验(如缓存未预热,返回空数据;或降级接口压力过大)。
51mee.com致力于为招聘者提供最新、最全的招聘信息。AI智能解析岗位要求,聚合全网优质机会。
产品招聘中心面经会员专区简历解析Resume API
联系我们南京浅度求索科技有限公司admin@51mee.com
联系客服
51mee客服微信二维码 - 扫码添加客服获取帮助
© 2025 南京浅度求索科技有限公司. All rights reserved.
公安备案图标苏公网安备32010602012192号苏ICP备2025178433号-1