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

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

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  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

        if 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发起一次请求:

查看Nginx日志

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

周国庆

2017/10/01

时间: 2024-11-05 06:33:51

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

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

上篇博文中,我们介绍了Azure IoT Hub的使用配额和缩放级别: Azure IoT 技术研究系列4-Azure IoT Hub的配额及缩放级别 本文中,我们比较一下Azure IoT Hub和Event Hub,同时启动Azure Event Hub(事件中心)的研究. Azure IoT Hub的另一个主要应用场景是从设备侧接收遥测数据. 与 Azure IoT Hub一样,Azure Event Hub是一个事件处理服务,主要用于向云端提供大规模的事件与遥测数据入口,并且具有较低的延

Azure IoT 技术研究系列2-设备注册到Azure IoT Hub

上篇博文中,我们主要介绍了Azure IoT Hub的基本概念.架构.特性: Azure IoT 技术研究系列1-入门篇 本文中,我们继续深入研究,做一个起步示例程序:模拟设备注册到Azure IoT Hub, 设备到云通信,云到设备通信. 整体篇幅较大,我们先来第一步:将模拟设备注册到Azure IoT Hub. 首先,我们需要有一个联网的设备,例如树莓派.Win10 IoT设备等等,只要能联网,Azure IoT Hub有编程SDK即可,为了方便演示,本篇中我们做了一个模拟设备: TeldP

第二百六十三也,Tornado框架-基于正则的动态路由映射分页

Tornado框架-基于正则的动态路由映射分页 分页基本显示数据 第一步.设置正则路由映射配置,(r"/index/(?P<page>\d*)", index.indexHandler),正则匹配访问路径,访问录index/后面可以是可以是0个或多个数字第二步.配置逻辑处理方法,get()方法里显示对应的页面,并传值一个SHUJU全局变量列表到html模板,这个全局变量列表里是字典显示的数据第三步.在html模板里用模板语言,循环这个列表里的字典,显示到表格里第四步.设置用

Redis缓存技术学习系列之邂逅Redis

??作为一个反主流的开发者,在某种程度上,我对传统关系型数据库一直有点"讨厌",因为关系型数据库实际上和面向对象思想是完全冲突的,前者建立在数学集合理论的基础上,而后者则是建立在软件工程基本原则的基础上.虽然传统的ORM.序列化/反序列化在一定程度上解决了这种冲突,但是软件开发中关于使用原生SQL语句还是使用ORM框架的争论从来没有停止过.可是实际的业务背景中,是完全无法脱离数据库的,除非在某些特定的场合下,考虑到信息安全因素而禁止开发者使用数据库,在主流技术中数据库是一个非常重要的组

Azure IoT 技术研究系列1-入门篇

物联网技术已经火了很多年了,业界各大厂商都有各自成熟的解决方案.我们公司主要搞新能源汽车充电,充电桩就是我们物联网技术的最大应用,车联网.物联网. 互联网三网合一.作为Azure重要的Partner和使用者,我们对Azure的IoT方案也是非常期待的,因此,最近计划研究一下Azure的IoT技术,同时将研究的成果分享给大家. 以本文作为IoT入门的第一篇吧. IoT:Internet of Things,即连接一切. Azure提供了Azure IoT Hub:直译为Azure的物联网中心. A

Azure IoT 技术研究系列1

物联网技术已经火了很多年了,业界各大厂商都有各自成熟的解决方案.我们公司主要搞新能源汽车充电,充电桩就是我们物联网技术的最大应用,车联网.物联网. 互联网三网合一.作为Azure重要的Partner和使用者,我们对Azure的IoT方案也是非常期待的,因此,最近计划研究一下Azure的IoT技术,同时将研究的成果分享给大家. 以本文作为IoT入门的第一篇吧. IoT:Internet of Things,即连接一切. Azure提供了Azure IoT Hub:直译为Azure的物联网中心. A

基于复杂网络隐藏度量空间的互联网自适应可扩展路由理论与关键 技术研究

随着信息技术的迅速发展与互联网创新应用的不断涌现,互联网体系结构所对应的基本能力与当今人们对互联网规模.功能.性能.服务和安全等方面的需求所对应的能力要求产生了明显矛盾.构建规模更大,性能更高和可扩展的下一代互联网体系结构是解决这一矛盾的主要途径.在此背景下,需重新反思互联网信息传递.转发.路由.拥塞控 制等基本问题.本项目重点研究互联网路由系统规模可扩展性问题,其主要内容包括:互联网拓扑特征及其演化模型研究,基于拓扑特征的可扩展路由模型及其优化方法与关键技术研究. 本项目已取得了如下一些结果:

[转载] 基于Redis实现分布式消息队列

转载自http://www.linuxidc.com/Linux/2015-05/117661.htm 1.为什么需要消息队列?当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异. 举个例子:业务系统触发短信发送申请,但短信发送模块速度跟不上,需要将来不及处理的消息暂存一下,缓冲压力. 再举个例子:调远程系统下订单成本较高,且因为网络等因素,不稳定,攒一批一起发送. 再举个栗子,交互模块5:00到24:00和电商系统联通,和内部ERP断开.

基于Redis的分布式锁到底安全吗(上)?

网上有关Redis分布式锁的文章可谓多如牛毛了,不信的话你可以拿关键词"Redis 分布式锁"随便到哪个搜索引擎上去搜索一下就知道了.这些文章的思路大体相近,给出的实现算法也看似合乎逻辑,但当我们着手去实现它们的时候,却发现如果你越是仔细推敲,疑虑也就越来越多. 实际上,大概在一年以前,关于Redis分布式锁的安全性问题,在分布式系统专家Martin Kleppmann和Redis的作者antirez之间就发生过一场争论.由于对这个问题一直以来比较关注,所以我前些日子仔细阅读了与这场争