當前位置:
首頁 > 知識 > 史上最透徹的 RabbitMQ 可靠消息傳輸實戰

史上最透徹的 RabbitMQ 可靠消息傳輸實戰

作者:極客慧

鏈接:https://my.oschina.net/jikeh/blog/2207127


可能是緩存架構之史上講的最明白的 RabbitMQ 可靠消息傳輸實戰演練。

一、背景介紹:消息可靠傳遞的重要性

比如:某個廣告主(如:天貓)想在我們的平台(如:今日頭條)投放廣告,當通過我們的廣告系統新建廣告的時候,該消息在同步給redis緩存(es)的時候丟失了,而我們又沒有發現,造成該廣告無法正常顯示出來,那這損失就大了,如果1天都沒有該廣告的投放記錄,那就有可能是上百萬的損失了,所以消息的可靠傳輸對我們的廣告系統也是很重要的。 其實,生活中這樣的場景很常見,再比如:交易系統、訂單系統都必須保證消息的可靠傳輸,否則,損失是巨大的!!!


二、如何保證消息的可靠傳遞呢?

1、設置交換機、隊列和消息都為持久化

**持久化:**保證在伺服器重啟的時候可以保持不丟失相關信息,重點解決伺服器的異常崩潰而導致的消息丟失問題。但是,將所有的消息都設置為持久化,會嚴重影響RabbitMQ的性能,寫入硬碟的速度比寫入內存的速度慢的不只一點點。對於可靠性不是那麼高的消息可以不採用持久化處理以提高整體的吞吐率,在選擇是否要將消息持久化時,需要在可靠性和吞吐量之間做一個權衡。 處於某種應用場景,如:大流量的訂單交易系統,為了不影響性能,我們可以不設置持久化,但是我們會定時掃描資料庫中的未發送成功的消息,進行重試發送,實際應用場景,我們其實有很多解決方案,不要故步自封,換個角度多想想,只有經歷多了,才能應用的更加得心應手。

1)交換機的持久化

注釋:查看源碼,易知,默認是持久化的

2)隊列的持久化

注釋:查看源碼,易知,默認是持久化的

3)消息的持久化

當我們使用RabbitTemplate調用了 convertAndSend(String exchange, String routingKey, final Object object) 方法。默認就是持久化模式

注意:

持久化的消息在到達隊列時就被寫入到磁碟,並且如果可以,持久化的消息也會在內存中保存一份備份,這樣可以提高一定的性能,只有在內存吃緊的時候才會從內存中清除。

非持久化的消息一般只保存在內存中,在內存吃緊的時候會被換入到磁碟中,以節省內存空間。


2、生產者消息確認機制

當消息發送出去之後,我們如何知道消息有沒有正確到達exchange呢?如果在這個過程中,消息丟失了,我們根本不知道發生了什麼,也不知道是什麼原因導致消息發送失敗了 為解決這個問題,主要有如下兩種方案:

通過事務機制實現

通過生產者消息確認機制(publisher confirm)實現

但是使用事務機制實現會嚴重降低RabbitMQ的消息吞吐量,我們採用一種輕量級的方案——生產者消息確認機制

什麼是消息確認機制? 簡而言之,就是:生產者發送的消息一旦被投遞到所有匹配的隊列之後,就會發送一個確認消息給生產者,這就使得生產者知曉消息已經正確到達了目的地。 如果消息和隊列是持久化存儲的,那麼確認消息會在消息寫入磁碟之後發出。 再補充一個Mandatory參數:當Mandatory參數設為true時,如果目的不可達,會發送消息給生產者,生產者通過一個回調函數來獲取該信息。


3、消費者消息確認機制

為了保證消息從隊列可靠地到達消費者,RabbitMQ提供了消費者消息確認機制(message acknowledgement)。採用消息確認機制之後,消費者就有足夠的時間來處理消息,不用擔心處理消息過程中消費者進程掛掉後消息丟失的問題,因為RabbitMQ會一直等待並持有消息,直到消費者確認了該消息。


4、死信隊列

DLX,Dead Letter Exchange 的縮寫,又死信郵箱、死信交換機。DLX就是一個普通的交換機,和一般的交換機沒有任何區別。 當消息在一個隊列中變成死信(dead message)時,通過這個交換機將死信發送到死信隊列中(指定好相關參數,rabbitmq會自動發送)。

什麼是死信呢?什麼樣的消息會變成死信呢?

消息被拒絕(basic.reject或basic.nack)並且requeue=false.

消息TTL過期

隊列達到最大長度(隊列滿了,無法再添加數據到mq中)

應用場景分析: 在定義業務隊列的時候,可以考慮指定一個死信交換機,並綁定一個死信隊列,當消息變成死信時,該消息就會被發送到該死信隊列上,這樣就方便我們查看消息失敗的原因了 **如何使用死信交換機呢?

定義業務(普通)隊列的時候指定參數:

x-dead-letter-exchange: 用來設置死信後發送的交換機

x-dead-letter-routing-key:用來設置死信的routingKey


三、實戰演練

項目代碼下載地址:https://gitee.com/jikeh/JiKeHCN-RELEASE.git 項目名:spring-boot-rabbitmq-reliability


1、開啟生產者消息確認機制

2、開啟消費者消息確認機制

3、基本配置

注釋:hell_queue就配置了死信交換機、死信隊列


4、生產者核心代碼


5、消費者核心代碼


6、測試生產者消息確認功能:分為4種場景來測試


7、測試消費者消息確認功能

1)當添加這行代碼的時候: channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 測試結果:消息被正常消費,消息從隊列中刪除

2)當注釋掉這行代碼的時候: channel.basicAck(message.getMessageProperties().getDeliveryTag(),false); 測試結果:消息會被重複消費,一直保留在隊列當中


8、測試死信隊列

當執行這行代碼的時候: channel.basicNack(message.getMessageProperties().getDeliveryTag(), false,false); 消息會被加入到死信隊列中:


四、拓展

除了我們上面講的基本可靠性保證外,其實還有很多性能優化方案、可靠性保證方案:集群監控、流控、鏡像隊列、HAProxy+Keeplived高可靠負載均衡 我們後續會繼續分享上述內容,歡迎持續關注…… 下節課,我們將會將該功能應用到緩存架構上了

本文轉載自【開源中國】


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員之家 的精彩文章:

7天內我面試了10家公司,如何從命中率0%到命中率至70%?
大張偉侮辱了恩克,優酷侮辱了世界盃

TAG:程序員之家 |