resty.limit.conn 限制併發請求的lua模塊
限制接口總併發數
場景:按照 ip 限制其併發鏈接數nginx
1.共享內存加入到nginx的http標籤:算法
[root@VM_82_178_centos vhost]# grep my_limit_conn_store /usr/local/openresty/nginx/conf/nginx.conf lua_shared_dict my_limit_conn_store 10m;
2.limit.conn.lua 模塊lua腳本以下:centos
[root@VM_82_178_centos limit_lua]# cat /usr/local/openresty/nginx/conf/limit_lua/limit.conn.lua local limit_conn = require "resty.limit.conn" --限制200個併發請求下的請求和一個100個併發的額外的突發請求。也就是咱們延遲 --請求300個併發鏈接之內以及200個以上鍊接,並拒絕任何超過300的新請求鏈接。 --另外,咱們假設默認請求時間爲0.5秒,也就是說經過下面的log_by_lua中的leaving()調用動態調整。 --以上是官網給的配置參數的的說明介紹。("my_limit_conn_store", 200, 100, 0.5) 這個是官網給的參數 --咱們能夠調整參數爲以下("my_limit_conn_store", 1, 0, 0.5) -- 限制一個 ip 客戶端最大 1 個併發請求 -- burst 設置爲 0,若是超過最大的併發請求數,則直接返回503, -- 若是此處要容許突增的併發數,能夠修改 burst 的值(漏桶的桶容量) -- 最後一個參數實際上是你要預估這些併發(或者說單個請求)要處理多久,以便於對桶裏面的請求應用漏桶算法 local lim, err = limit_conn.new("my_limit_conn_store", 200, 100, 0.5) if not lim then ngx.log(ngx.ERR, "failed to instantiate a resty.limit.conn object: ", err) return ngx.exit(500) end --如下調用必須是每一個請求。 這裏咱們使用遠程(IP)地址做爲限制key -- commit 爲true 表明要更新shared dict中key的值, -- false 表明只是查看當前請求要處理的延時狀況和前面還未被處理的請求數 local key = ngx.var.binary_remote_addr local delay, err = lim:incoming(key, true) if not delay then if err == "rejected" then return ngx.exit(503) end ngx.log(ngx.ERR, "failed to limit req: ", err) return ngx.exit(500) end ---- 若是請求鏈接計數等信息被加到shared dict中,則在ctx中記錄下, -- 由於後面要告知鏈接斷開,以處理其餘鏈接 if lim:is_committed() then local ctx = ngx.ctx ctx.limit_conn = lim ctx.limit_conn_key = key ctx.limit_conn_delay = delay end local conn = err -- 其實這裏的 delay 確定是上面說的併發處理時間的整數倍, -- 舉個例子,每秒處理100併發,桶容量200個,當時同時來500個併發,則200個拒掉 -- 100個在被處理,而後200個進入桶中暫存,被暫存的這200個鏈接中,0-100個鏈接其實應該延後0.5秒處理, -- 101-200個則應該延後0.5*2=1秒處理(0.5是上面預估的併發處理時間) if delay >= 0.001 then --請求超過200鏈接比但低於300個鏈接,因此咱們故意將它延遲到這裏以符合200鏈接限制。 ngx.sleep(delay) end
3.關於log_by_lua_block段的log_by_lua.lua 腳本以下:併發
[root@VM_82_178_centos limit_lua]# cat /usr/local/openresty/nginx/conf/limit_lua/log_by_lua.lua local ctx = ngx.ctx local lim = ctx.limit_conn if lim then --若是您在內容階段使用上游模塊 --那麼你可能想要使用$ upstream_response_time 響應時間而不是($ request_time - ctx.limit_conn_delay)的時間 local latency = tonumber(ngx.var.request_time) - ctx.limit_conn_delay local key = ctx.limit_conn_key -- 這個鏈接處理完後應該告知一下,更新shared dict中的值,讓後續鏈接能夠接入進來處理 -- 此處能夠動態更新你以前的預估時間,可是別忘了把limit_conn.new這個方法抽出去寫, -- 要不每次請求進來又會重置 assert(key) local conn, err = lim:leaving(key, latency) if not conn then ngx.log(ngx.ERR,"failed to record the connection leaving ","request: ", err) return end end
測試說明:ide