C#如何实现接口限流_C# ASP.NET Core内置RateLimiter中间件【前沿】
.NET7内置RateLimiter中间件实现接口限流,无需手写令牌桶。需配置IDistributedCache支持多实例,否则降级为内存限流。PermitLimit代表并发请求上限而非QPS,需结合接口响应时间合理设置。中间件注册顺序必须为UseRouting后、UseEndpoints前才能生效。
限流这事儿,.NET 生态里早就给你备好了现成的轮子——Microsoft.Extensions.RateLimiting,从 .NET 7 开始内置,线程安全,支持分布式,中间件注册也极简。换句话说,别再自己手写个 TokenBucketLimiter 类了,费力不讨好。

为什么不用自己写 TokenBucketLimiter 类
手写一个令牌桶,细节太容易翻车了。比如 Interlocked 的竞态处理没做好,系统时间回拨导致令牌误补,突发流量下令牌预分配逻辑写漏——这些都是坑。更隐蔽的问题是,很多人习惯用 DateTime.Now,一到容器环境或者跨时区部署就出问题。官方实现默认用 DateTimeOffset.UtcNow,底层已经用无锁队列加上高精度时间戳封装好了。你手写的类,压测时可能 QPS 一过 500 就开始丢统计,而 TokenBucketRateLimiter 全程稳如狗。
AddRateLimiter 必须配 IDistributedCache 才能多实例生效
单机跑当然没问题,但一旦部署多个 API 实例,没接缓存就退化成“每台机器各自限流”,等于没限。常见错误是只调了 services.AddRateLimiter() 却忘了注册缓存:
- 内存模式(仅开发/单实例):
services.AddMemoryCache()必须在AddRateLimiter()之前 - Redis 分布式模式:
services.AddStackExchangeRedisCache(opt => opt.Configuration = "your-redis-conn"),且需确保 Redis 可写 - 若用
TokenBucketRateLimiter但没配IDistributedCache,它会静默降级为内存模式,日志里不会报错,但线上扩实例后限流就失效了——你可能很久之后才发现
PermitLimit 不是 QPS,而是并发请求数上限
这个参数最容易设错。举个例子:接口平均响应 300ms,P99 达到 1.2s,你设 PermitLimit = 10,看起来像是“每秒最多 10 次”,实际含义是“最多 10 个请求同时卡在处理中”。如果突发 15 个请求进来,前 10 个拿令牌执行,后 5 个立刻排队或被拒——取决于你设的 QueueLimit。
合理设置要注意几个要点:
PermitLimit至少 ≥ 接口最大容忍并发数(可以参考线程池当前活跃数或者数据库连接池上限)TokensPerPeriod和ReplenishmentPeriod共同决定平均吞吐,比如TokensPerPeriod = 60+ReplenishmentPeriod = TimeSpan.FromMinutes(1)≈ 平均 1 QPS,但允许短时突发QueueLimit别设太高:假设接口平均耗时 500ms,设 20 就意味着第 21 个请求可能排队 10 秒才失败,应取Math.Min(5, (int)(30 / 0.5))这类保守值
中间件顺序错一个位置,限流就完全不触发
注册阶段和中间件阶段必须严格按顺序来,否则限流形同虚设:
- 注册阶段(
Program.cs):AddMemoryCache()或AddStackExchangeRedisCache()→AddRateLimiter()→AddControllers() - 中间件阶段(
app.Use...):UseRouting()→UseRateLimiter()→UseEndpoints() - 漏掉
UseRateLimiter()或把它放在UseRouting()之前,所有请求都绕过限流;放在UseEndpoints()之后,则 endpoint 已经执行完了 - 如果你还用了
UseAuthorization()或UseAuthentication(),UseRateLimiter()必须在它们之后、UseEndpoints()之前
真正麻烦的不是配置本身,而是限流策略和接口真实响应时间的耦合——PermitLimit 设小了影响可用性,设大了失去保护意义;ReplenishmentPeriod 设短了抖动大,设长了无法应对突发。上线前一定要用真实链路压测,而不是只看单接口的 BenchMark 数据。


































