ngx-lua實現高階限流方式一
阿新 • • 發佈:2022-05-08
基於POST請求體中的某個引數限流
背景
電商平臺有活動,活動涉及優惠券的搶券,優惠券系統對大併發支援略差,為了保護整體系統平穩,因此在入口Nginx層對搶券介面做了一層限流。
完整實現如下:
lua_shared_dict my_limit_req_store 100m; server { listen 80; server_name test.abc.com; # 搶券介面 location = /api/v1/test { lua_need_request_body on; access_by_lua_block { local cjson = require("cjson") -- 獲取POST請求體 if ngx.var.request_method == "POST" then ngx.req.read_body() local data = ngx.req.get_body_data() -- 獲取限流欄位 appName, 獲取不到則跳出lua if data then params = cjson.decode(data) if params["appName"] then limit_key = params["appName"] else ngx.log(ngx.ERR, "未獲取到appName,不做限流") -- 退出access_by_lua階段,繼續執行其他階段。 ngx.exit(0) end else ngx.log(ngx.ERR, "獲取請求體失敗,跳過限流配置") ngx.exit(0) end else ngx.log(ngx.ERR, "不對非POST請求進行處理") ngx.exit(0) end -- 限流邏輯 local limit_req = require "resty.limit.req" local lim, err = limit_req.new("my_limit_req_store", 200, 100) if not lim then ngx.log(ngx.ERR, "failed to instantiate a resty.limit.req object: ", err) return ngx.exit(500) end local delay, err = lim:incoming(limit_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 if delay >= 0.001 then local excess = err ngx.sleep(delay) end } try_files $uri $uri/ /index.php?$query_string; } location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { # 設定專案根目錄 set $PROJECT_NAME "/data/www/test.abc.com/public"; # 設定upstream_name set $fastcgi_name test; index index.php index.html index.htm; include fastcgi_params; fastcgi_pass $fastcgi_name; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $PROJECT_NAME$fastcgi_script_name; # 指定專案根目錄 } }
核心解讀
-
獲取請求體
- POST請求
- JSON格式
- 獲取不到不能影響其他階段繼續執行
-
解析請求體獲取目標引數
- cjson.decode()
- 操作map獲取目標資料(限流的指標)
- 獲取不到不能影響其他階段繼續執行
-
確定限流方式
- 限請求速率
- 限連線數