在将消息发布到处于阻塞状态的 rabbitmq 服务器时,我们遇到了灾难性的行为。
例如内存警报或磁盘警报会导致rabbitmq 阻止所有发布,直到警报消除。所有尝试写入的连接都必须等待。这一切都很好,但问题是我们找不到任何方法来超时这个等待。
所以产生的行为是,请求永远不会结束(或者由于 nginx 超时而超时)导致崩溃。我们可以用这段代码重现问题:
function p()
{
$c = new \AMQPConnection([
'host' => 'shoprabbit',
'port' => 5672,
'read_timeout' => 1,
'write_timeout' => 1,
'connect_timeout' => 1,
'confirm_timeout' => 1,
'rpc_timeout' => 1,
'login' => 'guest',
'password' => 'guest',
'heartbeat' => '3',
]);
$c->connect();
$ch = new \AMQPChannel($c);
$ch->setPrefetchCount(0);
$ex = new \AMQPExchange($ch);
$ex->setType(AMQP_EX_TYPE_DIRECT);
$queue = new \AMQPQueue($ch);
$queue->setName('demo');
$queue->setFlags(AMQP_DURABLE);
$queue->declareQueue();
$ex->publish('empty', 'demo', AMQP_NOPARAM, ['delivery_mode' => AMQP_DURABLE]);
}
p();
并在rabbitmq中模拟阻塞状态rabbitmqctl set_vm_memory_high_watermark 0
如您所见,在这种情况下,没有任何超时发生。Heartbeat 也不起作用,因为 php 是单线程的,并且无法关闭阻塞连接。
谁能找到解决方案?