.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
一.场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统. 也就是面对大流量时,如何进行流量控制? 服务接口的流量 ...
随机推荐
- docker入门_image、container相关命令
docker入门_image.container相关命令 镜像仓库服务.镜像仓库.镜像相关概念 镜像仓库服务:docker镜像仓库服务.阿里云镜像服务 镜像仓库:docker镜像仓库服务中会有很多仓库 ...
- MATLAB地图工具箱学习心得(二)设计可变参数和位置拾取的“放大镜”式投影程序
最近刚好因为一些原因整理这方面的内容,所以还是把这篇鸽了一年多的博客顺手写出来了∠( ᐛ 」∠)_.因为是当时课程设计的一部分,程序上难免会有一些不足和bug,在这里将设计的思路分享给大家. 本篇博客 ...
- PicLite 开发日志 v0.0.2
PicLite 开发日志 (v0.0.2) 感谢您阅读本片文章! Gitee 地址:https://gitee.com/XiaoQuQuSD/pic-lite. 新增功能 添加复制 url 的格式选项 ...
- 【原创】浅谈指针(十二)关于static(上)
0.前言 这个系列基本上是一月一更到两月一更 今天写一篇关于static的,内含大量干货,做好准备 1.基础知识的回顾 1.1.内存的种类 一般来说,我们之前已经讲过的变量(或者说是内存)可以大体分为 ...
- 最新 x86_64 系统调用入口分析 (基于 5.7.0)
最新 x86_64 系统调用入口分析 (基于5.7.0) 整体概览 最近的工作涉及系统调用入口,但网上的一些分析都比较老了,这里把自己的分析过程记录一下,仅供参考. x86_64位系统调用使用 SYS ...
- RabbitMQ 3.9( 基础 )
1.认识MQ 1.1.什么是MQ? MQ全称:message queue 即 消息队列 这个队列遵循的原则:FIFO 即 先进先出 队列里面存的就是message 1.2.为什么要用MQ? 1.2.1 ...
- SpringCloud Gateway 漏洞分析 (CVE-2022-22947)
背景 SpringCloud 是Spring提供的微服务实现框架,其中包含网关.配置中心和注册中心等内容,网关的第一代实现为zuul,第二代实现为Gateway,提供了更好的性能和特性. 网关可以提供 ...
- Redis设计与实现3.2:Sentinel
Sentinel哨兵 这是<Redis设计与实现>系列的文章,系列导航:Redis设计与实现笔记 哨兵:监视.通知.自动故障恢复 启动与初始化 Sentinel 的本质只是一个运行在特殊模 ...
- 好客租房9-jsx的学习目标
1能够知道什么是jsx 2能够使用jsx创建react元素 3能够在jsx使用javascript表达式 4能够使用jsx的条件渲染和列表渲染 5能够给jsx添加样式 jsx的基本使用 jsx中使用j ...
- k8s client-go源码分析 informer源码分析(4)-DeltaFIFO源码分析
client-go之DeltaFIFO源码分析 1.DeltaFIFO概述 先从名字上来看,DeltaFIFO,首先它是一个FIFO,也就是一个先进先出的队列,而Delta代表变化的资源对象,其包含资 ...