使用lua语言做高并发限流,lua语言并发限


https://blog.csdn.net/shecanwin/article/details/51719746 

lua语言介绍

       Lua[1]  是一个小巧的脚本语言。是巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组,由Roberto Ierusalimschy、Waldemar Celes 和 Luiz Henrique de Figueiredo所组成并于1993年开发。 其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。Lua由标准C编写而成,几乎在所有操作系统和平台上都可以编译,运行。Lua并没有提供强大的库,这是由它的定位决定的。所以Lua不适合作为开发独立应用程序的语言。Lua 有一个同时进行的JIT项目,提供在特定平台上的即时编译功能。(引自百度百科)

      其实,关于lua只需知道两点,类c的语言语法和较高的性能。这让lua语言在游戏开发或者项目某些组件的开发时常常用到lua,游戏开发啥的咱也不懂,这次就主要说一下我在某个项目中使用lua开发的限流模块。

lua限流模块

      该项目是国内某知名公司的项目,对项目的可用性要求很高,在访问量非常大的情况下保证项目的服务能力,所以一定要对项目访问做限流。限流的整体思路是根据用户的访问ip、cookie、访问的uri来进行计数,达到一定数量之后就 限制访问。这应该是限流算法中的计数法,另外还有令牌算法和漏桶算法,不再详细介绍。

     模块的流程图如下:

   

     下面根据流程图来分解代码。

  首先,是系统初始化,初始化主要做一些内存分配,名单载入的工作,


 


 


 

可以看得出来,刚开始做的就是把几个缓存区刷新,然后根据要求载入ip黑白名单、uri黑白名单等,最后加入了一个叫做statics_uri的文件,这个文件的作用是把需要统计监测的uri记录下来,并不是把所有的uri都监测起来,那样肯定不现实,一个大的web项目会有很多uri,只能说找出几个比较重要的来监测和控制。对了,这些内存实在配置文件中设置好的,使用了nginx-lua模块,具体的环境配置可以看我另外一篇教程。


 

配置文件上来先配置了lua文件的根目录,还有lua库的目录,然后根据需要分配了ip黑名单、ip白名单等几个缓存区,以及初始化lua文件的指定,log阶段的处理文件,还有一个定时任务的lua文件。其中初始化文件就是刚才说的那个文件,叙述顺序有点乱哈,见谅!

       定义好这些准备工作之后,就可以来看看系统是怎么做到限流的,要使用这个模块,在需要检测的location中添加配置:

     access_by_lua_file ,这个配置项的值是access.lua的路径,access是整个项目进行限流的核心文件,当一个请求到达nginx时候,会首先由这个文件来判断是否能进行下一步的访问,如果能,就提供服务,不能的话返回403。下边贴出access的代码:


 

这个文件的逻辑是,先判断这个请求的ip地址是不是在黑名单、白名单,如果是在黑名单则拒绝访问,白名单的话则任何情况下不会禁止访问,urihi额白名单类似,也是这样一个判断逻辑。然后呢,就是判断这个ip地址的访问频率是不是超过了要求,这里多加了一个ip和uri共同的这样的一个标准判断,如果同一个ip地址在同一时间内访问某一个uri超过了规定的次数,就返回403。uri的判断标准也是一样的。那么,这个判断的标准怎么产生的呢,是不是记录了访问次数啊?跟这个差不多,但是更复杂一些,也更能适应高并发压力一些。下边以ip为准说明这个问题,首先每一个ip进来都会被记录,键值为ip,value为次数,但是呢,这个统计并不是一个长时间的统计,而是一段时间,比方说只统计3秒内的访问量,然后计算平均值,如果这个平均值超过了这一要求,也并不是就马上封掉这个ip,而是再统计几个相同的时间段,如果这几个时间段内均超过要求的频率,那么这时候才封掉这个ip。为什么要这么做呢,是因为封掉一个ip不是很随意的就封掉,有可能这个ip确实是在某一个时间段内需要这个高频率的访问,但是并不是恶意的,这个时候直接把他封掉,就不合适了,所以要看几个时间段内的访问情况,再来确定是不是要封掉。那怎么让系统知道这个ip已经被疯掉了呢,很简单,把这个ip保存到redis中。上边所说的ip检查就是去redis里查询这个。这里又有一个问题,既然之前保存黑白名单用的是nginx的缓存,也就是本地内存,为什么保存这个标志的时候去用了redis,这个主要是因为在我这个项目中,我们刚好用到了redis,而且服务器的数量偏多,为了做到精确控制,才这么做的。当然也可以直接使用本地缓存来保存这个,这样的话就是只针对这一台服务器,而不是整个集群做限流。

相关内容

    暂无相关文章