返回

ASP.NET Core WebAPI 限流与节流实战:高性能 API 防护与优化策略

2025-12-12 ASP.NET Core WebAPI 315 0

为什么要限流与节流?

随着业务成长,高并发、大流量请求成为 WebAPI 面临的常见挑战。如果没有控制 API 的访问频率,会出现:

  • 服务器 CPU/内存飙升
  • 数据库连接耗尽
  • 服务响应延迟扩大
  • 恶意攻击或流量突发导致宕机

因此,限流与节流是保障 API 稳定性的重要手段。

限流与节流的核心概念

限流(Rate Limiting)

限流是对单位时间内允许访问的最大请求次数进行控制。常见策略如:每秒 N 次、每分钟 N 次、每小时 N 次。应用场景:

  • 防止恶意刷接口
  • 分配公平访问资源
  • 避免峰值流量冲垮系统

节流(Throttling)

节流是对请求执行频率进行控制,通过延迟处理将高频请求“平滑”分布。通常用于:

  • 控制请求峰值
  • 减少重复运算
  • 优化资源利用

与限流相比,节流更强调平缓处理,而非简单拒绝请求。

ASP.NET Core WebAPI 如何实现限流/节流?

ASP.NET Core 6.0+ 自带 Rate Limiting 中间件,可通过配置策略实现多种流控需求。

使用 ASP.NET Core 内置限流中间件

1. 添加 NuGet 包

dotnet add package Microsoft.AspNetCore.RateLimiting

2. 配置限流策略(Program.cs)

using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRateLimiter(options =>
{
    // 全局限流策略
    options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
        RateLimitPartition.GetFixedWindowLimiter(
            partitionKey: httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown",
            factory: key => new FixedWindowRateLimiterOptions
            {
                PermitLimit = 100, // 每窗口允许的最大请求数
                Window = TimeSpan.FromMinutes(1), // 窗口周期
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                QueueLimit = 0
            })
    );

    options.OnRejected = async (context, token) =>
    {
        context.HttpContext.Response.StatusCode = 429;
        await context.HttpContext.Response.WriteAsync("请求过于频繁,请稍后再试。");
    };
});

var app = builder.Build();

app.UseRateLimiter();

app.MapGet("/api/data", () => "限流测试接口");

app.Run();

解释:

  • PermitLimit(许可数):每分钟最多允许 100 次请求。
  • 超出请求会返回 429(Too Many Requests)。
  • 基于客户端 IP 作为限流 Key。

自定义节流策略案例

节流模式可以采用滑动窗口、漏桶算法等逻辑。

builder.Services.AddRateLimiter(options =>
{
    options.AddPolicy("SlidingWindow", httpContext =>
        RateLimitPartition.GetSlidingWindowLimiter(
            partitionKey: httpContext.User?.Identity?.Name ?? httpContext.Connection.RemoteIpAddress?.ToString(),
            factory: key => new SlidingWindowRateLimiterOptions
            {
                PermitLimit = 50,
                Window = TimeSpan.FromSeconds(30),
                SegmentsPerWindow = 6,
                QueueLimit = 10,
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst
            }));
});

滑动窗口策略优势

  • 更精细控制瞬时请求峰值
  • 避免集中重置导致“爆发式”短时间请求

按接口分组设置策略

app.UseRateLimiter(new RateLimiterOptions
{
    RejectionStatusCode = 429,
    OnRejected = async (context, token) =>
    {
        await context.HttpContext.Response.WriteAsync("当前请求被限流");
    }
});

app.MapGet("/api/user", () => "用户接口")
   .RequireRateLimiting("UserPolicy");

app.MapGet("/api/order", () => "订单接口")
   .RequireRateLimiting("OrderPolicy");

可以针对不同 API 路径制定不同策略,如:

  • /api/user 每分钟 30 次
  • /api/order 每分钟 80 次

结合缓存与 Redis 实现分布式限流

在分布式场景下,可使用 Redis 保存请求计数器,实现跨服务限流。示例伪代码:

// 伪代码逻辑
var count = await redis.StringIncrementAsync(key);

if (count == 1)
    redis.KeyExpire(key, TimeSpan.FromMinutes(1));

if (count > limit)
    return 429;

Redis 可用于:

  • 多实例共享限流状态
  • 实现分布式滑动窗口

限流与节流的最佳实践

  • 区分业务场景设定策略
  • 优先采取平滑节流再拒绝模式
  • 返回明确提示(HTTP 429)
  • 在生产环境监控限流效果
  • 避免对静态内容进行不必要限流

总结

ASP.NET Core 提供了强大而灵活的限流/节流中间件,可结合策略实现不同性能目标。无论是抵御高并发、保护下游服务还是提升用户体验,良好的流控策略都是高质量 WebAPI 的必备能力。

顶部