当前位置: 首页 > article >正文

### net7 + 出现了 自带的 限流中间件 固定窗口、滑动窗口 并发 令牌桶 全局限流器

资料
限流的方法

速率限制算法

固定窗口算法 是最简单的算法之一。它将请求限制为一个固定的时间窗口,该窗口在任何时间点都只允许固定数量的请求。

滑动窗口算法 是固定窗口算法的改进版本,它将请求限制为一个可变的窗口,该窗口在任何时间点都只允许固定数量的请求。

令牌桶算法 使用固定大小的令牌桶来限制请求的速率。令牌桶最初被填满了指定数量的令牌。每次请求都会消耗一个令牌,如果令牌桶中没有令牌,则该请求会被拒绝。

并发算法 是一种非常简单的算法,它只允许固定数量的并发请求,但是不限制一段时间内的请求数。

在这里插入图片描述

IOC注册内置的限流中间件

//使用限流器
app.UseRateLimiter();

 #region 限流中间件 IOC 注册
 builder.Services.AddRateLimiter(options => {
    //1、固定窗口限流策略
    //配置说明:该固定窗口5s时间内,可以最多有5+2=7个请求,5个会被处理,2个会被排队,其他则会在一定时间后拒绝返回 
     options.AddFixedWindowLimiter(policyName: "fixed", op =>
     {
         op.PermitLimit = 5; //每个窗口时间范围内,允许100个请求被处理
         op.Window = TimeSpan.FromSeconds(5);//窗口大小。即窗口时间长度5s。必须>TimeSpan.Zero
         //5s 内只能5个请求--过后继续
         //排队请求的处理顺序。这里设置为有限处理先来的请求
         op.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
         //窗口阈值。即每个窗口时间范围内,最多允许的请求个数。该值必须>0。
         //当窗口请求达到最大值,后续请求会进入排队。该值用于设置对垒大小(即允许几个请求在排队队列等待)
         op.QueueLimit = 2;
         //开启新窗口时是否自动重置请求限制,默认true。如果是false,
         //则需要手动调佣 FixedWindowRateLimiter.TryReplenish来重置
         op.AutoReplenishment = true;
     });
 });
 #endregion

启用限流中间件

app.UseRateLimiter();//限流中间件
//  这个是所有都增加限流了 不是是特点路由限流了
//app.MapControllers().RequireRateLimiting("fixed"); 
app.MapControllers();

按需加特性

[EnableRateLimiting("fixed")]

固定窗口限流器

在这里插入图片描述

滑动窗口

在这里插入图片描述

#region 限流中间件 IOC 注册
 builder.Services.AddRateLimiter(options => {
    //2、滑动窗口限流则略
	//配置说明:窗口时间长度为30s,每个窗口内,最多允许100个请求,窗口段数3,每个段的时间间隔为30/3=10s,即窗口每10s滑动一段。
	options.AddSlidingWindowLimiter(policyName:"sliding", slidingOptions =>
	{
	    slidingOptions.PermitLimit = 100;
	    slidingOptions.Window = TimeSpan.FromSeconds(30);
	    slidingOptions.QueueLimit = 2;
	    slidingOptions.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
	    slidingOptions.AutoReplenishment = true;//开启新窗口时是否自动重置请求限制,默认true
	    slidingOptions.SegmentsPerWindow = 3;
	});
 });
 #endregion

令牌桶限流

#region 限流中间件 IOC 注册
 builder.Services.AddRateLimiter(options => {
     //策略说明:桶最多装4个令牌,每10秒发放一次令牌,每次发放2个令牌,所以在一个发放周期,
     //最多可以处理4个请求(TokenLimit ),至少可以处理2个请求(TokensPerPeriod 一个周期发两个令牌)。
	options.AddTokenBucketLimiter(policyName:"token_bucket", tokenBucketOptions =>
	{
	    tokenBucketOptions.TokenLimit = 4;//桶最多可以装的令牌数,发放的多余令牌会被丢弃
	    tokenBucketOptions.ReplenishmentPeriod = TimeSpan.FromSeconds(10);//令牌发放周期
	    tokenBucketOptions.TokensPerPeriod = 2;//每个周期发放令牌数
	    tokenBucketOptions.QueueLimit = 2;//当桶内的令牌全部被拿完(token=0)时,后续请求会进入排队
	    tokenBucketOptions.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
	    tokenBucketOptions.AutoReplenishment = true;//进入新令牌发放周期,是否自动发放令牌。如果设置为false,则需要手动调用 TokenBucketRateLimiter.TryReplenish来发放
	});
 });
 #endregion

并发限流器

并发限流器不是限制一段时间内的最大请求数,而是限制并发数。

           【原理】:限制同一时刻并发请求的数量。

           【特点】:可以充分利用服务器的性能,当出现突发流量时,服务器负载可能会持续过高。
#region 限流中间件 IOC 注册
 builder.Services.AddRateLimiter(options => {
    //策略说明:最大并发请求4,超过最大并发请求,则后续最多2个请求进入排队队列。
	options.AddConcurrencyLimiter(policyName:"concurrency", concurrencyOptions =>
	{
	    concurrencyOptions.PermitLimit = 4;//最大并发请求数
	    concurrencyOptions.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
	    concurrencyOptions.QueueLimit = 2;//当并发请求数达到最大,后续请求进入排队,该参数用于配置队列大小
	});
 });
 #endregion

全局限流器

通过GlobalLimiter,我们可以设置全局限流器,更准确的说法是全局分区限流器,该限流器会应用于所有请求。执行顺序为先执行全局限流器,再执行特定于路由终结点的限流器(如果存在的话)。

需要注意的是,相对于上面注册的限流策略来说,GlobalLimiter已经是一个限流器实例了,所以需要分配给他一个分区限流器实例,通过PartitionedRateLimiter.Create来创建。

builder.Services.AddRateLimiter(limiterOptions =>
{
    limiterOptions.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, IPAddress>(context =>
    {
        IPAddress? remoteIpAddress = context.Connection.RemoteIpAddress;

        // 针对非回环地址限流
        if (!IPAddress.IsLoopback(remoteIpAddress!))
        {
            return RateLimitPartition.GetTokenBucketLimiter
            (remoteIpAddress!, _ =>
                new TokenBucketRateLimiterOptions
                {
                    TokenLimit = 4,
                    QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                    QueueLimit = 2,
                    ReplenishmentPeriod = TimeSpan.FromSeconds(10),
                    TokensPerPeriod = 10,
                    AutoReplenishment = true
                });
        }

        // 若为回环地址,则不限流
        return RateLimitPartition.GetNoLimiter(IPAddress.Loopback);
    });
});

链式组合限流器

在这里插入图片描述
在这里插入图片描述

builder.Services.AddRateLimiter(limiterOptions =>
{    
	var chainedLimiter = PartitionedRateLimiter.CreateChained(
	PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
	{
	    var userAgent = httpContext.Request.Headers.UserAgent.ToString();
	
	    return RateLimitPartition.GetFixedWindowLimiter
	    (userAgent, _ =>
	        new FixedWindowRateLimiterOptions
	        {
	            AutoReplenishment = true,
	            PermitLimit = 4,
	            Window = TimeSpan.FromSeconds(2)
	        });
	}),
	PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
	{
	    var userAgent = httpContext.Request.Headers.UserAgent.ToString();
	
	    return RateLimitPartition.GetConcurrencyLimiter
	    (userAgent, _ =>
	        new ConcurrencyLimiterOptions
	        {
	            PermitLimit = 4,
	            QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
	            QueueLimit = 2
	        });
	})
	limiterOptions.GlobalLimiter = chainedLimiter ;
);

注意 注意 注意

在这里插入图片描述
比如一个政策限流是 最大Limit=100
这个政策,分别加在两个路由中 [EnableRateLimiting(“xxx”)]
只有这个两个路由 请求 总和到达100,就会现在访问了。

下面我们就借助AddPolicy,分别使用两种方式添加一个自定义策略“my_policy”:一个用户一个分区,匿名用户共享一个分区。

通过委托创建自定义限流策略

builder.Services.AddRateLimiter(limiterOptions =>
{
    limiterOptions.AddPolicy(policyName: "my_policy", httpcontext =>
    {
        var userId = "anonymous user";
        if (httpcontext.User.Identity?.IsAuthenticated is true)
        {
            userId = httpcontext.User.Claims.First(c => c.Type == "id").Value;
        }
        
        return RateLimitPartition.GetFixedWindowLimiter(partitionKey: userId, _ => new 
            FixedWindowRateLimiterOptions
            {
                PermitLimit = 3,
                Window = TimeSpan.FromSeconds(60),
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                QueueLimit = 0
            });
    });
});

在这里插入图片描述
在这里插入图片描述

通过IRateLimiterPolicy创建自定义限流策略

public interface IRateLimiterPolicy<TPartitionKey>
{
    // 若不为空,则执行它(不会执行全局的),如果它为空,则执行全局的
    Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; }

    // 获取限流分区
    RateLimitPartition<TPartitionKey> GetPartition(HttpContext httpContext);
}

public class MyRateLimiterPolicy : IRateLimiterPolicy<string>
{
    // 可以通过依赖注入参数
    public MyRateLimiterPolicy(ILogger<MyRateLimiterPolicy> logger)
    {
        // 可以设置自己的限流拒绝回调逻辑,而不使用上面全局设置的 limiterOptions.OnRejected
        OnRejected = (ctx, token) =>
        {
            ctx.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;

            logger.LogWarning($"Request rejected by {nameof(MyRateLimiterPolicy)}");

            return ValueTask.CompletedTask;
        };
    }

    public Func<OnRejectedContext, CancellationToken, ValueTask>? OnRejected { get; }

    public RateLimitPartition<string> GetPartition(HttpContext httpContext)
    {
        var userId = "anonymous user";
        if (httpContext.User.Identity?.IsAuthenticated is true)
        {
            userId = httpContext.User.Claims.First(c => c.Type == "id").Value;
        }

        return RateLimitPartition.GetFixedWindowLimiter(partitionKey: userId, _ => new 
            FixedWindowRateLimiterOptions
            {
                PermitLimit = 3,
                Window = TimeSpan.FromSeconds(60),
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                QueueLimit = 0
            });
    }
}

// 记得注册它
builder.Services.AddRateLimiter(limiterOptions =>
{
    limiterOptions.AddPolicy<string, MyRateLimiterPolicy>(policyName: "my_policy");
}

限流应用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

EnableRateLimitingAttribute & DisableRateLimitingAttribute

在这里插入图片描述


http://www.kler.cn/a/550108.html

相关文章:

  • 力扣算法-1
  • 《机器学习数学基础》补充资料:四元数、点积和叉积
  • Linux重定向 2>1 中的是什么含义
  • 采用 Ansys Workbench CFX 的 TwinMesh 应用
  • ES 渗透查询 (Percolate query)
  • 机器学习数学基础:27.数字特征
  • 智慧医疗胃肠道息肉分割数据集labelme格式1000张1类别
  • 【设计模式】适配器模式和桥接模式
  • MySQL 入门大全:常用函数
  • C/C++字符串格式化全解析:从printf到std::format的安全演进与实战指南
  • LabVIEW用CANopen的设备属性配置与心跳消息和PDO读取
  • 【JAVA工程师从0开始学AI】,第四步:闭包与高阶函数——用Python的“魔法函数“重构Java思维
  • (8/100)每日小游戏平台系列
  • 【SpringBoot整合系列】SpringBoot3.x整合Swagger
  • redis sentinel模式 与 redis 分片集群 配置
  • 基于Springboot校园综合服务平台校园生活服务系统数据库源代码
  • uniapp 打包安卓 集成高德地图
  • Simula语言的测试开发
  • 基于机器学习的多浮埋层 LDMOS 建模与击穿电压优化
  • PHP 可用的函数