Nginx集成Lua实现根据POST请求报文内容自定义负载策略
需求概要
如下图,上游服务调用下游服务的接口,部分接口业务高峰期请求量大,下游服务器压力很大,会影响到其它接口的访问。如果通过增加下游服务器横向扩容会增加成本,且在业务高峰期还是有可能影响其他接口。所以需要使用Lua配置一种可以根据报文内容进行负载的策略(调用接口的URL是固定的,下游服务通过解析报文调用对应接口)。
Nginx集成Lua单元
1.资源准备
- luajit-2.1:https://github.com/openresty/luajit2/archive/refs/tags/v2.1-20210510.tar.gz
- nginx-1.18.0.tar.gz:http://nginx.org/download/nginx-1.18.0.tar.gz
- ngx_devel_kit:https://github.com/vision5/ngx_devel_kit/releases/tag/v0.3.1
- lua-nginx-module:https://github.com/openresty/lua-nginx-module/archive/refs/tags/v0.10.10.tar.gz
- 执行命令:yum install -y gcc gcc-c++ make automake cmake
- 执行命令:yum install -y zlib.x86_64 zlib-devel.x86_64 perl.x86_64 perl-devel.x86_64 pcre.x86_64 pcre-devel.x86_64 openssl.x86_64 openssl-devel.x86_64
2.安装luajit
1)解压luajit2-2.1.tar.gz
执行命令:tar -zxvf luajit2-2.1.tar.gz
2)编译安装
执行命令:
cd luajit2-2.1-20210510
make && make install
export LUAJIT_LIB=/usr/local/lib
export LUAJIT_INC=/usr/local/include/luajit-2.1
3.安装Nginx
1)解压相关资源
执行命令:
tar -zxvf lua-nginx-module-0.10.10.tar.gz
tar -zxvf nginx-1.18.0.tar.gz
tar -zxvf ngx_devel_kit-0.3.1.tar.gz
2)编译安装
执行命令:
cd nginx-1.18.0/
执行下面命令前,先配置好最后两行add-module的ngx_devel_kit-0.3.1、lua-nginx-module-0.10.10的正确路径。
执行命令:
./configure \
--user=nobody \
--group=nobody \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/nginx.conf \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/run/nginx.lock \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--with-http_ssl_module \
--with-pcre \
--with-file-aio \
--with-http_realip_module \
--without-http_scgi_module \
--without-http_uwsgi_module \
--without-http_fastcgi_module ${NGINX_DEBUG:+--debug} \
--with-ld-opt="-Wl,-rpath,/usr/local/lib" \
--add-module=/home/nginx_with_lua/ngx_devel_kit-0.3.1 \
--add-module=/home/nginx_with_lua/lua-nginx-module-0.10.10
执行:make && make install
4.验证Lua
1)修改Nginx配置文件
执行命令:
vi /etc/nginx/nginx.conf
添加如下内容:
server {
listen 80;
server_name localhost;
location /hello_lua {
default_type 'text/plain';
content_by_lua 'ngx.say("hello, lua!")';
}
}
执行命令:
nginx -s reload
如下图,在浏览器输入地址返回“hello,lua”后,则Lua单元安装成功。
实现Lua解析POST请求报文
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream tom1 {
#配置业务高峰期承担主要业务的服务器列表
server 192.168.64.4:8081;
server 192.168.64.5:8081;
server 192.168.64.6:8081;
}
upstream tom2 {
#配置业务高峰期承担次要业务的服务器列表
server 192.168.64.6:8082;
}
server {
listen 80;
server_name localhost;
location /hello {
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Url-Scheme $scheme;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
if ($request_method = POST ) {
set $upstream '';
#access_by_lua用于请求访问阶段处理,用于访问控制
access_by_lua '
#读取请求报文
ngx.req.read_body()
local data = ngx.req.get_body_data()
#判断报文中是否含有WMA2000字段
local match1 = ngx.re.match(ngx.var.request_body, "WMA2000")
#判断报文中是否含有WMA2001字段
local match2 = ngx.re.match(ngx.var.request_body, "WMA2001")
#如果POST报文内容中含有WMA2000,则将请求发往tom1负载列表
if match1 then
#使用tom1负载列表
ngx.var.upstream = "tom1"
end
#如果POST报文内容中含有WMA2001,则将请求发往tom2负载列表
if match2 then
#使用tom2负载列表
ngx.var.upstream = "tom2"
end
';
proxy_pass http://$upstream;
}
}
}
}
经验证当POST请求报文带有“WMA2000”字段时,会负载到tom1列表中的服务器。当POST请求报文带有“WMA2001”字段时会负载到tom2列表中的服务器。
欢迎大家留言交流!