Go RabbitMQ 死信消息隊列(二)


實現原理:

   /**

 (1)創建一個正常的隊列 Q1,目的是處理業務邏輯,比如發送訂單消息等 ,對應交換器和綁定鍵  分別為  E1 和  Bingkey1

 (2)創建一個延時消息隊列 Q2,設定隊列的延時時間為10s,對應的交換器和綁定鍵分別為 E2和Bingkey2;並在該隊列創建時候,設定隊列的  (a)超時時間 (b) 超時后跳轉的 路由E1和綁定Bingkey1,即超時后跳到     隊列Q1上

 (3) 將消息先發送到 隊列Q2 上,然后等着隊列超時,執行邏輯

 

 

 

 

 * 主要測試一個死信隊列,功能主要實現延時消費,原理是先把消息發到正常隊列,

 * 正常隊列有超時時間,當達到時間后自動發到死信隊列,然后由消費者去消費死信隊列里的消息. */

 

延遲隊列的應用場景

1、未支付訂單定時取消 2、定時清理緩存對象、空閑連接等 3、下單成功后30分鍾內,按不同時間間隔發送通知等(1min、3min、10min發一次)


1、設置隊列的過期時間

$this->channel->queue_declare( $this->retry_queue(), false, true, false, false, false, new AMQPTable( [ # 不設置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 = new AMQPMessage( 'msg', array( # 消息持久化 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSITENT, # ttl過期時間 '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, new AMQPTable( [ # 不設置x-dead-letter-routing-key,使用原先的routing_key,10s過期后自動重回原先的隊列里面,那x-dead-letter-exchange交換機就需綁定原先隊列 'x-dead-letter-exchange' => $this->retry_exchange(), ] ) );

第一個消息設置500s過期,先推進隊列

 

 

第一個消息設置500s過期,先推進隊列

$message = new AMQPMessage( 'msg', array( # 消息持久化 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSITENT, # ttl過期時間 'expiration' => 500000, ) );

第二個消息設置5s過期,后推進隊列

$message = new AMQPMessage( 'msg', array( # 消息持久化 'delivery_mode' => AMQPMessage::DELIVERY_MODE_PERSITENT, # ttl過期時間 'expiration' => 5000, ) );

結果發現,5s之后,隊列里還存在2個消息。說明第二個消息並沒有“真的過期失效”。原因是位於隊列首部的消息沒有過期。而rabbitmq的死信隊列,是基於首部消息實現的。

5、結論

當MQ檢查隊列中的第一個消息時,發現其並未過期,則不會繼續檢查之后的消息了。即使之后的消息過期了,也會因為沒在隊列頭部而無法流轉到其他隊列,這是MQ隊列的特性決定的。你不能去消費隊列中間的消息,隊列必須先進先出。

對於設置隊列TTL屬性的方法,一旦消息過期,就會從隊列中抹去,而設置消息頭部屬性,即使消息過期,也不會馬上從隊列中抹去,因為每條消息是否過期時在即將投遞到消費者之前判定的,為什么兩者得處理方法不一致?因為第一種方法里,隊列中已過期的消息肯定在隊列頭部,RabbitMQ只要定期從隊頭開始掃描是否有過期消息即可,而第二種方法里,每條消息的過期時間不同,如果要刪除所有過期消息,勢必要掃描整個隊列,所以不如等到此消息即將被消費時再判定是否過期,如果過期,再進行刪除。

官方的敘述

"Only when expired messages reach the head of a queue will they actually be discarded (or dead-lettered)." 只有當過期的消息到了隊列的頂端(隊首),才會被真正的丟棄或者進入死信隊列。

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM