限流是一种限制系统中某些操作的频率或数量的技术。在高负载情况下,系统可能无法处理大量的请求,导致响应时间变慢甚至宕机。为了避免这种情况的发生,可以通过限流技术来限制请求的数量或频率,使系统可以平稳运行。限流可以在不同的层面上实现,如应用程序层面、网络层面以及硬件层面。
DotNetRateLimiter是一个开源的.NET Core限流库,用于帮助开发人员实现在高并发环境下的请求限制和流量控制。这个库实现了常见的限流算法,包括滑动窗口、令牌桶、漏桶等,可以根据具体的业务场景选择不同的算法进行限流。
DotNetRateLimiter库提供了易于使用的API,使得开发人员可以轻松地将限流逻辑集成到自己的代码中,从而保护应用程序避免被过多的请求打垮。另外,该库还支持自定义规则和策略,使得开发人员可以根据自己的业务需求自定义限流规则和处理逻辑,从而实现更加灵活的限流方案。
DotNetRateLimiter库是.NET Core开发中非常实用的一个限流工具,可以帮助开发人员避免因过多的请求而导致的应用程序崩溃和性能问题。
ActionFilters官网:https://github.com/sa-es-ir/DotNet.RateLimit
DotNetRateLimiter
appsettings.json添加如下配置:
"RateLimitOption": {
"EnableRateLimit": true, //Optional: if set false rate limit will be disabled, default is true
"HttpStatusCode": 429, //Optional: default is 429
"ErrorMessage": "Rate limit Exceeded", //Optional: default is Rate limit Exceeded
"IpHeaderName": "X-Forwarded-For" //Optional: header name for get Ip address, default is X-Forwarded-For
"RedisConnection": "127.0.0.1:6379", //Optional
"IpWhiteList": ["::1"], //Optional
"ClientIdentifier": "X-Client-Id" Optional: for getting client id from request header if this present the rate limit will not use IP for limit requests
"ClientIdentifierWhiteList": ["test-client"] Optional
}
修改 Program.cs, 添加限流服务
builder.Services.AddRateLimitService(builder.Configuration);
[HttpGet("")]
[RateLimit(PeriodInSec = 60, Limit = 3)]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
DotNetRateLimiter中的PeriodInSec和Limit参数是限流策略的两个重要参数,具体介绍如下:
PeriodInSec和Limit参数配合使用,可以精确控制接口的调用频率。我们可以根据系统的负载和业务需求来灵活配置这两个参数,以达到最佳的限流效果。
RateLimit(PeriodInSec = 60, Limit = 3) 这个接口方法每分钟只允许 3 个请求, 如果调用 api 超过 3 次,就会收到 429(请求过多), 我们使用自动化API测试工具进行压力测试,结果如下:
DotNetRateLimiter是一个基于ASP.NET Core的限流框架,提供了一些限流的功能和配置参数,其中包括RouteParams参数。
RouteParams参数是一个字典类型的参数,其中包括了当前请求的路由参数(RouteData)。 当一个请求到达时,DotNetRateLimiter会自动获取当前请求的路由以及路由参数,并将其作为字典参数传递给限流策略。这样可以让开发者在限流策略中自由的使用路由参数进行更加精细的限流。
[HttpGet("by-route/{id}")]
[RateLimit(PeriodInSec = 60, Limit = 3, RouteParams = "id")]
public IEnumerable<WeatherForecast> Get(int id)
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
DotNetRateLimiter是一个基于.NET的速率限制库,QueryParams参数是指请求中的查询参数。查询参数通常出现在请求URL的问号(?)后面,例如:https://www.example.com/api?id=1234&name=john
。在DotNetRateLimiter中,可以通过配置QueryParams参数来仅对特定的查询参数进行速率限制。
[HttpGet("by-query/{id}")]
[RateLimit(PeriodInSec = 60, Limit = 3, RouteParams = "id", QueryParams = "name,family")]
public IEnumerable<WeatherForecast> Get(int id, string name, [FromQuery] List<string> family)
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
DotNetRateLimiter是一种限制访问频率的工具,可以用于防止恶意攻击或限制API的访问频率。其中BodyParams参数用于指定请求的正文参数,这些参数将被用于计算请求频率。具体来说,BodyParams参数可以用于以下目的:
1.区分不同的API请求:如果API的请求接口相同,但请求正文参数不同,可以将BodyParams参数设置为请求正文参数的组合,以便对不同的请求进行区分和计数。
2.增加计数的细粒度:将BodyParams参数设置为请求正文中需要计入限制次数的参数,可以增加计数的细粒度,从而更准确地限制访问频率。
需要注意的是,BodyParams参数应该是一个字符串列表,每个字符串表示一个请求正文参数的名称。在使用DotNetRateLimiter时,需要根据具体的API和限制策略,选择合适的BodyParams参数来计算请求频率。
[HttpPut]
[RateLimit(PeriodInSec = 60, Limit = 3, BodyParams = "temperatureC")]
public IActionResult Update([FromBody] WeatherForecast weatherForecast)
{
return Ok();
}
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string Summary { get; set; }
}
DotNetRateLimiter中的Scope参数是用于标识要限流的资源的作用域或范围。它是一个字符串类型的参数,可以是任何合法的字符串。
Scope参数主要用于将不同的限流规则应用于不同的资源或服务。例如,对于一个在线支付系统,可以将不同的支付接口或业务操作(如支付、退款、查询等)定义为不同的作用域,然后针对每个作用域分别设置不同的限流规则。
Scope参数在DotNetRateLimiter中属于必需的参数,如果不设置Scope参数,则无法启用限流功能。
[ApiController]
[Route("rate-limit-on-controller")]
//if set Scope to Controller to rate limit on all actions no matter which actions call
//the default value is Action means this rate limit check for each action separately
[RateLimit(Limit = 3, PeriodInSec = 60, Scope = RateLimitScope.Controller)]
public class RateLimitOnAllController : ControllerBase
{
private static readonly string[] Summaries = {
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[HttpGet("")]
[IgnoreRateLimit]//ignore rate limit for this action
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
[HttpGet("by-route/{id}")]
public IEnumerable<WeatherForecast> GetByRoute(int id)
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
[HttpGet("by-query/{id}")]
public IEnumerable<WeatherForecast> GetByQuery(int id, string name, [FromQuery] List<string> family)
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
[HttpPut]
public IActionResult Update(WeatherForecast weatherForecast)
{
return Ok();
}
}
亲爱的读者,
我在这篇文章中投入了大量的心血和时间,希望为您提供有价值的内容。这篇文章包含了深入的研究和个人经验,我相信这些信息对您非常有帮助。
如果您觉得这篇文章对您有所帮助,我诚恳地请求您考虑赞赏1元钱的支持。这个金额不会对您的财务状况造成负担,但它会对我继续创作高质量的内容产生积极的影响。
我之所以写这篇文章,是因为我热爱分享有用的知识和见解。您的支持将帮助我继续这个使命,也鼓励我花更多的时间和精力创作更多有价值的内容。