概述

FireflySoft.RateLimit自2021年1月发布第一个版本以来,经历了多次升级迭代,目前已经十分稳定,被很多开发者应用到了生产系统中,最新发布的版本是3.0.0。

它的核心是一个基于 .NET Standard 的限流类库,其内核简单轻巧,能够灵活应对各种需求的限流场景。其主要特点包括:

  • 多种限流算法:内置固定窗口、滑动窗口、漏桶、令牌桶四种算法,方便自定义扩展。
  • 多种计数存储:目前支持内存、Redis(含集群)两种存储方式。
  • 分布式友好:通过Redis存储支持分布式程序统一计数。
  • 限流目标灵活:可以从请求中提取各种数据用于设置限流目标,不仅仅是客户端IP和Id。
  • 支持限流惩罚:可以在客户端触发限流后锁定一段时间不允许其访问。
  • 时间窗口增强:支持到毫秒级别;支持从秒、分钟、小时、日期等时间周期的自然起始点开始。
  • 实时限流跟踪:当前计数周期内已处理的请求数、剩余允许请求数,以及计数周期重置的时间。
  • 动态更改规则:支持程序运行时动态更改限流规则。
  • 自定义错误:可以自定义触发限流后的错误码和错误消息。
  • 普适性:原则上可以满足任何需要限流的场景,可用于各种B/S、C/S程序。

基于这个核心又实现了两个中间件:

相比使用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就会被限流。

规则中还有其它几个属性,不同算法的规则也略有不同,这里就不一一列举了。感兴趣的朋友可以去示例代码单元测试中认识它们。

一个算法中可以添加多个对应算法的规则,这无疑会比较灵活。

更多使用说明


以上就是本文的主要内容了,如有问题欢迎留言交流。

.NET服务治理之限流中间件-FireflySoft.RateLimit的更多相关文章

  1. 服务接口API限流 Rate Limit 续

    一.前言 上一篇文章中粗浅的介绍使用Redis和基于令牌桶算法进行对服务接口API限流,本文介绍另一种算法---漏桶算法的应用.Nginx想必大家都有所了解是一个高性能的 HTTP 和反向代理服务器, ...

  2. Hystrix介绍以及服务的降级限流熔断

    (dubbo熔断,Hystrix问的少) 无论是缓存层还是存储层都会有出错的概率,可以将它们视同为资源.作为并发量较大的系统,假如有一个资源不可用,可能会造成线程全部 hang (挂起)在这个资源上, ...

  3. Asp.Net Core 7 preview 4 重磅新特性--限流中间件

    前言 限流是应对流量暴增或某些用户恶意攻击等场景的重要手段之一,然而微软官方从未支持这一重要特性,AspNetCoreRateLimit这一第三方库限流库一般作为首选使用,然而其配置参数过于繁多,对使 ...

  4. ASP.NET Core WebApi AspNetCoreRateLimit 限流中间件学习

    AspNetCoreRateLimit介绍: AspNetCoreRateLimit是ASP.NET核心速率限制框架,能够对WebApi,Mvc中控制限流,AspNetCoreRateLimit包包含 ...

  5. 从-99打造Sentinel高可用集群限流中间件

    接上篇Sentinel集群限流探索,上次简单提到了集群限流的原理,然后用官方给的 demo 简单修改了一下,可以正常运行生效. 这一次需要更进一步,基于 Sentinel 实现内嵌式集群限流的高可用方 ...

  6. 服务接口API限流 Rate Limit

    一.场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统. 也就是面对大流量时,如何进行流量控制? 服务接口的流量 ...

  7. Golang微服务:Micro限流、熔断

    Wrapper Wrapper提供了一种包装机制,使得在执行某方法前先执行Wrapper,优点Filter的意思:因此可以在客户端和服务器做很多功能:熔断限流.Filter.Auth等. client ...

  8. Laravel 限流中间件 throttle 简析

    1. 在Laravel 中配置 在 app\Http\Kernel.php 中,默认添加到中间件组 api 下,1分钟60次. 2. 限流原理 获取唯一请求来源,进行唯一标识(key) 获取该请求请求 ...

  9. java 服务接口API限流 Rate Limit

    一.场景描述 很多做服务接口的人或多或少的遇到这样的场景,由于业务应用系统的负载能力有限,为了防止非预期的请求对系统压力过大而拖垮业务应用系统. 也就是面对大流量时,如何进行流量控制? 服务接口的流量 ...

随机推荐

  1. mongodb 数据块的迁移流程介绍

    1. 基本概念 1.1 Chunk(数据块) 表示特定服务器上面,连续范围的分片键值所包含的一组数据,是一个逻辑概念. 例如,某数据块记录如下: { "_id" : "c ...

  2. C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解

    系列目录     [已更新最新开发文章,点击查看详细] 在我的博客<C#二次开发BIMFACE系列61 File Management文件管理服务接口二次开发及实战详解>最后列出了 Fil ...

  3. 最大数maxnumber - 题解【树状数组】

    原题: 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度. 2. 插入操作.语法 ...

  4. k8s入门之namespace(三)

    namespace的作用就是用来隔离资源,将同一集群中的资源划分为相互隔离的组.同一名称空间内的资源名称要唯一,但不同名称空间时没有这个要求.有些k8s资源对象与名称空间没有关系,例如 Storage ...

  5. XCTF练习题---MISC---hit-the-core

    XCTF练习题---MISC---hit-the-core flag:ALEXCTF{K33P_7H3_g00D_w0rk_up} 解题步骤: 1.观察题目,下载附件,发现是一个.core文件 2.打 ...

  6. python数据可视化-matplotlib入门(5)-饼图和堆叠图

    饼图常用于统计学模块,画饼图用到的方法为:pie( ) 一.pie()函数用来绘制饼图 pie(x, explode=None, labels=None, colors=None, autopct=N ...

  7. 定时 ——setTimeout | setInterval

    使用场景,setTimeout 只调用一次,setInterval 会重复调用,直到清除或重载. <div id="countDown"></div> &l ...

  8. Resource wordnet not found. Please use the NLTK Downloader to obtain the resource:

    第一次使用nltk的时候,出现了这样的错误: from nltk.stem.wordnet import WordNetLemmatizer lemmatizer = WordNetLemmatize ...

  9. 通过Go实现AES加密和解密工具

    本文包含如下两个内容: AES加密介绍及实现原理 Go实现AES加密和解密工具 AES加密介绍及实现原理 AES( advanced encryption standard)使用相同密钥进行加密和解密 ...

  10. Android 子线程 UI 操作真的不可以?

    作者:vivo 互联网大前端团队- Zhang Xichen 一.背景及问题 某 SDK 有 PopupWindow 弹窗及动效,由于业务场景要求,对于 App 而言,SDK 的弹窗弹出时机具有随机性 ...