一、經典問題
1.為什么要用MQ?
MQ的作用主要是3個,
? 第一個是流量削峰:當某個活動舉行時,訪問量可能是平時的幾百倍,可能一下會把服務器弄崩潰,所以通過MQ的形式,引入中間者,客戶端將請求都發到MQ這里,服務器根據自身的容量去MQ中取請求進行處理,這樣起了流量削峰的作用。
? 第二個是應用解耦:當一個應用中有許多系統,訂單系統,庫存系統,支付系統等,任何一個子系統出現了故障,都會造成下單操作的故障,引入了MQ之后,一個子系統故障了,另外的子系統仍然可以進行相應的操作。
? 第三個是異步處理:當A調用了B方法之后,B方法要執行很久,但A還有許多方法還要執行,就可以使用MQ進行異步的方式執行B方法,A繼續執行其他方法,之后B方法執行完成之后就通知A一次,就節省了運行時間。
2.常見MQ的區別
區別 | RabbitMQ | RocketMQ | KafKa |
語言 | Erlang | Java | Scala & Java |
支持語言 | 幾乎支持所有語言 | Java,C++不成熟 | 多種語言 |
單機吞吐量 | 萬級3 | 十萬級1 | 十萬級2 |
消息延遲 | 微秒級 | 毫秒級 | 毫秒以內 |
可用性 | 高,基于主從架構 | 非常高,分布式結構 | 非常高,分布式結構,一個數據多個副本 |
消息可靠性 | ? -? | 可以做到零丟失 | 可以做到零丟失 |
優勢 | 支持所有語言,吞吐量萬級,功能齊全 | 接口簡單易用,吞吐量大,分布式使用方便 | 超高吞吐量,ms的延遲,可用性有保障 |
劣勢 | 吞吐量較低,erlang語言不易定制開發,二次開發 | 只支持Java和C++,C++還不成熟 | 有可能進行消息的重復消費 |
應用 | 都有使用 | 大規模,復雜的業務 | 大數據的實時計算和日志采集 |
3.RabbitMQ各組件功能
1.Server:接收客戶端的連接,實現AMQP的實體服務。
2.Connection:連接,應用程序和Server的網絡連接,TCP連接
3.Channel:一個信道中有多個Connection,減輕了TCP connection的開銷
4.Message:消息
5.VirtualHost:虛擬主機,可以有多個,一個虛擬主機里面有許多交換機和隊列,但名稱不能相同
6.交換機:按照路由規則將消息映射到對應的隊列中。如果路由不到,就返回給消費者或者直接丟棄,常見類型有direct,fanout,topic,headers四種
7.隊列:保存消息,給消費者消息
8.綁定:交換機和隊列之間的路由規則
4.RabbitMQ的工作原理
? 生產者連接到Server,并開啟一個信道,建立許多連接,生產者將消息發送給broker server,然后brokersever根據virtualhost中的交換機和隊列的路由規則保存在隊列中,消費者和中間者建立連接了之后,從隊列中取消息進行一定的消費。
5.RabbitMQ的工作模式
1.simple模式:
? 生產者將消息直接發送到隊列中,消費者監聽隊列中存在消息,就直接取出消費掉,隊列之后將消息刪除。
? 隱患:消息可能沒有被消費者正確處理,但隊列仍然將消息刪除了,造成了消息的丟失,這時候設置手動的ack比較合適。
2.work Queues模式:
? 生成者將消息發送到隊列中,有多個消費者去搶奪這個消息,多并發的情況下就設置一個開關,保證消息只能被一個消費者消費
3.publish/subscribe發布訂閱模式
? 消費者監聽隊列,生產者將消息發給broker,由交換機將消息轉發到綁定每個交換機的每個隊列,每個綁定交換機的隊列都會收到消息
4.routing路由模式
? 只有當交換機和隊列的key能夠匹配之后,交換機才將消息轉發到對應的隊列中,之后綁定隊列的消費者才能消費
5.topic主題模式(路由模式的一種)
? 存在模糊匹配的方式
6.RabbitMQ消息丟失的情況有哪些?
1.生產者發送消息到broker server時發生丟失
2.broker server 存儲的消息丟失
3.broker server 存儲的消息分發給消費者時丟失
7.消息丟失的原因和解決方法
1.生產者發送消息到broker server時發生丟失:
? 原因:1.發送過程中存在網絡問題? ?2.代碼本身邏輯問題
? 解決方法:發送方確認機制(publisher confirm):生產者將信道設置成confirm模式,一旦信道進入這個confirm模式,信道上面的消息就會被指派一個唯一id,一旦消息被投遞到隊列中,broker就會返回一個確認消息給生產者(包含消息的唯一id),這就確保了消息的成功傳遞(confirm模式最大的好處就是它是異步的,一旦發布了一條消息,生產者可以繼續發送消息,消息被確認了之后,生產者會調用回調方法來確認,如果broker server因為自身錯誤丟失了消息就會返回一個nack,生產者之后再重新做相應的處理)
? 發布確認的情況:
1.單獨發布確認:一條消息只有被確認了之后,才能繼續發送消息,如果指定時間沒有返回確認信息就會拋異常
2.批量發布確認:一次性發布一批消息,但如果發送故障導致發布出現問題之后,就無法知道是哪個消息出現了問題,就導致需要重新發一整批消息,同步操作,會阻塞消息的發布
3.異步發布確認:邏輯雖然比前兩個復雜,但是因為異步提高了許多效率,將消息的確認異步處理,發送消息之后仍然可以繼續發送消息。
? 還可以使用AMQP的事務處理,但是這樣的方式效果不是特別的好,因為這個事務是同步的,一旦有一條消息丟失了之后,就會阻塞整個發送的過程。跟單獨發布類似了
2.Broker Server 中存儲的消息丟失:
原因:消息沒有持久化,服務器重啟的時候導致消息丟失
? 解決方式:1.消息回退:通過設置mandatory參數可以在當消息傳遞過程中不可達目的地時將消息返回給生產者。對于這些無法路由的消息就設定一個備份交換機,然后將消息存儲到備份交換機的隊列中,這時候之后就手動地對這些隊列中的消息進行處理
? 2.設置持久化:當MQ接收到消息的時候,通過持久化的方式將消息存儲到硬盤中
3.RabbitMQ 發給消費者時消息丟失:
原因:1.消費者接收到消息之后,還沒來得及處理消息,消費者機器就宕機了
2.處理消息存在異常
解決方案:默認采用了自動應答的方式,要想消息在消費過程中不丟失,需要把手動應答轉換成自動應答。
8.RabbitMQ消息基于什么傳輸
? 由于TCP連接的創建和銷毀開銷較大,且并發數會受到系統資源的限制,RabbitMQ采用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,每個tcp上的信道數量是沒有限制的。
9.RabbitMQ支持消息冪等性?
? 支持的,當生產者給mq發送一條消息的時候,mq內部都會生成一個inner-msg-id,作為去重的依據(消息投遞失敗并重傳),防止重復的消息進入隊列。消費同理,要求消費體中必須要有一個bizid,避免一條消息被重復消費。
10.RabbitMQ消息持久化的條件
1.聲明隊列必須設置為持久化durable設置為true
2.消息推送投遞模式必須設置持久化,deliveryMode設置為2(持久)
3.消息到達持久化的交換機
4.消息到達持久化的隊列
11.RabbitMQ死信隊列的介紹
定義:由于一些原因導致queue種的某些消息無法被正常消費,這些消息沒有后續的處理,就變成了死信消息
來源:消息TTL過期,(隊列達到最大值,消息無法加入到隊列中),消息被拒絕
用處:用于實現延遲隊列
12.RabbitMQ延遲隊列的介紹
用來存放在指定時間被處理的隊列
使用場景:
1.訂單在10分鐘內未支付自動取消
2.用戶注冊之后,3天沒有登錄就發短信提醒
3.用戶發起退款,3天內商家沒有處理,就直接通知運營人員
4.預定會議后,開始前10分鐘通知各個人員進行參會
實現條件:1.消息設置TTL? 2.存在死信隊列
13.RabbitMQ如何處理消息堆積
? 當出現消息擠壓之后,先處理宕機的消費者,然后創建原先N倍的隊列,將堆積的消息都輪詢到這些隊列中,然后再創建N倍的消費者,每一個消費者對應一個隊列,快速地把堆積的消息給消費了之后,恢復到原來的模式。(這種做法就相當于臨時將queue的資源和消費者的i資源擴大了N倍,消費的速度也變為了N倍)
14.RabbitMQ如何處理消息中丟失的數據
? 在流量的低峰期的時候,寫一個程序去手動查詢那些丟失的信息,然后將消息重新發送到mq中,讓消費者進行消費
15.RabbitMQ如何處理長時間未處理導致寫滿的情況?
? 和上面的情況類似,先寫一個程序直接去MQ中消費消息,消費一個就丟棄一個,先降低MQ的壓力,等到流量低峰期時,就去手動地查詢丟失的數據
16.如何設計一個消息隊列
這個問題可以觀看我以前的博客:Java項目--仿RabbitMQ的消息隊列_04Koi.的博客-CSDN博客
這里面詳細講解了如何簡單設計一個消息隊列,感謝觀看!