电商平台有活动,活动涉及优惠券的抢券,优惠券系统对大并发支持略差,为了保护整体系统平稳,因此在入口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; # 指定项目根目录 }}获取请求体
解析请求体获取目标参数
确定限流方式