MQ消息隊列


 
 
 
1 、 exchange queue binding-key routing-key概念及相互間的關系
 
1.queue :存儲消息的隊列,可以指定name來唯一確定
 
2.exchange:交換機(常用有三種),用於接收生產者發來的消息,並通過binding-key 與 routing-key 的匹配關系來決定將消息分發到指定queue
 
  Direct(路由模式):完全匹配 > 當消息的routing-key 與 exchange和queue間的binding-key完全匹配時,將消息分發到該queue
 
  Fanout (訂閱模式):與binding-key和routing-key無關,將接受到的消息分發給有綁定關系的所有隊列(不論binding-key和routing-key是什么)
 
  Topic (通配符模式):用消息的routing-key 與 exchange和queue間的binding-key 進行模式匹配,當滿足規則時,分發到滿足規則的所有隊列
 
 
 

2.為什么要使用rabbitmq

采用AMQP高級消息隊列協議的一種消息隊列技術,
實現了服務之間的高度解耦
 
1.在分布式系統下具備異步,削峰,負載均衡等一系列高級功能;
2.擁有持久化的機制,進程消息,隊列中的信息也可以保存下來。
3.實現消費者和生產者之間的解耦
4.對於高並發場景下,削峰限流,利於數據庫的操作。
5.可以使用消息隊列達到異步下單的效果,排隊中,后台進行邏輯下單。
 
 

3.使用rabbitmq的場景

 
1.服務間異步通信
2.順序消費
3.定時任務
4.請求削峰
 
 

4.如何確保消息正確地發送至RabbitMQ? 如何確保消息接收方消費了消息?如何避免消息重復投遞或重復消費?

 
持久化有兩種方式 MQ事物(太耗性能,不使用)與confirm模式
發送方確認模式:
將信道設置成confirm模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的ID。
一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一ID)。
如果RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(not acknowledged,未確認)消息。
發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。
 
接收方確認機制
接收方消息確認機制:消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。
這里並沒有用到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。保證數據的最終一致性;
下面羅列幾種特殊情況:
如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。(可能存在消息重復消費的隱患,需要去重)
如果消費者接收到消息卻沒有確認消息,連接也未斷開,則RabbitMQ認為該消費者繁忙,將不會給該消費者分發更多的消息。
 
在消息生產時,MQ內部針對每條生產者發送的消息生成一個inner-msg-id,作為去重的依據(消息投遞失敗並重傳),避免重復的消息進入隊列;
在消息消費時,要求消息體中必須要有一個bizId(對於同一業務全局唯一,如支付ID、訂單ID、帖子ID等)作為去重的依據,避免同一條消息被重復消費。
 
消息持久化,當然前提是隊列、交換機必須持久化
RabbitMQ確保持久性消息能從服務器重啟中恢復的方式是,將它們寫入磁盤上的一個持久化日志文件,當發布一條持久性消息到持久交換器上時,Rabbit會在消息提交到日志文件后才發送響應。
一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ會在持久化日志中把這條消息標記為等待垃圾收集。如果持久化消息在被消費之前RabbitMQ重啟,那么Rabbit會自動重建交換器和隊列(以及綁定),並重新發布持久化日志文件中的消息到合適的隊列。
 
消息持久化
ACK確認機制
設置集群鏡像模式
消息補償機制
   
  
 
 

5.消息基於什么傳輸?

由於TCP連接的創建和銷毀開銷較大,且並發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制。
 
6.消息如何分發?
 
若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息並進行確認)。
通過路由可實現多消費的功能
 
 

7.消息怎么路由?

 
消息提供方->路由->一至多個隊列
消息發布到交換器時,消息將擁有一個路由鍵(routing key),在消息創建時設定。
通過隊列路由鍵,可以把隊列綁定到交換器上。
消息到達交換器后,RabbitMQ會將消息的路由鍵與隊列的路由鍵進行匹配(針對不同的交換器有不同的路由規則);
常用的交換器主要分為一下三種:
fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上
direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用topic交換器時,可以使用通配符
 
 

8.使用RabbitMQ有什么好處?

 
服務間高度解耦,
異步通信性能高,
流量削峰
 
缺點:增加了系統復雜度,系統可用性低,外部依賴過多,一致性問題。
持久化的缺地就是降低了服務器的吞吐量,因為使用的是磁盤而非內存存儲,從而降低了吞吐量。可盡量使用 ssd 硬盤來緩解吞吐量的問題。
 
 

9.rabbitmq的集群

主備模式:
普通集群模式:節點數據不復制,消息在某一台中,節點間通信,一台掛了 就不可用了。
 
鏡像集群模式:
你創建的queue,無論元數據還是queue里的消息都會存在於多個實例上,然后每次你寫消息到queue的時候,都會自動把消息到多個實例的queue里進行消息同步。
 
好處在於,你任何一個機器宕機了,沒事兒,別的機器都可以用。壞處在於,第一,這個性能開銷也太大了吧,消息同步所有機器,導致網絡帶寬壓力和消耗很重!第二,這么玩兒,就沒有擴展性可言了,如果某個queue負載很重,你加機器,新增的機器也包含了這個queue的所有數據,並沒有辦法線性擴展你的queue
 
 
10、Kafka的高可用
 
        

Kafka 一個最基本的架構認識:由多個 broker 組成,每個 broker 是一個節點;你創建一個 topic,這個 topic 可以划分為多個 partition,每個 partition 可以存在於不同的 broker 上,每個 partition 就放一部分數據。

這就是天然的分布式消息隊列,就是說一個 topic 的數據,是分散放在多個機器上的,每個機器就放一部分數據。

寫數據的時候,生產者就寫 leader,然后 leader 將數據落地寫本地磁盤,接着其他 follower 自己主動從 leader 來 pull 數據。一旦所有 follower 同步好數據了,就會發送 ack 給 leader,leader 收到所有 follower 的 ack 之后,就會返回寫成功的消息給生產者。(當然,這只是其中一種模式,還可以適當調整這個行為)

消費的時候,只會從 leader 去讀,但是只有當一個消息已經被所有 follower 都同步成功返回 ack 的時候,這個消息才會被消費者讀到。

 

11、什么情況下會出現 blackholed 問題? 

 
答:blackholed 問題是指,向 exchange 投遞了 message ,而由於各種原因導致該 message 丟失,但發送者卻不知道。可導致 blackholed 的情況:1.向未綁定 queue 的 exchange 發送 message;2.exchange 以 binding_key key_A綁定了 queue queue_A,但向該 exchange 發送 message 使用的 routing_key 卻是 key_B。 
 
 

12、如何防止出現 blackholed 問題? 

 
答:沒有特別好的辦法,只能在具體實踐中通過各種方式保證相關 fabric 的存在。另外,如果在執行 Basic.Publish 時設置 mandatory=true ,則在遇到可能出現 blackholed 情況時,服務器會通過返回 Basic.Return 告之當前 message 無法被正確投遞(內含原因 312 NO_ROUTE)。 
 
 

13、Consumer Cancellation Notification 機制用於什么場景? 

 
答:用於保證當鏡像 queue 中 master 掛掉時,連接到 slave 上的 consumer 可以收到自身 consume 被取消的通知,進而可以重新執行 consume 動作從新選出的 master 出獲得消息。若不采用該機制,連接到 slave 上的 consumer 將不會感知 master 掛掉這個事情,導致后續無法再收到新 master 廣播出來的 message 。另外,因為在鏡像 queue 模式下,存在將 message 進行 requeue 的可能,所以實現 consumer 的邏輯時需要能夠正確處理出現重復 message 的情況。 
 
 

14、Basic.Reject 的用法是什么? 

 
答:該信令可用於 consumer 對收到的 message 進行 reject 。若在該信令中設置 requeue=true,則當 RabbitMQ server 收到該拒絕信令后,會將該 message 重新發送到下一個處於 consume 狀態的 consumer 處(理論上仍可能將該消息發送給當前 consumer)。若設置 requeue=false ,則 RabbitMQ server 在收到拒絕信令后,將直接將該 message 從 queue 中移除。 
另外一種移除 queue 中 message 的小技巧是,consumer 回復 Basic.Ack 但不對獲取到的 message 做任何處理。 
而 Basic.Nack 是對 Basic.Reject 的擴展,以支持一次拒絕多條 message 的能力。 
 

 

15、什么是死信呢?什么樣的消息會變成死信呢?

方便我們查看消息失敗的原因了

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

消息TTL過期

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

 
16、如果讓你寫一個消息隊列,該如何進行架構設計?說一下你的思路。
    
快速擴容, 分布式, 數據持久化, 磁盤順序讀寫, 高可用, 消息0丟失(ack)
 
17、rabbitMQ怎么做的持久化
    寫入文件前會有一個Buffer,大小為1M(1048576),數據在寫入文件時,首先會寫入到這個Buffer,如果Buffer已滿,則會將Buffer寫入到文件(未必刷到磁盤) 
    有個固定的刷盤時間:25ms,也就是不管Buffer滿不滿,每隔25ms,Buffer里的數據及未刷新到磁盤的文件內容必定會刷到磁盤 
    每次消息寫入后,如果沒有后續寫入請求,則會直接將已寫入的消息刷到磁盤:使用Erlang的receive x after 0來實現,只要進程的信箱里沒有消息,則產生一個timeout消息,而timeout會觸發刷盤操作
 
 

18、RabbitMQ、kafka之間的比較

 

1、 RabbitMq比kafka成熟,在可用性上,穩定性上,可靠性上,RabbitMq超過kafka。rabbitMq 延遲度低。

2、 Kafka設計的初衷就是處理日志的,可以看做是一個日志系統,針對性很強,所以它並沒有具備一個成熟MQ應該具備的特性(不支持事物)

3、 Kafka的性能(吞吐量、tps)比RabbitMq要強,這篇文章的作者認為,兩者在這方面沒有可比性。

4.技術上面,使用rabbitMq比kafka 長,兩者社區活躍度都高。

5.RocketMQ 阿里出品,社區活躍度不是很高,技術實力強大的公司可選擇。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


免責聲明!

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



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