Nginx-动态路由升级版
前几篇文章我们介绍了Nginx的配置、OpenResty安装配置、基于Redis的动态路由以及Nginx的监控。
Nginx技术研究系列1-通过应用场景看Nginx的反向代理
[原创]Nginx监控-Nginx+Telegraf+Influxb+Grafana
在分布式环境下,我们要考虑高可用性和性能:
1. 不能因为Redis宕机影响请求的反向代理
2. 每次请求如果都访问Redis,性能有一定的损耗,同时Redis集群的压力随着流量的激增不断增加。
因此,我们要升级一下动态路由的设计方案。 我们还是先从应用场景出发:
1.提升性能,降低Redis的访问频率
2.Redis宕机不影响Nginx反向代理
实现上述两个应用场景,我们采用本地缓存+Redis缓存的双缓存配合机制。
- 第一次请求时,从Redis中获取路由地址,然后放到本地缓存中,同时设置本地缓存项的有效时间
- 后续请求时,从本地缓存直接获取路由地址,如果本地缓存已经失效,则再次从Redis获取路由地址,再放到本地缓存中。
确定了上述实现方案后,我们回顾一下我们已有的Redis动态路由实现:
upstream redis_cluster {
server 192.0..*:;
server 192.0..*:;
server 192.0..*:;
}
location = /redis {
internal;
set_unescape_uri $key $arg_key;
redis2_query get $key;
redis2_pass redis_cluster;
}
location / {
set $target '';
access_by_lua '
local query_string = ngx.req.get_uri_args()
local sid = query_string["RequestID"]
if sid == nil then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
local key = sid
local res = ngx.location.capture(
"/redis", { args = { key = key } }
)
if res.status ~= then
ngx.log(ngx.ERR, "redis server returned bad status: ",
res.status)
ngx.exit(res.status)
end
if not res.body then
ngx.log(ngx.ERR, "redis returned empty body")
ngx.exit()
end
local parser = require "redis.parser"
local server, typ = parser.parse_reply(res.body)
if typ ~= parser.BULK_REPLY or not server then
ngx.log(ngx.ERR, "bad redis response: ", res.body)
ngx.exit()
end
if server == "" then
server = "default"
end
server = server .. ngx.var.request_uri
ngx.var.target = server
';
resolver 255.255.255.0;
proxy_pass http://$target;
}
我们要在上述代码中增加一层本地缓存实现,因此,我们需要找一个本地缓存的实现Lib。
我们在OpenResty的官网上找了一遍已提供的组件,发现了:lua-resty-lrucache - Lua-land LRU Cache based on LuaJIT FFI
Git Hub的地址:https://github.com/openresty/lua-resty-lrucache
尝试写了一下,发现这个cache实现是worker进程级别的,我们Nginx是Auto的进程数配置,一般有4~8个,这个缓存每个进程都New一个,貌似不符合我们的要求,同时,这个cache是预分配好缓存的大小和数量,启动的时候如果数量太多,分配内存很慢。
测试了一下,果真是这样,因此,我们继续查找新的Cache实现。
ngx.shared.DICT,https://github.com/openresty/lua-nginx-module#ngxshareddict
这个 cache 是 nginx 所有 worker 之间共享的,内部使用的 LRU 算法(最近经常使用)来判断缓存是否在内存占满时被清除。同时提供了如下方法:

然后,我们基于这个组件实现了我们升级版的Redis动态路由,直接上代码Show:
upstream redis_cluster {
server 192.0..*:;
server 192.0..*:;
server 192.0..*:;
}
lua_shared_dict localcache 10m;——
location = /redis {
internal;
set_unescape_uri $key $arg_key;
redis2_query get $key;
redis2_pass redis_cluster;
}
location / {
set $target '';
access_by_lua '
local query_string = ngx.req.get_uri_args()
local sid = query_string["RequestID"]
if sid == nil then
ngx.exit(ngx.HTTP_FORBIDDEN)
end
local key = sid
local cache = ngx.shared.localcache
local server = cache:get(key)
if server == nil then
local res = ngx.location.capture(
"/redis", { args = { key = key } }
)
if res.status ~= then
ngx.log(ngx.ERR, "redis server returned bad status: ",
res.status)
ngx.exit(res.status)
end
if not res.body then
ngx.log(ngx.ERR, "redis returned empty body")
ngx.exit()
end
local parser = require "redis.parser"
local serveradr, typ = parser.parse_reply(res.body)
if typ ~= parser.BULK_REPLY or not serveradr then
ngx.log(ngx.ERR, "bad redis response: ", res.body)
ngx.exit()
end
server = serveradr
cache:set(key, server,3)
end
if server == "" then
server = "default"
end
server = server .. ngx.var.request_uri
ngx.var.target = server
';
resolver 255.255.255.0;
proxy_pass http://$target;
}
}
重点说一下上面的代码:
首先,定义了一个本地缓存:
lua_shared_dict localcache 10m;
然后,从本地缓存中获取路由地址
local cache = ngx.shared.localcache
local server = cache:get(key)
如果本地缓存中没有,从Redis中获取,从Redis中获取到之后,加入到本地缓存中,缓存有效时间3600s:
server = serveradr
cache:set(key, server, )
升级后的Redis+本地缓存的动态路由方案,压测性能提升1.4倍,同时解决了Redis宕机的问题。
以上这个方案和实现都分享给大家。
周国庆
2017/11/13
Nginx-动态路由升级版的更多相关文章
- Nginx动态路由的新姿势:使用Go取代lua
导语: 在Nitro 中, 我们需要一款专业的负载均衡器. 经过一番研究之后,Mihai Todor和我使用Go构建了基于Nginx.Redis 协议的路由器解决方案,其中nginx负责所有繁重工作, ...
- Nginx技术研究系列5-动态路由升级版
前几篇文章我们介绍了Nginx的配置.OpenResty安装配置.基于Redis的动态路由以及Nginx的监控. Nginx-OpenResty安装配置 Nginx配置详解 Nginx技术研究系列1- ...
- Nginx技术研究系列2-基于Redis实现动态路由
上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...
- Ngnix技术研究系列2-基于Redis实现动态路由
上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...
- 基于hi-nginx的web开发(python篇)——动态路由和请求方法
hi.py的提供的路由装饰器接受两个参数,第一个参数指定动态路由的正则模式,第二个参数指定同意的http请求方法列表. 比如: @app.route(r"^/client/?$", ...
- Consul+upsync+Nginx 动态负载均衡
1,动态负载均衡 传统的负载均衡,如果修改了nginx.conf 的配置,必须需要重启nginx 服务,效率不高.动态负载均衡,就是可配置化,动态化的去配置负载均衡. 2,实现方案 1. Consul ...
- AIX 环境下动态路由
IBM AIX v5.3操作系统环境下动态路由配置如下: 1,用命令lssrc -S routed和lssrc -S gated分别检查routed和gated子系统是是活动状态.如果这两个子系统为活 ...
- asp.net MVC动态路由
项目中遇到需要动态生成控制器和视图的. 于是就折腾半天,动态生成控制器文件和视图文件,但是动态生成控制器不编译是没法访问的. 找人研究后,得到要领: 1.放在App_Code文件夹内 2.不要命名空间 ...
- RIP、OSPF、BGP、动态路由选路协议、自治域AS
相关学习资料 tcp-ip详解卷1:协议.pdf http://www.rfc-editor.org/rfc/rfc1058.txt http://www.rfc-editor.org/rfc/rfc ...
随机推荐
- 【bzoj2761】[JLOI2011]不重复数字
给出N个数,要求把其中重复的去掉,只保留第一次出现的数. 例如,给出的数为1 2 18 3 3 19 2 3 6 5 4,其中2和3有重复,去除后的结果为1 2 18 3 19 6 5 4. Inpu ...
- Python协程爬取妹子图(内有福利,你懂得~)
项目说明: 1.项目介绍 本项目使用Python提供的协程+scrapy中的选择器的使用(相当好用)实现爬取妹子图的(福利图)图片,这个学会了,某榴什么的.pow(2, 10)是吧! 2.用到的知 ...
- php中常用的字符串截取函数mb_substr实例解释
string mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_ ...
- Ubuntu访问window下的磁盘分区出现“Error mounting /dev/sda5 at/media”错误的解决方法
我装ubuntu之前,电脑上安装了windows 10,为了装ubuntu,在window 10下的磁盘工具分配了30G的磁盘空间.安装完Ubuntu之后,访问window 10的磁盘分区出现“Err ...
- SpringMVC框架(四)文件的上传下载,上下文路径
文件目录: SpringMVC配置文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmln ...
- python之线程学习
一.进程与线程简介 进程 进程是程序的一次执行,由进程段.数据段.进程控制块三部分组成.具体三个基本状态,就绪.执行.阻塞,是一个拥有资源的独立单位. 线程 属于进程的一个实体,拥有极少的资源.也具有 ...
- win10 UWP 圆形等待
看到一个圆形好像微软ProgressRing 我们可以用自定义控件 按ctrl+shift+a 用户控件 我们可以用Rectangle做圆形边 只要Rectangle RadiusX>0圆角 因 ...
- Python学习笔记(七)
Python学习笔记(七): 深浅拷贝 Set-集合 函数 1. 深浅拷贝 1. 浅拷贝-多层嵌套只拷贝第一层 a = [[1,2],3,4] b = a.copy() print(b) # 结果:[ ...
- hibernate5使用注解遇到的问题
问题描述 出现MappingException:Unknown entity,看到这个我以为在cfg配置文件中没有配置,实际上我是配置了的,那么问题出在那里呢,既然找不到实体,那么会不会是注解类出现了 ...
- 动态主机配置协议DHCP
一.什么是DHCP DHCP,动态主机配置协议,提供一种称为“即插即用连网”的机制,允许一台计算机加入新的网络和获取IP地址而不用手工配置. 二.DHCP工作原理和工作流程 DHCP服务器被动打开UD ...