ASP.NET Core中间件实现限流的代码

 更新时间:2022年03月01日 14:10:58   作者:愚公搬代码  
这篇文章主要介绍了ASP.NET Core中间件实现限流的方法,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

一、限流算法

在高并发系统中,有三把利器用来保护系统:缓存、降级和限流。

本文主要是介绍限流,限流算法主要有以下三种:

1.计数器算法

  • 固定窗口
  • 滑动窗口

2.令牌桶算法

3.漏桶算法

1.计数器算法

1.1 固定窗口算法

计数器算法是限流算法里最简单也是最容易实现的一种算法。比如我们规定,对于A接口来说,我们1分钟的访问次数不能超过100个。那么我们可以这么做:在一开 始的时候,我们可以设置一个计数器counter,每当一个请求过来的时候,counter就加1,如果counter的值大于100并且该请求与第一个 请求的间隔时间还在1分钟之内,那么说明请求数过多;如果该请求与第一个请求的间隔时间大于1分钟,且counter的值还在限流范围内,那么就重置 counter。

java中的具体实现如下:

public class CounterTest {
    public long timeStamp = getNowTime();
    public int reqCount = 0;
    public final int limit = 100; // 时间窗口内最大请求数
    public final long interval = 1000; // 时间窗口ms

    public boolean grant() {
        long now = getNowTime();
        if (now < timeStamp + interval) {
            // 在时间窗口内
            reqCount++;
            // 判断当前时间窗口内是否超过最大请求控制数
            return reqCount <= limit;
        } else {
            timeStamp = now;
            // 超时后重置
            reqCount = 1;
            return true;
        }
    }

    public long getNowTime() {
        return System.currentTimeMillis();
    }
}

.NET Core中的具体实现如下:

AspNetCoreRateLimit是目前ASP.NET Core下最常用的限流解决方案,AspNetCoreRateLimit的源码实现是固定窗口算法如下:

var entry = await _counterStore.GetAsync(counterId, cancellationToken);

if (entry.HasValue)
{
    // entry has not expired
    if (entry.Value.Timestamp + rule.PeriodTimespan.Value >= DateTime.UtcNow)
    {
        // increment request count
        var totalCount = entry.Value.Count + _config.RateIncrementer?.Invoke() ?? 1;
        // deep copy
        counter = new RateLimitCounter
        {
            Timestamp = entry.Value.Timestamp,
            Count = totalCount
        };
    }
}

固定窗口算法缺点

在这里插入图片描述

从上图中我们可以看到,假设有一个恶意用户,他在0:59时,瞬间发送了100个请求,并且1:00又瞬间发送了100个请求,那么其实这个用户在 1秒里面,瞬间发送了200个请求。我们刚才规定的是1分钟最多100个请求,也就是每秒钟最多1.7个请求,用户通过在时间窗口的重置节点处突发请求, 可以瞬间超过我们的速率限制。用户有可能通过算法的这个漏洞,瞬间压垮我们的应用。

1.2 滑动窗口算法

滑动窗口类似于固定窗口算法,但它通过将前一个窗口中的加权计数添加到当前窗口中的计数来计算估计数,如果估计数超过计数限制,则请求将被阻止。

具体公式如下:

估计数 = 前一窗口计数 * (1 - 当前窗口经过时间 / 单位时间) + 当前窗口计数

在这里插入图片描述

窗口[00:00, 00:01)中有9个请求,窗口[00:01, 00:02)中有5个请求。对于01:15到达的请求,即窗口[00:01, 00:02)的25%位置,通过公式计算请求计数:9 x (1 - 25%) + 5 = 11.75 > 10. 因此我们拒绝此请求。

即使两个窗口都没有超过限制,请求也会被拒绝,因为前一个和当前窗口的加权和确实超过了限制。

2.令牌桶算法

令牌桶算法是比较常见的限流算法之一,大概描述如下:
1)所有的请求在处理之前都需要拿到一个可用的令牌才会被处理;
2)根据限流大小,设置按照一定的速率往桶里添加令牌;
3)桶设置最大的放置令牌限制,当桶满时、新添加的令牌就被丢弃或者拒绝;
4)请求达到后首先要获取令牌桶中的令牌,拿着令牌才可以进行其他的业务逻辑,处理完业务逻辑之后,将令牌直接删除;
5)令牌桶有最低限额,当桶中的令牌达到最低限额的时候,请求处理完之后将不会删除令牌,以此保证足够的限流;

在这里插入图片描述

3.漏桶算法

漏桶算法其实很简单,可以粗略的认为就是注水漏水过程,往桶中以一定速率流出水,以任意速率流入水,当水超过桶流量则丢弃,因为桶容量是不变的,保证了整体的速率。

在这里插入图片描述

二、ASP.NET Core中间件实现限流

1.中间件代码

public class SlidingWindow
{
    private readonly object _syncObject = new object();

    private readonly int _requestIntervalSeconds;
    private readonly int _requestLimit;
    private DateTime _windowStartTime;
    private int _prevRequestCount;
    private int _requestCount;
    public SlidingWindow(int requestLimit, int requestIntervalSeconds)
    {
        _windowStartTime = DateTime.Now;
        _requestLimit = requestLimit;
        _requestIntervalSeconds = requestIntervalSeconds;
    }
    public bool PassRequest()
        lock (_syncObject)
        {
            var currentTime = DateTime.Now;
            var elapsedSeconds = (currentTime - _windowStartTime).TotalSeconds;
            if (elapsedSeconds >= _requestIntervalSeconds * 2)
            {
                _windowStartTime = currentTime;
                _prevRequestCount = 0;
                _requestCount = 0;
                elapsedSeconds = 0;
            }
            else if (elapsedSeconds >= _requestIntervalSeconds)
                _windowStartTime = _windowStartTime.AddSeconds(_requestIntervalSeconds);
                _prevRequestCount = _requestCount;
                elapsedSeconds = (currentTime - _windowStartTime).TotalSeconds;
            } 
            var requestCount = _prevRequestCount * (1 - elapsedSeconds / _requestIntervalSeconds) + _requestCount + 1;
            if (requestCount <= _requestLimit)
                _requestCount++;
                return true;
        }
        return false;
}

如果最近的2次请求相距2个窗口时间,则可以认为前一窗口计数为0,重新开始计数。

public class RateLimitMiddleware : IMiddleware
{
    private readonly SlidingWindow _window;

    public RateLimitMiddleware()
    {
        _window = new SlidingWindow(10, 60);
    }
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        if (!_window.PassRequest())
        {
            context.SetEndpoint(new Endpoint((context) =>
            {
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                return Task.CompletedTask;
            },
                        EndpointMetadataCollection.Empty,
                        "限流"));
        }

        await next(context);
    }
}

2.在管道中的使用

需要注意的是,我们注册Middleware时,必须使用单例模式,保证所有请求通过同一SlidingWindow计数:

services.AddSingleton<RateLimitMiddleware>();

到此这篇关于ASP.NET Core中间件-限流的文章就介绍到这了,更多相关ASP.NET Core中间件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • ASP.NET Core文件上传与下载实例(多种上传方式)

    ASP.NET Core文件上传与下载实例(多种上传方式)

    下面小编就为大家分享一篇ASP.NET Core文件上传与下载实例(多种上传方式),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • .NET Core简单读取json配置文件

    .NET Core简单读取json配置文件

    这篇文章主要为大家详细介绍了.NET Core简单读取json配置文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • Entity Framework Core实现Like查询详解

    Entity Framework Core实现Like查询详解

    本文详细讲解了Entity Framework Core实现Like查询的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • aspx实现的 jquery ui 的 flexgrid demo

    aspx实现的 jquery ui 的 flexgrid demo

    这几天没事研究着jquery,真是个好东西,慢慢的知道了有jquery ui,一开始就被华丽的界面和简单的操作给吸引了,尤其是里面的flexgrid,对我而言可以说是非常宝贵的东西
    2009-12-12
  • 详解Asp.Net Core 2.1+的视图缓存(响应缓存)

    详解Asp.Net Core 2.1+的视图缓存(响应缓存)

    本篇文章给大家通过实例讲述了Asp.Net Core 2.1+的视图缓存(响应缓存)的相关知识点,对此有兴趣的读者们可以学习下。
    2018-03-03
  • MVC5下拉框绑定的方法(单选)

    MVC5下拉框绑定的方法(单选)

    这篇文章主要为大家详细介绍了MVC5下拉框绑定,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • 基于.NET程序默认启动线程数讲解

    基于.NET程序默认启动线程数讲解

    本篇文章小编为大家介绍,基于.NET程序默认启动线程数讲解。需要的朋友参考下
    2013-04-04
  • asp.net一些很酷很实用的.Net技巧

    asp.net一些很酷很实用的.Net技巧

    方便使用asp.net编程的朋友,都是一些非常有用的东西
    2008-08-08
  • ASP.NET中Config文件的读写示例

    ASP.NET中Config文件的读写示例

    通常我们在.NET开发过程中,会接触二种类型的配置文件:config文件,xml文件,下面这篇文章主要给大家介绍了关于ASP.NET中Config文件读写的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-08-08
  • 在ASP.NET中读写XML数据的多种方法

    在ASP.NET中读写XML数据的多种方法

    在ASP.NET日常开发中,XML(可扩展标记语言)是一种常用的数据交换格式,它被广泛用于配置文件、数据传输和Web服务等场景,在.NET框架中,提供了多种类和方法来读写XML数据,以下是对ASP.NET中读写XML的详解,需要的朋友可以参考下
    2025-01-01

最新评论