上篇博文我们写了个引子:

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

发现了新大陆,OpenResty

OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

回到我们的原始需求:

http://api.***.com/action    => http://192.168.0.11/api/action

Header: ***                            Header: ***

Body:   ***                             Body: ***    

通过Actiton获取对应的后端服务器地址

Action和服务器的对应关系(路由表)存储在Redis中.(实时更新实时获取)

根据请求的Action动态解析对应的内网服务器地址,再实现服务的转发。

Nginx原生的路由配置无法实现上述动态路由配置,因为我们要访问Redis,获取到反向代理的路由信息,再实现服务的转发。详细的实现步骤:

1. 解析URL中的Action

2.访问Redis,Key=Action Value=内网服务器地址

3.Http请求转发到内网服务器

明确了具体的实现方案后,我们需要先详细的研究一下OpenResty和Lua

http://openresty.org/cn/

https://www.tutorialspoint.com/lua/

大致了解OpenResty是什么,能做什么,同时能简单写一些Lua脚本。

然后,我们重点看OpenResty提供的样例:

Dynamic Routing Based On Redis

通过这个样例,我们就可以模仿着写一个我们自己的配置和脚本,实现上面的动态路由的需求。

Come On。

一、解析URL中的Action

首先,要解析并拆分URL字符串,各种百度和Google,需要写一段Lua代码,实现字符串按"/"拆分

其实就是定义了一个split_path函数。

然后我们将上面的Split.lua文件,配置到Nginx的配置文件中

/usr/local/openresty/nginx/conf/nginx.conf

注:split.lua文件我们放在了

/usr/local/openresty/nginx/lua

编辑/usr/local/openresty/nginx/conf/nginx.conf文件

http {
include mime.types;
default_type application/octet-stream; sendfile on;
#tcp_nopush on; #keepalive_timeout ;
keepalive_timeout ; #gzip on;
init_worker_by_lua_file /usr/local/openresty/nginx/lua/split.lua;
server {
listen ;
location = /redis {
internal;
set_unescape_uri $key $arg_key;
redis2_query get $key;
redis2_pass RedisServer:;
} location / {
set $target '';
access_by_lua '
local parameters = split_path(ngx.var.uri)
local action = parameters[]

location中的access_by_lua '这一段负责执行Lua脚本和方法
local action = parameters[1]

这样,我们便解析到了Action,注:Lua中数组的下标从1开始

二.访问Redis,Key=Action Value=内网服务器地址

继续编辑Nginx配置文件

 location / {
set $target '';
access_by_lua '
local parameters = split_path(ngx.var.uri)
local action = parameters[]
if(#parameters == ) then
ngx.exit(ngx.HTTP_FORBIDDEN)
end

local key = action
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.com"
end

三.Http请求转发到内网服务器

继续编辑Nginx.Conf文件

 init_worker_by_lua_file /usr/local/openresty/nginx/lua/split.lua;
server {
listen ;
location = /redis {
internal;
set_unescape_uri $key $arg_key;
redis2_query get $key;
redis2_pass RedisServer:;
} location / {
set $target '';
access_by_lua '
local parameters = split_path(ngx.var.uri)
local action = parameters[]
if(#parameters == ) then
ngx.exit(ngx.HTTP_FORBIDDEN)
end local key = action
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.com"
end

server = server .. "/api/" .. action
if ngx.var.QUERY_STRING ~= nil and ngx.var.QUERY_STRING ~= "" then
server = server .."&"..ngx.var.QUERY_STRING
end ngx.var.target = server
';
resolver 8.8.8.8;
proxy_pass http://$target;
}
}

至此,我们完成了Nginx的配置文件。

启动Nginx测试:

sudo /usr/local/openresty/nginx/sbin/nginx -c /usr/local/openresty/nginx/conf/Nginx.conf

PostMan发起一次请求:

查看Nginx日志

以上就是使用Nginx+lua+redis实现动态路由。分享给大家

周国庆

2017/10/01

Ngnix技术研究系列2-基于Redis实现动态路由的更多相关文章

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

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

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

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

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

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

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

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

  5. Nginx技术研究系列5-动态路由升级版

    前几篇文章我们介绍了Nginx的配置.OpenResty安装配置.基于Redis的动态路由以及Nginx的监控. Nginx-OpenResty安装配置 Nginx配置详解 Nginx技术研究系列1- ...

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

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

  7. Azure IoT 技术研究系列5-Azure IoT Hub与Event Hub比较

    上篇博文中,我们介绍了Azure IoT Hub的使用配额和缩放级别: Azure IoT 技术研究系列4-Azure IoT Hub的配额及缩放级别 本文中,我们比较一下Azure IoT Hub和 ...

  8. ML.NET技术研究系列-2聚类算法KMeans

    上一篇博文我们介绍了ML.NET 的入门: ML.NET技术研究系列1-入门篇 本文我们继续,研究分享一下聚类算法k-means. 一.k-means算法简介 k-means算法是一种聚类算法,所谓聚 ...

  9. Azure IoT 技术研究系列3

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

随机推荐

  1. 拨开字符编码的迷雾--MySQL数据库字符编码

    拨开字符编码迷雾系列文章链接: 拨开字符编码的迷雾--字符编码概述 拨开字符编码的迷雾--编译器如何处理文件编码 拨开字符编码的迷雾--字符编码转换 拨开字符编码的迷雾--MySQL数据库字符编码 1 ...

  2. [PSIDE]PeopleSoft PSIDE无法启动因为缺失MSVCR100.dll解决办法

    “The program can’t start because MSVCR100.dll is missing from your computer” 当开发工具是绿色版的时候,在打开PSIDE时很 ...

  3. 搞java的都土鳖

    spring不就几个破框架让人们下载使用吗,但是官网什么都有,就是没有下载链接.java程序员被那些垃圾框架强奸的体无完肤,还乐在其中,还什么SSH,哇哦!java好像跟企业干上了,什么企业bean, ...

  4. ASP.NET Core的身份认证框架IdentityServer4(8)- 使用密码认证方式控制API访问

    前言 本文及IdentityServer这个系列使用的都是基于.net core 2.0的.上一篇博文在API项目中我使用了icrosoft.AspNetCore.Authentication.Jwt ...

  5. java对象 深度克隆(不实现Cloneable接口)和浅度克隆

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt128 为什么需要克隆: 在实际编程过程中,我们常常要遇到这种情况:有一个对象 ...

  6. js(javascript) 继承的5种实现方式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt240 js继承有5种实现方式:1.继承第一种方式:对象冒充  functio ...

  7. vim插件ctags的安装与使用

    LINUX系统下看程序或者编程序时,看到一个函数经常需要知道该函数的定义,这时ctags就派上用场了,其安装和使用方法如下: 安装方法: sudo apt-get install ctags (ubu ...

  8. iBatis的一个问题

    写了一段查询语句,条件中有一条alarmtype<>'1004'这样的条件,原来是这样写的 <![CATA[ and alarmtype<>'1004']]> 然后 ...

  9. 201521123047 j第五周学习总结

    1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. 参考资料: 百度脑图 XMind 2. 书面作业 1.代码阅读:Child压缩包 ...

  10. 201521044091 《Java程序设计》第3周学习总结

    1. 本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用思维导图将这些碎片化的概念.知识组织起来.请使用纸笔或者下面的工具画出本周学习到的知识点.截图或者拍照上传. 本周学习总结 ...