前几篇文章我们介绍了Nginx的配置、OpenResty安装配置、基于Redis的动态路由以及Nginx的监控。

Nginx-OpenResty安装配置

Nginx配置详解

Nginx技术研究系列1-通过应用场景看Nginx的反向代理

Nginx技术研究系列2-基于Redis实现动态路由

[原创]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技术研究系列5-动态路由升级版的更多相关文章

  1. Nginx技术研究系列2-基于Redis实现动态路由

    上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...

  2. Nginx技术研究系列3-OpenResty安装配置

    上两篇中介绍了: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 Ngnix技术研究系列2-基于Redis实现动态路由 发现,应该加一篇OpenResty的安装部署说明,方便大家按图索骥 ...

  3. Nginx技术研究系列6-配置详解

    前两篇文章介绍了Nginx反向代理和动态路由: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 Ngnix技术研究系列2-基于Redis实现动态路由 随着研究的深入,很重要的一点就是了解 ...

  4. Nginx技术研究系列1-通过应用场景看Nginx的反向代理

    随着我们业务规模的不断增长,整个系统规模由两年前的几十台服务器,井喷到现在2个数据中心,接近400台服务器,上百个WebApi站点,上百个域名. 这么多的WebApi站点这么多的域名,管理和维护成本很 ...

  5. Nginx技术研究系列7-Azure环境中Nginx高可用性和部署架构设计

    前几篇文章介绍了Nginx的应用.动态路由.配置.在实际生产环境部署时,我们需要同时考虑Nginx的高可用性和部署架构. Nginx自身不支持集群以保证自身的高可用性,商业版本的Nginx+推荐: T ...

  6. Nginx技术研究系列4-Nginx监控-Nginx+Telegraf+Influxb+Grafana

    搭建了Nginx集群后,需要继续深入研究的就是日常Nginx监控. Nginx如何监控?相信百度就可以找到:nginx-status 通过Nginx-status,实时获取到Nginx监控数据后,如何 ...

  7. Ngnix技术研究系列2-基于Redis实现动态路由

    上篇博文我们写了个引子: Ngnix技术研究系列1-通过应用场景看Nginx的反向代理 发现了新大陆,OpenResty OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台 ...

  8. Azure IoT 技术研究系列2-起步示例之设备注册到Azure IoT Hub

    上篇博文中,我们主要介绍了Azure IoT Hub的基本概念.架构.特性: Azure IoT 技术研究系列1-入门篇 本文中,我们继续深入研究,做一个起步示例程序:模拟设备注册到Azure IoT ...

  9. Azure IoT 技术研究系列3-设备到云、云到设备通信

    上篇博文中我们将模拟设备注册到Azure IoT Hub中:我们得到了设备的唯一标识. Azure IoT 技术研究系列2-设备注册到Azure IoT Hub 本文中我们继续深入研究,设备到云.云到 ...

随机推荐

  1. Maven项目错误解决小结

    http://blog.csdn.net/typa01_kk/article/details/49185759 Maven项目错误解决小结 注:整理错误,不喜欢为了一个小问题,占篇幅,所以请Ctrl+ ...

  2. postgresql某进程占用cpu资源过高,降不下来

    由于是开发阶段,所以并没有配置postgres的参数,都是使用安装时的默认配置,以前运行也不见得有什么不正常,可是前几天我的cpu资源占用突然升高.查看进程,发现有一个postgres的进程占用CPU ...

  3. Inside The C++ Object Model(三)

    ============================================================================3-0. 类所占的内存大小受到三个因素的影响:( ...

  4. Nginx子域名配置

    extends:http://blog.csdn.net/xiaoping0915/article/details/53899465 ,http://www.myhack58.com/Article/ ...

  5. poj3255 Roadblocks

    Roadblocks Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 13594   Accepted: 4783 Descr ...

  6. Java课程寒假之开发记账本软件(网页版)之二

    一.实现基础功能之一(记账) 一个记账本最基础之一的功能就是记账,所以也是首先要解决的问题,我选择了上学期使用的MySQL数据库来对账本进行存储. 我选择记账的方法是分开记账,就是支出放在一个表,收入 ...

  7. Java课程寒假之开发记账本软件(网页版)之一

    一.制定网页版记账本的基础功能 首先是下载了几个记账本APP,大致地看了一下记账本的功能:添加记录(支出,收入,自定义模板),查询流水(分类查询),账户. 二.开始做出框架 鉴于记账本有上面的功能,所 ...

  8. roadhog 介绍

    官方网站:https://www.npmjs.com/package/roadhog; 项目搭建demo: https://github.com/ght5935/antd-dva-less-webpa ...

  9. linux 远程连接ssh提示IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY解决

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: REMOTE HOST IDENTIFICATION HA ...

  10. 点击app分享链接,js判断手机是否安装某款app,有就尝试打开,没有就下载

    html: <h1 class="downlink"> 前往 </h1> js: document.addEventListener('DOMContent ...