需求:
nginx上將特定請求拒絕,並返回特定值。
解決辦法:
使用lua腳本,實現效果。
操作步驟:
- 安裝Luajit環境
- 重新編譯nginx(目標機器上
nginx -V
配置一致,並新增兩個模塊ngx_devel_kit
,lua-nginx-module
) - 熱升級(不中斷服務)或重啟
配置文件添加lua腳本:
#匹配請求體里的 hello=world時返回此變量和值
location /hello {
rewrite_by_lua_block {
ngx.req.read_body()
local own_a = ngx.req.get_post_args()["hello"]
if ( own_a == "world" ) then
ngx.say("hello world")
end
}
proxy_pass xxxx;
}
一、安裝Luajit環境
#安裝lua-nginx模塊需要先安裝Luajit
$ tar xf LuaJIT-2.0.4.tar.gz
$ cd LuaJIT-2.0.4
$ make PREFIX=/usr/local/luajit
$ make install PREFIX=/usr/local/luajit
$ cat <<EOF > /etc/profile.d/luajit.sh
export LUAJIT_LIB=/usr/local/luajit/lib
export LUAJIT_INC=/usr/local/luajit/include/luajit-2.0
EOF
$ source /etc/profile.d/luajit.sh
#判斷是否有庫函數鏈接
if [ ! -f /lib64/libluajit-5.1.so.2 ];then
ln -s /usr/local/luajit/lib/libluajit-5.1.so.2 /lib64/libluajit-5.1.so.2
fi
#添加庫函數鏈接
if [ ! -f /lib64/libprofiler.so.0 ];then
ln -sv /usr/local/lib/libprofiler.so.0.4.18 /lib64/libprofiler.so.0 || echo "/usr/local/lib/libprofiler.so.0.4.18 fasle,please check this"
fi
#可以使用 ldd $(which /usr/local/nginx/sbin/nginx) 查看缺少的庫文件
二、編譯二進制文件
可在測試機(目標機器環境相同)編譯好最新的nginx二進制文件(
nginx -V
相同並且新增兩個模塊即可)。也可直接在目標機器上編譯,但是最后make install
不可執行,否則就覆蓋目標環境了。
目標環境:
#將生成的nginx二進制文件替換至目錄機器
$ cd /usr/loca/nginx/sbin/
$ mv nginx{,_bak} #先備份老的
$ mv /home/install_nginx/src/nginx ./ #將新的移動過來
$ nginx -t #檢查配置,這一步很重要,一但報錯,說明nginx二進制文件編譯有問題,需要重新核對環境信息並重新編譯
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
$ nginx -s reload
$
$ curl -d "hello=world" http://192.168.20.13/hello
xxx #返回結果不是hello world,lua腳本配置未生效。此時老的配置並不影響
查看錯誤日志:
2019/10/08 17:25:22 [notice] 30580#0: signal process started
2019/10/08 17:25:22 [emerg] 22066#0: unknown directive "rewrite_by_lua_block" in /usr/local/nginx/conf/vhost/text.conf:41
未識別rewrite_by_lua_block
配置,說明lua腳本配置未生效。看來nginx -s reload
是不行,只能通過熱升級了。
nginx啟動時master進程會初始化每個模塊的信息,reload只是重新開啟新的worker進程。所以新增模塊只能重啟或熱升級。
nginx 信號:
信號 | nginx內置shell | 說明 |
---|---|---|
HUP | nginx -s reload | 重載配置文件 |
USR1 | nginx -s reopen | 重新打開日志文件,配置mv,用做日志切割 |
USR2 | - | 熱升級nginx程序 |
WINCH | - | 優雅的關閉相關的worker進程 |
QUIT | nginx -s squit | 優雅的停止nginx |
TERM,INT | nginx -s stop | 立即停止nginx |
nginx -s reload
執行后的nginx操作順序:
- 檢測配置是否正確
- 錯誤,則不應用新的配置,還是使用老的配置
- 正確,使用新的配置,並新建worker進程,並通知老的worker進程優雅的關閉
發送熱升級信號:
$ kill -USR2 `cat /tmp/nginx.pid`
$
#執行完后查看進程,調接口都沒生效
##查看error log
2019/10/08 17:25:41 [alert] 30599#0: execve() failed while executing new binary process "nginx" (2: No such file or directory)
上面的報錯: 找不到nginx命令。nginx程序依賴環境變量,而上一次啟動肯定不是用絕對路徑啟動(nginx命令直接啟)。這種情況就無法做熱升級,只能
restart
了,restart
后配置即生效,接口調通了。
正確的nginx熱升級步驟
[root@node2013 vhost]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf #正確的啟動nginx
重新執行編譯nginx步驟,為了升級服務器可執行文件,應首先將新的可執行文件替換舊文件。之后,USR2信號應發送到主進程。主進程首先將其具有進程ID的文件重命名為帶有.oldbin后綴的新文件,例如 /tmp/nginx.pid.oldbin,然后啟動一個新的可執行文件,該文件又啟動新的工作進程:
[root@node2013 vhost]# kill -USR2 `cat /tmp/nginx.pid` #發送熱升級信號
[root@node2013 vhost]# ps -ef | grep nginx
root 31118 1 0 17:36 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody 31119 31118 0 17:36 ? 00:00:00 nginx: worker process
nobody 31120 31118 0 17:36 ? 00:00:00 nginx: worker process
nobody 31121 31118 0 17:36 ? 00:00:00 nginx: worker process
nobody 31122 31118 0 17:36 ? 00:00:00 nginx: worker process
root 31177 31118 0 17:36 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody 31178 31177 0 17:36 ? 00:00:00 nginx: worker process
nobody 31179 31177 0 17:36 ? 00:00:00 nginx: worker process
nobody 31180 31177 0 17:36 ? 00:00:00 nginx: worker process
nobody 31181 31177 0 17:36 ? 00:00:00 nginx: worker process
root 31185 30078 0 17:37 pts/0 00:00:00 grep --color=auto nginx
[root@node2013 vhost]# ll /tmp/
total 12
-rw-r--r-- 1 root root 6 Oct 8 17:36 nginx.pid
-rw-r--r-- 1 root root 6 Oct 8 17:36 nginx.pid.oldbin
$ curl -d "hello=world" http://192.168.20.13/hello #正常返回結果,lua腳本生效。如未生效則直接發送`QUIT`信號給新的master進程。
hello world
之后,所有工作進程(舊的和新的)繼續接受請求。如果WINCH
或QUIT
信號發送到第一個主進程,它將向其工作進程發送消息,要求它們正常關閉,然后它們將開始退出:
[root@node2013 vhost]# kill -QUIT `cat /tmp/nginx.pid.oldbin` #優雅的退出進程
[root@node2013 vhost]# ps -ef | grep nginx #最后查看效果,只剩下新的master和其worker進程
root 31177 1 0 17:36 ? 00:00:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody 31178 31177 0 17:36 ? 00:00:00 nginx: worker process
nobody 31179 31177 0 17:36 ? 00:00:00 nginx: worker process
nobody 31180 31177 0 17:36 ? 00:00:00 nginx: worker process
nobody 31181 31177 0 17:36 ? 00:00:00 nginx: worker process
root 31254 30078 0 17:38 pts/0 00:00:00 grep --color=auto nginx
[root@node2013 vhost]#
總結:
nginx啟動須使用絕對路徑,不然無法處理USR2
信號。
文檔鏈接:
nginx 安裝lua模塊: https://github.com/openresty/lua-nginx-module#installation
nginx 信號: http://nginx.org/en/docs/control.html
nginx main初始化:https://blog.csdn.net/time_change/article/details/78470901