php rabbitmq消费者程序crontab定时执行后出现很多连接,导致服务器瘫痪,如何解决?

问题描述

框架说明:自己公司用composer搭建的框架,而非tp,laravel等。
rabbitmq库:"php-amqplib/php-amqplib": "^2.8"
php版本:7.0+
linux:nginx

我写了一个消费队列的php,然后使用crontab定时每分钟跑一次,也可以消费。后来发现crontab每次执行代码后,都不会关闭connection和channel。因为消费者程序里面有这样的代码,按照rabbitmq官方demo写的,这里有个infinite loop.

while (count($this->channel->callbacks)) {
    $this->channel->wait();
}

程序在这里进行阻塞了,所以crontab每过一分钟执行一次,就多一个conectiion,都没有退出。

问题出现的环境背景及自己尝试过哪些方法

主要是用来取出来消费队列里的消息,我自己本机使用php /path/to/consumer.php 是可以的,不过都是ctrl+c来退出的。但是如果真正放在linux要怎么调用呢?

  • 我再想是不是不该用crontab定时任务,而要用nohub这样的常驻程序来执行。
  • 或者说是如何让程序跳出那个infinite loop?

相关代码

while (count($this->channel->callbacks)) {
    $this->channel->wait();
}

你期待的结果是什么?实际看到的错误信息又是什么?

目前使用crontab定时每分钟跑的结果就是每次都会创建一个connection,然后都没关闭,最后就N个connection,服务器cpu rabbitmq占用很高,后面就瘫痪了。

阅读 5.4k
7 个回答

可以改成nohup常驻进程的方式运行,不用定时任务。

用supervisor呀,你这个程序本来就是常驻的,用crontab的话,一分钟开一个,每一个都存在肯定不行。

这种程序一般只会开启一个,crontab的功能除了开启程序,还要监控这个程序是否挂了,如果挂了就重新启动。
所以,只需要在程序前面加一个检测代码就可以了

<?php
// 脚本名称
$ps_name = 'my_ps_name';
// $1为用户名,$2为PID
$cmd = "ps -ef|grep {$ps_name}|grep -v grep|awk '{print $1, $2}'";
exec($cmd, $out);
if (!empty($out)) {
    exit("服务正在运行,跳过" . PHP_EOL);
}

while (count($this->channel->callbacks)) {
    $this->channel->wait();
}

你的需求是常驻。
问题的原因是每分钟都跑1个进程,但是又不会退出,时间一久就出问题了。
比较保险的方式是使用文件锁,连接队列之前获取锁,锁失败就退出进程,锁成功就连接队列,进程挂了会自动释放锁,再配合crontab即可
不用crontab的话,你进程挂了没人把他搞起来

$fp =  fopen('lock','r');
$locked = flock($fp,LOCK_EX|LOCK|UB);
if(!$locked) {
    die("获取锁失败");
}
// 连接队列

你这个是是常驻进程 用supervisor监控存活 跑挂了可以自动重拉

不需要 contab 做每次重启
一个实例就会监听一个 socket,可以实时的接收消息

while (true) {
    $result = $queue->get();
    if ($result) {
        $data = $result->getBody();
        sleep(3); //模拟处理过程
        $queue->ack($result->getDeliveryTag());
    } else {
        sleep(3);
    }
}

最后,再搭配supervisor.
done.
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题