主要记录开发中使用rabbitmq死信队列的一些笔记。下单成功后30分钟内,按不同时间间隔(1min、3min、10min)发送通知1.设置队列的过期时间$this->channel->queue_declare($this->retry_queue(),false,true,false,false,false,newAMQPTable([#不设置x-dead-letter-routing-key,使用原来的routing_key,10s过期后自动返回原队列,然后x-dead-letter-exchange开关将需要绑定原始队列'x-dead-letter-exchange'=>$this->retry_exchange(),#10s'x-message-ttl'=>10000,]));所有推送到这个队列(未设置ttl)的消息,10s后过期,根据原来的routing_key进入指定exchange,再进入指定队列。2.设置消息的过期时间$message=newAMQPMessage('msg',array(#messagepersistence'delivery_mode'=>AMQPMessage::DELIVERY_MODE_PERSITENT,#ttlexpirationtime'expiration'=>50000,));每条消息都设置了相同的过期时间,过期后消息将失效。3.同时设置队列和消息的过期时间。如果同时设置了消息的过期时间,则消息的过期时间将取决于一个较小的值。例如队列的'x-message-ttl'设置为10s,消息的'expiration'设置为50s。然后消息将在10s后失效。4、后续只要设置队列的ttl,或者简单的设置同样的消息过期时间,死信队列就可以正常工作了。但是,如果设置不同的消息过期时间,可能会导致死信队列无法正常使用。队列不设置ttl$this->channel->queue_declare($this->retry_queue(),false,true,false,false,false,newAMQPTable([#不设置x-dead-letter-routing-key,使用原来的routing_key会在10s过期后自动回到原来的队列,这时x-dead-letter-exchange开关需要绑定到原来的队列'x-dead-letter-exchange'=>$this->retry_exchange(),]));第一条消息设置500s过期,优先推送队列$message=newAMQPMessage('msg',array(#消息持久化'delivery_mode'=>AMQPMessage::DELIVERY_MODE_PERSITENT,#ttl过期时间'expiration'=>500000,));第二条消息设置5s过期,然后推送到队列$message=newAMQPMessage('msg',array(#消息持久化'delivery_mode'=>AMQPMessage::DELIVERY_MODE_PERSITENT,#ttl过期时间'expiration'=>5000,));原来5s后,队列中还有2条消息。说明第二条消息没有“真的过期”。原因是队列头部的消息还没有过期。rabbitmq的死信队列是基于首条消息实现的。5、结束语当MQ检查队列中的第一条消息,发现它还没有过期时,就不会继续检查后面的消息了。即使后续消息过期,也不会流向其他队列,因为它不在队头,这是MQ队列的特性决定的。不能在队列中间消费消息,队列必须先进先出。对于设置队列TTL属性的方法,一旦消息过期,就会从队列中擦除,如果设置了消息的header属性,即使消息过期,也不会从队列中擦除immediately,因为每条消息过期是在快要交付给消费者之前判断的,为什么两者会有不同的处理方式呢?因为在第一种方法中,队列中的过期消息必须在队列的头部。RabbitMQ只需要定期从队列的头部扫描过期的消息。在第二种方法中,每条消息的过期时间是不同的。如果要删除所有过期的消息,需要扫描整个队列,所以最好等消息快要被消费的时候再判断是否过期,如果过期再删除。官方声明“只有当过期消息到达队列头部时,它们才会真正被丢弃(或死信化)。”字母队列。参考http://blog.lbanyan.com/rabbitmq_delay/https://blog.csdn.net/u013256816/article/details/54916011https://juejin.im/post/5b5e52ecf265da0f716c3203
