OpenResty (Nginx + Lua) 实现流量定向分发

September 28, 2022 作者: dyzmj 分类: 物联网 浏览: 3 评论: 0

OpenResty(Nginx + Lua)实现流量定向分发

一、概要

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

由Ngnix实现负载均衡的优势此处不再赘述,本篇主要结合实际的业务场景谈下流量的定向分发负载。基于NB-IoT技术的物联网燃气表设备通讯到基站及运营商IoT平台时,多采用COAP或UDP协议,通讯参数到达运营商IoT平台后由平台自动转为HTTP协议回调发出,由于后台的采集抄表系统使用的是TCP服务,因此在运营商IoT平台和采集抄表系统中间增加了一层HTTP转TCP的前置服务,如下图:

image-20230531090517623

不过当设备数量不断增加时,HTTP转TCP前置服务就需要增加负载,而前置服务在与采集抄表系统进行通讯交互时,要建立一条Socket连接通道,一台设备在通讯周期内仅有一个连接,这就为负载问题增加了复杂度,多机负载时,设备进行指令交互就需要保证运营商IoT平台发出的HTTP请求每次都是发到同一台前置服务上。

运营商平台回调通讯时,请求参数中会附带NB设备的device_id,根据设备请求参数的不同,在Nginx中实现特定的负载均衡算法,从而达到定向的流量分发。

image-20230531090542541

二、环境搭建

OpenResty环境搭建

服务器环境:CentOS 7.5 IP:10.200.6.171

1、安装基础依赖组件

yum install -y libreadline-dev libpcre3-dev pcre-devel openssl-devel libssl-dev perl gcc

2、创建目录并下载安装包,完成后解压即可

mkdir -p /usr/local/software
cd /usr/local/software
wget https://openresty.org/download/ngx_openresty-1.9.7.1.tar.gz
tar -zxvf ngx_openresty-1.9.7.1.tar.gz

3、进入解压目录后编译安装

cd ngx_openresty-1.9.7.1
./configure

image-20230531090703689

配置完成后执行完成安装

gmake
gmake install

默认情况下程序会被安装到 /usr/local/openresty 目录,可以使用

./configure --help

查看更多配置选项。

4、运行实例

安装成功后,进入OpenResty目录中可以看到有很多模块,Nginx和Lua都包含其中,进入nginx目录,启动nginx服务试试。

image-20230531090808521

image-20230531090817698

image-20230531090827661

可以看到nginx服务正常运行,但这并不是我们想要达到的效果,nginx可以作为反向代理服务器拦截特定的请求,做负载均衡转发等,但对于特定接口的类似于http之类的接口的精细化配置,直接使用nginx的话,实际是有点麻烦的,也不推荐这种做法。而OpenResty正是基于这些需求集成了像Redis、MySQL、Cache等大量组件,同时无缝整合了nginx和lua开发环境,使得上述的需求场景实现起来更方便更简单。

三、引入 Lua 脚本

下面通过配置OpenResty来实现访问特定的路径,也就是基于nginx做进一步的拦截,实现nginx和lua的开发。

创建一个工作目录:

mkdir -p /home/www
cd /home/www/
mkdir logs/ conf/

logs目录用于存放日志,conf用于存放配置文件。

然后在conf目录下创建 nginx.conf配置文件,配置内容如下(此处我们将html代码直接写入文件中):

worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    server {
        listen 9000;
        location /lua {
            default_type text/html;
            content_by_lua '
                ngx.say("<p>Hello, OpenResty!</p>")
            ';
        }
    }
}

启动openresty

cd /home/www
/usr/local/openresty/nginx/sbin/nginx -p `pwd`/ -c conf/nginx.conf

浏览器访问:http://10.200.6.171:3247/lua 页面展示正常

image-20230531091000876

上述我们实现了一个简单的页面打印"hello,OpenResty"功能,下面我们使用OpenResty来实现nginx集群的负载均衡。

准备三台服务器,

10.200.6.171 cache1 - 部署OpenResty

10.200.6.170 cache2 - 部署nginx

10.20.11.72 cache3 - 部署nginx

将cache1作为流量或接口转发的节点,所有需要通过nginx作为代理的请求节点首先经过OpenResty进行分发,cache1统一将流量按照特定的负载均衡算法转到cache2和cache3服务器。

image-20230531091038382

进入conf目录添加配置文件

cd /home/www/conf
vim hello.conf
server {
    listen  8181;
    server_name _;

    location /lua {
        default_type 'text/html';
        content_by_lua_file /home/www/conf/hello.lua;
    }
}

修改nginx.conf文件,添加lua配置环境

vim nginx.conf
worker_processes  1;
error_log logs/error.log;
events {
    worker_connections 1024;
}
http {
    lua_package_path "/usr/local/openresty/lualib/?.lua;;";
    lua_package_cpath "/usr/local/openresty/lualib/?.so;;";
    include       hello.conf;
}

添加hello.lua脚本,实现负载均衡算法(此处演示简单的GET请求的负载方法)

vim hello.lua
-- 获取url地址,并取出GET请求的参数
local uri_args = ngx.req.get_uri_args()
local deviceId = uri_args["deviceId"]
-- 配置负载的服务器地址
local host = {"10.20.11.72:12580", "10.200.6.170:12580"}
-- 对参数进行取模计算
local hash = ngx.crc32_long(deviceId)
hash = (hash % 2) + 1
backend = "http://"..host[hash]

local requestBody = "?deviceId="..deviceId
-- 将请求转发到指定的负载地址中
local http = require("resty.http")
local httpc = http.new()
local urlpath = backend..requestBody
local resp, err = httpc:request_uri(urlpath, {
    method = "GET",
    keepalive = false
})

if not resp then
    ngx.say("request error :", err)
    return
end

ngx.say(resp.body)
  
httpc:close()

由于OpenResty默认包中没有"resty.http"依赖,我们需要手动加入

下载lua-resty-http 依赖包,解压后将http.lua和http_header.lua复制到

/usr/local/openresty/lualib/resty

image-20230531091237140

运行 nging -t 检查下配置文件是否正确

/usr/local/openresty/nginx/sbin/nginx -p `pwd`/ -t

image-20230531091320379

运行nginx

/usr/local/openresty/nginx/sbin/nginx -p `pwd`/ -c conf/nginx.conf

打开浏览器输入地址:

http://10.200.6.171:8181/lua?deviceId=2233

image-20230531091411899

修改地址后的参数:

http://10.200.6.171:8181/lua?deviceId=2234

image-20230531091439693

可以看到根据deviceId参数的不同,经负载均衡算法后请求被转发到指定的节点。

四、一致性哈希算法

当然上述的负载算法仅仅只是计算RCR校验和并进行取模,直接使用取模计算效率较低,实际使用不推荐这种方式,这里建议可以使用nginx实现的一致性哈希算法,原理可参考白话解析:一致性哈希算法

下载依赖包 ngx_http_consistent_hash-master.zip

将压缩包上传至 /usr/local/software 目录后解压

unzip ngx_http_consistent_hash-master.zip

完成后进入之前的openresty的解压目录后,重新配置新模块

cd ngx_openresty-1.9.7.1
./configure --add-module=../ngx_http_consistent_hash-master

image-20230531091533714

完成后使用 gmake 进行编译

image-20230531091604576

复制编译好的nginx包到openresty下的nginx目录中,先将原来的可执行文件备份

cd /usr/local/openresty/nginx/sbin
cp nginx nginx.old

复制编译好的nginx可执行文件

cd /usr/local/software/ngx_openresty-1.9.7.1/build/nginx-1.9.7/objs
cp -r nginx /usr/local/openresty/nginx/sbin/

完成后我们开始修改配置文件(此处演示POST请求的负载方案,负载机部署的为实际使用程序)

cd /home/www/conf
vim hello.conf
server {
    listen  8181;
    server_name _;

    location /HWIoT {
        set $hashkey "";
        set $backendupstream "hashbackend";
        rewrite_by_lua_file '/home/www/conf/hello.lua';
        proxy_pass http://$backendupstream;
    }

}

upstream hashbackend {
    consistent_hash $hashkey;
    server 10.200.6.170:30235;
    server 10.20.11.72:30238;
}

修改hello.lua脚本

vim hello.lua
-- 入参:$hashkey, $backendupstream
-- 如果是一致性hash,会set $hashkey
-- $backendupstream 表示将会采用的upstream
--
-- 获取POST请求的参数
ngx.req.read_body()
local param = ngx.req.get_body_data()

-- 调用cjson解析库取出参数对象中的deviceId参数
local cjson = require("cjson")
local json = cjson.decode(param)
local deviceId = json["deviceId"]

-- 对nginx中的计算HASH值的参数进行赋值
ngx.var.hashkey = deviceId
ngx.var.backendupstream = "hashbackend"
ngx.log(ngx.INFO, "backendupstream=", ngx.var.backendupstream, ", key=", deviceId)

修改后检测一下

cd /home/www
/usr/local/openresty/nginx/sbin/nginx -p `pwd`/ -t

完成后启动,在postman中使用不同的deviceId参数,查看后台日志也被分发到不同的服务器端中。

cd /home/www
/usr/local/openresty/nginx/sbin/nginx -p `pwd`/ -c conf/nginx.conf

image-20230531091812857

本篇OpenResty的定向负载方案就介绍到这儿,OpenResty的强大之处远不至此,需要大家自己去探索了,附录为OpenResty的一些使用案例。

五、附录

OpenResty实战应用

OpenResty在马蜂窝广告监测中的应用

#OpenResty(1)

评论