.net 接口调用接口发送文件_.Net 如何模拟会话级别的信号量,对接口调用频率进行限制...

本文探讨如何在.NET中实现接口调用频率限制,以防止过度访问和DDoS攻击。文章通过示例说明了单机环境下基于信号量的限制方法,指出HttpRuntime.Cache的不足,并提出了会话级别的信号量解决方案。此外,还介绍了分布式环境下利用Redis的有序集合进行频率限制,以及使用Lua脚本优化性能。
摘要由CSDN通过智能技术生成

现在,因为种种因素,你必须对一个请求或者方法进行频率上的访问限制。

比如, 你对外提供了一个API接口,注册用户每秒钟最多可以调用100次,非注册用户每秒钟最多可以调用10次。

比如, 有一个非常吃服务器资源的方法,在同一时刻不能超过10个人调用这个方法,否则服务器满载。

比如, 有一些特殊的页面,访客并不能频繁的访问或发言。

比如, 秒杀活动等进行。

比如 ,防范DDOS,当达到一定频率后调用脚本iis服务器ip黑名单,防火墙黑名单。

如上种种的举例,也就是说,如何从一个面向切面的方式对调用的方法进行频率上的限制。而对频率限制,服务器层面都有最直接的解决方法,现在我说的则是代码层面上的频率管控。

本文给出两个示例,一个是基于单机环境的实现,第二个则是基于分布式的Redis实现

以第一个API接口需求为例,先说下单机环境下的实现。

按照惯性思维,我们自然会想到缓存的过期策略这种方法,但是严格来讲就HttpRuntime.Cache而言,通过缓存的过期策略来对请求进行频率的并发控制是不合适的。

HttpRuntime.Cache 是应用程序级别的Asp.Net的缓存技术,通过这个技术可以申明多个缓存对象,可以为每个对象设置过期时间,当过期时间到达后该缓存对象就会消失(也就是当你访问该对象的时候为Null)

为什么这样说呢?比如对某个方法(方法名:GetUserList)我们要进行1秒钟最多10次的限制,现在我们就新建一个int型的Cache对象,然后设置1秒钟后过期消失。那么每当访问GetUserList方法前,我们就先判断这个Cache对象的值是否大于10,如果大于10就不执行GetUserList方法,如果小于10则允许执行。每当访问该对象的时候如果不存在或者过期就新建,这样周而复始,则该对象永远不可能超过10。

 if ((int)HttpRuntime.Cache["GetUserListNum"] > 10) //大于10请求失败 { Console.WriteLine("禁止请求"); } else { HttpRuntime.Cache["GetUserListNum"] = (int)HttpRuntime.Cache["GetUserListNum"] + 1; //否则该缓存对象的值+1 Console.WriteLine("允许请求"); }

这样的思想及实现相对来说非常简单,但是基于这样的一个模型设定,那么就会出现这种情况:

20c5d7c4e2c2a3c78d12f997305a2d04.png

如上图,每个点代表一次访问请求,我在0秒的时候 新建了一个名字为GetUserListNum的缓存对象。

在0~0.5秒期间 我访问了3次,在0.5~1秒期间,我们访问了7次。此时,该对象消失,然后我们接着访问,该对象重置为0.

在第1~1.5秒期间,还是访问了7次,在第1.5秒~2秒期间访问了3次。

基于这种简单缓存过期策略的模型,在这2秒钟内,我们虽然平均每秒钟都访问了10次,满足这个规定,但是如果我们从中取一个期间段,0.5秒~1.5秒期间,也是1秒钟,但是却实实在在的访问了14次!远远超过了我们设置的 1秒钟最多访问10次的 限制。

那么如何科学的来解决上面的问题呢?我们可以通过模拟会话级别的信号量这一手段,这也就是我们今天的主题了。

什么是信号量?

仅就以代码而言, static SemaphoreSlim semaphoreSlim = new SemaphoreSlim(5); 它的意思就代表在多线程情况下,在任何一时刻,只能同时5个线程去访问。

4容器4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值