.NET服务治理之限流中间件-FireflySoft.RateLimit
概述
FireflySoft.RateLimit自2021年1月发布第一个版本以来,经历了多次升级迭代,目前已经十分稳定,被很多开发者应用到了生产系统中,最新发布的版本是3.0.0。
- Github:https://github.com/bosima/FireflySoft.RateLimit
- 码云:https://gitee.com/bosima/FireflySoft.RateLimit
它的核心是一个基于 .NET Standard 的限流类库,其内核简单轻巧,能够灵活应对各种需求的限流场景。其主要特点包括:
- 多种限流算法:内置固定窗口、滑动窗口、漏桶、令牌桶四种算法,方便自定义扩展。
- 多种计数存储:目前支持内存、Redis(含集群)两种存储方式。
- 分布式友好:通过Redis存储支持分布式程序统一计数。
- 限流目标灵活:可以从请求中提取各种数据用于设置限流目标,不仅仅是客户端IP和Id。
- 支持限流惩罚:可以在客户端触发限流后锁定一段时间不允许其访问。
- 时间窗口增强:支持到毫秒级别;支持从秒、分钟、小时、日期等时间周期的自然起始点开始。
- 实时限流跟踪:当前计数周期内已处理的请求数、剩余允许请求数,以及计数周期重置的时间。
- 动态更改规则:支持程序运行时动态更改限流规则。
- 自定义错误:可以自定义触发限流后的错误码和错误消息。
- 普适性:原则上可以满足任何需要限流的场景,可用于各种B/S、C/S程序。
基于这个核心又实现了两个中间件:
- FireflySoft.RateLimit.AspNet:应用于传统的.NET Framework的Web应用程序。
- FireflySoft.RateLimit.AspNetCore:应用于ASP.NET Core的Web应用程序。
相比使用FireflySoft.RateLimit核心类库,直接使用这两个中间件比较方便一些。如果这两个中间件不能满足你的需求,比如不是应用在官方的Web框架中,甚至不是Web程序,问题不大,可以基于核心类库满足你的限流需求,你要做的只是定义好你要限流的请求,并在触发限流时执行自己的业务逻辑,限流的算法如何实现都不需要关心。
这些类库和中间件都是可以通过Nuget安装的,搜索 FireflySoft.RateLimit 即可找到。
使用示例
这篇文章以一个ASP.NET Core程序为例,说明FireflySoft.RateLimit的使用方法。
程序的业务需求是:对获取天气预报的接口,根据客户端IP和ClientId进行限流,每个IP每秒钟1次,每个ClientId每秒钟3次。ClientId是预先分配给调用方的。根据规则,调用方如果只有1个出口IP,那么每秒钟只能访问1次,如果有多个出口IP,那么每秒钟最多访问3次。
这个示例程序是基于.NET6开发的,当然你用.NET Core 3.1也没有问题,只是.NET6默认把服务和中间件注册都放到了Program.cs 中。(建议升级到.NET6,.NET6相比.NET Core 3.1的性能有明显的提升。)
来看代码吧,只需要注册服务和Middleware就可以了。
using FireflySoft.RateLimit.AspNetCore;
using FireflySoft.RateLimit.Core.InProcessAlgorithm;
using FireflySoft.RateLimit.Core.Rule;
var builder = WebApplication.CreateBuilder(args);
...
builder.Services.AddRateLimit(new InProcessFixedWindowAlgorithm(
new[] {
new FixedWindowRule()
{
ExtractTarget = context =>
{
var httpContext= context as HttpContext;
// Through CDN
var ip = httpContext!.Request.Headers["Cdn-Src-Ip"].FirstOrDefault();
if (!string.IsNullOrEmpty(ip))
return ip;
// Through SLB
ip = httpContext!.Request.Headers["X-Forwarded-For"].FirstOrDefault();
if (!string.IsNullOrEmpty(ip))
return ip;
ip = httpContext!.Connection.RemoteIpAddress?.ToString();
return ip??"Anonymous-IP";
},
CheckRuleMatching = context =>
{
var requestPath = (context as HttpContext)!.Request.Path.Value;
if (requestPath == "/WeatherForecast/Future")
{
return true;
}
return false;
},
Name = "ClientIPRule",
LimitNumber = 3,
StatWindow = TimeSpan.FromSeconds(1)
},
new FixedWindowRule()
{
ExtractTarget = context =>
{
var httpContext= context as HttpContext;
var clientID = httpContext!.Request.Headers["X-ClientId"].FirstOrDefault();
return clientID??"Anonymous-ClientId";
},
CheckRuleMatching = context =>
{
var requestPath = (context as HttpContext)!.Request.Path.Value;
if (requestPath == "/WeatherForecast/Future")
{
return true;
}
return false;
},
Name = "ClientIdRule",
LimitNumber = 1,
StatWindow = TimeSpan.FromSeconds(1)
}
})
);
...
app.UseRateLimit();
...
粘贴的代码中只保留了此中间件需要的内容,注册服务使用 AddRateLimit,使用中间件通过 UseRateLimit。
算法
AddRateLimit 时需要指定一个限流算法,示例中是基于本地内存的固定窗口算法,可以根据需要更换为其它算法,比如可以应对短时突发流量的令牌桶算法。
对于某种具体的算法,基于本地内存和基于Redis的实现是不同的类,因为为了更好的性能,Redis实现的算法是通过Lua脚本写的,它完全运行在Redis服务端。
为了方便使用,将这些算法的名字列在这里:
| 基于本地内存(进程内) | 基于Redis | |
|---|---|---|
| 固定窗口算法 | InProcessFixedWindowAlgorithm | RedisFixedWindowAlgorithm |
| 滑动窗口算法 | InProcessSlidingWindowAlgorithm | RedisSlidingWindowAlgorithm |
| 漏桶算法 | InProcessFixedWindowAlgorithm | RedisFixedWindowAlgorithm |
| 令牌桶算法 | InProcessTokenBucketAlgorithm | RedisokenBucketAlgorithm |
目前一个ASP.NET Core程序中只能使用一种算法,不知道是否有多种算法的需求,如有需要可以对FireflySoft.RateLimit.AspNetCore 进行一些改造:
AddRateLimit时注册IAlgorithm改为注册IAlgorithm的解析器,解析器提供一个方法根据某个Key返回IAlgorithm的具体实现。
RateLimitMiddleware中根据当前请求确定要使用的算法,然后调用解析器的方法获取IAlgorithm的具体实现。
规则
创建算法实例的时候,还需要指定算法的规则,这里根据算法使用的是 FixedWindowRule,对于同一个算法,进程内实现和Redis实现使用相同的规则。
看一下这里使用的规则的几个属性:
ExtractTarget 设置一个函数,用于从HTTP请求中提取要限流的目标,比如这里的客户端IP和客户端ID,还可以是各种可以从请求中提取或关联到的东西,比如Http Header中携带的用户Id,或者根据用户Id查询到的用户年龄。
CheckRuleMatching 设置一个函数,返回当前请求是否能匹配到某个限流规则,如果能匹配到,则返回true。比如只对 /api/req 这个路径限流,那么只要判断请求的路径是它,就返回true,其它路径都返回false。当然也可以是根据各种可以从请求中提取或关联到的东西来进行判断。
Name 限流规则的名字,方便人跟踪的时候进行区分。
StatWindow 限流的时间窗口。比如需求中的每秒钟3次,这里的时间窗口就要设置为1秒。
LimitNumber 限流的次数阈值。比如需求中的每秒钟3次,这里的时间窗口就要设置为3,超过3就会被限流。
规则中还有其它几个属性,不同算法的规则也略有不同,这里就不一一列举了。感兴趣的朋友可以去示例代码和单元测试中认识它们。
一个算法中可以添加多个对应算法的规则,这无疑会比较灵活。
更多使用说明
- ASP.NET Core中使用固定窗口限流
- ASP.NET Core中使用滑动窗口限流
- ASP.NET Core中使用漏桶算法限流
- ASP.NET Core中使用令牌桶限流
- ASP.NET Core中如何对不同类型的用户进行区别限流
- 多租户系统中如何实现分别限流
- .NET6运行时动态更新限流阈值
- 如何使用数组实现滑动窗口
- 限流的非常规用途 – 缓解抢购压力
- 限流的非正式用途 – 解决重复提交问题
- 服务限流惩罚是怎么一回事
以上就是本文的主要内容了,如有问题欢迎留言交流。
.NET服务治理之限流中间件-FireflySoft.RateLimit的更多相关文章
- 服务接口API限流 Rate Limit 续
一.前言 上一篇文章中粗浅的介绍使用Redis和基于令牌桶算法进行对服务接口API限流,本文介绍另一种算法---漏桶算法的应用.Nginx想必大家都有所了解是一个高性能的 HTTP 和反向代理服务器, ...
- Hystrix介绍以及服务的降级限流熔断
(dubbo熔断,Hystrix问的少) 无论是缓存层还是存储层都会有出错的概率,可以将它们视同为资源.作为并发量较大的系统,假如有一个资源不可用,可能会造成线程全部 hang (挂起)在这个资源上, ...
- Asp.Net Core 7 preview 4 重磅新特性--限流中间件
前言 限流是应对流量暴增或某些用户恶意攻击等场景的重要手段之一,然而微软官方从未支持这一重要特性,AspNetCoreRateLimit这一第三方库限流库一般作为首选使用,然而其配置参数过于繁多,对使 ...
- ASP.NET Core WebApi AspNetCoreRateLimit 限流中间件学习
AspNetCoreRateLimit介绍: AspNetCoreRateLimit是ASP.NET核心速率限制框架,能够对WebApi,Mvc中控制限流,AspNetCoreRateLimit包包含 ...
- 从-99打造Sentinel高可用集群限流中间件
接上篇Sentinel集群限流探索,上次简单提到了集群限流的原理,然后用官方给的 demo 简单修改了一下,可以正常运行生效. 这一次需要更进一步,基于 Sentinel 实现内嵌式集群限流的高可用方 ...
- 服务接口API限流 Rate Limit
一.场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统. 也就是面对大流量时,如何进行流量控制? 服务接口的流量 ...
- Golang微服务:Micro限流、熔断
Wrapper Wrapper提供了一种包装机制,使得在执行某方法前先执行Wrapper,优点Filter的意思:因此可以在客户端和服务器做很多功能:熔断限流.Filter.Auth等. client ...
- Laravel 限流中间件 throttle 简析
1. 在Laravel 中配置 在 app\Http\Kernel.php 中,默认添加到中间件组 api 下,1分钟60次. 2. 限流原理 获取唯一请求来源,进行唯一标识(key) 获取该请求请求 ...
- java 服务接口API限流 Rate Limit
一.场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统. 也就是面对大流量时,如何进行流量控制? 服务接口的流量 ...
随机推荐
- python基础练习题(九九乘法表)
又把python捡起来了,动手能力偏弱,决定每日一练,把基础打好! ------------------------------------------------------------------ ...
- JavaWeb和WebGIS学习笔记(六)——使用ArcGIS for Server发布地图服务
系列链接: Java web与web gis学习笔记(一)--Tomcat环境搭建 Java web与web gis学习笔记(二)--百度地图API调用 JavaWeb和WebGIS学习笔记(三)-- ...
- Gson解析:java.lang.IllegalArgumentException: declares multiple JSON fields named status 问题的解决
在一次写定义系统统一返回值的情况下,碰到了java.lang.IllegalArgumentException: declares multiple JSON fields named status这 ...
- XCTF练习题---MISC---hong
XCTF练习题---MISC---hong flag:BCTF{cute&fat_cats_does_not_like_drinking} 解题步骤: 1.观察题目,下载附件 2.下载文件后发 ...
- 为 ASP.NET Core (6.0)服务应用添加ApiKey验证支持
这个代码段演示了如何为一个ASP.NET Core项目中添加Apikey验证支持. 首先,通过下面的代码创建项目 dotnet new webapi -minimal -o yourwebapi 然后 ...
- 用 Go 快速开发一个 RESTful API 服务
何时使用单体 RESTful 服务 对于很多初创公司来说,业务的早期我们更应该关注于业务价值的交付,而单体服务具有架构简单,部署简单,开发成本低等优点,可以帮助我们快速实现产品需求.我们在使用单体服务 ...
- 力扣算法JS LC 59-螺旋矩阵2,LC 152-乘积最大子数组
LC 59-螺旋矩阵2 给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix . 示例 1: 输入:n = 3输出:[[1,2 ...
- 好客租房48-组件的props(基本使用)
组件是封闭的 要接受外部数据应该通过props来实现 props的作用:接受传递给组件的数据 传递数据:给组件标签添加属性 接收数据:函数组件通过参数props接收数据 类组件通过this.props ...
- 程序分析与优化 - 4 工作列表(worklist)算法
本章是系列文章的第四章,介绍了worklist算法.Worklist算法是图分析的核心算法,可以说学会了worklist算法,编译器的优化方法才算入门.这章学习起来比较吃力,想要融汇贯通的同学,建议多 ...
- 「NOI2019」序列
NKOJ卡常卡不过QAQ description 给两个A,B序列,让你分别在A,B中各选k个数,其中至少有L对下标相等. Solution 把问题转化为至多选n-K对下标不同的对. 配对问题就用费用 ...