突破log_by_lua中限制Cosocket API的使用
Create date: 2013/11/10 12:30 Last Update: 2013/11/10 15:59
1. Ngx-Lua中的回调函数
1.1. 用法
syntax: ok, err = ngx.timer.at(delay, callback, user_arg1, user_arg2, ...)
参数说明:
delay: 表示多长时间调用callback函数,单位为秒,表示微妙可以使用0.001,0时意味马上运行。
callback: 定义的Lua函数,在delay时间后运行
用户定义的回调函数(callback)会自动由Ngxin Core去请求,它会带上参数 premature, user_arg1, user_arg2, …
其中premature是boolean类型,正常情况下值为false,当nginx work process关闭的时候,会返回true
此时调用ngx.timer.at返回nil,正常是返回1,错误信息为”process exiting”。
user_arg1, user_arg2 为用户在ngx.timer.at中传递到callback的参数,
callback捕获这些数据时,需要注意,前面第一个参数为 premature。
--因为该例子使用递归,所以要提前定义handler变量 local handler --第一个参数为premature function handler(premature, params) local red = redis:new() red:connect("10.5.17.191", "6379", { pool = "my_redis_pool" }) red:set(ngx.now(), ngx.now()) ngx.log(ngx.DEBUG, "ngx.time.at:", ngx.now(), " premature:", url, " params:", url2) --递归 local ok, err = ngx.timer.at(5, handler, "params-data") ngx.log(ngx.DEBUG, "ok:", ok, " err:", err) end --每隔5s进行一次处理, 每次请求都是独立的, 请求10次就会调用10次ngx.timer.at函数 local ok, err = ngx.timer.at(5, handler, "params-data") ngx.log(ngx.DEBUG, "ok:", ok, " err:", err) if not ok then ngx.log(ngx.ERR, "err:", err) end
1.2. 相关设置
由于都是Nginx Core进行调用,当lua代码编写错误时,可能会导致消耗大量系统资源,
所以使用参数”pending timers”与”running timers”进行限制。
pending timers: 表示delay时间还未走完,待进行callback的数目
running timers: 表示已经在运行的callback数目
通过nginx.conf在http里面设置:
lua_max_pending_timers 1024 lua_max_running_timers 256
以上为默认值
在callback函数可使用绝大部分API, 除了 ngx.location.capture, ngx.req.*, ngx.say, ngx.print, ngx.flush几个等。
ngx.timer.at的请求数也会被worker_connections的参数大小限制,
正常应该使用长连接和后端通信,以免TIME_WAIT状态的连接而耗尽系统的端口。
2. 应用场景
2.1. 鹰眼系统
在该系统中,需要实时收集大量nginx日志,此阶段在log_by_lua中处理。
收集完的日志,要经过网络传输到redis中存储, 但该阶段是无法开启sock的。
原方案: 在log_by_lua收集日志,然后存储到ngx.shared.DICT内存中,通过定时脚本
访问某个url,在content_by_lua阶段把DICT中的内存数据传输到redis。
新方案: 通过log_by_lua、ngx.shared.DICT与ngx.timer.at一起配合,即可完成任务。
原方案收集存在误差,且配置繁琐,当访问url异常时,redis无法收集数据。
2.2. 其他应用
可以在log_by_lua、header_filter、body_filter阶段不能使用sock,而通过0延迟的定时器进行异步处理
实现类似系统上 cron 的定时计划任务, 心跳检测