2016年1月8日 16:08:43 星期五
情景: 用户登录日志, 发邮件, 发短信等等实时性要求不怎么高的业务通常会异步执行
之前接触过几种redis+crontab配套的实现方法,
比如: crontab定时执行curl脚本
1. 用curl 访问URL执行PHP脚本去pop队列
2. PHP程序pop一次并处理后返回同样的URL
3. curl收到这个URL后就可以再次跟踪访问并执行该PHP程序, 这样就可以实现循环pop的效果
4. 最后给curl设定下最大跟踪次数(--max-redirs), 就可以限定每次pop的最大值
但总感觉那么不顺畅
1. 不是实时的
2. 不同时间段打入队列的数据是不确定的, 比如白天登录用户会比晚上多, crontab执行频率不好的话, 白天入队列的数据可能大于出队列的数据导致延时加大
这两天学到了一个新的方法, 可以解决实时性的问题:
PHP程序: 一个阻塞型的死循环去pop队列
crontab:去监控这个PHP循环是不是在运行, 没有则启动
PHP程序:
1 while (TRUE) { 2 $element = $redis->brPop($key, 10); // 阻塞执行, 超时为10s钟 3 $content = json_decode($element[1], TRUE);// 返回为PHP数组, 其中$element[0]是队列的名字, $element[1]是内容 (因为brpop可以同时监控多个队列) 4 }
while true, 看似是死循环, 但是里边的brpop是阻塞型的代码, 队列里边没有数据的时候会让出CPU直到数据的到来, 等待10秒钟后还没有数据就停掉, 进入下一次循环(下一个10s)
因为是死循环, 要一直执行下去, 所以最好的方式是php_cli模式下执行, 这个模式下是不会有超时限制的
crontab是怎么配合: 定期检查这个PHP脚本是否是在执行, 如果没有就启动它
* * * * * /path/to/watch/bash_script/start.sh
start.sh:
1 #!/bin/bash 2 # remember chmod +x 3 4 #判断进程是否存在 5 count=`ps -ef | grep php/cli/script/name | grep -v "grep" | wc -l` 6 7 #如果不存在就启动, 并把输出信息或错误信息写到日志里边 8 if [ $count -eq 0 ]; then 9 cd /path/to/web/root && /path/to/bin/php /path/to/cli_test.php params > /tmp/brpop.log 2>&1 10 fi
这中实现方式可以达到实时的
但是没数据的时候, 死循环会一直阻塞下去, 单貌似也不耗费什么资源
原文:http://www.cnblogs.com/iLoveMyD/p/5113865.html