目前来看Webman程序运行期间一切是正常的,只是当我把服务停止时,会报出很多下面这样的报错:
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
webman版本是最新的,workerman版本是最新的,操作系统是centos7.9,php版本7.4.30,event版本也是目前最新的3.0.8
因为当我试着把所有消费监听进程都关掉后,无论怎样开启服务、停止服务、重启服务、重载服务,怎么搞都不会发生Epoll报错。
简单说一下我的操作:
class Rabbitmq
{
/**
* 发布消息到worker队列,支持一次性发布多个消息
*
* @author Aaron <chenqiang@h024.cn>
*
* @param string|array $msgData 需要入队的消息,单一消息为字符串类型,多个消息是数组类型
* @param string $queueName 队列名称,默认空串就是默认队列
* @param \PhpAmqpLib\Channel\AMQPChannel $channel 指定rabbit通道,默认null表示使用默认通道
*/
public static function publishWorkerQueue($msgData, string $queueName = '', \PhpAmqpLib\Channel\AMQPChannel $channel = null)
{
// $log = \support\Log::channel('producer');
if ($queueName == '') {
$queueName = env('RABBITMQ_DEFAULT_QUEUE', 'default');
}
if (is_null($channel)) {
$channel = \app\bootstrap\Rabbitmq::$defaultProducerChannel;
}
$channel->queue_declare($queueName, false, true, false, false);
if (!is_array($msgData)) {
$msgData = array($msgData);
}
// 遍历数组,对每一个元素做入队操作
foreach ($msgData as $dataBody) {
// 把字符串类型的元素入队,忽略其他类型的元素
try {
$dataBody = (string)$dataBody;
} catch (\Exception $e) {
$dataBody = json_encode($dataBody);
}
$msg = new AMQPMessage(
$dataBody,
array('delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSISTENT)
);
// $log->debug("{$queueName}入队数据: {$dataBody}");
$channel->basic_publish($msg, '', $queueName);
}
}
/**
* 用workerman的rabbitmq组件实现的异步消息发布
*
* @author Aaron <chenqiang@h024.cn>
*
* @param array $option // 连接客户端的配置
* @param string $queue // 指定队列名
* @param string $message // 要发布的消息
*/
public static function asyncPublishWorkerQueue(array $option, string $queue, string $message)
{
(new \Workerman\RabbitMQ\Client($option))->connect()->then(function (\Workerman\RabbitMQ\Client $client) use ($message) {
return $client->channel();
})->then(function (\Bunny\Channel $channel) use ($message, $queue) {
return $channel->queueDeclare($queue, false, true, false, false)->then(function () use ($channel) {
return $channel;
});
})->then(function (\Bunny\Channel $channel) use ($message, $queue) {
$briefMsg = mb_substr($message, 0, 50);
// \support\Log::channel('producer')->debug(" [x] Sending {$briefMsg} to {$queue}\n");
return $channel->publish($message, [], '', $queue)->then(function () use ($channel) {
return $channel;
});
})->then(function (\Bunny\Channel $channel) use ($message, $queue) {
$briefMsg = mb_substr($message, 0, 50);
// \support\Log::channel('producer')->debug(" [x] Sent {$briefMsg} to {$queue}\n");
$client = $channel->getClient();
// return $client;
return $channel->close()->then(function () use ($client) {
return $client;
});
// });
})->then(function (\Workerman\RabbitMQ\Client $client) {
$client->disconnect();
});
}
/**
* 通过workerman的rqbbitmq组件实现的异步队列消费,需要执行$channel->ack方法以完成消费
*
* @author Aaron <chenqiang@h024.cn>
*
* @param array $option // 连接客户端的配置
* @param string $queue
* @param callable $callback // 消费的具体回调方法,接收参数\Bunny\Message $message, \Bunny\Channel $channel, \Workerman\RabbitMQ\Client $client
*/
public static function asyncConsumeWorkerQueue(array $option, string $queue, callable $callback, bool $noAck = MQ_NO_AUTO_ACK)
{
(new \Workerman\RabbitMQ\Client($option))->connect()->then(function (\Workerman\RabbitMQ\Client $client) {
return $client->channel();
})->then(function (\Bunny\Channel $channel) use ($queue) {
return $channel->queueDeclare(
$queue,
false,
true,
false,
false
)->then(function () use ($channel) {
return $channel;
});
})->then(function (\Bunny\Channel $channel) {
return $channel->qos(0, 1, false)->then(function () use ($channel) {
return $channel;
});
})->then(function (\Bunny\Channel $channel) use ($callback, $queue, $noAck) {
echo " [*] Waiting for messages on {$queue}.\n";
// noAck = false表示需要消费进程手动判断
$channel->consume(
$callback,
$queue,
'',
false,
$noAck
);
});
}
}
class TestConsumer
{
public function onWorkerStart(Worker $worker)
{
// 回调函数就是具体的队列消费者程序
$callback = array($this, 'asyncConsume');
// 用异步rabbitmq组件来监听队列并完成消费,不会造成worker阻塞
\util\Rabbitmq::asyncConsumeWorkerQueue(
\app\bootstrap\Rabbitmq::$asyncConsumerOption,
QUEUENAME_TEST,
$callback
);
}
/**
* 异步消费回调函数
*
* @author Aaron <chenqiang@h024.cn>
*
* @param \Bunny\Message $message 异步消息体
* @param \Bunny\Channel $channel 异步队列通道
* @param \Workerman\RabbitMQ\Client $client 异步队列客户端
*/
public function asyncConsume(Message $message, Channel $channel, Client $client)
{
\support\Log::channel('consumer')->debug("test消费者: 收到消息 " . $message->content);
$data = json_decode($message->content, true);
/// ... 具体消费动作 ...
$channel->ack($message);
\support\Log::channel('consumer')->debug("test消费者: 消费完毕 " . $message->content);
}
}
Epoll数量与rabbitmq队列消费进程数量正相关
# php start.php start
Workerman[start.php] start in DEBUG mode
-------------------------------------------------- WORKERMAN --------------------------------------------------
Workerman version:4.0.33 PHP version:7.4.30
--------------------------------------------------- WORKERS ---------------------------------------------------
proto user worker listen processes status
tcp root data_worker http://0.0.0.0:9607 8 [OK]
tcp root esl_listener none 1 [OK]
tcp root async_task_proxy websocket://0.0.0.0:9608 1 [OK]
tcp root task_init text://0.0.0.0:9611 4 [OK]
tcp root task_start text://0.0.0.0:9612 4 [OK]
tcp root task_call_consumer none 4 [OK]
tcp root task_data_update_consumer none 4 [OK]
tcp root task_billing_consumer none 8 [OK]
---------------------------------------------------------------------------------------------------------------
Press Ctrl+C to stop. Start success.
[*] Waiting for messages on task_data_update.
[*] Waiting for messages on task_data_update.
[*] Waiting for messages on task_call.
[*] Waiting for messages on task_data_update.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_data_update.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_call.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_billing.
[*] Waiting for messages on task_call.
[*] Waiting for messages on task_call.
^CPHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Workerman[start.php] stopping ...
PHP Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 8 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 8 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(1) on fd 6 failed. Old events were 6; read change was 0 (none); write change was 2 (del): Bad file descriptor in Unknown on line 0
PHP Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Warning: Unknown: Epoll MOD(4) on fd 6 failed. Old events were 6; read change was 2 (del); write change was 0 (none): Bad file descriptor in Unknown on line 0
Workerman[start.php] has been stopped
rabbitmq client用单例,一个进程保持一个连接,你的epoll在fd 6上面失败了,失败原因就是读取不到描述文件了,一般情况就是你的loop覆盖了;
每个rabbitmq client会复用当前进程的globalEvent,如果使用new的话,每次的client对象都不是同一个;
除了上述问题的可能性外,还有一种:当你的消费进程启动后,client的消费是异步的,也就是你在这一个loop内进行stop的话,你的消费可能还正在消费中,相当于在循环中中止该消费loop,可能因为一些意外情况不能等待消费完毕后中止,而是直接中断;
当然具体的还是得具体代码来分析;
推荐webman环境下可以直接使用rabbitmq客户端插件,是生产可用的,可以放心使用;
https://www.workerman.net/plugin/67