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 ...
随机推荐
- C - Coin Change (III)(多重背包 二进制优化)
C - Coin Change (III) Time Limit:2000MS Memory Limit:32768KB 64bit IO Format:%lld & %llu ...
- hdu1540 区间操作,合并,模板题
During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast a ...
- 通过修改 LayoutInflater,全局替换字体!!!
序 在 Android 下使用自定义字体已经是一个比较常见的需求了,最近也做了个比较深入的研究. 那么按照惯例我又要出个一篇有关 Android 修改字体相关的文章,但是写下来发现内容还挺多的,所以我 ...
- Python-MongoDB的驱动安装、升级
安装pip,并通过此来安装pymongo–Python mongodb驱动 1.下载pip安装包,下载地址:http://pypi.python.org/packages/source/p/pip/p ...
- Echarts数据可视化polar极坐标系,开发全解+完美注释
全栈工程师开发手册 (作者:栾鹏) Echarts数据可视化开发代码注释全解 Echarts数据可视化开发参数配置全解 6大公共组件详解(点击进入): title详解. tooltip详解.toolb ...
- plsql经验之谈
工具你用熟悉了,可以解决实际生活得问题,且是快速的.比如我们要需要表的字段,和注释的时候,直接右击,详情,可以复制. 我们讲个熟悉的场景或者案例,比如,我们需要把已经建立的源表,需要一定的加工和处理, ...
- JavaWeb之Maven配置
Maven和C#的nuget类似,可以通过设置就能引入框架等第三方,方便又省事.Java中使用Maven来管理第三方.今天尝试着配置了一下. 一.JDK的安装 关于JDK的安装可以查看百度经验,设置P ...
- LINUX 笔记-crontab命令
用户所建立的crontab文件中,每一行都代表一项任务,每行的每个字段代表一项设置,它的格式共分为六个字段,前五段是时间设定段,第六段是要执行的命令段,格式如下: minute hour da ...
- LeetCode 110. Balanced Binary Tree (平衡二叉树)
Given a binary tree, determine if it is height-balanced. For this problem, a height-balanced binary ...
- 解决执行sql脚本报错:没有足够的内存继续执行程序。
出现执行sql脚本报错:没有足够的内存继续执行程序.是因为sql脚本过大,大家可能分为多个文件多次执行,这种笨方法可行,不过比较麻烦,大家可以用下面的方式,利用sqlcmd一次就行了: 执行cmd ...