降级其实当网站出现高并发时,丢车保帅的一个策略。
降级分为:内容降级,限流降级,限速降级
内容降级
1.不重要的功能->平时从mysql获取的数据,
如果突然来了很多请求,系统负载不过来 请求开关 用redis(分配到2,3,4,5)
2.从缓存中获取数据,
3.静态文件。
4.nginx直接返回空数据(关停某个功能)
5.兜底文件
1.根据开关的位置:可以分为代码降级和前置降级
2.读写,可以分读降级,写降级
写降级,有一定延迟,对实时性要求比较低的项目,可以用,防止系统崩掉。
功能重要性排序,功能重要性越低,越有可能成为我们降级的对象。
秒杀都是直接降级,然后秒杀结束处理(消息队列,或者redis)
限流降级
安装模块,nginx限流模块:
ngx_http_limit_req_moudule 里面有配置
ngx_http_limit_conn_moudule 里面有配置
修改nginx配置文件 nginx.conf 处理请求数
--判断错误的响应,并进行计算
--1.如果nginx响应不等于200
if tonumber(ngx.var.status) ~=200 then
ngx.say(ngx.var.status)
ngx.log(ngx.ERR,"upstream reponse status is" .. ngx.var.status..",please notice it)
local error_count,err=redis_instance:get("error_count_goods_list_advert")
--得到的数据为空处理
if error_count == ngx.null then
error_count = 0;
end
--计数
error_count = error_count + 1;
--统一错误次数到error_count_goods_list_advert 记到redis里
local resp,err = redis_instance:set("error_count_goods_list_advert",error_count)
if not resp then
ngx.say("set msg error : ",err)
return close_redis(redis_instance)
end
end
close_redis(redis_instance)
降级的维护方式,分为手动降级和自动降级
手动降级,后台配置,开关
nginx+lua+redis进行自动降级,限流降级(比nginx自带的那个模块要灵活)
nginx.conf 文件
http{
#下载redis模块 安装lua语言(没有也不能获取数据) nginx配置redis模块
lua_package_path "";
lua_package_cpath "";
}
server {
#进行匹配那个地址需要被降级
#根据test.lua实现逻辑
location /test{
default_type 'application/x-javascript;charset=ust-8';
content_by_lua_file /etc/nginx/lua/test.lua;
}
#从服务层+mysql读取数据
location /good_data{
default_type 'application/x-javascript;charset=utf-8';
proxy_pass http://127.0.0.1/:8080/getlist;
}
}
如果需要返回json文件 需要引入json
---获取get或者post参数
local request_method = ngx.var.request_method
local args = nil
local param = nil
--获取参数的值
if "GET" == request_method then
args = ngx.req.get_uri_args()
elseif "POST" == request_method then
ngx.req.read_body()
args = ngx.req.get_post_args()
end
sku_id = args("sku_id")
--关闭redis的函数
local function close_redis(redis_instance)
if not redis_instance then
return
end
local ok,err = redis_instance:close();
if not ok then
ngx.say("close redis error: ",err);
end
end
--连接redis
local redis = require("resty.redis");
--local redis = require "redis"
--创建一个redis对象实例,失败,返回nil和描述错误的字符串的情况下
local redis_instance = redis:new();
--设置后续操作的超时(以毫秒为单位)保护,包含connect方法
redis_instance:set_timeout(1000)
--建立连接
local ip = '127.0.0.1'
local port = 6379
--尝试连接到redis服务器正在监听的远程主机和端口
local ok,err = redis_instance:connect(ip,port)
if not ok then
ngx.say("connect redis error :",err)
return close_redis(redis_instance);
end
-- 从redis里面读取开关
local key = "读取开关key"
local switch,err = redis_instance:get(key)
if not switch then
ngx.say("get msg error:",err)
return close_redis(redis_instance)
end
--得到的开关为空处理
if switch == ngx.null then
switch = "FROM_DATA_BY_MYSQL" --默认值
end
--当开关是要从服务中获取数据时
if "FROM_DATA_BY_MYSQL" == switch then
ngx.exec('/goods_data');
--当开关是要从缓存中获取数据时
elseif "FROM_CACHE" == switch then
local resp,err = redis_instance:get("redis_goods")
ngx.say(resp)
--当开关是要从静态资源中获取数据时
elseif "FROM_STATIC" == switch then
ngx.header.content_type = "application/x-javascript;charset=utf-8"
local file = "/etc/nginx/html/good_static.json"
local f = io.open(file,"rb")
local content = f:read("*all")
f:close()
ngx.print(content)
-- 当开关是要停掉数据获取时
elseif "SHUT_DOWN" == switch then
ngx.say('no data')
end
--close_redis(redis_instance)
--判断错误的响应,并进行计算
--1.如果nginx响应不等于200
if tonumber(ngx.var.status) ~=200 then
ngx.say(ngx.var.status)
ngx.log(ngx.ERR,"upstream reponse status is" .. ngx.var.status..",please notice it)
local error_count,err=redis_instance:get("error_count_goods_list_advert")
--得到的数据为空处理
if error_count == ngx.null then
error_count = 0;
end
--计数
error_count = error_count + 1;
--统一错误次数到error_count_goods_list_advert 记到redis里
local resp,err = redis_instance:set("error_count_goods_list_advert",error_count)
if not resp then
ngx.say("set msg error : ",err)
return close_redis(redis_instance)
end
end
close_redis(redis_instance)
redis-cli -h 127.0.0.1