常见的应用限流手段

应用开发中常见的限流的都有哪些呢?其实常用的限流手段都比较简单,关键都是限流服务的高并发。为了在LB上实现高效且有效的限流,普遍的做法都是Nginx+Lua或者Nginx+Redis去实现服务服务限流,所以市面上比较常用的waf框架都是基于Openresty去实现的。我们看下比较常用的几个限流方式。

Openresty+共享内存实现的计数限流

先看下代码限流代码

lua_shared_dict limit_counter 10m; server { listen 80; server_name www.test.com; location / { root html; index index.html index.htm; }  location /test { access_by_lua_block { local function countLimit() local limit_counter =ngx.shared.limit_counter local key = ngx.var.remote_addr .. ngx.var.http_user_agent .. ngx.var.uri .. ngx.var.host local md5Key = ngx.md5(key) local limit = 10 local exp = 300 local current =limit_counter:get(key) if current ~= nil and current + 1> limit then return 1 end if current == nil then limit_counter:add(key, 1, exp) else limit_counter:incr(key, 1) end return 0 end  local ret = countLimit() if ret > 0 then ngx.exit(405) end } content_by_lua 'ngx.say(111)'; } }

解释下上面这段简单的代码,对于相同的IP UA HOST URI组合的唯一KEY,就是同一个URI每个用户在5分钟内只允许有10次请求,如果超过10次请求,就返回405的状态码,如果小于10次,就继续执行后面的处理阶段。
看下访问结果

curlhttp://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test 111 curl http://www.test.com/test <html> <head><title>405 Not Allowed</title></head> <body bgcolor="white"> <center><h1>405 Not Allowed</h1></center> <hr><center>openresty/1.13.6.2</center> </body> </html>

这就是一个简单的计数限流的例子

Openresty 限制连接数和请求数的模块

限制连接数和请求数的模块是 lua-resty-limit-traffic。它的限速实现基于以前说过的漏桶原理。
蓄水池一边注水一边放水的问题。 这里注水的速度是新增请求/连接的速度,而放水的速度则是配置的限制速度。 当注水速度快于放水速度(表现为池中出现蓄水),则返回一个数值 delay。调用者通过 ngx.sleep(delay) 来减慢注水的速度。 当蓄水池满时(表现为当前请求/连接数超过设置的 burst 值),则返回错误信息 rejected。调用者需要丢掉溢出来的这部份。
看下配置代码

http { lua_shared_dict my_req_store 100m; lua_shared_dict my_conn_store 100m;  server { location / { access_by_lua_block { local limit_conn = require "resty.limit.conn" local limit_req = require "resty.limit.req" local limit_traffic = require "resty.limit.traffic"  local lim1, err = limit_req.new("my_req_store", 300, 150) --300r/s的频率,大于300小于450就延迟大概0.5秒,超过450的请求就返回503错误码 local lim2, err = limit_req.new("my_req_store", 200, 100) local li