由于独立秒杀目前接过来了,但是其核心是利用openresty实现的,本人对此技术栈较为陌生,特写下本篇指导,以期快速上手。
一、openresty入门初步
安装openresty
首先是安装openresty,macOS的安装方式
brew tap openresty/brew
brew install openresty
安装完毕之后,可以得到安装路径,配置到系统PATH中并生效:
export PATH=/usr/local/Cellar/openresty/1.21.4.1_2/nginx/sbin:$PATH
之后就可以校验是否安装成功了,按照如下命令检测:
which nginx
结果显示如下的路径:/usr/local/Cellar/openresty/1.21.4.1_2/nginx/sbin/nginx,则证明安装成功;如果没有任何输出,则表明未安装成功,可以检查安装路径是否正确。
初步使用
新建个文件夹,然后利用如下命令新建conf,logs两个字文件夹:
mkdir conf logs
之后,进行nginx配置文件配置,运行命令如下:
nano conf/nginx.conf
输入内容如下:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
default_type text/html;
content_by_lua_block {
ngx.say("<p>hello, world</p>")
}
}
}
}
写完之后,可以测试脚本是否正常:
openresty -p $PWD/ -c conf/nginx.conf -t
之后在当前目录启动即可:
openresty -p $PWD/ -c conf/nginx.conf
利用如下命令可以看到启动的master,worker进程
ps aux|grep nginx|grep -v /tmp/
这里需要注意下,一些常用的openresty命令如下
(1) 启动 openresty
(2) 重启 openresty -s reload
(3) 关闭 openresty -s stop
浏览器中输入 http://127.0.0.1:8080就可以看到正常的输出结果了。
二、简单的lua脚本
创建新的文件夹,名称分别为 log,conf, lua,命令如下:
mkdir logs conf lua
nginx.conf文件内容如下:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location / {
default_type text/html;
content_by_lua_file /Users/shichaoyang/openresty/hello-module/lua/hello.lua;
}
}
}
可以看到,这里利用content_by_lua_file命令来制定lua脚本文件。其中hello.lua的内容为 :
ngx.say("hello lua");
之后在当前目录启动即可:
openresty -p $PWD/ -c conf/nginx.conf
在浏览器访问,即可以看到正确的输出结果了。
三、lua脚本模块
同样创建logs,conf,lua文件夹,其中nginx.conf文件内容如下:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
lua_package_path "/usr/local/Cellar/openresty/1.21.4.1_2/?.lua;;$prefix/lua/?.lua;";
server {
listen 8081 reuseport;
location / {
default_type text/plain;
content_by_lua_block {
local hello = require "mod"
hello.greet("a lua module");
}
}
}
}
脚本内容如下:
local _M = {}
function _M.greet(name)
ngx.say("hello from name ",name)
end
return _M
之后在当前目录启动即可:
openresty -p $PWD/ -c conf/nginx.conf
可以看到,脚本模块的封装方式。这里需要说明下,nginx启动的时候会从lua_package_path指定的路径中将lua文件加载进来。而content_by_lua_block则可以指定执行的业务逻辑代码。
这里也许有人要问,为什么把openresty按住根目录下的lua文件都加载进来呢,主要原因是因为模块的执行需要resty.core的支持,如果不加入usr/local/Cellar/openresty/1.21.4.1_2/?.lua;; 报错:
ginx: [alert] failed to load the 'resty.core' module (https://github.com/openresty/lua-resty-core); ensure you are using an OpenResty release from https://openresty.org/en/download.html (reason: module 'resty.core' not found:
no field package.preload['resty.core']
所以这里需要将lua_package_path改成 lua_package_path "$prefix/lua/?.lua;/usr/local/lib/lua/?.lua;;";
参见:https://github.com/openresty/lua-nginx-module/issues/1533
四、lua脚本传参
本指导来源于chatGPT回答:
我:openresty多模块之间传参,写一个在两个网页中传参的代码示例
ChatGPT:
以下是一个在两个页面之间传参的OpenResty代码示例:
location /page1 {
content_by_lua_block {
local param1 = ngx.var.arg_param1
local param2 = ngx.var.arg_param2
ngx.redirect("/page2?param1=" .. param1 .. "& param2=" .. param2)
}
}
location /page2 {
content_by_lua_block {
local param1 = ngx.var.arg_param1
local param2 = ngx.var.arg_param2
-- Do something with the two parameters here
}
}
这里我们就根据其指导来实现一下。
同样的,创建logs,conf,lua文件夹,然后nginx.conf内容如下:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
server {
listen 8080;
location /p1 {
default_type text/html;
content_by_lua_file /Users/shichaoyang/openresty/trans-module/lua/p1.lua;
}
location /p2 {
default_type text/html;
content_by_lua_file /Users/shichaoyang/openresty/trans-module/lua/p2.lua;
}
}
}
lua脚本p1内容如下:
local param1 = ngx.var.arg_param1
local param2 = ngx.var.arg_param2
ngx.redirect("/p2?param1=" .. param1 .. "& param2=" .. param2)
lua脚本p2内容如下:
local param1 = ngx.var.arg_param1
local param2 = ngx.var.arg_param2
ngx.say(param1)
ngx.say(param2)
之后在当前目录启动即可:
openresty -p $PWD/ -c conf/nginx.conf
之后访问:
http://127.0.0.1:8080/p1?param1=1& param2=2
则会自动跳转到
http://127.0.0.1:8080/p2?param1=1& param2=2
并输出1 2
更多内容请访问:https://openresty-reference.readthedocs.io/en/latest/Lua_Nginx_API/
五、lua脚本调试
同样的,创建logs,conf,lua文件夹,然后nginx.conf内容如下:
worker_processes 1;
error_log logs/error.log;
events {
worker_connections 1024;
}
http {
lua_package_path "/usr/local/Cellar/openresty/1.21.4.1_2/?.lua;;$prefix/lua/?.lua;";
server {
listen 8080;
location / {
default_type text/html;
content_by_lua_file /Users/shichaoyang/openresty/ut-module/lua/ut.lua;
}
location /test {
content_by_lua_file /Users/shichaoyang/openresty/ut-module/lua/uttest.lua;
}
}
}
ut.lua脚本内容如下:
ngx.say("111")
uttest.lua脚本内容如下:
local iresty_test = require "iresty_test"
local tb = iresty_test.new({unit_name="example"})
function tb:init( )
self:log("init complete")
end
function tb:test_00001( )
error("invalid input")
end
function tb:atest_00002()
self:log("never be called")
end
function tb:test_00003( )
self:log("ok")
end
-- units test
tb:run()
这里需要从https://github.com/iresty/lua-resty-test/blob/master/lib/resty/iresty_test.lua将此文件下载,并放到lua文件夹下面
之后在当前目录启动即可:
openresty -p $PWD/ -c conf/nginx.conf
访问:http://127.0.0.1:8080/test 即可得到测试结果:
0.000 [32m[example] [m[32munit test start
[m0.000 [32m[example] [minit complete
0.000 [32m \_[test_00001] [m[33mfail /Users/shichaoyang/openresty/ut-module/lua/uttest.lua:9: invalid input
[m0.000 [32m \_[test_00003] [m鈫搊k
0.000 [32m \_[test_00003] [m[32mPASS
[m0.000 [32m[example] [m[32munit test complete
[m
六、openresty配置必知必会
1. proxy_pass, 反向代理,是指以代理服务器接收Internet上的链接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接的客户端。
举个例子,比如我的内部服务器是放在212环境上,那么开发的接口如下这样的:
http://192.168.1.212:8136/xxxx 然后端口号是8136,然后直接访问该接口会返回对应的数据,但是接口一般都是域名访问的,因此我们需要在nginx上配置一个域名,假如为 xy.xxx.com, 然后当我们在联调接口的时候,我们使用 http://xy.xxx.com/xxxx 这样的接口时,它会反向代理到 http://192.168.1.212:8136/xxxx 上来,这样它会返回内部服务器的数据给客户端,客户端就拿到对应的数据显示出来了。
2. resolver , DNS解析,一般配制成公共的或者公司内部的都行。
3. allow & deny, allow 和 deny 指令在 ngx_http_access_module 模块中,两个指令分别表示允许或禁止源 IP 访问,用于对源 IP 做访问控制,nginx 是按照自上而下的顺序进行匹配,匹配到一个就不往下继续了。
allow 指令
a、允许哪些 IP 访问,all 表示允许所有;
b、作用域 http / server / location / limit_except ;
deny 指令
a、禁止哪些 IP 访问,all 表示禁止所有;
b、作用域 http / server / location / limit_except ;
location = /request_stat {
allow 192.168.0.0/16;
deny all;
request_status on;
}
4. stub_status, stub_status模块参数可以用来查看Nginx的一些状态信息如连接数、请求数统计等,需要安装好相应的模块stub_status才支持配置,安装时需要指定–with-http_stub_status_module。参考: https://blog.csdn.net/jxlhljh/article/details/126270472
location = /status {
allow 192.168.0.0/16;
deny all;
stub_status on;
access_log off;
}
5. access_log, 日志文件一般存放在 /var/log/nginx 下,若是docker启动则可以使用主机挂载位置,直接使用 tail -f命令即可查看access日志。参考: https://blog.csdn.net/weixin_45698637/article/details/128486012
6. set指令, set 指令是用于定义一个变量,并且赋值。这些变量值可以通过ngx.arg.xxx在lua文件内部使用。
#black list redis
set $risk_control_server "127.0.0.1";
set $risk_control_port 6380;
7. log_by_lua, log_by_lua* 是一个请求经历的最后阶段。由于记日志跟应答内容无关,Nginx 通常在结束请求之后才更新访问日志。由此可见,如果我们有日志输出的情况,最好统一到 log_by_lua* 阶段。如果我们把记日志的操作放在 content_by_lua* 阶段,那么将线性的增加请求处理时间。 api文档参考: https://www.kancloud.cn/qq13867685/openresty-api-cn/159199
8. localtion @, 命名location,用@标识,类似于定于goto语句块。
location @item_fail {
default_type application/json;
content_by_lua_file /export/runtime/WEB-INF/classes/new_lua/item_fail.lua;
}
error_page 404 @item_fail;
error_page 500 502 503 504 @item_fail;
9. limit_req & limit_req_zone, 限流,基于漏桶算法实现的。
limit_req_zone $binary_remote_addr zone=perip_rps:10m rate=5r/s; #单ip每秒限制5个请求
limit_req_zone $server_name zone=perserver_rps:10m rate=3000r/s; #每个server每秒限制处理3000个请求
上面分别是按照ip和server来限流rps,zone=perip_rps:10m是设定这个limit_req_zone的名字为perid_rps,且在nginx内存里分配10m的空间来存储访问频次信息,rate=15r/s表示每秒15个请求,30r/m每分钟30次请求。
一般在http里配置好了limit_req_zone之后,就可以在server或者location里边配置limit_req了,比如:
limit_req zone=perserver_rps burst=2000 nodelay; #server每秒请求限流
limit_req zone=perip_rps burst=10 nodelay; #每个ip每秒请求如果超过limit_req_zone的配置,最多可以缓冲10个
这里设置 brust=10,表示在超过限制速率 5r/s 的时候,同时至多允许额外有 10 个请求排队等候,待平均速率回归正常后,队列前面的请求会优先被处理。
参考: http://events.jianshu.io/p/9db107f579a5
参考: https://www.upyun.com/opentalk/opentalk/417.html
参考: https://www.w3cschool.cn/openresty1/