如何避免每个TCP连接的最大通道与amqp php,持​​久连接和php-fpm

时间:2014-05-26 07:13:58

标签: rabbitmq amqp php

我只是在学习rabbitMQ而且遇到了一个问题。

使用http://pecl.php.net/package/amqp版本1.4(最新版本)和RabbitMQ 3.3.1。 我们必须使用php5-fpm和amqp-> pconnect()的持久连接。

过了一会儿(我想65500个请求),停止所有写操作都会出现问题 "

  

无法创建频道。连接没有开放通道插槽   其余

"

从我在源代码中读到的内容是因为每个tcp连接都有一个自动增量通道ID达到最大值。这是因为每个请求都必须使用该通道,并且无法使用相同的通道(我无法找到进入php-amqp通道类的方法使其持久化)并且脚本无法通信(使用相同的实例)通道作为php对象)。

要降低php-fpm生命周期不是一个选项,要么通过另一个技术/库等将application-rabbitmq通信解耦。

有没有简单的方法来解决这个问题?

理论上它应该是每个线程一个通道(在这种情况下是php5-fpm worker)但是如何使用这个库实现?

我现在使用的代码(类似)

$this->con = new AMQPConnection(array(
    'host'          => $this->con_params['host'],
    'port'          => $this->con_params['port'],
    'vhost'         => $this->con_params['vhost'],
    'login'         => $this->con_params['user'],
    'password'      => $this->con_params['pass'],
    'read_timeout'  => 1,//seconds
    'write_timeout' => 1,//seconds
'connect_timeout' => 1,//seconds
));
$this->con->pconnect();
$channel = new AMQPChannel($this->con);
$queue = new AMQPQueue($channel);
$queue->setName($queueName);
$queue->setFlags(AMQP_DURABLE);
//$queue->declareQueue();//make sure it exists
$exchange = new AMQPExchange($channel);
$exchange->setName($exchangeName);
$exchange->setFlags(AMQP_DURABLE);
$exchange->setType(AMQP_EX_TYPE_DIRECT);
//$exchange->declareExchange();
$this->queues[$queueName]->bind($exchangeName);

谢谢!

1 个答案:

答案 0 :(得分:6)

简短回答:不要使用php-amqp扩展名的持久连接,并且即使在高负载(例如2k + req)下,使用常规connect()性能降级来打开连接也不应该很重要/秒)。

答案很长:

php-amqp分机(#define DEFAULT_CHANNELS_PER_CONNECTION 255)中的每个连接限制同时存在最多同时打开的硬编码频道。封闭渠道在关闭后会尝试重复使用。

但是在一个物理连接中rabbitmq-c (aka librabbitmq)到最大通道数还存在另一个限制 - #define AMQP_DEFAULT_MAX_CHANNELS 0,这意味着没有应用自定义限制,因此应用了协议限制。根据规范(section 4.9 Limitations),协议限制为:

  

每个连接的通道数:16位通道号。

according to wikipedia Unsigned: From 0 to 65,535。在AMQP中,0从不用作通道号并被解释为错误。

因此,当您在本地关闭所有频道但未关闭时,RabbitMQ将继续频道编号序列,因此它将达到指定的上限。

除非关闭连接,否则没有其他方法可以摆脱此类行为。

另外,我建议你不要使用持久连接,因为它有potential memory leak,一般来说有点不稳定。有计划从php-amqp中完全删除持久性。