zoukankan      html  css  js  c++  java
  • redis+crontab+php异步处理任务

    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 }

    注意:

    1. while true, 看似是死循环, 但是里边的brpop是阻塞型的代码, 队列里边没有数据的时候会让出CPU直到数据的到来, 等待10秒钟后还没有数据就停掉, 进入下一次循环(下一个10s)

    2. 因为是死循环, 要一直执行下去, 所以最好的方式是php_cli模式下执行, 这个模式下是不会有超时限制的

    3. "read error on connection" 报错, 因为brpop阻塞10s, 所以PHP在连接redis时设置的timeout时间必须得大于这个时间, 或者干脆就不设置超时:

    1 $this->connect('REDIS_HOST', 'REDIS_PORT', 'GLOBAL_TIME_OUT');
    2 $this->auth('REDIS_AUTH');

    crontab怎么配合: 定期检查这个PHP脚本是否是在执行, 如果没有就启动它

    * * * * * /bin/sh /path/to/watch/bash_script/start.sh online

    start.sh:

     1 #!/bin/bash
     2 # 使用了 Redis 的 bRpop 函数去实时监控, 发送报警邮件和短信
     3 # 先检查是否启动了该进程, 没有的话就启动
     4 # 保证该文件是可执行的
     5 # crontab:  /bin/sh /path/to/shell.sh env #env: online/test/someone
     6 
     7 count=`ps -ef | grep process_name | grep -v "grep" | wc -l`
     8 start_time=`date +%Y-%m-%d_%X`
     9 if [ $count -eq 0 ] && [ online = "$1" ] #生产环境
    10 then
    11     echo ${start_time}" start redisLog "
    12     #code here: cd /path/to/onlien/webroot && /path/to/php/bin/php /path/to/shell/file/cli.php args >> /path/to/error.log 2>&1
    13 
    14 elif [ $count -eq 0 ] && [ test = "$1" ] #公共测试环境
    15 then
    16     echo ${start_time}" start redisLog "
    17     #code here: cd /path/to/test/webroot && /path/to/php/bin/php /path/to/shell/file/cli.php args >> /path/to/error.log 2>&1
    18 
    19 elif [ $count -eq 0 ] #个人测试环境
    20 then
    21     echo ${start_time}" start redisLog "
    22     #code here: cd /path/to/someone/webroot && /path/to/php/bin/php /path/to/shell/file/cli.php args >> /path/to/error.log 2>&1
    23 
    24 else
    25     echo ${start_time}" redisLog already running "
    26 fi

    这中实现方式可以达到实时的

    但是没数据的时候, 死循环会一直阻塞下去, 但貌似也不耗费什么资源

    注意 windows 和 Linux的换行符是不一样的, windows转Linux:

    vi xxx.sh

    :set fileformat=unix

    :x

     summerPHP

  • 相关阅读:
    新博客
    【Gym-100712 #H】Bridges
    【CodeForces817F】MEX Queries
    【POJ1734】Sightseeing trip
    【Aizu2968】Non-trivial Common Divisor
    【Gym-101473 #I】Patches
    【POJ2228】Naptime
    【CodeForces219D】Choosing Capital for Treeland
    【URAL1018】Binary Apple Tree
    深入探索C++对象模型(五)
  • 原文地址:https://www.cnblogs.com/iLoveMyD/p/5113865.html
Copyright © 2011-2022 走看看