php redis 怎么能无延迟处理队列?

需求是要通过服务器发送微信模板消息

目前使用的方案:
1、发送任务是先进redis队列里
2、然后crontab每分钟去执行出队列的发送任务
3、但是是每分钟去执行的,如何能无延迟去处理任务

============================分隔线==============================
补充:
首先感谢回复的亲们!

还有几个疑问想要咨询的
1、如果用脚本do.php,守护进程去处理,并通过定时任务脚本去监控这个进程,这样运行对服务器会产生多大的压力?还是可以忽略不计
2、如果采用其他的异步消息处理队列方法(主要需求是高频发送微信模板消息):
如用swool开启WebSocket,直接把任务发送至WebSocket去处理
这样的方法和采用 redis 守护进程去执行出队列的方法相比,会有哪些优点和不足的?

============================分隔线==============================
补充2:
又遇到几个问题

问题一:

在终端使用如下nohup命令,创建不了进程

nohup php /www/wwwroot/127.0.0.1/do.php &

后台切换终端目录至网站根目录下,再次运行nohup命令,创建进程成功了

cd /www/wwwroot/127.0.0.1
nohup php do.php &

不知道造成这个问题的原因是什么?
难道是do.php里面有include包含其他文件的关系吗?

问题二:

do.php脚本创建进程后,通过如下ps命令可以看到,重启服务器后,这个进程就没有了。
看了下shell语法,do.sh文件如下

#!/bin/bash
ps -fe | grep do.php | grep -v grep
if [ $? -eq 0 ]
then
    echo "runing"
else
    echo "not runing"
fi

但是一直提示如下错误

do.sh:行8: 未预期的符号 `fi' 附近有语法错误
do.sh:行8: `fi'

do.sh的语句应该没有问题啊

阅读 1.9k
评论
    8 个回答

    要做到无延迟处理,就只能起一个常驻内存的 php 服务,可以写成 php 脚本,然后 nohup 启动,阻塞监听 redis 消息

    代码参考

    while(true) {
        $result = $redis->brpop(REDIS_KEY, 0);
        var_dump($result);
    }

    疑问解答:

    1. 忽略不计,除非监控脚本有问题
    2. 直接发给 socket 而不是队列,相当于把压力都给到 socket 服务
      优点: 少了一环,架构变简单,消息链路短,反馈效果好
      缺点: socket 所在服务要承担更高的压力

    补充2:

    1. 使用 nohup 如果不指定日志文件,会有一个叫 nohup.out 的日志文件在执行目录,看一下报错信息
    2. 怀疑是换行符的问题,用 dos2unix 改为 Linux 换行符: dos2unix do.sh。遇到这种诡异的问题,如果确认语法没问题,可以尝试在新文件重写一次(不要复制)

      一、如果是每分钟执行一下,为什么不放到mysql中呢?redis现在做的也就是数据库的作用啊!!!所以这个问题和redis的关系不大。
      二、redis中有个pub/sub模式,其实是个变相的消息队列,这个基本上是可以实现你这边发送,接受者那边就会收到。
      三、其实这个更多的可以用消息队列去做,比如rabbitMq等,

        1、如果用脚本do.php,守护进程去处理,并通过定时任务脚本去监控这个进程,这样运行对服务器会产生多大的压力?还是可以忽略不计。

        这个常驻进程,主要是通过死循环来处理,然后结合redis的brpop阻塞处理队列信息,这个进程对系统的消耗还是有,但是并不是主要消耗的来源,因为这个进程主要是监控redis队列,也可以理解成忽略不计。监控进程可以结合supervisor来处理。

        2、如果采用其他的异步消息处理队列方法(主要需求是高频发送微信模板消息):
        如用swool开启WebSocket,直接把任务发送至WebSocket去处理 这样的方法和采用 redis
        守护进程去执行出队列的方法相比,会有哪些优点和不足的?

        这个要看你们应用的场景,你高频发送模版消息,使用redis队列,应该是考虑到消息模版返回的时间比较长,通过队列的异步处理,可以避免逻辑的阻塞,影响体验。
        如果是基于这种场景,使用swoole的task异步处理,也能很好的完成需求。你所说的用swoole的websocket来处理,是怎么处理?

          你这种场景,无延迟处理可以用Pub/Sub机制

          用这个扩展,可以帮你进一步简化
          http://github.com/immusen/yii...
          调用的时候直接从你的Web应用(比如xx/controllers/OrderContrller.com的某个action里面)执行如下代码:
          Yii::$app->hook->runOnce('wechat/push', ['openid' =>xxx, 'template'=>'xxx','data' => [...]]);
          如果你本来就一台服务器(一个实例)运行swoole,可以把runOnce()改成run()...

          当然,这行代码能真正执行的前提还有,你自己去创建一个WechatController.php在指定目录下,然后里面有一个actionPush(),里面是执行推送的代码,这里也可以不重复造轮子,直接调用你在Web那边已经下好的(比如xx/utils/what::push($params)),因为是Yii的一个扩展,可以用过命名空间调框架下任意方法。
          这里有个中文简介: https://www.yiichina.com/exte...

            1.如果想无延迟就只能阻塞处理,但是服务器性能得不到保障。
            2.降低处理频率,每分钟 改为 每秒。

              • 681

              Redis pub/sub了解下。

                我曾经用swoole + php 来实现你这样的需求,见博文:http://blog.star7th.com/2016/...
                后来用node写一个一个任务队列,从此抛弃用php实现队列的想法。https://github.com/star7th/htq
                这个队列服务起来后,通过http接口来进出队列,并且支持三种队列场景,可以完美跟多种语言(包括php)一起使用

                  • 29
                  while (true) {
                      $result = $queue->get();
                      if ($result) {
                          $data = $result->getBody();
                          sleep(3); //模拟处理过程
                          $queue->ack($result->getDeliveryTag());
                      } else {
                          sleep(3);
                      }
                  }
                  
                  最后,再搭配supervisor.
                  done.

                  我用的是rabbitMQ,上面是consumer的伪代码

                    撰写回答

                    登录后参与交流、获取后续更新提醒