OpenResty使用

  |  

OpenResty使用

Nginx 执行的阶段

Nginx 流程定义

​ nginx实际把请求处理流程划分为了11个阶段,这样划分的原因是将请求的执行逻辑细分,各阶段按照处理时机定义了清晰的执行语义,开发者可以很容易分辨自己需要开发的模块应该定义在什么阶段,其定义在http/ngx_http_core_module.h中有定义:

NGX_HTTP_POST_READ_PHASE接收完请求头之后的第一个阶段,它位于uri重写之前,实际上很少有模块会注册在该阶段,默认的情况下,该阶段被跳过
NGX_HTTP_SERVER_REWRITE_PHASEserver级别的uri重写阶段,也就是该阶段执行处于server块内,location块外的重写指令,在读取请求头的过程中nginx会根据host及端口找到对应的虚拟主机配置
NGX_HTTP_FIND_CONFIG_PHASE寻找location配置阶段,该阶段使用重写之后的uri来查找对应的location,值得注意的是该阶段可能会被执行多次,因为也可能有location级别的重写指令
NGX_HTTP_REWRITE_PHASElocation级别的uri重写阶段,该阶段执行location基本的重写指令,也可能会被执行多次
NGX_HTTP_POST_REWRITE_PHASElocation级别重写的后一阶段,用来检查上阶段是否有uri重写,并根据结果跳转到合适的阶段
NGX_HTTP_PREACCESS_PHASE访问权限控制的前一阶段,该阶段在权限控制阶段之前,一般也用于访问控制,比如限制访问频率,链接数等
NGX_HTTP_ACCESS_PHASE访问权限控制阶段,比如基于ip黑白名单的权限控制,基于用户名密码的权限控制等
NGX_HTTP_POST_ACCESS_PHASE问权限控制的后一阶段,该阶段根据权限控制阶段的执行结果进行相应处理
NGX_HTTP_TRY_FILES_PHASEtry_files指令的处理阶段,如果没有配置try_files指令,则该阶段被跳过
NGX_HTTP_CONTENT_PHASE内容生成阶段,该阶段产生响应,并发送到客户端
NGX_HTTP_LOG_PHASE日志记录阶段,该阶段记录访问日志

Nginx 11阶段

​ 1. 当请求进入Nginx后先READ REQUEST HEADERS 读取头部 然后再分配由哪个指令操作

  1. Identity 寻找匹配哪个Location*

  2. Apply Rate Limits 是否要对该请求限制

  3. Preform Authertication 权限验证

  4. Generate Content 生成给用户的响应内容

  5. 如果配置了反向代理 那么将要和上游服务器通信 Upstream Services

  6. 当返回给用户请求的时候要经过过滤模块 Response Filter

  7. 发送给用户的同时 记录一个Log日志

详细介绍

阶段描述
post-read接收到完整的http头部后处理的阶段,在uri重写之前。一般跳过
server-rewritelocation匹配前,修改uri的阶段,用于重定向,location块外的重写指令(多次执行)
find-configuri寻找匹配的location块配置项(多次执行)
rewrite找到location块后再修改uri,location级别的uri重写阶段(多次执行)
post-rewrite防死循环,跳转到对应阶段
preaccess权限预处理
access判断是否允许这个请求进入
post-access向用户发送拒绝服务的错误码,用来响应上一阶段的拒绝
try-files访问静态文件资源
content内容生成阶段,该阶段产生响应,并发送到客户端
log记录访问日志

OpenResty简介

​ OpenResty(又称:ngx_openresty) 是一个基于 NGINX 的可伸缩的 Web 平台,由中国人章亦春发起,提供了很多高质量的第三方模块。

​ OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台。我们知道开发 Nginx 的模块需要用 C 语言,同时还要熟悉它的源码,成本和门槛比较高。国人章亦春把 LuaJIT VM 嵌入到了 Nginx 中,使得可以直接通过 Lua 脚本在 Nginx 上进行编程,同时还提供了大量的类库(如:lua-resty-mysql lua-resty-redis 等),直接把一个 Nginx 这个 Web Server 扩展成了一个 Web 框架,借助于 Nginx 的高性能,能够快速地构造出一个足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

​ Nginx 采用的是 master-worker 模型,一个 master 进程管理多个 worker 进程,worker 真正负责对客户端的请求处理,master 仅负责一些全局初始化,以及对 worker 进行管理。在 OpenResty 中,每个 worker 中有一个 Lua VM,当一个请求被分配到 worker 时,worker 中的 Lua VM 里创建一个 coroutine(协程) 来负责处理。协程之间的数据隔离,每个协程具有独立的全局变量 _G

处理请求流程

​ 由于 Nginx 把一个请求分成了很多阶段,第三方模块就可以根据自己的行为,挂载到不同阶段处理达到目的。OpenResty 也应用了同样的特性。不同的阶段,有不同的处理行为,这是 OpenResty 的一大特色。OpenResty 处理一个请求的流程参考下图(从 Request start 开始):

指令描述
init_by_lua,init_by_lua_block运行在Nginx loading-config 阶段,注册Nginx Lua全局变量,和一些预加载模块。是Nginx master进程在加载Nginx配置时执行
init_worker_by_lua在Nginx starting-worker阶段,即每个nginx worker启动时会调用,通常用来hook worker进程,并创建worker进行的计时器,用来健康检查,或者设置熔断记时窗口等等。
access_by_lua在access tail阶段,用来对每次请求做访问控制,权限校验等等,能拿到很多相关变量。例如:请求体中的值,header中的值,可以将值添加到ngx.ctx, 在其他模块进行相应的控制
balancer_by_lua通过Lua设置不同的负载均衡策略, 具体可以参考lua-resty-balancer
content_by_lua在content阶段,即content handler的角色,即对于每个api请求进行处理,注意不能与proxy_pass放在同一个location下
proxy_pass真正发送请求的一部分, 通常介于access_by_lua和log_by_lua之间
header_filter_by_lua在output-header-filter阶段,通常用来重新响应头部,设置cookie等,也可以用来作熔断触发标记
body_filter_by_lua对于响应体的content进行过滤处理
log_by_lua记录日志即,记录一下整个请求的耗时,状态码等

常用命令

主要帮助对http请求取参、取header头、输出等

命令描述
ngx.arg指令参数,如跟在content_by_lua_file后面的参数
ngx.varrequest变量,ngx.var.VARIABLE引用某个变量,lua使用nginx内置的绑定变量. ngx.var.remote_addr为获取远程的地址,
ngx.ctx请求的lua上下文,每次请求的上下文,可以在ctx里记录,每次请求上下文的一些信息,例如:request_id, access_key等等
ngx.header响应头,ngx.header.HEADER引用某个头
ngx.status响应码
ngx.log输出到error.log
ngx.send_headers发送响应头
ngx.headers_sent响应头是否已发送
ngx.resp.get_headers获取响应头
ngx.is_subrequest当前请求是否是子请求
ngx.location.capture发布一个子请求
ngx.location.capture_multi发布多个子请求
ngx.print输出响应
ngx.say输出响应,自动添加‘\n‘
ngx.flush刷新响应
ngx.exit结束请求

Openresty安装

yum安装

你可以在你的 CentOS 系统中添加 openresty 仓库,这样就可以便于未来安装或更新我们的软件包(通过 yum update 命令)

运行下面的命令就可以添加我们的仓库:

1
2
sudo yum install yum-utils
sudo yum-config-manager --add-repo https://openresty.org/package/centos/openresty.repo

然后就可以像下面这样安装软件包,比如 openresty:

1
sudo yum install openresty

如果你想安装命令行工具 resty,那么可以像下面这样安装 openresty-resty 包:

1
sudo yum install openresty-resty

源代码编译安装

安装所需依赖包

安装编译环境

1
yum install -y make cmake gcc gcc-c++ autoconf automake libpng-devel libjpeg-devel zlib libxml2-devel ncurses-devel bison libtool-ltdl-devel libiconv libmcrypt mhash mcrypt pcre-devel openssl-devel freetype-devel libcurl-devel lua-devel readline-devel curl wget
下载最新版源码

下载最新版源码

1
2
wget https://openresty.org/download/openresty-1.17.8.2.tar.gz
tar -zxvf openresty-1.15.8.1.tar.gz # 解压openresty
下载缓存插件

http://labs.frickle.com/nginx_ngx_cache_purge/地址下载最新版缓存插件

1
2
wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz
tar -zxvf ngx_cache_purge-2.3.tar.gz #解压缓存插件
编译OpenResty

选择需要的插件启用, –with-Components 激活组件,–without 则是禁止组件 ,–add-module是安装第三方模块

1
./configure --prefix=/usr/local/openresty --with‐luajit --without‐http_redis2_module --with-http_stub_status_module --with-http_v2_module --with-http_gzip_static_module --with-http_sub_module --add-module=/usr/local/openresty/modules/ngx_cache_purge-2.3 #配置缓存插件的源码路径

出现如下界面表示编译成功

安装OpenResty
1
gmake && gmake install

环境设置
1
2
3
vi /etc/profile	##加入path路径
export PATH=$PATH:/usr/local/openresty/nginx/sbin/
source /etc/profile ##生效配置
查看环境
1
2
nginx -v
nginx version: openresty/1.17.8.2

查看安装的组件

1
nginx -V

运行测试

创建Nginx配置文件

我们在 conf 目录下创建一个 nginx.conf 文件 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
worker_processes  1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 9000;
location / {
default_type text/html;
content_by_lua '
ngx.say("<p>Hello, World!</p>")
';
}
}
}

如果你熟悉 nginx 的配置,应该对以上代码就很熟悉。这里我们将 html 代码直接写在了配置文件中。

启动 OpenResty
1
nginx -c /usr/local/openresty/nginx/conf/nginx.conf

接下来我们可以使用 curl 来测试是否能够正常范围

1
2
[root@localhost ~]# curl http://localhost:9000/
<p>Hello, World!</p>

我们在配置文件写的 html 已正常输出。

OpenResty 命令详解

openresty -h | -?

含义:查看OpenResty的帮助,可以得知当前的版本号以及全部指令的使用方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost bin]# ./openresty -h
nginx version: openresty/1.17.8.2
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
-?,-h : this help
-v : show version and exit
-V : show version and configure options then exit
-t : test configuration and exit
-T : test configuration, dump it and exit
-q : suppress non-error messages during configuration testing
-s signal : send signal to a master process: stop, quit, reopen, reload
-p prefix : set prefix path (default: /usr/local/openresty/nginx/)
-c filename : set configuration file (default: conf/nginx.conf)
-g directives : set global directives out of configuration file

openresty -v

含义:查看当前OpenResty的版本

1
2
[root@localhost bin]# ./openresty -v
nginx version: openresty/1.17.8.2

openresty -V

含义:查看当前OpenResty的编译信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[root@localhost bin]# ./openresty -V
nginx version: openresty/1.17.8.2
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC)
built with OpenSSL 1.0.2k-fips 26 Jan 2017
TLS SNI support enabled
configure arguments:
--prefix=/usr/local/openresty/nginx
--with-cc-opt=-O2
--add-module=../ngx_devel_kit-0.3.1
--add-module=../echo-nginx-module-0.62
--add-module=../xss-nginx-module-0.06
--add-module=../ngx_coolkit-0.2
--add-module=../set-misc-nginx-module-0.32
--add-module=../form-input-nginx-module-0.12
--add-module=../encrypted-session-nginx-module-0.08
--add-module=../srcache-nginx-module-0.32
--add-module=../ngx_lua-0.10.17
--add-module=../ngx_lua_upstream-0.07
--add-module=../headers-more-nginx-module-0.33
--add-module=../array-var-nginx-module-0.05
--add-module=../memc-nginx-module-0.19
--add-module=../redis-nginx-module-0.3.7
--add-module=../rds-json-nginx-module-0.15
--add-module=../rds-csv-nginx-module-0.09
--add-module=../ngx_stream_lua-0.0.8
--with-ld-opt=-Wl,-rpath,/usr/local/openresty/luajit/lib
--with-http_stub_status_module
--with-http_v2_module
--with-http_gzip_static_module
--with-http_sub_module
--add-module=/usr/local/openresty/modules/ngx_cache_purge-2.3
--with-stream
--with-stream_ssl_module
--with-stream_ssl_preread_module
--with-http_ssl_module

openresty -t | -T

含义:检查当前nginx.conf文件的语法错误。运行这个命令只是去检查语法并不会去启动OpenResty。

1
2
3
[root@localhost bin]# ./openresty -t
nginx: the configuration file /usr/local/openresty/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/openresty/nginx/conf/nginx.conf test is successful

openresty -s 信号

含义:使用”-s”选项,会主动想openrest的master进程发送信号,可以通过信号的类型来执行不同的操作。

1
./openresty -s stop

Lua基础功能使用

hello world

创建 helloworld.lua
1
ngx.exec("/item/get?id=1");
修改 nginx.conf
1
2
3
location /helloworld {
content_by_lua_file ../lua/helloworld.lua;
}
重启 nginx
1
nginx -s reload
验证

访问 http://localhost/helloworld

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"status": "success",
"data": {
"id": 1,
"title": "聚焦Java性能优化 打造亿级流量秒杀系统(附赠秒杀项目)",
"price": 366,
"stock": 98,
"description": "打破秒杀项目性能提升的多重瓶颈 多种硬核技术实现全面优化",
"sales": 12,
"imgUrl": "https://img2.mukewang.com/szimg/5cda946c0826e4c006000338-228-128.jpg",
"promoStatus": 0,
"promoPrice": null,
"promoId": null,
"startDate": null
}
}

获取请求 uri 参数

获取url参数 ngx.var.arg_xx与ngx.req.get_uri_args[“xx”]两者都是为了获取请求uri中的参数

修改nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
location /print_param {
content_by_lua_block {
local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
ngx.say("[GET ] key:", k, " v:", v)
end

ngx.req.read_body() -- 解析 body 参数之前一定要先读取 body
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
ngx.say("[POST] key:", k, " v:", v)
end
}
}
输出结果
1
2
3
4
5
curl '127.0.0.1/print_param?a=1&b=2%26' -d 'c=3&d=4%26'
[GET ] key:b v:2&
[GET ] key:a v:1
[POST] key:d v:4&
[POST] key:c v:3

​ 从这个例子中,我们可以很明显看到两个函数 ngx.req.get_uri_argsngx.req.get_post_args 获取数据来源是有明显区别的,前者来自 uri 请求参数,而后者来自 post 请求内容。

传递请求 uri 参数

当我们可以获取到请求参数,自然是需要这些参数来完成业务控制目的。大家都知道,URI 内容传递过程中是需要调用 ngx.encode_args 进行规则转义。

修改nginx.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
location /test {
content_by_lua_block {
local res = ngx.location.capture(
'/print_param',
{
method = ngx.HTTP_POST,
args = ngx.encode_args({a = 1, b = '2&'}),
body = ngx.encode_args({c = 3, d = '4&'})
}
)
ngx.say(res.body)
}
}
输出结果:
1
2
3
4
5
curl '127.0.0.1/test'
[GET] key:b v:2&
[GET] key:a v:1
[POST] key:d v:4&
[POST] key:c v:3

与我们预期是一样的。

获取请求类型

修改nginx.conf
1
2
3
4
5
location /lua_request{
default_type 'text/html';
lua_code_cache off;
content_by_lua_file /usr/example/lua/lua_request.lua;
}
lua_request.lua

vim /usr/example/lua/lua_request.lua ,添加一下代码:

1
2
3
4
5
6
7
8
9
10
local arg = ngx.req.get_uri_args()
for k,v in pairs(arg) do
ngx.say("[GET ] key:", k, " v:", v)
end

ngx.req.read_body() -- 解析 body 参数之前一定要先读取 body
local arg = ngx.req.get_post_args()
for k,v in pairs(arg) do
ngx.say("[POST] key:", k, " v:", v)
end

在上述例子中有以下的api

  • ngx.req.get_uri_args 获取在uri上的get类型参数,返回的是一个table类型的数据结构。
  • ngx.req.read_body 读取body,这在解析body之前,一定要先读取body。
  • ngx.req.get_post_args 获取form表单类型的参数,返回结果是一个table类型的数据。
使用curl模拟请求

curl ‘http://116.196.177.123/lua_request?a=323&b=ss’ -d ‘c=12w&d=2se3’

返回的结果:

1
2
3
4
[GET ] key:b v:ss
[GET ] key:a v:323
[POST] key:d v:2se3
[POST] key:c v:12w

获取请求头

修改lua_request.lua

在原有的代码基础上,再添加一下代码

1
2
3
4
5
6
7
8
9
10
11
12
local headers = ngx.req.get_headers()
ngx.say("headers begin", "<br/>")
ngx.say("Host : ", headers["Host"], "<br/>")
ngx.say("user-agent : ", headers["user-agent"], "<br/>")
ngx.say("user-agent : ", headers.user_agent, "<br/>")
for k,v in pairs(headers) do
if type(v) == "table" then
ngx.say(k, " : ", table.concat(v, ","), "<br/>")
else
ngx.say(k, " : ", v, "<br/>")
end
end

重新加载nginx -s reload

使用curl模拟请求

curl ‘http://116.196.177.123/lua_request?a=323&b=ss’ -d ‘c=12w&d=2se3’

1
2
3
4
5
6
7
8
9
10
11
12
13
[GET ] key:b v:ss
[GET ] key:a v:323
[POST] key:d v:2se3
[POST] key:c v:12w
headers begin<br/>
Host : 116.196.77.157<br/>
user-agent : curl/7.53.0<br/>
user-agent : curl/7.53.0<br/>
host : 116.196.77.157<br/>
content-type : application/x-www-form-urlencoded<br/>
accept : */*<br/>
content-length : 12<br/>
user-agent : curl/7.53.0<br/>

获取http的其他方法

在原有的代码基础上,再添加一下代码

1
2
3
4
5
6
7
8
ngx.say("ngx.req.http_version : ", ngx.req.http_version(), "<br/>")  
--请求方法
ngx.say("ngx.req.get_method : ", ngx.req.get_method(), "<br/>")
--原始的请求头内容
ngx.say("ngx.req.raw_header : ", ngx.req.raw_header(), "<br/>")
--请求的body内容体
ngx.say("ngx.req.get_body_data() : ", ngx.req.get_body_data(), "<br/>")
ngx.say("<br/>")

重新加载nginx -s reload

使用curl模拟请求

curl ‘http://116.196.177.123/lua_request?a=323&b=ss’ -d ‘c=12w&d=2se3’

1
2
3
4
5
6
7
8
//....
ngx.req.http_version : 1.1<br/>
ngx.req.get_method : POST<br/>
ngx.req.raw_header : POST /lua_request?a=323&b=ss HTTP/1.1
Host: 116.196.77.157
User-Agent: curl/7.53.0
Accept: */*
Content-Length: 12

输出响应

修改nginx.conf
1
2
3
4
5
location /lua_response{
default_type 'text/html';
lua_code_cache off;
content_by_lua_file /usr/example/lua/lua_response.lua ;
}
lua_response.lua

lua_response.lua 添加一下代码

1
2
3
4
5
ngx.header.a="1"
ngx.header.b={"a","b"}
ngx.say("hello","</br>")
ngx.print("sss")
return ngx.exit(200)

上述代码中有以下api:

  • ngx.header 向响应头输出内容
  • ngx.say 输出响应体
  • ngx.print输出响应体
  • ngx.exit 指定http状态码退出
使用curl模拟请求

curl ‘http://116.196.177.123/lua_response’ ,获取的响应体如下:

1
2
hello
sss

日志输出

修改nginx.conf
1
2
3
4
5
location /lua_log{
default_type 'text/html';
lua_code_cache off;
content_by_lua_file /usr/example/lua/lua_log.lua;
}
lua_log.lua

lua_log.lua 加上以下代码

1
2
3
4
local log="i'm log"
local num =10
ngx.log(ngx.ERR, "log",log)
ngx.log(ngx.INFO,"num:" ,num)

重新加载配置文件nginx -s reload

测试

重新加载配置文件nginx -s reload

curl ‘http://116.196.177.123/lua_log’

打开nginx 的logs目录下的error.log 文件:

tail -fn 1000 /usr/servers/nginx/logs/error.log

日志级别

可以看到在日志文件中已经输出了日志,这种日志主要用于记录和测试。

  • ngx.STDERR – 标准输出
  • ngx.EMERG – 紧急报错
  • ngx.ALERT – 报警
  • ngx.CRIT – 严重,系统故障,触发运维告警系统
  • ngx.ERR – 错误,业务不可恢复性错误
  • ngx.WARN – 告警,业务中可忽略错误
  • ngx.NOTICE – 提醒,业务比较重要信息
  • ngx.INFO– 信息,业务琐碎日志信息,包含不同情况判断等
  • ngx.DEBUG – 调试

Lua多级缓存架构

Redis集群配置

安装配置

lua_resty_redis 它是一个基于cosocket API的为ngx_lua模块提供Lua redis客户端的驱动。

lua_resty_redis模块地址:https://github.com/cuiweixie/lua-resty-redis-cluster

  • lua-resty-redis-cluster/lib/redis_slot.c 拷贝到 openresty/lualib 目录下

  • lua-resty-redis-cluster/lib/resty/rediscluster.lua 拷贝到 openresty/lualib/resty

编译redis_slot

需要将edis_slot.c编译成libredis_slot.so才能使用

cd 到 openresty/lualib目录下 执行下面命令进行编译

1
gcc redis_slot.c -fPIC -shared -o libredis_slot.so

如果出现 redis_slot.c:1:17: 致命错误:lua.h:没有那个文件或目录 找不到lua.h等文件

yum install lua-devel下载一个依赖

连接Redis集群封装

创建redis.lua的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
--操作Redis集群,封装成一个模块
--引入依赖库
local redis_cluster = require "resty.rediscluster"

--配置Redis集群链接信息
local config = {
name = "test",
serv_list = {
{ip="192.168.64.143", port = 7001},
{ip="192.168.64.143", port = 7002},
{ip="192.168.64.143", port = 7003},
{ip="192.168.64.143", port = 7004},
{ip="192.168.64.143", port = 7005},
{ip="192.168.64.143", port = 7006},
},
idle_timeout = 1000,
pool_size = 10000,
}

--定义一个对象
local lredis = {}

--创建set()添加数据方法
function lredis.set(key,value)
--1)打开链接
local red = redis_cluster:new(config)
red:init_pipeline()

--2)执行命令【set】
red:set(key,value)
red:commit_pipeline()

--3)关闭链接
red:close()
end


--创建查询数据get()
function lredis.get(key)
--1)打开链接
local red = redis_cluster:new(config)
red:init_pipeline()

--2)执行命令【set】
red:get(key)
local result = red:commit_pipeline()

--3)关闭链接
red:close()

--4)返回结果集
return result
end

return lredis

Mysql配置

安装配置

因为安装OpenResty是已经自带了mysql所以无需在安装mysql模块

查看mysql模块

1
2
3
[root@localhost resty]# /usr/local/openresty/lualib/resty
[root@localhost resty]# ls |grep mysql
mysql.lua

已经存在mysql模块

连接Mysql封装

创建mysql.lua的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
--MySQL查询操作,封装成一个模块
--Java操作MySqL
--导入依赖包
local mysql = require "resty.mysql"

--配置数据源链接
local props = {
host = "192.168.64.143",
port = 3306,
database = "test",
user = "root",
password = "root"
}

--创建一个对象
local mysqldb = {}


--查询数据库
function mysqldb.query(sql)
--创建链接
local db = mysql:new()
--设置超时时间
db:set_timeout(10000)
db:connect(props)

--配置编码格式
db:query("SET NAMES utf8")

--查询数据库 "select * from activity_info where id=1"
local result = db:query(sql)

--关闭链接
db:close()
--返回结果集
return result
end

return mysqldb

创建多级缓存脚本

创建activity.lua

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
--多级缓存流程操作
--1)Lua脚本查询Nginx缓存
--2)Nginx如果没有缓存
--2.1)Lua脚本查询Redis
--2.1.1)Redis如果有数据,则将数据存入到Nginx缓存,并响应用户
--2.1.2)Redis没有数据,Lua脚本查询MySQL
-- MySQL有数据,则将数据存入到Redis、Nginx缓存[需要额外定义],响应用户
--3)Nginx如果有缓存,则直接将缓存响应给用户



--响应数据为JSON类型
ngx.header.content_type="application/json;charset=utf8"
--引入依赖库
--cjson:对象转JSON或者JSON转对象
local cjson = require("cjson")
local mysql = require("mysql")
local lrredis = require("redis")

--获取请求参数ID http://192.168.211.141/act?id=1
local id = ngx.req.get_uri_args()["id"];

--加载本地缓存
local cache_ngx = ngx.shared.act_cache;

--组装本地缓存的key,并获取nginx本地缓存
local ngx_key = 'ngx_act_cache_'..id
local actCache = cache_ngx:get(ngx_key)

--如果nginx中没有缓存,则查询Redis集群缓存
if actCache == "" or actCache == nil then
--从Redis集群中加载数据
local redis_key = 'redis_act_'..id
local result = lrredis.get(redis_key)

--Redis中数据为空,查询数据库
if result[1]==nil or result[1]==ngx.null then
--组装SQL语句
local sql = "select * from activity_info where id ="..id
--执行查询
result = mysql.query(sql)
--数据不为空,则添加到Redis中
if result[1]==nil or result[1]==ngx.null then
ngx.say("no data")
else
--数据添加到Nginx缓存和Redis缓存
lrredis.set(redis_key,cjson.encode(result))
cache_ngx:set(ngx_key, cjson.encode(result), 2*60);
ngx.say(cjson.encode(result))
end
else
--将数据添加到Nginx缓存中
cache_ngx:set(ngx_key, result, 2*60);
--直接输出
ngx.say(result)
end
else
--输出缓存数据
ngx.say(actCache)
end

前置工作

安装mysql

参考【Docker安装MySQL

安装Redis集群

参考【Redis安装部署

配置docker-compose

编辑docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
version: '2'   
services:
redis01:
image: redis
hostname: redis01
container_name: redis01
networks:
docker-network:
ipv4_address: 172.18.0.2
ports:
- "7001:6379"
volumes:
- "/tmp/etc/redis/redis.conf:/etc/redis/redis.conf"
- "/tmp/data/redis/node1:/data"
command:
redis-server /etc/redis/redis.conf
redis02:
image: redis
hostname: redis02
container_name: redis02
networks:
docker-network:
ipv4_address: 172.18.0.3
ports:
- "7002:6379"
volumes:
- "/tmp/etc/redis/redis.conf:/etc/redis/redis.conf"
- "/tmp/data/redis/node2:/data"
command:
redis-server /etc/redis/redis.conf
redis03:
image: redis
hostname: redis03
container_name: redis03
networks:
docker-network:
ipv4_address: 172.18.0.4
ports:
- "7003:6379"
volumes:
- "/tmp/etc/redis/redis.conf:/etc/redis/redis.conf"
- "/tmp/data/redis/node3:/data"
command:
redis-server /etc/redis/redis.conf
redis04:
image: redis
hostname: redis04
container_name: redis04
networks:
docker-network:
ipv4_address: 172.18.0.5
ports:
- "7004:6379"
volumes:
- "/tmp/etc/redis/redis.conf:/etc/redis/redis.conf"
- "/tmp/data/redis/node4:/data"
command:
redis-server /etc/redis/redis.conf
redis05:
image: redis
hostname: redis05
container_name: redis05
networks:
docker-network:
ipv4_address: 172.18.0.6
ports:
- "7005:6379"
volumes:
- "/tmp/etc/redis/redis.conf:/etc/redis/redis.conf"
- "/tmp/data/redis/node5:/data"
command:
redis-server /etc/redis/redis.conf
redis06:
image: redis
hostname: redis06
container_name: redis06
networks:
docker-network:
ipv4_address: 172.18.0.7
ports:
- "7006:6379"
volumes:
- "/tmp/etc/redis/redis.conf:/etc/redis/redis.conf"
- "/tmp/data/redis/node6:/data"
command:
redis-server /etc/redis/redis.conf
mysql:
image: mysql:5.7
hostname: mysql
container_name: mysql
networks:
docker-network:
ipv4_address: 172.18.0.10
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- "/tmp/etc/mysql:/etc/mysql/conf.d"
- "/tmp/data/mysql:/var/lib/mysql"

networks:
docker-network:
ipam:
config:
- subnet: 172.18.0.0/16
gateway: 172.18.0.1

执行docker-compose up -d启动mysql以及redis集群环境

执行集群搭建命令搭建redis集群,参考【Redis安装部署

执行初始化sql

在刚刚创建的mysql中执行初始化sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
/*
SQLyog Ultimate v13.1.1 (64 bit)
MySQL - 5.7.32 : Database - test
*********************************************************************
*/

/*!40101 SET NAMES utf8 */;

/*!40101 SET SQL_MODE=''*/;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
CREATE DATABASE /*!32312 IF NOT EXISTS*/`test` /*!40100 DEFAULT CHARACTER SET latin1 */;

USE `test`;

/*Table structure for table `activity_info` */

DROP TABLE IF EXISTS `activity_info`;

CREATE TABLE `activity_info` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(100) DEFAULT NULL COMMENT '活动名称',
`desc` varchar(3000) DEFAULT NULL COMMENT '活动介绍',
`starttime` datetime DEFAULT NULL,
`endtime` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

/*Data for the table `activity_info` */

insert into `activity_info`(`id`,`name`,`desc`,`starttime`,`endtime`) values
(1,'双十一红包雨活动','10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!10亿红包等你拿,活动只有1小时!','2020-06-30 23:19:49','2020-05-26 23:19:56');

/*Table structure for table `money_log` */

DROP TABLE IF EXISTS `money_log`;

CREATE TABLE `money_log` (
`id` varchar(60) NOT NULL,
`money` double DEFAULT NULL COMMENT '抢到的金额',
`createtime` datetime DEFAULT NULL COMMENT '抢到的时间',
`username` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='抢红包记录';

/*Data for the table `money_log` */

insert into `money_log`(`id`,`money`,`createtime`,`username`) values
('0bd5b66e-d94a-43e9-8a9f-26cfcac60d8a',10,'2020-08-23 17:53:47','zhangsan'),
('6dc4d8ce-1548-4285-b9e7-da441a304a64',57,'2020-08-23 17:48:11','zhangsan'),
('8afbc7b9-11fa-4840-bc3a-086d6a1ce0d4',6,'2020-08-23 17:53:45','zhangsan'),
('ce40d6cb-3763-403a-9c8e-9be371aa1318',24,'2020-08-23 17:47:38','zhangsan'),
('ttttt',15,'2020-08-23 17:48:41','zhangsan');

/*Table structure for table `money_package` */

DROP TABLE IF EXISTS `money_package`;

CREATE TABLE `money_package` (
`id` int(11) NOT NULL COMMENT '主键ID',
`money` int(11) NOT NULL COMMENT '红包总金额',
`count` int(11) NOT NULL COMMENT '红包数量',
`sort` int(2) DEFAULT NULL COMMENT '发红包顺序',
`type` int(11) DEFAULT '1' COMMENT '红包发放类型 1:延时发放 2:立即发放',
`hasload` int(1) DEFAULT '1' COMMENT '加载位置 1:未加载 2:加载到程序 3:加载到Redis缓存',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `money_package` */

insert into `money_package`(`id`,`money`,`count`,`sort`,`type`,`hasload`) values
(1,9000,20,1,1,3),
(2,1500,11,2,1,3),
(3,1600,100,3,1,3),
(4,1900,10,4,1,3),
(5,1500,11,5,1,3),
(6,111,11,6,1,3),
(7,9999,10,7,1,3),
(8,2,2,8,1,3),
(9,222,2,9,1,3);

/*Table structure for table `user_info` */

DROP TABLE IF EXISTS `user_info`;

CREATE TABLE `user_info` (
`username` varchar(20) NOT NULL COMMENT '用户名',
`sex` varchar(2) DEFAULT NULL,
`name` varchar(20) DEFAULT NULL,
`level` int(1) NOT NULL DEFAULT '1' COMMENT '会员等级',
`age` int(3) DEFAULT NULL,
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `user_info` */

insert into `user_info`(`username`,`sex`,`name`,`level`,`age`) values
('c','男','C',1,34),
('lisi','男','李四',1,31),
('wangwu','男','王五',1,29);

/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

OpenResty配置

配置lua脚本

将刚刚创建的redis.luamysql.lua以及activity.lua复制到 /usr/local/openresty/nginx/lua目录下

1
2
3
4
5
6
[root@localhost local]# cd openresty/nginx/lua
[root@localhost lua]# ll
总用量 12
-rw-r--r--. 1 root root 1859 10月 26 17:55 activity.lua
-rw-r--r--. 1 root root 689 10月 26 17:53 mysql.lua
-rw-r--r--. 1 root root 1128 10月 26 17:21 redis.lua
nginx配置文件

修改nginx.conf

vi conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

#user nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;


#gzip on;
#脚本位置
lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";

#定义Nginx缓存
lua_shared_dict act_cache 128m;

server {
listen 80;
server_name localhost;

#跨域配置
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET,POST';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';


#根据ID实现活动查询
location /act {
content_by_lua_file /usr/local/openresty/nginx/lua/activity.lua;
}
}
}

注意:lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";后面是两个分号,只有一个分号将导致加载默认lua库失败

启动nginx

指定配置文件启动

如果nginx没有启动执行如下命令启动

1
nginx -c /usr/local/openresty/nginx/conf/nginx.conf
重新加载配置文件

如果nginx已经启动只是更改了配置文件,执行如下命令重新加载新的配置

1
nginx -s reload

测试

访问测试

访问 http://192.168.64.143/act?id=1

能够访问成功说明已经搭建成功

检查Redis数据

检查redis也存在数据

Lua发送MQ消息

准备工作

安装RabbitMQ环境

因为lua 连接rabbitmq 需要使用STOMP插件的61613端口,普通RabbitMQ安装

docker 运行rabbitmq
1
docker run -d -p 5672:5672 -p 15672:15672 -p 61613:61613 --name rabbitmq rabbitmq:management
  • -p 15672:15672 将在容器15672接口的控制台map到本地的8080接口

  • -p 5672:5672 暴漏MQ默认服务端口

  • -p 61613:61613 暴露STOMP插件的默认服务端口

安装STOMP插件

获得容器的bash

1
docker exec -ti rabbitmq /bin/bash

手动安装rabbitmq_stomp插件

1
rabbitmq-plugins enable rabbitmq_stomp

登录验证

RabbitMQ控制台查看显示STOMP插件在61613端口启动

安装RabbitMQ模块
  1. 在release页面https://github.com/wingify/…下载项目源码,截止到目前最新版为v0.1
  2. 将压缩包中目录lua-resty-rabbitmqstomp-0.1\lib\resty下的所有lua文件复制到OpenResty的lualib/resty目录
安装JWT模块
  1. 在release页面https://github.com/SkyLothar/…下载项目源码,截止到目前最新版为v0.1.11

  2. 将压缩包中目录lua-resty-jwt-0.1.11/lib/resty/下的所有lua文件复制到OpenResty的lualib/resty目录

测试验证

修改nginx.conf验证是否生效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
worker_processes  1;
error_log logs/error.log info;


events {
worker_connections 1024;
}
http {
server {
listen 8080;
default_type text/plain;
location = / {
content_by_lua '
local cjson = require "cjson"
local jwt = require "resty.jwt"

local jwt_token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9" ..
".eyJmb28iOiJiYXIifQ" ..
".VAoRL1IU0nOguxURF2ZcKR0SGKE1gCbqwyh8u2MLAyY"
local jwt_obj = jwt:verify("lua-resty-jwt", jwt_token)
ngx.say(cjson.encode(jwt_obj))
';
}
location = /sign {
content_by_lua '
local cjson = require "cjson"
local jwt = require "resty.jwt"

local jwt_token = jwt:sign(
"lua-resty-jwt",
{
header={typ="JWT", alg="HS256"},
payload={foo="bar"}
}
)
ngx.say(jwt_token)
';
}
}
}

访问测试

1
curl localhost:8080
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"signature": "VAoRL1IU0nOguxURF2ZcKR0SGKE1gCbqwyh8u2MLAyY",
"reason": "everything is awesome~ :p",
"valid": true,
"raw_header": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9",
"payload": {
"foo": "bar"
},
"header": {
"alg": "HS256",
"typ": "JWT"
},
"verified": true,
"raw_payload": "eyJmb28iOiJiYXIifQ"
}

验证通过,jwt模块安装完毕

JWT-TOKEN再封装

创建token.lua的lua文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
--依赖jwt库
local jwt = require("resty.jwt")

-- 定义一个名为 jwttoken 的模块
jwttoken = {}

--秘钥
--令牌校验auth_header->Bearer DSFLSFJLDLKSDJLJF
function jwttoken.check(auth_header,secret)
--定义响应数据
local response = {}

--如果请求头中没有令牌,则直接返回401
if auth_header == nil then
response["code"]=401
response["message"]="没有找到令牌数据"
return response
end

--查找令牌中的Bearer前缀字符,并进行截取
local _, _, token = string.find(auth_header, "Bearer%s+(.+)")

--如果没有Bearer,则表示令牌无效
if token == nil then
response["code"]=401
response["message"]="令牌格式不正确"
return response
end

--校验令牌
local jwt_obj = jwt:verify(secret, token)

--如果校验结果中的verified==false,则表示令牌无效
if jwt_obj.verified == false then
response["code"]=401
response["message"]="令牌无效"
return response
end

--全部校验完成后,说明令牌有效,返回令牌数据
response["code"]=200
response["message"]="令牌校验通过"
response["body"]=jwt_obj
return response
end

return jwttoken
RabbitMQ再封装

创建mq.lua的lua文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
--设置JSON响应
ngx.header.content_type="application/json;charset=utf8"

--引入依赖包
local cjson = require "cjson"
local rabbitmq = require "resty.rabbitmqstomp"
--依赖token.lua,解析令牌数据
local jwttoken = require "token"

--获取请求头Authorization
local auth_header = ngx.var.http_Authorization
--秘钥
local secret = "5pil6aOO5YaN576O5Lmf5q+U5LiN5LiK5bCP6ZuF55qE56yR"
--通过token.lua中的check方法校验
local result = jwttoken.check(auth_header,secret)

--令牌校验通过了,则发送MQ排队信息
if result.code==200 then
--校验通过
--配置MQ的账号密码
local opts = { username = "guest",
password = "guest",
vhost = "/" }
--创建RabbitMQ对象
local mq, err = rabbitmq:new(opts)

--设置超时时间
mq:set_timeout(10000)

--链接RabbitMQ
local ok, err = mq:connect("192.168.64.143",61613)

--配置请求头信息 配置给哪个Queue(队列)发送消息、消息的编码等等
local headers = {}
--目标地址
headers["destination"] = "/queue/red.queue"
headers["receipt"] = "msg#1"
headers["app-id"] = "luaresty"
headers["persistent"] = "true"
--传递的数据的类型
headers["content-type"] = "text/plain"
--编码格式
headers["content_encoding"] = "UTF-8"

--准备消息
local msg = {}
msg["user"]=result.body.payload.username

--发送
local ok, err = mq:send(cjson.encode(msg), headers)

--响应消息
local resp = {}

if not ok then
resp["code"]=500
resp["message"]="手太慢了"
resp["body"]=err
ngx.say(cjson.encode(resp))
return
end

--成功
resp["code"]=200
resp["message"]="排队抢红包!"
resp["body"]=err
ngx.say(cjson.encode(resp))
return
else
--校验失败输出结果集
ngx.say(cjson.encode(result))
end

监听RabbitMQ队列

创建RabbitMQ配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

@Configuration
public class RabbitMQConfig {

/***
* 声明交换机
*/
@Bean(name = "redExchange")
public Exchange topicExchange() {
return ExchangeBuilder.directExchange("exchange.direct").durable(true).build();
}

/***
* 声明队列
*/
@Bean(name = "redQueue")
public Queue itemQueue() {
return QueueBuilder.durable("red.queue").build();
}

/***
* 队列绑定到交换机上
*/
@Bean
public Binding itemQueueExchange(@Qualifier("redQueue") Queue queue,
@Qualifier("redExchange") Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with("red.queue").noargs();
}
}
创建监听器

监听队列red.queue

1
2
3
4
5
6
7
8
9
10
11
@Component
public class QueueConsumer {

private static final Logger logger = LoggerFactory.getLogger(QueueConsumer.class);

@RabbitListener(queues = "red.queue")
public void receiveDelay(Message message) throws IOException {
String msg = new String(message.getBody());
logger.info("接收到消息:{}", msg);
}
}

OpenResty配置

配置lua脚本

将刚刚创建的token.luamq.lua 复制到 /usr/local/openresty/nginx/lua目录下

1
2
3
4
5
6
7
8
[root@localhost local]# cd openresty/nginx/lua
[root@localhost lua]# ll
总用量 20
-rw-r--r--. 1 root root 1859 10月 26 17:55 activity.lua
-rw-r--r--. 1 root root 1763 10月 28 11:27 mq.lua
-rw-r--r--. 1 root root 689 10月 26 17:53 mysql.lua
-rw-r--r--. 1 root root 1128 10月 26 17:21 redis.lua
-rw-r--r--. 1 root root 1271 10月 28 11:27 token.lua
nginx配置文件

修改nginx.conf

vi conf/nginx.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#user  nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;


events {
worker_connections 1024;
}


http {
include mime.types;
default_type application/octet-stream;

#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;


#gzip on;
#脚本位置
lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";

#定义Nginx缓存
lua_shared_dict act_cache 128m;

server {
listen 80;
server_name localhost;

#跨域配置
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET,POST';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';


#根据ID实现活动查询
#http://192.168.64.143/act?id=1
location /act {
content_by_lua_file /usr/local/openresty/nginx/lua/activity.lua;
}
#抢红包
location /red {
content_by_lua_file /usr/local/openresty/nginx/lua/mq.lua;
}
#生成token
location /generate {
default_type text/html;
content_by_lua_block {
--依赖jwt库
local jwt = require("resty.jwt")
local secret = "5pil6aOO5YaN576O5Lmf5q+U5LiN5LiK5bCP6ZuF55qE56yR"
local jwt_token = jwt:sign(
secret,
{
header={typ="JWT", alg="HS256"},
payload={username="baiyp",name="123456"}
}
)
ngx.say(jwt_token)
}
}
}
}

注意:lua_package_path "/usr/local/openresty/nginx/lua/?.lua;;";后面是两个分号,只有一个分号将导致加载默认lua库失败

测试

生成token

浏览器访问 http://192.168.64.143/generate 生成TOKEN

1
2
[root@localhost lua]# curl http://192.168.64.143/generate
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImJhaXlwIiwibmFtZSI6IjEyMzQ1NiJ9.TO_tT57_hY47Y-N1RdN1S8MaOJPl-Vn9h3JB0G8Prkw
Postman 请求队列

运行项目测试

启动MQ监听服务,点击Postman 进行队列测试

1
2
3
2020-10-28 17:41:53.178  INFO 9004 --- [ntContainer#0-1] c.heima.rabbitmq.consumer.QueueConsumer  : 接收到消息:{"user":"baiyp"}
2020-10-28 17:43:01.541 INFO 9004 --- [ntContainer#0-1] c.heima.rabbitmq.consumer.QueueConsumer : 接收到消息:{"user":"baiyp"}
2020-10-28 17:43:02.123 INFO 9004 --- [ntContainer#0-1] c.heima.rabbitmq.consumer.QueueConsumer : 接收到消息:{"user":"baiyp"}

 评论