在nginx层限制API每秒以及每分钟的请求次数,防止进程被打满。
保护接口
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
# 设置纯 Lua 扩展库的搜寻路径(';;' 是默认路径)
lua_package_path "/data/www/code/nginx+lua/config/lua_p/?.lua;;";
# 设置 C 编写的 Lua 扩展模块的搜寻路径(也可以用 ';;')
lua_package_cpath "/data/www/code/nginx+lua/config/lua_p_c/?.so;;";
# 缓存大小5m
lua_shared_dict url_limit 5m;
server {
listen 8080;
location /limiter {
lua_code_cache off;
content_by_lua_file ./config/lua/limiter.lua;
}
}
}
ngx.header.content_type = "text/html; charset=utf-8";
local method = ngx.req.get_method();
local curl = ngx.md5(ngx.var.request_uri);
local request_uri_without_args = ngx.re.sub(ngx.var.request_uri, "\\?.*", "");
local match = string.match;
local ngxmatch = ngx.re.match;
--限流计数
local function limit_url_check(key, s, m)
local localkey = key;
local yyy_limit = ngx.shared.url_limit;
--每分钟限制
local key_m_limit = localkey .. os.date("%Y-%m-%d %H:%M", ngx.time());
--每秒限制
local key_s_limit = localkey .. os.date("%Y-%m-%d %H:%M:%S", ngx.time());
local req_key, _ = yyy_limit:get(localkey);
local req_key_s, _ = yyy_limit:get(key_s_limit);
local req_key_m, _ = yyy_limit:get(key_m_limit);
--每秒处理
if req_key_s then
yyy_limit:incr(key_s_limit, 1);
if req_key_s > s then
return false;
end
else
yyy_limit:set(key_s_limit, 1, 60);
end
--每分钟处理
if req_key_m then
yyy_limit:incr(key_m_limit, 1);
if req_key_m > m then
return false;
end
else
yyy_limit:set(key_m_limit, 1, 85);
end
return true;
end
local url, err = ngx.re.match(request_uri_without_args, "/limiter");
if url then
if not limit_url_check("limiter", 5, 15) then
ngx.say('{"code": 1000,"msg":当前访问的用户过多,请稍后再试!"}');
ngx.exit(200);
return;
end
end