首页 > 编程语言 >ASP.NET Core Web API 接口限流

ASP.NET Core Web API 接口限流

时间:2023-03-23 16:00:40浏览次数:43  
标签:Core ASP RateLimitInterface 限速 接口 并发 限流 public

一. 前言

ASP.NET Core Web API 接口限流、限制接口并发数量,我也不知道自己写的有没有问题,抛砖引玉、欢迎来喷!

二. 需求

  1. 写了一个接口,参数可以传多个人员,也可以传单个人员,时间范围限制最长一个月。简单来说,当传单个人员时,接口耗时很短,当传多个人员时,一般人员会较多,接口耗时较长,一般耗时几秒。
  2. 当传多个人员时,并发量高时,接口的耗时就很长了,比如100个用户并发请求,耗时可长达几十秒,甚至1分钟。
  3. 所以需求是,当传单个人员时,不限制。当传多个人员时,限制并发数量。如果并发用户数少于限制数,那么所有用户都能成功。如果并发用户数,超出限制数,那么超出的用户请求失败,并提示"当前进行XXX查询的用户太多,请稍后再试"。
  4. 这样也可以减轻被请求的ES集群的压力。

三. 说明

  1. 使用的是.NET6
  2. 我知道有人写好了RateLimit中间件,但我暂时还没有学会怎么使用,能否满足我的需求,所以先自己实现一下。

四. 效果截图

下面是使用jMeter并发测试时,打的接口日志:

ASP.NET Core Web API 接口限流_限流

五. 代码

1. RateLimitInterface

接口参数的实体类要继承该接口

using JsonA = Newtonsoft.Json;
using JsonB = System.Text.Json.Serialization;

namespace Utils
{
    /// <summary>
    /// 限速接口
    /// </summary>
    public interface RateLimitInterface
    {
        /// <summary>
        /// 是否限速
        /// </summary>
        [JsonA.JsonIgnore]
        [JsonB.JsonIgnore]
        bool IsLimit { get; }
    }
}

2. 接口参数实体类

继承RateLimitInterface接口,并实现IsLimit属性

public class XxxPostData : RateLimitInterface
{
    ...省略

    /// <summary>
    /// 是否限速
    /// </summary>
    [JsonA.JsonIgnore]
    [JsonB.JsonIgnore]
    public bool IsLimit
    {
        get
        {
            if (peoples.Count > 2) //限速条件,自己定义
            {
                return true;
            }
            return false;
        }
    }
}

3. RateLimitAttribute

作用:标签打在接口方法上,并设置并发数量

namespace Utils
{
    /// <summary>
    /// 接口限速
    /// </summary>
    public class RateLimitAttribute : Attribute
    {
        private Semaphore _sem;

        public Semaphore Sem
        {
            get
            {
                return _sem;
            }
        }

        public RateLimitAttribute(int limitCount = 1)
        {
            _sem = new Semaphore(limitCount, limitCount);
        }
    }
}

4. 使用RateLimitAttribute

标签打在接口方法上,并设置并发数量。
服务器好像是24核的,并发限制为8应该没问题。

[HttpPost]
[Route("[action]")]
[RateLimit(8)]
public async Task<List<XxxInfo>> Query([FromBody] XxxPostData data)
{
    ...省略
}

5. 限制接口并发量的拦截器RateLimitFilter

/// <summary>
/// 接口限速
/// </summary>
public class RateLimitFilter : ActionFilterAttribute
{
    public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        Type controllerType = context.Controller.GetType();
        object arg = context.ActionArguments.Values.ToList()[0];
        var rateLimit = context.ActionDescriptor.EndpointMetadata.OfType<RateLimitAttribute>().FirstOrDefault();

        bool isLimit = false; //是否限速
        if (rateLimit != null && arg is RateLimitInterface) //接口方法打了RateLimitAttribute标签并且参数实体类实现了RateLimitInterface接口时才限速,否则不限速
        {
            RateLimitInterface model = arg as RateLimitInterface;
            if (model.IsLimit) //满足限速条件
            {
                isLimit = true;
                Semaphore sem = rateLimit.Sem;

                if (sem.WaitOne(0)) //注意:超时时间为0,表示不等待
                {
                    try
                    {
                        await next.Invoke();
                    }
                    catch
                    {
                        throw;
                    }
                    finally
                    {
                        sem.Release();
                    }
                }
                else
                {
                    var routeList = context.RouteData.Values.Values.ToList();
                    routeList.Reverse();
                    var route = string.Join('/', routeList.ConvertAll(a => a.ToString()));
                    var msg = $"当前访问{route}接口的用户数太多,请稍后再试";
                    LogUtil.Info(msg);
                    context.Result = new ObjectResult(new ApiResult
                    {
                        code = (int)HttpStatusCode.ServiceUnavailable,
                        message = "当前查询的用户太多,请稍后再试。"
                    });
                }
            }
        }

        if (!isLimit)
        {
            await next.Invoke();
        }
    }
}

上述代码说明:sem.WaitOne(0)这个超时时间,最好是0,即不等待,否则高并发下会有问题。SemaphoreSlim的异步wait没试过。如果超时时间大于0,意味着,高并发下,会有大量的等待,异步等待也是等待。
SemaphoreSlim短时间是自旋,想象一下一瞬间产生大量自旋会怎么样?所以最好不等待,如果要等待,那代码还得再研究研究,经过测试才能用。

6. 注册拦截器

//拦截器
builder.Services.AddMvc(options =>
{
    ...省略

    options.Filters.Add<RateLimitFilter>();
});

六. 使用jMeter进行压力测试

测试结果:

  1. 被限速的接口,满足限速条件的调用并发量大时,部分用户成功,部分用户提示当前查询的人多请稍后再试。但不影响未满足限速条件的传参调用,也不影响其它未限速接口的调用。
  2. 测试的所有接口、所有查询参数条件的调用,耗时稳定,大量并发时,不会出现接口耗时几十秒甚至1分钟的情况。

七. 同时测试三个接口

测试三个接口,一个是触发限流的A接口,一个是未触发限流的A接口,一个是未被限流的B接口。

jMeter测试设置

触发限流的A接口,并发量设置为200:

ASP.NET Core Web API 接口限流_实体类_02


未触发限流的A接口以及未被限流的B接口,并发量设置为1:

ASP.NET Core Web API 接口限流_高并发_03

测试日志截图

ASP.NET Core Web API 接口限流_高并发_04


截图说明:可以看到被限流接口共1000次调用,只有大约40次调用是成功的,剩下的返回请稍后再试。

ASP.NET Core Web API 接口限流_高并发_05


截图说明:实际上触发限流的接口,并发量为8,压力依然很大,会拖慢自身以及其它接口,当触发限流的接口请求结束时,其它接口访问速度才正常。

八. 实际情况

  1. 这种接口计算量大,是难以支持高并发的,需要限流。争取客户的理解,仅支持少量用户在同一时间查询。
  2. 实际上只要用户错开几秒访问,接口的耗时就很正常。问题是,如何错开几秒呢?当用户看到"请稍后再试"的提示,关闭提示,重新点击查询,就可以错开了。如果一次两次不行,就多点几次查询。



标签:Core,ASP,RateLimitInterface,限速,接口,并发,限流,public
From: https://blog.51cto.com/u_5496753/6145629

相关文章

  • 微服务的熔断限流降级
    1、引言在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以相互调用(RPC)。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保......
  • ASP.NET Core - 选项系统之选项使用
    上一篇ASP.NETCore-选项系统之选项配置中提到IOptions、IOptionsMonitor和IOptionsSnapshot三个接口,通过这三个接口都可以从依赖注入容器中解析出已经配置的选项......
  • HCIP-Datacom-Core 1.4 OSPF Stub区域与NSSA区域
    前言:HCIP-core的OSPF实验拓扑就更新完啦1.4.1实验介绍实现OSPFStub区域的配置实现OSPFNSSA区域的配置描述Type7LSA的内容描述Type7LSA与Type5LSA......
  • JasperReport 如何利用list嵌套list循环展示数据
    https://www.wanaright.com/2021/01/26/jasperreport-list-nest-list/需求描述有时候我们在做JasperReport报表的时候时常会遇到利用list循环数据的问题。这时候用......
  • ASP.NET Web API 实现 Token 验证代码
    publicclassTokenController:ApiController//定义一个名为TokenController的类,继承自ApiController类。{[HttpPost]//使用HTTPPOST请求方式。p......
  • 《渗透测试》WEB攻防-ASP安全&MDB下载植入&IIS短文件名&写权限&解析 2022 Day18
    1  ➢ ASP-数据库-MDB默认下载➢ ASP-数据库-ASP后门植入连接➢ ASP-中间件-IIS短文件名探针-安全漏洞➢ ASP-中间件-IIS文件上传解析-安全漏洞➢ ASP-中......
  • ASP.NET Core API模型绑定和Action数据返回格式
    参考文档:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_20.html模型绑定[FromQuery]-从URL中取值。[FromRoute]-从路由中取值。[FromForm]-从表单中取值。Pos......
  • ASP.NET Core 诊断工具
    .NETCore诊断全局工具.NETCore诊断工具官方地址dotnet-countersdotnet-counters是一个性能监视工具,用于初级运行状况监视和性能调查。它通过EventCounterAPI观......
  • 关于asp.net core filters生命周期的探究
    1.背景昨天看了关于一篇api限流的文章,ASP.NETCoreWebApi接口限流,作者给出了demo,写的很好,但是我看了一遍,api限流用actionfilterattribute,觉得很奇怪,难道说每次都是用的......
  • .NET Core WebApi接口ip限流实践
    .NETCoreWebApi接口ip限流实践前言之前一直想实现接口限流,但一直没去实现,然后刚好看到一篇文章是基于AspNetCoreRateLimit组件的限流策略。这个组件不做多的介绍,想了......