一、啥是请求限流以及为啥要搞它

在咱开发 API 的时候,有时候会遇到一些不怀好意的人恶意刷新接口,这就会给服务器带来很大的压力,甚至可能让服务器崩溃。请求限流就是一种防止这种情况发生的策略,它可以控制在一定时间内,某个客户端或者某个 IP 地址对 API 的请求次数。

比如说,你开了一家小超市,每天只能接待一定数量的顾客。如果一下子来了太多顾客,超市就会变得拥挤不堪,员工也忙不过来,甚至可能会出乱子。请求限流就相当于超市门口的保安,他会根据超市的承载能力,控制进入超市的顾客数量。

二、ASP.NET Core 里的请求限流策略

在 ASP.NET Core 中,有好几种请求限流的策略可以用,下面咱来详细说说。

固定窗口策略

这个策略就像是一个固定大小的窗口,在这个窗口时间内,只允许一定数量的请求通过。比如说,我们规定在 1 分钟内,每个 IP 地址最多只能请求 10 次 API。如果超过了这个次数,就会被拒绝。

下面是一个使用固定窗口策略的示例(技术栈:DotNetCore、C#):

// 首先,我们需要安装 AspNetCoreRateLimit 包,使用 Nuget 或者 Package Manager 都可以
using AspNetCoreRateLimit;

// 在 Startup.cs 里配置服务
public void ConfigureServices(IServiceCollection services)
{
    // 配置 IP 限流服务
    services.AddMemoryCache();
    services.Configure<IpRateLimitOptions>(options =>
    {
        // 定义规则
        options.GeneralRules = new List<RateLimitRule>
        {
            new RateLimitRule
            {
                Endpoint = "*", // 对所有端点生效
                Limit = 10, // 限制 10 次请求
                Period = "1m" // 时间窗口为 1 分钟
            }
        };
    });

    services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
    services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();

    services.AddControllers();
}

// 在 Configure 方法里启用中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseIpRateLimiting();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

滑动窗口策略

滑动窗口策略比固定窗口策略更灵活一些。它不是固定一个时间窗口,而是随着时间的推移,窗口会不断滑动。比如说,在 1 分钟内,每个 IP 地址最多只能请求 10 次 API。但是这个 1 分钟的窗口是不断滑动的,而不是固定的。

下面是一个使用滑动窗口策略的示例(技术栈:DotNetCore、C#):

// 同样,先安装 AspNetCoreRateLimit 包
using AspNetCoreRateLimit;

// 在 Startup.cs 里配置服务
public void ConfigureServices(IServiceCollection services)
{
    services.AddMemoryCache();
    services.Configure<IpRateLimitOptions>(options =>
    {
        // 定义规则,使用滑动窗口
        options.GeneralRules = new List<RateLimitRule>
        {
            new RateLimitRule
            {
                Endpoint = "*",
                Limit = 10,
                Period = "1m",
                // 滑动窗口的间隔
                Window = "10s" 
            }
        };
    });

    services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
    services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();

    services.AddControllers();
}

// 在 Configure 方法里启用中间件
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }

    app.UseIpRateLimiting();

    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

三、请求限流的应用场景

请求限流在很多场景下都能派上用场,下面给大家举几个例子。

防止恶意攻击

就像前面说的,有些坏人会恶意刷新 API,想把服务器搞垮。通过请求限流,我们可以限制他们的请求次数,保护服务器的安全。

控制资源使用

有些 API 可能会消耗大量的服务器资源,比如数据库查询、文件上传等。通过请求限流,我们可以控制每个客户端对这些 API 的使用频率,避免资源被过度占用。

遵守第三方服务的规则

有些第三方服务可能会对我们的请求次数有限制,比如一些 API 提供商。通过在自己的 API 里设置请求限流,我们可以确保不会超过第三方服务的限制。

四、技术优缺点分析

优点

  • 提高服务器稳定性:通过限制请求次数,可以避免服务器因为过多的请求而崩溃,提高服务器的稳定性。
  • 保护资源:可以控制对服务器资源的使用,避免资源被过度占用。
  • 防止恶意攻击:有效防止恶意刷新 API 的行为,保护系统的安全。

缺点

  • 可能影响正常用户:如果限流规则设置得不合理,可能会影响正常用户的使用体验。比如说,有些用户可能需要频繁地请求 API,但是因为限流规则的限制,他们的请求会被拒绝。
  • 增加开发复杂度:实现请求限流需要额外的代码和配置,会增加开发的复杂度。

五、注意事项

在使用请求限流的时候,有一些注意事项需要大家了解。

合理设置限流规则

限流规则要根据实际情况来设置,不能太严格也不能太宽松。如果太严格,会影响正常用户的使用;如果太宽松,就起不到限流的作用。

考虑分布式系统

如果你的应用是分布式的,那么在使用请求限流的时候,要考虑如何在多个服务器之间同步限流信息。可以使用 Redis 等分布式缓存来实现。

监控和调整

要对请求限流的效果进行监控,根据监控结果及时调整限流规则。比如说,如果发现某个 IP 地址经常被限流,但是它实际上是正常用户,那么就需要调整规则。

六、总结

请求限流是一种非常重要的策略,可以帮助我们防止 API 被恶意刷新,保护服务器的安全和稳定。在 ASP.NET Core 中,我们可以使用固定窗口、滑动窗口等策略来实现请求限流。在使用请求限流的时候,我们要合理设置规则,考虑分布式系统的情况,并且要对效果进行监控和调整。