张木木 发表于 2023-3-9 18:37:58

ASP.NET Core Web API 接口限流

前言

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


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


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

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

代码

RateLimitInterface

接口参数的实体类要继承该接口
using JsonA = Newtonsoft.Json;
using JsonB = System.Text.Json.Serialization;

namespace Utils
{
    /// <summary>
    /// 限速接口
    /// </summary>
    public interface RateLimitInterface
    {
      /// <summary>
      /// 是否限速
      /// </summary>
      
      
      bool IsLimit { get; }
    }
}接口参数实体类

继承RateLimitInterface接口,并实现IsLimit属性
public class XxxPostData : RateLimitInterface
{
    ...省略

    /// <summary>
    /// 是否限速
    /// </summary>
   
   
    public bool IsLimit
    {
      get
      {
            if (peoples.Count > 2) //限速条件,自己定义
            {
                return true;
            }
            return false;
      }
    }
}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);
      }
    }
}使用RateLimitAttribute

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

")]

public async Task<List<XxxInfo>> Query( XxxPostData data)
{
    ...省略
}限制接口并发量的拦截器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();
      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))
                {
                  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.BadRequest,
                        message = msg
                  });
                }
            }
      }

      if (!isLimit)
      {
            await next.Invoke();
      }
    }
}注册拦截器

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

    options.Filters.Add<RateLimitFilter>();
});使用jMeter进行压力测试

测试结果:

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

来源:https://www.cnblogs.com/s0611163/archive/2023/03/09/17199379.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: ASP.NET Core Web API 接口限流