限流中间件.md 18 KB

限流中间件

本文引用的文件

  • server/src/middleware/rate-limiter.ts
  • server/src/services/redis.service.ts
  • server/src/middleware/usageLimit.ts
  • server/src/middleware/errorHandler.ts
  • server/src/types/index.ts
  • server/src/app.ts
  • server/src/modules/tts/tts.controller.ts
  • server/src/modules/auth/auth.controller.ts

目录

  1. 简介
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能考虑
  8. 故障排查指南
  9. 结论
  10. 附录

简介

本文件为 AI 有声书生成平台的限流中间件综合文档,围绕基于 rate-limiter-flexible 的令牌桶限流实现,系统阐述以下内容:

  • 限流算法与策略选择:令牌桶与漏桶的对比、在本项目中的取舍与实现细节
  • 限流规则设计:按 IP、按用户、按 API 接口等多维限流策略
  • 配置参数与调优:阈值、时间窗口、封锁时长、突发处理
  • 实现示例:在不同场景下的应用方法、监控与限流触发处理
  • 与 Redis 的集成:高并发下的性能优化与降级策略

项目结构

限流相关代码主要分布在以下位置:

  • 限流中间件:server/src/middleware/rate-limiter.ts
  • 使用量限流中间件:server/src/middleware/usageLimit.ts
  • Redis 服务:server/src/services/redis.service.ts
  • 错误处理:server/src/middleware/errorHandler.ts
  • 类型定义(会员配额):server/src/types/index.ts
  • 应用入口与路由注册:server/src/app.ts
  • 控制器示例:server/src/modules/tts/tts.controller.ts、server/src/modules/auth/auth.controller.ts

    graph TB
    subgraph "应用层"
    APP["应用入口<br/>server/src/app.ts"]
    ROUTER["路由注册<br/>各模块控制器"]
    end
    subgraph "中间件层"
    RL["限流中间件<br/>server/src/middleware/rate-limiter.ts"]
    USAGELIMIT["用量限流中间件<br/>server/src/middleware/usageLimit.ts"]
    ERR["错误处理中间件<br/>server/src/middleware/errorHandler.ts"]
    end
    subgraph "服务层"
    REDIS["Redis 服务<br/>server/src/services/redis.service.ts"]
    TYPES["类型与配额<br/>server/src/types/index.ts"]
    end
    APP --> ERR
    APP --> RL
    APP --> USAGELIMIT
    APP --> ROUTER
    RL --> REDIS
    USAGELIMIT --> TYPES
    

图表来源

  • server/src/app.ts:1-190
  • server/src/middleware/rate-limiter.ts:1-120
  • server/src/middleware/usageLimit.ts:1-66
  • server/src/services/redis.service.ts:1-274
  • server/src/types/index.ts:1-124

章节来源

  • server/src/app.ts:1-190

核心组件

  • 限流中间件(令牌桶):基于 rate-limiter-flexible,支持内存与 Redis 两种存储后端,自动降级;提供通用限流中间件工厂与若干内置策略(API 全局、登录、短信、TTS、上传)。
  • 使用量限流中间件:基于会员等级的每日次数与字数配额,结合数据库进行每日重置与校验。
  • Redis 服务:提供连接管理、可用性检测、基础读写能力,作为限流器持久化存储。
  • 错误处理:统一捕获限流与业务异常,返回标准响应格式。
  • 类型与配额:定义会员等级与配额映射,支撑使用量限流。

章节来源

  • server/src/middleware/rate-limiter.ts:1-120
  • server/src/middleware/usageLimit.ts:1-66
  • server/src/services/redis.service.ts:1-274
  • server/src/middleware/errorHandler.ts:1-67
  • server/src/types/index.ts:114-124

架构总览

限流中间件通过 Redis 或内存实现令牌桶算法,对请求进行消费与拒绝;使用量限流中间件则在业务层对用户每日次数与字数进行配额控制。两者可组合使用,形成“网络层限流 + 业务层配额”的双重保护。

sequenceDiagram
participant C as "客户端"
participant A as "应用入口<br/>app.ts"
participant RL as "限流中间件<br/>rate-limiter.ts"
participant RS as "Redis 服务<br/>redis.service.ts"
participant U as "使用量限流中间件<br/>usageLimit.ts"
participant CTRL as "控制器<br/>tts.controller.ts"
C->>A : "HTTP 请求"
A->>RL : "进入限流中间件"
RL->>RS : "consume(key, 1)"
alt "Redis 可用"
RS-->>RL : "允许/拒绝"
else "Redis 不可用"
RL-->>RL : "内存限流器"
end
RL-->>A : "允许继续或返回 429"
A->>U : "进入使用量限流中间件"
U-->>A : "允许继续或抛出配额错误"
A->>CTRL : "转发到控制器"
CTRL-->>C : "业务响应"

图表来源

  • server/src/app.ts:62-129
  • server/src/middleware/rate-limiter.ts:49-72
  • server/src/services/redis.service.ts:43-45
  • server/src/middleware/usageLimit.ts:7-49
  • server/src/modules/tts/tts.controller.ts:52-127

详细组件分析

限流中间件(令牌桶)

  • 算法与策略
    • 采用令牌桶(Token Bucket)思想,通过 consume(key, 1) 对每个请求进行扣减。
    • 当 Redis 可用时使用 RateLimiterRedis,否则回退到 RateLimiterMemory。
    • 支持自定义 keyGenerator,便于按 IP、用户 ID、API 名称等维度区分限流键。
  • 关键配置项
    • points:时间窗口内的配额(令牌数)
    • duration:时间窗口(秒)
    • blockDuration:封禁时长(秒),默认 duration*2
    • keyGenerator:自定义键生成函数
  • 内置策略
    • API 全局限流:按 IP 维度,每分钟 100 次
    • 登录接口限流:按 IP 维度,每分钟 5 次,封禁 5 分钟
    • 短信发送限流:每分钟 1 次,每小时 5 次,封禁 1 小时
    • TTS 生成限流:按用户维度,每分钟 20 次
    • 文件上传限流:按用户维度,每分钟 10 次
  • 触发处理

    • 拒绝时设置 Retry-After 响应头,并返回 429 与 retryAfter 字段

      flowchart TD
      Start(["进入限流中间件"]) --> GenKey["生成限流键<br/>keyGenerator(ctx) 或 ctx.ip"]
      GenKey --> ChooseStore{"Redis 可用?"}
      ChooseStore --> |是| UseRedis["使用 RateLimiterRedis"]
      ChooseStore --> |否| UseMemory["使用 RateLimiterMemory"]
      UseRedis --> Consume["consume(key, 1)"]
      UseMemory --> Consume
      Consume --> Allowed{"是否允许?"}
      Allowed --> |是| Next["继续下一个中间件/控制器"]
      Allowed --> |否| Reject["设置 Retry-After<br/>返回 429"]
      

图表来源

  • server/src/middleware/rate-limiter.ts:20-72
  • server/src/services/redis.service.ts:43-45

章节来源

  • server/src/middleware/rate-limiter.ts:1-120

使用量限流中间件(按用户/会员等级)

  • 设计思路
    • 基于会员等级的每日次数与字数配额,每日重置使用次数。
    • 在业务流程中对 TTS 文本长度进行字数校验,避免超配额生成。
  • 关键逻辑
    • usageLimitMiddleware:加载用户信息,重置每日使用次数,校验次数配额
    • checkWordLimit:在生成环节对文本字数进行校验
  • 配额映射

    • 免费用户:每日 3 次、5000 字
    • 月卡用户:每日 20 次、50000 字
    • 年卡用户:无限制

      flowchart TD
      Enter(["进入使用量限流中间件"]) --> HasUser{"是否登录?"}
      HasUser --> |否| AllowGuest["设置无限制配额<br/>继续"]
      HasUser --> |是| LoadUser["查询用户信息"]
      LoadUser --> ResetDaily{"是否跨日?"}
      ResetDaily --> |是| UpdateDaily["重置每日使用次数"]
      ResetDaily --> |否| SkipReset["跳过重置"]
      UpdateDaily --> CheckDaily["校验每日次数配额"]
      SkipReset --> CheckDaily
      CheckDaily --> DailyOK{"次数未超?"}
      DailyOK --> |是| SaveQuota["保存配额到 ctx.state"]
      DailyOK --> |否| ThrowDaily["抛出配额超限错误"]
      SaveQuota --> Next["继续下一个中间件/控制器"]
      

图表来源

  • server/src/middleware/usageLimit.ts:7-49
  • server/src/types/index.ts:120-124

章节来源

  • server/src/middleware/usageLimit.ts:1-66
  • server/src/types/index.ts:114-124

Redis 集成与降级

  • 连接与可用性
    • RedisService 提供连接、可用性检测、基础读写与错误日志
    • isAvailable() 用于限流器选择 Redis 或内存后端
  • 性能与可靠性

    • Redis 可用时使用分布式限流,保证多实例一致性
    • Redis 不可用时自动降级为内存限流,避免服务中断

      classDiagram
      class RedisService {
      +isAvailable() boolean
      +get(key) Promise<string|null>
      +set(key, value, ttl) Promise<boolean>
      +del(key) Promise<boolean>
      +incr(key) Promise<number>
      +expire(key, seconds) Promise<boolean>
      +exists(key) Promise<boolean>
      +testConnection() Promise<boolean>
      +disconnect() Promise<void>
      }
      class RateLimiterRedis {
      +consume(key, points) Promise<void>
      }
      class RateLimiterMemory {
      +consume(key, points) Promise<void>
      }
      RedisService <.. RateLimiterRedis : "提供存储客户端"
      RedisService <.. RateLimiterMemory : "降级使用"
      

图表来源

  • server/src/services/redis.service.ts:1-274
  • server/src/middleware/rate-limiter.ts:20-43

章节来源

  • server/src/services/redis.service.ts:1-274
  • server/src/middleware/rate-limiter.ts:20-43

错误处理与响应

  • 统一错误处理中间件负责捕获限流与业务异常,返回标准化响应体
  • 限流触发时设置 429 状态码与 retryAfter 字段,便于客户端重试控制

章节来源

  • server/src/middleware/errorHandler.ts:1-67
  • server/src/middleware/rate-limiter.ts:60-71

实际应用示例

TTS 生成接口的限流组合

  • 场景:用户提交文本生成音频,需要同时满足网络层限流与业务层配额
  • 步骤: 1) optionalAuth:可选认证,确保 ctx.state.user 可用 2) usageLimitMiddleware:检查用户每日次数与字数配额 3) ttsRateLimiter:按用户维度进行令牌桶限流 4) 业务处理:调用 TTS 服务并消耗配额

    sequenceDiagram
    participant C as "客户端"
    participant R as "路由<br/>tts.controller.ts"
    participant M1 as "optionalAuth"
    participant M2 as "usageLimitMiddleware"
    participant M3 as "ttsRateLimiter"
    participant S as "TTS 服务"
    C->>R : "POST /api/tts/generate"
    R->>M1 : "可选认证"
    M1-->>R : "设置 ctx.state.user"
    R->>M2 : "检查每日次数与字数配额"
    M2-->>R : "允许或抛出配额错误"
    R->>M3 : "令牌桶限流"
    M3-->>R : "允许或返回 429"
    R->>S : "生成音频"
    S-->>R : "返回结果"
    R-->>C : "响应"
    

图表来源

  • server/src/modules/tts/tts.controller.ts:52-127
  • server/src/middleware/rate-limiter.ts:105-110
  • server/src/middleware/usageLimit.ts:7-49

章节来源

  • server/src/modules/tts/tts.controller.ts:52-127

登录接口的限流

  • 场景:防止暴力破解与短信轰炸
  • 策略:按 IP 维度每分钟 5 次,封禁 5 分钟
  • 应用:在 auth.controller.ts 的登录路由上挂载 loginRateLimiter

章节来源

  • server/src/middleware/rate-limiter.ts:83-91
  • server/src/modules/auth/auth.controller.ts:32-52

依赖关系分析

  • 限流中间件依赖 Redis 服务进行分布式存储,Redis 不可用时回退内存
  • 使用量限流中间件依赖数据库与类型定义,提供业务层配额控制
  • 应用入口集中注册中间件与路由,控制中间件顺序与生效范围

    graph LR
    RL["rate-limiter.ts"] --> RS["redis.service.ts"]
    RL --> EH["errorHandler.ts"]
    UL["usageLimit.ts"] --> EH
    UL --> TY["types/index.ts"]
    APP["app.ts"] --> RL
    APP --> UL
    APP --> ROUTERS["各模块控制器"]
    

图表来源

  • server/src/middleware/rate-limiter.ts:1-120
  • server/src/services/redis.service.ts:1-274
  • server/src/middleware/usageLimit.ts:1-66
  • server/src/middleware/errorHandler.ts:1-67
  • server/src/types/index.ts:114-124
  • server/src/app.ts:62-129

章节来源

  • server/src/app.ts:62-129

性能考虑

  • Redis 连接池与重试策略
    • RedisService 提供 retryStrategy,避免瞬时故障导致限流器不可用
    • 建议在生产环境启用 Redis 集群或哨兵,提升可用性
  • 限流键前缀与命名空间
    • 使用 keyPrefix 避免键冲突,便于运维清理与统计
  • 内存限流的适用场景
    • 单实例或临时降级时使用,注意跨实例不一致问题
  • 并发与延迟
    • Redis 操作为 O(1),限流延迟主要来自网络往返;可通过批量操作与连接复用优化
  • 窗口与突发
    • 适当增大 points 与 duration 可平滑突发流量;blockDuration 用于阻断恶意攻击

故障排查指南

  • 限流频繁触发
    • 检查 points 与 duration 是否过小,适当增大配额或窗口
    • 查看 Redis 连接状态,确认 isAvailable() 返回值
    • 客户端应读取 Retry-After 并进行指数退避重试
  • Redis 不可用
    • 确认连接参数与网络连通性
    • 观察 RedisService 的连接事件日志,定位错误原因
  • 使用量限流错误
    • 确认用户登录状态与会员等级
    • 检查每日重置逻辑与 lastUsageDate 字段
  • 响应格式
    • 统一由 errorHandler 中间件处理,确保 code、message、data 结构一致

章节来源

  • server/src/services/redis.service.ts:24-37
  • server/src/middleware/errorHandler.ts:3-24
  • server/src/middleware/usageLimit.ts:26-37

结论

本限流中间件以 rate-limiter-flexible 为基础,结合 Redis 实现分布式令牌桶限流,并提供内存降级与多种内置策略。配合使用量限流中间件,形成“网络层限流 + 业务层配额”的双层防护,既保障系统稳定性,又兼顾用户体验。建议在生产环境中启用 Redis 集群、合理配置限流参数,并完善监控与告警体系。

附录

限流配置参数与调优建议

  • 通用参数
    • points:时间窗口内允许的请求数
    • duration:时间窗口(秒)
    • blockDuration:封禁时长(秒),默认 duration*2
    • keyGenerator:自定义键生成函数,支持按 IP、用户、API 等维度
  • 调优建议
    • 全局限流:API 全局每分钟 100 次,适合开放接口
    • 登录接口:每分钟 5 次,封禁 5 分钟,平衡安全与体验
    • 短信发送:每分钟 1 次,每小时 5 次,封禁 1 小时,防刷
    • TTS 生成:按用户维度每分钟 20 次,结合会员等级动态调整
    • 文件上传:按用户维度每分钟 10 次,避免资源滥用

章节来源

  • server/src/middleware/rate-limiter.ts:74-119

限流规则设计思路

  • 按 IP 限流:适用于匿名接口与敏感操作(登录、短信)
  • 按用户限流:适用于付费功能(TTS、上传),体现用户价值
  • 按 API 限流:针对热点接口进行精细化控制
  • 组合策略:网络层限流(令牌桶)+ 业务层配额(次数/字数)

章节来源

  • server/src/middleware/rate-limiter.ts:54-56
  • server/src/middleware/rate-limiter.ts:80-81
  • server/src/middleware/rate-limiter.ts:90-91
  • server/src/middleware/rate-limiter.ts:100-101
  • server/src/middleware/rate-limiter.ts:109-110
  • server/src/middleware/rate-limiter.ts:118-119

监控与可观测性建议

  • 指标采集:记录 429 次数、Redis 命中率、平均限流延迟
  • 告警阈值:当 429 次数超过基线一定比例时触发告警
  • 日志审计:记录被拒绝的请求键与原因,便于定位攻击源

[本节为通用建议,无需列出章节来源]