是什麼:微服務之間的消息通訊方式
常見的消息中間件:
ActiveMQ:基於JMS
RabbitMQ:基於AMQP協議,erlang語言開發,穩定性好
RocketMQ:基於JMS,阿里巴巴產品,目前交由Apache基金會
Kafka:分佈式消息系統,高吞吐量
MQ實現方式:AMQP (只是一種協議因此支持跨平臺)與jms(必須是java語言)
一、解耦,消費方只須要訂閱讀取消息便可
二、靈活性,峯值處理好
三、MQ的處理異步的,這樣就提高了系統的處理性能。
四、可恢復性
五、順序保證
六、緩衝能力,消息中間件像是一個巨大的蓄水池,將高峯期大量的請求存儲下來慢慢交給後臺進行處理,對於秒殺業務來講尤其重要
缺點:
一、系統複雜度增長,考慮消息的重複問題,消息丟失問題。
二、通常消息中間件的服務崩潰了,涉及的相關係統就不可用了。
Rabbit 執行原理:
消息生產方推送消息到隊列,消息放消費隊列中的消息。(下圖是基本消費模型)
消息模型:*******重要******
基本消息模型 消息發送方 -----》隊列 ------》 一個消息消費方
work 消息模型 消息發送方 -----》 隊列 ------》 多個消息消費方
消息發送流程:
1) 一個隊列綁定多個消費者
2)消費者呈合做者分別處理一部分消息解決消息堆積問題。
發佈訂閱消息模型(該模型包含基本與work 消息模型的):
消息發佈方 -->交換機 -->隊列 -->消息訂閱方
1、Fanout:在廣播模式下,消息發送流程是這樣的:
-
1) 消息生產方生產消息發送到交換機html
-
2) 消費方監聽queue(隊列)java
-
3) 隊列與Exchange(交換機)綁定node
-
4) 生產者發送的消息發送到交換機(在代碼中將隊列與交換機綁定就發送給對應隊列,生產者沒法決定)。面試
-
5) 交換機把消息發送給綁定過的全部隊列redis
-
6) 隊列中的消息被消費者監聽到從而執行。實現一條消息被多個消費者消費spring
2、Direct:控制發佈的消息的隊列被哪些訂閱方收到。
特色: 消息生產方會指定routingKey 的關鍵字,這樣交換機就會將消息發送給與該routingkey徹底匹配的隊列。
例如:在路由模式中,咱們將添加一個功能 - 咱們將只能訂閱一部分消息。 例如,咱們只能將重要的錯誤消息引導到日誌文件(以節省磁盤空間),同時仍然可以在控制檯上打印全部日誌消息。可是,在某些場景下,咱們但願不一樣的消息被不一樣的隊列消費。這時就要用到Direct類型的Exchange。
P:生產者,向Exchange發送消息,發送消息時,會指定一個routing key 如:rabbit 服務器
X:Exchange(交換機),接收生產者的消息,而後把消息遞交給 與routing key徹底匹配的隊列網絡
C1:消費者,其所在隊列指定了須要routing key 爲 error 的消息異步
C2:消費者,其所在隊列指定了須要routing key 爲 info、error、warning 的消息分佈式
3、Topic模型 : 和Direct 同樣。只是可使用通配符進行匹配(更加靈活通用)
上圖中:Q1匹配全部的橙色動物。Q2匹配關於兔子以及懶惰動物的消息。
如下的routingKey 配置後哪些會進入Q1,Q2隊列。
quick.orange.rabbit Q1 Q2
lazy.orange.elephant Q1 Q2
quick.orange.fox Q1
lazy.pink.rabbit Q2
quick.brown.fox 不匹配任意隊列,被丟棄
面試熱點: 如下P方 = 消息生產方 C方 = 消息消費方
1、如何保證消息不丟失? 問到過!
一、採用消費者消息確認機制(ACK),ACK分爲手動和自動,
自動ACK:消費方接受到消息則隊列中的消息就會被刪除
手動ACK:若是在接受到消息後發生了錯誤拋異常 這種狀況應該使用手動確認 相似手動啓動關閉事務這樣
二、採用生產者消息回執確認機制:
消息生產者 交換機發送消息發送成功後,交換機回執ACK給消息生產者
2、若是MQ服務器掛掉怎麼辦?
一、搭建集羣
二、將消息持久化,在spring集成中消息和隊列以及交換機 都是持久化的
3、如何解決隊列中的消息積壓過大?
work 消息模型 配置多臺消息的消費方進行消費。
4、冪等性(如何解決消息被重複執行): 問到過!
消息被重複發送,例以下訂單我點了兩次也許是網絡緣由點了2次。
發生緣由:當交換機回執ACK給P方時,因爲網絡故障致使生產方未收到消息,當網絡恢復
P方沒有收到ACK回執則從新發送一條消息致使消息重複。
解決方案:
給消息設置惟一ID,判斷該消息被消費過,而後再業務方進行去重。
實現方式兩種:
一、在ZK中建立node 當判斷是否重複的時候就去建立node 若是存在建立會報錯。
二、使用redis 當放入MQ後就往redis 中存入一個惟一id 判斷重複的時候就去看看是否存在,存在即重複。
5、延遲隊列實現方式:問到過!
場景介紹:商品訂單超過半小時自動刪除。
解決方案:(經過TTL死信 與 DLX 死信隊列實現。)
一、設置消息的有效期,例如30Min,當超過該效期,則該信息變爲死信 (TTL)
二、當出現死信,MQ提供對於死信處理的死信隊列,例如當訂單超過半小時,則將消息放入死信隊列,而後由綁定死信隊列的消費方進行處理,從而將訂單刪除。(DLX) 這樣就利用了MQ的特性實現了延遲隊列。
擴展:通常死信處理狀況有三種:
一、消息超時
二、消息被拒絕
三、隊列達到最大長度