如何限制用户的访问频率?

通过使用 Redis 计数器和滑动窗口算法实现对用户的访问频率限制,确保系统安全性和用户体验。

前端安全 中等 限流 限流算法 API

频率限制(Rate Limiting)是通过限制用户或IP在单位时间内的请求数量,防止恶意访问、确保系统公平性的关键技术。核心是动态追踪访问次数并在达到阈值时拦截请求。以下从原理、常见技术实现和面试角度全面解释。

1. 频率限制的原理

  • 动机:防范恶意攻击(如刷接口、DoS攻击)、控制API调用峰值,保护系统资源和用户体验。
  • 关键概念
    • 时间窗口(Time Window):定义单位时间范围(如1分钟、1小时)。
    • 阈值(Threshold):允许的最大访问次数(如10次/分钟)。
  • 统计指标
    • 用户标识:针对未认证用户使用IP,已认证用户使用User ID。
    • 记录每次访问的时间戳或递增计数器。

2. 常见技术实现方式

(1) Redis计数器实现(推荐,支持分布式系统)

  • 利用INCR指令记录访问次数,结合EXPIRE设置键值过期实现时间窗口的原子性统计。示例代码(基于Lua脚本确保高并发原子性):
    local key = "user_flow_control:" .. KEYS  -- 用户ID/IP
    local timeWindow = tonumber(ARGV)          -- 窗口时间(秒)
    local threshold = tonumber(ARGV)           -- 限流阈值
      
    local count = redis.call("INCR", key)
    if count == 1 then
        redis.call("EXPIRE", key, timeWindow)
    end
      
    if count > threshold then
        return 0 -- 拒绝访问
    else
        return 1 -- 允许访问
    end
    
    • 优点
      • INCR是原子操作,避免并发冲突。
      • EXPIRE首次调用时确保Key过期自动清除。
    • 应用:Redis支持HTTP拦截层(如Nginx+Lua)或直接在服务端使用(如Django, FastAPI)。

(2) 限流算法:时间窗口优化

  • 滑动窗口算法(Sliding Window):精准追踪动态时间窗内的访问密度(使用Redis队列存储时间戳),规避传统计数器在时间分界点的瓶颈。
  • 令牌桶算法(Token Bucket):基于令牌生成速率控制(适合均匀限流)。

(3) 框架内建方案(如REST API场景)

  • Django Rest Framework Throttle:基于Scope配置用户与匿名限流(如每个IP每天100次)。
    • 示例:
      # settings.py
      REST_FRAMEWORK = {
        "DEFAULT_THROTTLE_CLASSES": ["rest_framework.throttling.AnonRateThrottle"],
        "DEFAULT_THROTTLE_RATES": {"anon": "10/minute"}  # 匿名用户10次/分钟
      }
      
  • FastAPI Rate Limit:使用中间件配合Redis拦截请求(用户身份标识直接映射Key).

3. 面试实用建议

  • 典型用例
    • 限制短信发送或登录尝试。
    • 防爬虫:检测异常请求链(如封禁超20次/分钟的IP)。
  • 潜在坑点:独立INCR + EXPIRE存在并发原子性失效(使用Lua脚本保证一致性)。Redis集群时需考虑分布式同步。
  • 优化思路
    • 分层限流(例如优先缓存层防御)。
    • 自定义拒绝机制(返回429状态码,提示Wait时间)降低拒绝的可用性。