今天,我將那些大廠必問的消息隊列的場景問題為大家整理出來,本文將跟大家一起來探討如何回答這些問題。
為什麼要使用消息隊列?
保證消息有序,一個topic只能有一個partition嗎?(消息順序)
業務突然增長,導致消息消費不過來怎麼辦?(消息積壓)
生產者收到寫入成功響應後消息一定不會丟失嗎?(消息丟失)
高併發場景下怎麼保證消息不會重複消費?(重複消費)
如何保證消息的可靠性?
各大消息隊列中間件對比及使用場景
為什麼要使用消息隊列?
總結一下,主要三點原因:解耦、異步、削峯。面試的時候,用自己的語言將這三點講述出來就可以了。
- 解耦:比如,用户下單後,訂單系統需要通知庫存系統,假如庫存系統無法訪問,則訂單減庫存將失敗,從而導致訂單操作失敗。訂單系統與庫存系統耦合,這個時候如果使用消息隊列,可以返回給用户成功,先把消息持久化,等庫存系統恢復後,就可以正常消費減去庫存了。
- 異步:將消息寫入消息隊列,非必要的業務邏輯以異步的方式運行,不影響主流程業務。
- 削峯:消費端慢慢的按照數據庫能處理的併發量,從消息隊列中慢慢拉取消息。在生產中,這個短暫的高峯期積壓是允許的。比如秒殺活動,一般會因為流量過大,從而導致流量暴增,應用掛掉。這個時候加上消息隊列,服務器接收到用户的請求後,首先寫入消息隊列,如果消息隊列長度超過最大數量,則直接拋棄用户請求或跳轉到錯誤頁面。
保證消息有序,一個topic只能有一個partition嗎?(消息順序)
這個場景是針對 kafka 的,一個 Topic,一個 Partition,一個 Consumer,但是這樣會導致內部單線程消費,單線程吞吐量太低,一般不會用這個。
針對保證消息有序性的問題,解決方法就是保證生產者入隊的順序是有序的,出隊後的順序消費則交給消費者去保證。
方法一:
拆分 queue,使得一個 queue 只對應一個消費者。
由於 MQ 一般都能保證內部隊列是先進先出的,所以把需要保持先後順序的一組消息使用某種算法都分配到同一個消息隊列中。然後只用一個消費者單線程去消費該隊列,這樣就能保證消費者是按照順序進行消費的了。
但是消費者的吞吐量會出現瓶頸。如果多個消費者同時消費一個隊列,還是可能會出現順序錯亂的情況,這就相當於是多線程消費了
方法二:
對於多線程的消費同一個隊列的情況,可以使用重試機制:比如有一個微博業務場景的操作,發微博、寫評論、刪除微博,這三個異步操作。
如果一個消費者先執行了寫評論的操作,但是這時微博都還沒發,寫評論一定是失敗的,等一段時間。等另一個消費者,先執行發微博的操作後,再執行,就可以成功。
業務突然增長,導致消息消費不過來怎麼辦?(消息積壓)
消息堆積往往是生產者的生產速度與消費者的消費速度不匹配導致的。
有可能就是消費者消費能力弱,漸漸地消息就積壓了,也有可能是因為消息消費失敗反覆復重試造成的,也有可能是消費端出了問題,導致不消費了或者消費極其慢。
一般這個時候,只能臨時緊急擴容了,具體操作步驟和思路如下:
- 先修復 consumer 的問題,確保其恢復消費速度,然後將現有 consumer 都停掉;
- 新建一個 topic,partition 是原來的 10 倍,臨時建立好原先 10 倍的 queue 數量;
- 然後寫一個臨時的分發數據的 consumer 程序,這個程序部署上去消費積壓的數據,消費之後不做耗時的處理,直接均勻輪詢寫入臨時建立好的 10 倍數量的 queue;
- 接着臨時用 10 倍的機器來部署 consumer,每一批 consumer 消費一個臨時 queue 的數據。這種做法相當於是臨時將 queue 資源和 consumer 資源擴大 10 倍,以正常的 10 倍速度來消費數據;
- 等快速消費完積壓數據之後,得恢復原先部署的架構,重新用原先的 consumer 機器來消費消息。
生產者收到寫入成功響應後消息一定不會丟失嗎?(消息丟失)
一個消息從生產者產生,到被消費者消費,主要經過這 3 個過程:
因此如何保證 MQ 不丟失消息,可以從這三個階段闡述:
生產者保證不丟消息,存儲端不丟消息,消費者不丟消息
生產者保證不丟消息
生產端如何保證不丟消息呢?確保生產的消息能到達存儲端。
如果是 RocketMQ 消息中間件,生產者要想發消息時保證消息不丟失,可以:
採用同步方式發送,send 消息方法返回成功狀態,就表示消息正常到達了存儲端 Broker。
如果 send 消息異常或者返回非成功狀態,可以重試。
可以使用事務消息,RocketMQ 的事務消息機制就是為了保證零丟失來設計的。
存儲端不丟消息
如何保證存儲端的消息不丟失呢? 確保消息持久化到磁盤。大家很容易想到就是刷盤機制。
刷盤機制分同步刷盤和異步刷盤:
生產者消息發過來時,只有持久化到磁盤,RocketMQ 的存儲端 Broker 才返回一個成功的 ACK 響應,這就是同步刷盤。它保證消息不丟失,但是影響了性能。
異步刷盤的話,只要消息寫入 PageCache 緩存,就返回一個成功的 ACK 響應。這樣提高了 MQ 的性能,但是如果這時候機器斷電了,就會丟失消息。
消費者不丟消息
消費者執行完業務邏輯,再反饋會 Broker 説消費成功,這樣才可以保證消費階段不丟消息。
高併發場景下怎麼保證消息不會重複消費?(重複消費)
首先,對於正常業務而言消息重複是不可避免的。
正常情況下,消費者在消費消息後,會給消息隊列發送一個確認,消息隊列接收後就知道消息已經被成功消費了,然後就從隊列中刪除該消息,也就不會將該消息再發送給其他消費者了。
不同消息隊列發出的確認消息形式不同,RabbitMQ 是通過發送一個 ACK 確認消息。
但是因為網絡故障,消費者發出的確認並沒有傳到消息隊列,導致消息隊列不知道該消息已經被消費,然後就再次消息發送給了其他消費者,從而造成重複消費的情況。
重複消費問題的解決思路是:保證消息的唯一性,即使多次傳輸,也不讓消息的多次消費帶來影響,也就是保證消息等冪性。
具體辦法:
在消息生產時,MQ 內部針對每條生產者發送的消息生成一個唯一 id,作為去重和冪等的依據(消息投遞失敗並重傳),避免重複的消息進入隊列。
在消息消費時,要求消息體中也要有一全局唯一 id 作為去重和冪等的依據,避免同一條消息被重複消費
如何保證消息的可靠性?
關於消息丟失的情況也就是這三種情況,消息到 MQ 的過程中搞丟,MQ 自己搞丟,MQ 到消費過程中搞丟。針對不同的情況,用不同的解決方法,用自己的語言敍述即可。
生產者到 RabbitMQ:事務機制和 Confirm 機制,注意:事務機制和 Confirm 機制是互斥的,兩者不能共存,會導致 RabbitMQ 報錯。
RabbitMQ 自身:持久化、集羣、普通模式、鏡像模式。
RabbitMQ 到消費者:basicAck 機制、死信隊列、消息補償機制。
各大消息隊列中間件對比
| ActiveMQ | RabbitMQ | RocketMQ | Kafka | ZeroMQ | |
|---|---|---|---|---|---|
| 單機吞吐量 | 比 RabbitMQ 低 | 2.6w/s | 11.6w/s | 17.3w/s | 29w/s |
| 開發語言 | Java | Erlang | Java | Scala/Java | C |
| 成熟度 | 成熟 | 成熟 | 開源版本不夠成熟 | 比較成熟 | 只有 C、PHP 版本成熟 |
| 訂閲模式 | 點對點(p2p)、廣播(發佈-訂閲) | direct、topic、Headers、fanout | 基於 topic/messageTag 以及按照消息類型,屬性進行正則匹配的發佈訂閲模式 | 基於 topic 以及按照 topic 進行正則匹配的發佈訂閲模式 | 點對點(p2p) |
| 持久化 | 支持少量堆積 | 支持少量堆積 | 支持大量堆積 | 支持大量堆積 | 不支持 |
| 順序消息 | 不支持 | 不支持 | 支持 | 支持 | 不支持 |
| 性能穩定性 | 好 | 好 | 一般 | 較差 | 很好 |
| 集羣模式 | 支持簡單集羣模式,比如‘主-備’,對高級集羣模式支持不好 | 支持簡單集羣,‘複製’模式,對高級集羣模式支持不好 | 常用多對‘Master-Slave’模式,開源版本需手動切換 Slave 變成 Master | 天然的‘Leader-Slave’無狀態集羣,每台服務器既是 Master 也是 Slave | 不支持 |
| 管理界面 | 一般 | 較好 | 一般 | 無 | 無 |
各個消息中間件對比適用場景
ActiveMQ:
- 特點:可靠性、持久化、多種消息模式(點對點、發佈-訂閲、請求-回覆)。
- 適用場景:適合任務隊列、工作流、異步通信、RPC、事件驅動架構等場景。
RabbitMQ:
- 特點:易用性、靈活性、可靠性、多種消息模式(點對點、發佈-訂閲、請求-回覆)。
- 適用場景:適合任務隊列、工作流、異步通信、RPC、事件驅動架構等場景。
RocketMQ:
- 特點:高吞吐量、分佈式、強一致性、消息順序保證、支持消息隊列和廣播消息、多種消息協議(例如:HTTP、MQTT)。
- 適用場景:適合大規模分佈式系統、金融行業消息中間件、實時流處理、消息通知、事件驅動架構等場景。
Apache Kafka:
- 特點:高吞吐量、持久化、可伸縮性、分佈式、多副本複製、消息順序保證。
- 適用場景:適合大規模數據流處理、實時流式處理、日誌收集、事件驅動架構等場景。
ZeroMQ:
- 特點:輕量級、低延遲、高性能、無服務器架構、支持多種消息傳輸協議(如:發佈-訂閲、請求-回覆、推送-拉取)。
- 適用場景:適合高頻交易、低延遲通信、大規模分佈式應用、實時數據傳輸、微服務通信等場景。
就業陪跑訓練營學員投稿
歡迎關注 ❤
我們搞了一個免費的面試真題共享羣,互通有無,一起刷題進步。
沒準能讓你能刷到自己意向公司的最新面試題呢。
感興趣的朋友們可以加我微信:wangzhongyang1993,備註:面試羣。