Hello!
2013/12/2 Fei Liang:
> 用 ./nginx -s quit ./nginx -s stop
> 都没响应到呀,就是error.log
> 里面,没有打印出语句执行的信息,在ngx.timer.at上面,应该发个send心跳包的,暂时那个代码没写。具体咋用ngx.timer.at来检查worker退出?
>
我不清楚你哪些地方写错了,或者测试步骤本身有问题。注意你在让 nginx 退出之前,至少得先请求一下你的 nginx,以便创建你的第一个
timer. 如果你连第一个 timer 都没创建,那么你上面这些代码都没有执行入口。
考虑下面这个比较完整的例子:
location = /t {
content_by_lua '
local log = ngx.log
local WARN = ngx.WARN
local new_timer = ngx.timer.at
local sleep = ngx.sleep
local handler
handler = function(premature)
-- log(WARN, "entered timer handler")
if premature then
log(WARN, "timer expired prematurely")
return
end
sleep(1)
local ok, err = new_timer(1, handler)
if not ok then
log(WARN, "failed to create timer: ", err)
return
end
end
local ok, err = new_timer(1, handler)
if not ok then
log(WARN, "failed to create timer: ", err)
return
end
ngx.say("1st timer created.")
';
}
注意,为了能看到本例中 warn 级别的日志消息,你需要确保 error_log 配置指令里使用了 warn
或者更低的过滤级别,否则你永远不会看到 warn 级别(及以上)的消息的。即类似
error_log logs/error.log warn;
为方便起见(同时也为了避免操作上的低级错误),我准备了下面这个 bash 脚本用于自动化本例的测试过程,名为 test:
#!/bin/bash
export PATH=/path/to/nginx/sbin:$PATH
prefix=$PWD
pidfile=$prefix/logs/nginx.pid
if [ -f $prefix/logs/nginx.pid ]; then
echo "killing nginx with force..."
sudo kill -9 `cat $pidfile`
fi
echo > $prefix/logs/error.log
echo "starting nginx..."
sudo nginx
sleep 0.1 # wait nginx to start up
echo "querying /t..."
curl localhost:8080/t
seconds=`perl -e 'printf "%.03f", rand 3'`
echo "waiting for $seconds sec."
sleep $seconds
pid=`cat $pidfile`
echo "shutting nginx down..."
sudo kill -QUIT $pid
sleep 1 # wait nginx to quit
echo "checking error.log..."
grep warn $prefix/logs/error.log
这里假设当前工作目录是 nginx 服务器的 prefix,比如 /usr/local/openresty/nginx/
这样的位置。同时假设 nginx 监听的是 8080 端口。这里我们生成一个 0 ~ 3 秒之间的随机数,作为让 nginx
退出前的等待时间,这样我们就有机会撞上各种可能的情况。注意,我们在本例中向 nginx master 进程发 QUIT 信号之后等待了 1
秒这么长的时间,是因为我们的定时器回调里使用了 ngx.sleep(1) 这一行,所以 nginx 最多会延迟 1
秒钟退出。我们需要给它留足时间。当然,在真实的场景下自然会把 ngx.sleep(1) 替换成真实的计算或者 IO 请求。
下面是 test 脚本在我机器上的两次典型的运行结果:
$ ./test
starting nginx...
querying /t...
1st timer created.
waiting for 2.395 sec.
shutting nginx down...
checking error.log...
2013/12/03 15:25:13 [warn] 7006#0: [lua] [string
"content_by_lua"]:12: timer expired prematurely, context: ngx.timer
$ ./test
starting nginx...
querying /t...
1st timer created.
waiting for 1.753 sec.
shutting nginx down...
checking error.log...
2013/12/03 15:25:26 [warn] 7019#0: [lua] [string
"content_by_lua"]:20: failed to create timer: process exiting,
context: ngx.timer
从这两次输出我们可以看到,我上封邮件中提到的两种情况都被测试到了。
> cosocket有个连接池,这个我知道,但是我不知道这个连接池的具体概念,我的理解,就是有多个连接。
连接池里未必会有多个连接,这取决于你的实际用法。建议先仔细阅读 ngx_lua 相关的官方文档:
https://github.com/chaoslawful/lua-nginx-module#tcpsocksetkeepalive
如果你有更具体的问题,欢迎另辟新的邮件主题进行讨论。
> 第三方服务器要求你所有发送的包(包括心跳包),都必须有一个统一的ID,然后它异步给你返回响应信息,这就必须另外开个timer来recv数据包,如果连接池是不同连接的话,我怕出问题。
>
我没见到心跳检查这样最基础的服务还采取异步协议的,这无疑大大增加了复杂度。你要小心处理异步协议可能带来的 timer 和任务无限积压的巨大风险。
你这里的响应包会通过不同于发送请求包的 TCP 连接来发送吗?如果会的话,你需要自己在多个 nginx worker 进程乃至多个
nginx 服务器之间共享状态,以便把请求和响应按照你所说的 ID 进行关联。
> 另外问下,lua如何方便的构造二进制数据包呀。。类似c 的struct那样的。
>
可以直接使用 LuaJIT 的 bit 扩展:
http://luajit.org/extensions.html
你可以参考我的 lua-resty-mysql, lua-resty-dns, 和 lua-resty-websocket
这些客户端库中的实现,它们都是使用 bit 扩展库来构造 MySQL、DNS 名字服务器以及 WebSocket
客户端/服务器端所需的二进制数据包的。
最后,建议尽量创建独立的邮件主题来讨论和当前主题无关的问题。
Regards,
-agentzh