本文參考 傳值播客消息隊列面試題公開課 https://www.bilibili.com/video/BV1FE411A7AA?t=345
一文搞懂消息隊列面試常見問題
1、爲什麼要用消息隊列?(消息隊列的應用場景)
考察面試者是否知道爲什麼要用消息隊列,消息隊列在項目重解決什麼問題。
消息隊列是一種“先進先出”的數據結構,
用處1:解耦
系統的耦合性越高,容錯性就月底。以電商系統爲例,用戶創建訂單後,如果耦合調用庫存系統、物流系統、支付系統,任何一個子系統出了故障或者因爲升級等原因暫時不可用,都會造成下單操作異常,影響用戶使用體驗。
用處2:異步
A系統接收一個請求,需要在自己本地寫庫,還需要在B、C、D三個系統寫庫,自己在本地寫庫要3ms,B、C、D三個系統分別寫庫要300ms、450ms、200ms。最終請求總延時是3 + 300 +450 + 200 = 953ms,接近1s,用戶體驗非常不好。一般互聯網的企業,對於用戶的直接操作,一般要求都在每個請求200ms以內完成,對用戶幾乎是無感知的,如果用戶通過瀏覽器發起請求,等待1s,是不可接受的。
用處3:流量消峯
應用系統如果遇到系統請求流量的瞬間猛增,有可能會將系統壓垮。有了消息隊列可以將大量請求緩存起來,分散到一個很長時間處理,這樣可以大大提高系統的穩定性和用戶體驗。
或者業務正常時段如果是1000,高峯時段會達到10000,爲了節約成本,也可以引用MQ進行流量消峯。
2、各種消息隊列產品的比較
特性 | ActiveMQ | RabbitMQ | RocketMQ | kafka |
---|---|---|---|---|
開發語言 | java | erlang | java | scala |
單機吞吐量 | 萬級 | 萬級 | 10萬級 | 10萬級 |
時效性 | ms級 | us級 | ms級 | ms級以內 |
可用性 | 高(主從架構) | 高(主從架構) | 非常高(分佈式架構) | 非常高(分佈式架構) |
功能特性 | 成熟的產品,在很多公司得到應用;有較多的文檔;各種協議支持較好 | 基於erlang開發,所以併發能力很強,性能極其好,延時很低;管理界面較豐富 | MQ功能比較完備,擴展性佳 | 只支持主要的MQ功能,像一些消息查詢,消息回溯等功能沒有提供,畢竟是爲大數據準備的,在大數據領域應用廣。 |
- ActiveMQ,早期使用比較多,沒有經過大規模吞吐量場景的驗證,社區也不是很活躍.
不推薦使用
- RabbitMQ,開發語言erlang阻止了大量Java工程師深入瞭解它,對公司而言,基本處於不可控狀態.但RabbitMq是開源的,比較穩定,活躍度也較高,如不考慮二次開發,
追求穩定性和可靠性的情況,推薦使用
. - RocketMQ,開發語言是Java,在阿里內部經受過高併發業務的考驗,
穩定性和性能均不錯,考慮後期可能二次開發,推薦使用
. - Kafka,大數據領域的實時計算,日誌採集等場景,是kafka業內標準的,社區活躍度很高,推薦使.
大數據領域日誌採集等業務推薦使用
.
3、消息隊列的優點和缺點
考察面試者在使用這種新技術時,是否考慮過該技術對項目所帶來的優點和缺點,而不是隻停留在機械的使用.
優點:
- 解耦
- 異步
- 消峯
缺點:
- 系統可用性降低:系統引入的外部依賴越來越多,系統穩定性越差,就會對業務造成影響。
- 系統複雜度提高:MQ引入加大了系統的複雜度,系統由同步的遠程調用,變成了通過MQ進行異步調用。
- 一致性問題:A系統處理完業務,通過MQ給B、C、D三個系統發消息數據,如果B,C處理成功,D處理失敗,就會造成一致性問題。
可用分佈式事務解決
。
4、如何保證消息隊列的高可用
面試官想知道的是面試者針對可用性降低問題的思考和解決思路。
RabbitMQ高可用—普通集羣
- 在多臺機器上分別啓動RabbitMQ實例。
- 多個實例之間可以相互通信。
- 創建的Queue只會放在一個RabbitMQ上,其它實例都同步元數據。
- 消費的時候,如果連接的沒有Queue,那麼當前實例會從queue所在實例拉取數據。
特點:沒有做到真正的高可用
並且數據拉取的開銷和單實例的瓶頸問題
RabbitMQ高可用—鏡像集羣
- 在多態機器上分別啓動RabbitMQ實例.
- 多個實例之間可以互相通信
- 每次生產者寫消息到queue時,都會自動把消息同步到多個實例的queue上。每個RabbitMQ節點上都有queue的消息數據和元數據
- 某一個節點宕機,其它節點依然保持完整數據,不影響客戶段消費。
5、如何保證消息的不丟失
是否清除消息丟失的原因、如何保證消息不丟失
消息丟失的原因:
- 情況一:消息生產者沒有成功發送到MQ
- 情況二:消息發送給MQ,MQ宕機導致內存中消息丟失
- 情況三:消費者消費了消息,但沒有處理完畢就出現了異常導致丟失。
解決方案:
- 生產者發送給MQ後,MQ給生產者確認收到
- MQ收到消息後進行消息持久化
- 消費者收到消息處理完畢後手動進行ack確認
- MQ收到消費者ack確認後刪除持久化消息
6、如何保證消息不被重複消費?(如何保證消息消費的冪等性)
考察對重複消費產生原因的思考,對保證冪等性的方案
根本原因是網絡不可達
生產者消息重複 當一條消息發送到服務端後,出現了網絡閃斷,導致服務器對客戶端應答失敗。如果此時生產者意識到消息發送失敗並嘗試再次發送消息,消費者會後續收到兩條相同的消息。
消費者消息重複 消息消費的場景下,消息已經投遞到消費者並完成業務處理,當消費方給MQ反饋應答時網絡閃斷。導致MQ服務端再次投遞已被處理過的相同消息。
保證消費冪等性解決方案:
- 消息發送者發送消息時攜帶一個全局唯一的消息id
- 消費者獲取消費後先根據id在redis/db中查詢是否存在消費信息
- 如果沒有消費過就正常消費,消費完畢後寫入redis
- 如果消息消費過就直接捨棄
7、如何保證消息消費的順序性
考察是否理解什麼是消息順序消費以及是否思考過消息順序消費的方案
消息有序指的是可以按照消息的發送順序來消費
例如:一筆訂單產生了3條消息,分別是訂單創建、訂單付款、訂單完成
,同時多筆訂單可以並行消費。
解決方案:
- 生產者根據消息ID將同一組消息發送到一個Queue中。
- 多個消費者同時獲取Queue中的消息進行消費
- MQ使用分段鎖保證單個Queue中的有序消費