前言

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

需求

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

说明

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

效果截图

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

代码

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; }
}
}

接口参数实体类

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

public class XxxPostData : RateLimitInterface
{
...省略 /// <summary>
/// 是否限速
/// </summary>
[JsonA.JsonIgnore]
[JsonB.JsonIgnore]
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应该没问题。

[HttpPost]
[Route("[action]")]
[RateLimit(8)]
public async Task<List<XxxInfo>> Query([FromBody] 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()[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))
{
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. 被限速的接口,满足限速条件的调用并发量大时,部分用户成功,部分用户提示当前查询的人多请稍后再试。但不影响未满足限速条件的传参调用,也不影响其它未限速接口的调用。
  2. 测试的所有接口、所有查询参数条件的调用,耗时稳定,大量并发时,不会出现接口耗时几十秒甚至1分钟的情况。

最新文章

  1. IIS 7.0 部署MVC
  2. (5) 深入理解Java Class文件格式(四)
  3. Swift游戏实战-跑酷熊猫 14 熊猫打滚
  4. IEEE802.11数据帧在Linux上的抓取
  5. poj 3249 Test for Job (DAG最长路 记忆化搜索解决)
  6. C#错误:The Controls collection cannot be modified
  7. python list 去重
  8. matlab等高线绘制
  9. 使用Let&#39;s Encrypt生成免费SSL证书操作记录
  10. Django web编程2 -- 编辑页面内容
  11. 【Python3爬虫】网易云音乐歌单下载
  12. mixins混入
  13. c——简单排序
  14. 集合排序 Comparator和Comparable的使用区别
  15. vue中Axios请求豆瓣API数据并展示到Swipe中
  16. 2016-2017-2 20155312 实验三敏捷开发与XP实践实验报告
  17. Linux学习笔记:cp和scp复制文件
  18. C++ 标准头文件与C头文件区别与联系以及C风格字符串
  19. 0001_mysql 5.7.25安装初始化
  20. Maven项目中Spring整合Mybatis

热门文章

  1. 051_Lightning 定义 直接翻译来的
  2. vue3+ts获取dom元素高度
  3. 解决xpath提取的数据列表,保存时不能一一对应的问题
  4. flutter-linux(未完成)
  5. 实验:STM32-ARDUINO-ESP01采用AT指令,通过MQTT连接上ONENET
  6. [2004年NOIP提高组] 合并果子
  7. 在使用admin后台管理,添加或者修改数据库时,出现错误,no such table: main.auth_user__old
  8. Jetpack compose学习笔记之ConstraintLayout(布局)
  9. What is the Best Python IDE for Data Science?
  10. linux基础命令4