我搜索了这些信息(包括docs),我找不到它。
我在RabbitMQ v.2.7.1中使用了最新版本的php-amqplib。我有三个队列和三个交换:
// Declare the exchanges
$this->channel->exchange_declare(self::EXCHANGE_TO_PROCESS, 'direct', false, true, false, false, false);
$this->channel->exchange_declare(self::EXCHANGE_WAITING, 'direct', false, true, false, false, false);
$this->channel->exchange_declare(self::EXCHANGE_TO_CLEAN, 'direct', false, true, false, false, false);
// Messages in the to_process queue are sent to to_clean after 24 hours without being processed
$this->channel->queue_declare(self::QUEUE_TO_PROCESS, false, true, false, false, false, array(
'x-dead-letter-exchange' => array('S', self::EXCHANGE_TO_CLEAN),
'x-message-ttl' => array('I', 86400000), // 1 day in milli-seconds
));
// Messages in the waiting queue are sent to to_process after 5 minutes (wait period before retry)
$this->channel->queue_declare(self::QUEUE_WAITING, false, true, false, false, false, array(
'x-dead-letter-exchange' => array('S', self::EXCHANGE_TO_PROCESS),
'x-message-ttl' => array('I', 300000), // 5 minutes in milli-seconds
));
// Messages in the to_clean queue are kept until they are processed
$this->channel->queue_declare(self::QUEUE_TO_CLEAN, false, true, false, false, false);
// Bind the queues to the exchanges
$this->channel->queue_bind(self::QUEUE_TO_PROCESS, self::EXCHANGE_TO_PROCESS);
$this->channel->queue_bind(self::QUEUE_TO_CLEAN, self::EXCHANGE_TO_CLEAN);
$this->channel->queue_bind(self::QUEUE_WAITING, self::EXCHANGE_WAITING);
行为非常简单:消息发布到EXCHANGE_TO_PROCESS
。外部工作程序处理消息:如果处理进入A-OK,则消息被简单地确认,从而从队列中删除(这部分工作正常);如果处理出错,则将消息插入EXCHANGE_WAITING
,在5分钟的TTL之后,将其通过DLX重新插入EXCHANGE_TO_PROCESS
进行重新处理。但是,在第三次失败之后,它会被插入EXCHANGE_TO_CLEAN
,其中一个cron作业将来临并清理消息,记录错误等。
然而,我遇到的问题是代码清楚地将QUEUE_WAITING
绑定到EXCHANGE_WAITING
(正如预期的那样),但当我查看RabbitMQ管理页面时,我注意到两个队列按此顺序绑定到该交换,即QUEUE_TO_PROCESS
和QUEUE_WAITING
。当5分钟结束时,消息就会消失。我不太清楚为什么。
所有这些让我们回答我的问题:死信交换是否隐含地将参数中的交换绑定到队列中?并且:我丢失的消息可能会发生什么?
修改
我比以前更困惑。我尝试了以下非常基本的代码:
$this->channel->exchange_declare('exchangeA', 'fanout', false, true, false, false, false);
$this->channel->exchange_declare('exchangeB', 'fanout', false, true, false, false, false);
$this->channel->queue_declare('queueA', false, true, false, false, false, array(
'x-dead-letter-exchange' => array('S', 'exchangeB'),
'x-message-ttl' => array('I', 5000)
));
$this->channel->queue_declare('queueB', false, true, false, false, false);
$this->channel->queue_bind('queueA', 'exchangeA');
$this->channel->queue_bind('queueB', 'exchangeB');
$msg = new AMQPMessage('hello!');
$this->channel->basic_publish($msg, 'exchangeA');
这会创建两个队列和两个交换(我已经看到它们到fanout
以避免烦扰路由密钥),将queueA绑定到exchangeA,将queueB绑定到exchangeB,在queueA上设置TTL,在queueB上设置DLX。看着管理页面中发生的事情,我看到一条消息在queueA中花了5秒钟,正如预期的那样,然后消息消失了,就像上面我更复杂的代码一样。
答案 0 :(得分:3)
看起来您的消息流可能会循环播放。如果是这样,RabbitMQ将默认删除官方文档(Routing Dead-Lettered Messages部分)中指定的消息:
可以形成死信队列的循环。例如, 当队列将消息写入默认消息时,可能会发生这种情况 交换而不指定死信路由密钥。消息 这样的周期(即两次到达同一队列的消息)将是 如果整个周期是由于消息到期而导致丢弃。
要解决骑车问题,你必须选择一个选择:
这会给您的应用带来一些复杂性,但这是您必须为性能和稳定性付出的代价。
P.S:
我挖掘RabbitMQ邮件列表,发现类似你的问题 - Dead Letter, TTL and Cycle:
此刻你必须消费并重新发布以清除 在RabbitMQ之外的标题。
答案 1 :(得分:0)
当我偶然发现this blog并看到海报的情况与我们的情况非常相似时,我怀疑有什么不对劲,他提到它的工作没有问题......所以我开始挖掘更多。< / p>
我们遇到的问题只是一个版本问题。我被告知RabbitMQ软件包是最新的,但是我们使用的是Ubuntu 12.04 LTS,因此“最新”版本是2.7.1 - 这是一个超过3年的版本。
如果你和我们的情况相同(使用较旧的发行版),请查看RabbitMQ的download page并选择适合你的发行版的那个。在Ubuntu的情况下,我们只需添加官方仓库(您也可以简单地下载.dpkg文件),执行apt-get update
并等待服务器重启。之后,上面的代码完全按原样运行。