背景
面对高峰期间低频慢业务对主业务的影响时,一般的做法有两种,一种是大公司采用的底层优化, 代价大收效高,但性价比低,一种是小微企业采用的降级方案,在服务器资源消耗较高时,此做法性价比相对高一些,既不需要太大的研发工作量,也较好的保护了主业务不受影响。
方案
三层防御,首先是数据库层,一旦发现CPU较高,甚至达到100%,可使用脚本批量kill mysql线程,第二层是dubbo层,可利用dubbo admin一键禁止某服务,杀伤力较大,请谨慎使用,第三层也就是web层的防御,通过ngnix对请求进行拦截,只要url在我的黑名单里面,nginx统一返回500,提示用户当前业务已降级,请稍后再试,从而释放了底层数据库服务器资源,保护主业务正常访问。这里主要介绍第三层方案。
实施
- 使用redis destop创建键值集用于存放需要拦截的url地址,后续可以持续加入
SADD url_block /webapp/path/get
- 确保已安装了nginx并启用了lua,在nginx.conf文件中http模块加入以下配置:
lua_shared_dict limit 50m;
lua_shared_dict block_url 50m;
access_by_lua_file /usr/local/nginx/conf/url_block.lua;
- 上述url_block.lua主要内容是每隔10秒从redis中取出最新需要拦截的url,如果客户端url在黑名单中,则返回提示语,中断请求。脚本如下:
function get_client_url()
local CLIENT_URL = ngx.var.uri
if CLIENT_URL == nil then
CLIENT_URL = "unknown"
end
return CLIENT_URL
end
local redis_host = "172.27.66.1"
local redis_port = 6379
local redis_auth = "xxxxxxxx"
local limit = ngx.shared.limit
local random = ngx.var.cookie_seed
local CC_TOKEN = ngx.var.remote_addr .. "_token"
local redis_conn_timeout = 1000
local redis_key = "url_block"
local cache_ttl = 10
local url = get_client_url()
local url_list = ngx.shared.block_url
local last_update_time = url_list:get("last_update_time");
if last_update_time == nil or last_update_time < (ngx.now() - cache_ttl) then
local redis = require "resty.redis";
local r = redis:new();
r