天天看點

RabbitMQ常見問題

1.為什麼使用消息隊列(MQ)?

舉幾個MQ常見的使用場景,例如在一個系統中,本來有A子產品調用B、C子產品的方法,現在又加入了D子產品,但是此時如果要将A子產品産生的資料儲存到D子產品中,那麼必須修改A子產品的方法。如果加入消息隊列MQ,則可以将這幾個子產品之間的通信交給MQ解決,這就是MQ的解耦場景;

再比如在商城系統的秒殺系統中,如果建立訂單的請求全部怼到資料庫中,資料庫可能會因為無法承受瞬時流量而連接配接異常,通過MQ可以起到削峰的作用;

A系統接收一個請求,需要在自己本地寫庫,還需要在BCD三個系統寫庫,自己本地寫庫要3ms,BCD三個系統分别寫庫要300ms、450ms、200ms。最終請求總延時是3 + 300 + 450 + 200 = 953ms,接近1s,而如果用MQ的三個隊列,分别負責寫BCD三個資料庫,BCD資料庫通過消費各自隊列中的資訊寫入資料庫,則A系統無需等待BCD資料庫傳回寫入結果,起到異步效果。

總結:MQ的作用主要是解耦、異步、削峰。

2.RabbitMQ和其他MQ相比有什麼不同?

RabbitMQ的優點:

基于erlang語言開發具有高可用高并發的優點,适合叢集伺服器。

健壯、穩定、易用、跨平台、支援多種語言、文檔齊全。

有消息确認機制和持久化機制,可靠性高。

其他MQ的優點:

Kafka定位日志消息隊列,吞吐量大

阿裡RocketMQ可靠性更強,适用于對資料一緻性和穩定性要求高的場景

ActiveMQ曝光率高,但是可能會丢資訊

MQ的缺點:

系統可用性降低:MQ如果出問題,那麼可能會影響整個系統,造成系統崩潰

系統複雜性提高:引入MQ後,需要額外考慮重複消費、消息順序性和資料一緻性等問題,單引入MQ可能很簡單,但是解決這些問題需要付出大量的工作

一緻性問題:剛剛的例子,BCD三個資料庫寫庫,如果有一個寫入失敗,就會造成幾個資料庫之間的資料不一緻問題。在架構設計時就要考慮一緻性問題

3.如何保證消息的可靠傳輸?

從以下幾個方面來考慮:

生産者沒有将消息寫入MQ

1)引入事務,在發送資料之前開啟事務channel.txSelect,當消息成功被RabbitMQ接收到,那麼送出事務,否則復原事務;

2)confirm機制,RabbitMQ寫入成功後會異步回調一個資訊,如果沒有收到回調資訊或者回調資訊顯示接收失敗,可以重新發送;

confirm機制由于是異步的,是以不影響程式運作,相比事務機制性能更好。

MQ丢失資料

開啟MQ的持久化,可以解決絕大多數情況下的MQ丢失資料問題

消費者丢失資料

場景:收到了RabbitMQ發送的消息,馬上程式就挂了,此時RabbitMQ不會重新發送消息。

引入ack機制,隻有在處理完消息的時候才告知RabbitMQ消費完成

4.如何保證不重複消費,或者說保證消費的幂等性?

幂等性,指的是假設MQ發送的兩次相同的消息(例如訂單資訊),要保證在資料庫中不會重新寫入兩次。相應的,可以考慮利用主鍵查資料庫、加入唯一ID、Redis的set方法(Redis提供了保證幂等性的機制)等。

5.如何保證消息的順序性?

在一個RabbitMQ系統中,若存在多個消費者,那麼就可能會出現A消費者消費了消息,導緻RabbitMQ認為消息已經被消費,繼而B消費者無法擷取消息的問題。可以考慮引入多個QUEUE,即同一條消息,有多少個消費者就建立多少個QUEUE,根據每個消費者所需要的消息的順序,将消息放入對應的QUEUE中,讓消費者可以按順序消費相應的消息。

6.MQ中積壓了大量消息,無法及時被消費的解決辦法?

1)先修複consumer的問題,確定其恢複消費速度,然後将現有cnosumer都停掉

2)建立一個topic,partition是原來的10倍,臨時建立好原先10倍或者20倍的queue數量

3)然後寫一個臨時的分發資料的consumer程式,這個程式部署上去消費積壓的資料,消費之後不做耗時的處理,直接均勻輪詢寫入臨時建立好的10倍數量的queue

4)接着臨時征用10倍的機器來部署consumer,每一批consumer消費一個臨時queue的資料

5)這種做法相當于是臨時将queue資源和consumer資源擴大10倍,以正常的10倍速度來消費資料

6)等快速消費完積壓資料之後,得恢複原先部署架構,重新用原先的consumer機器來消費消息

(參考:https://blog.csdn.net/HiBoyljw/article/details/85123099)

7.如何進行MQ的架構設計,自己寫一個MQ?

1)首先這個mq得支援可伸縮性吧,就是需要的時候快速擴容,就可以增加吞吐量和容量,那怎麼搞?設計個分布式的系統呗,參照一下kafka的設計理念,broker -> topic -> partition,每個partition放一個機器,就存一部分資料。如果現在資源不夠了,簡單啊,給topic增加partition,然後做資料遷移,增加機器,不就可以存放更多資料,提供更高的吞吐量了?

2)其次你得考慮一下這個mq的資料要不要落地磁盤吧?那肯定要了,落磁盤,才能保證别程序挂了資料就丢了。那落磁盤的時候怎麼落啊?順序寫,這樣就沒有磁盤随機讀寫的尋址開銷,磁盤順序讀寫的性能是很高的,這就是kafka的思路。

3)其次你考慮一下你的mq的可用性啊?這個事兒,具體參考我們之前可用性那個環節講解的kafka的高可用保障機制。多副本 -> leader & follower -> broker挂了重新選舉leader即可對外服務。

4)能不能支援資料0丢失啊?可以的,參考我們之前說的那個kafka資料零丢失方案