设为首页 收藏本站
查看: 1218|回复: 0

[经验分享] Nginx技术研究系列2-基于Redis实现动态路由

[复制链接]

尚未签到

发表于 2017-12-21 15:36:46 | 显示全部楼层 |阅读模式
  上篇博文我们写了个引子:
  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代码,实现字符串按"/"拆分
DSC0000.png

  其实就是定义了一个split_path函数。
  然后我们将上面的Split.lua文件,配置到Nginx的配置文件中
  /usr/local/openresty/nginx/conf/nginx.conf
DSC0001.png

  注: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  
0;  
keepalive_timeout  
65;  

  
#
gzip  on;  
init_worker_by_lua_file
/usr/local/openresty/nginx/lua/split.lua;  
server {
  
listen
80;  
location
= /redis {  
internal;
  
set_unescape_uri $key $arg_key;
  
redis2_query get $key;
  
redis2_pass RedisServer
:6379;  
}
  

  
location
/ {  
set $target
'';  
access_by_lua
'  

        local parameters =split_path(ngx.var.uri)  
local action
= parameters[1]  

  

  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[1]  

if(#parameters == 0) then  
ngx.exit(ngx.HTTP_FORBIDDEN)
  
end
  

  local key
= action  
local res
= ngx.location.capture(  

"/redis", { args = { key = key } }  
)
if res.status ~= 200 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(
500)  
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(
500)  
end
  

  
i
f server == "" then  
server
= "default.com"  
end
  

  三.Http请求转发到内网服务器
  继续编辑Nginx.Conf文件
  

init_worker_by_lua_file /usr/local/openresty/nginx/lua/split.lua;  
server {
  
listen
80;  
location
= /redis {  
internal;
  
set_unescape_uri $key $arg_key;
  
redis2_query get $key;
  
redis2_pass RedisServer:
6379;  
}
  

  
location
/ {  
set $target
'';  
access_by_lua
'  

        local parameters = split_path(ngx.var.uri)  
local action
= parameters[1]  

if(#parameters == 0) then  
ngx.exit(ngx.HTTP_FORBIDDEN)
  
end
  

  
local key
= action  
local res
= ngx.location.capture(  

"/redis", { args = { key = key } }  
)
  

  

if res.status ~= 200 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(
500)  
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(
500)  
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发起一次请求:
DSC0002.png

  查看Nginx日志
DSC0003.png

  以上就是使用Nginx+lua+redis实现动态路由。分享给大家
  周国庆
  2017/10/01

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-426519-1-1.html 上篇帖子: Python3对redis的操作 下篇帖子: spring集成redis消息列队
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表