罷工助手在哪
1296
2025-04-01
文章目錄
1、什么是rabbitmq?
2、為什么要使用rabbitmq?
3、使用rabbitmq的場景。
4、如何確保消息正確地發送至RabbitMQ?如何確保消息接收方消費了消息?
5.如何避免消息重復投遞或重復消費?
6、消息基于什么傳輸?
7、消息如何分發?
8、消息怎么路由?
9、如何確保消息不丟失?
10、使用RabbitMQ有什么好處?
11、RabbitMQ的集群。
12、mq的缺點
13、什么是MQ ?
14、MQ的優點。
15、解耦、異步、削峰是什么?
16、消息隊列有什么缺點?
17、你們公司生產環境用的是什么消息中間件?
18、Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么優缺點?
19、MQ有哪些常見問題?如何解決這些問題?
20、RabbitMQ基本概念。
21、RabbitMQ的工作模式。
22、如何保證RabbitMQ消息的順序性?
23、消息如何分發?
24、消息怎么路由?
25、消息基于什么傳輸?
26、如何保證消息不被重復消費?或者說,如何保證消息消費時的冪等性?
27、如何確保消息正確地發送至 RabbitMQ? 如何確保消息接收方消費了消息?
28、如何保證RabbitMQ消息的可靠傳輸?
29、為什么不應該對所有的message都使用持久化機制?
30、如何保證高可用的?RabbitMQ的集群?
31、如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以后該怎么處理?有幾百萬消息持續積壓幾小時,怎么辦?
32、設計MQ思路。
總結
最近面試的小伙伴很多,對此我整理了一份Java面試題手冊:基礎知識、JavaOOP、Java集合/泛型面試題、Java異常面試題、Java中的IO與NIO面試題、Java反射、Java序列化、Java注解、多線程&并發、JVM、Mysql、Redis、Memcached、MongoDB、Spring、SpringBoot、SpringCloud、RabbitMQ、Dubbo、MyBatis、ZooKeeper、數據結構、算法、Elasticsearch、Kafka、微服務、Linux等等。可以分享給大家學習。【持續更新中】
完整版Java面試題地址:【2021最新版】Java面試真題匯總
1、什么是rabbitmq?
答:
采用AMQP高級消息隊列協議的一種消息隊列技術,最大的特點就是消費并不需要確保提供方存在,實現了服務之間的高度解耦。
2、為什么要使用rabbitmq?
答:
1、在分布式系統下具備異步,削峰,負載均衡等一系列高級功能;
2、擁有持久化的機制,進程消息,隊列中的信息也可以保存下來。
3、實現消費者和生產者之間的解耦。
4、對于高并發場景下,利用消息隊列可以使得同步訪問變為串行訪問達到一定量的限流,利于數據庫的操作。
5、可以使用消息隊列達到異步下單的效果,排隊中,后臺進行邏輯下單。
3、使用rabbitmq的場景。
答:
1、服務間異步通信
2、順序消費
3、定時任務
4、請求削峰
4、如何確保消息正確地發送至RabbitMQ?如何確保消息接收方消費了消息?
答:
發送方確認模式
1.將信道設置成confirm模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的ID。
2.一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一 ID)。
3.如果 RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(notacknowledged,未確認)消息。發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。
接收方確認機制
接收方消息確認機制
消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ才能安全地把消息從隊列中刪除。這里并沒有用到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。保證數據的最終一致性;
下面羅列幾種特殊情況
如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。
(可能存在消息重復消費的隱患,需要去重)如果消費者接收到消息卻沒有確認消息,連接也未斷開,則RabbitMQ認為該消費者繁忙,將不會給該消費者分發更多的消息。
5.如何避免消息重復投遞或重復消費?
答:
在消息生產時,MQ內部針對每條生產者發送的消息生成一個inner-msg-id,作為去重的依據(消息投遞失敗并重傳),避免重復的消息進入隊列;
在消息消費時,要求消息體中必須要有一個 bizId(對于同一業務全局唯一,如支付ID、訂單ID、帖子ID 等)作為去重的依據,避免同一條消息被重復消費。
6、消息基于什么傳輸?
答:
由于TCP連接的創建和銷毀開銷較大,且并發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的TCP連接內的虛擬連接,且每條TCP連接上的信道數量沒有限制
7、消息如何分發?
答:
若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息并進行確認)。
通過路由可實現多消費的功能
8、消息怎么路由?
答:
消息提供方->路由->一至多個隊列
消息發布到交換器時,消息將擁有一個路由鍵(routing key),在消息創建時設定。
通過隊列路由鍵,可以把隊列綁定到交換器上。
消息到達交換器后,RabbitMQ 會將消息的路由鍵與隊列的路由鍵進行匹配(針對不同的交換器有不同的路由規則);
常用的交換器主要分為一下三種
1.fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上
2.direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
3.topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用topic交換器時,可以使用通配符
9、如何確保消息不丟失?
答:
消息持久化,當然前提是隊列必須持久化
RabbitMQ確保持久性消息能從服務器重啟中恢復的方式是,將它們寫入磁盤上的一個持久化日志文件,當發布一條持久性消息到持久交換器上時,Rabbit會在消息提交到日志文件后才發送響應。
一旦消費者從持久隊列中消費了一條持久化消息,RabbitMQ會在持久化日志中把這條消息標記為等待垃圾收集。如果持久化消息在被消費之前RabbitMQ重啟,那么Rabbit會自動重建交換器和隊列(以及綁定),并重新發布持久化日志文件中的消息到合適的隊列。
10、使用RabbitMQ有什么好處?
答:
1、服務間高度解耦
2、異步通信性能高
3、流量削峰
11、RabbitMQ的集群。
答:
鏡像集群模式
你創建的queue,無論元數據還是queue里的消息都會存在于多個實例上,然后每次你寫消息到queue的時候,都會自動把消息到多個實例的queue里進行消息同步。
好處在于,你任何一個機器宕機了,沒事兒,別的機器都可以用。壞處在于,第一,這個性能開銷也太大了吧,消息同步所有機器,導致網絡帶寬壓力和消耗很重!第二,這么玩兒,就沒有擴展性可言了,如果某個queue負載很重,你加機器,新增的機器也包含了這個queue的所有數據,并沒有辦法線性擴展你的queue。
12、mq的缺點
答:
系統可用性降低
系統引入的外部依賴越多,越容易掛掉,本來你就是A系統調用BCD三個系統的接口就好了,人 ABCD四個系統好好的,沒啥問題,你偏加個MQ進來,萬一MQ掛了咋整?MQ掛了,整套系統崩潰了,你不就完了么。
系統復雜性提高硬生生加個MQ進來,你怎么保證消息沒有重復消費?怎么處理消息丟失的情況?怎么保證消息傳遞的順序性?頭大頭大,問題一大堆,痛苦不已。
一致性問題
A系統處理完了直接返回成功了,人都以為你這個請求就成功了;但是問題是,要是BCD三個系統那里,BD兩個系統寫庫成功了,結果C系統寫庫失敗了,咋整?你這數據就不一致了。
所以消息隊列實際是一種非常復雜的架構,你引入它有很多好處,但是也得針對它帶來的壞處做各種額外的技術方案和架構來規避掉,最好之后,你會發現,媽呀,系統復雜度提升了一個數量級,也許是復雜了10倍。但是關鍵時刻,用,還是得用的。
13、什么是MQ ?
答:
MQ就是消息隊列。是軟件和軟件進行通信的中間件產品。
14、MQ的優點。
答:
簡答
異步處理 - 相比于傳統的串行、并行方式,提高了系統吞吐量。
應用解耦 - 系統間通過消息通信,不用關心其他系統的處理。
流量削鋒 - 可以通過消息隊列長度控制請求量;可以緩解短時間內的高并發請求。
日志處理 - 解決大量日志傳輸。
消息通訊 - 消息隊列一般都內置了高效的通信機制,因此也可以用在純的消息通訊。比如實現點對點消息隊列,或者聊天室等。
15、解耦、異步、削峰是什么?
答:
解耦:A系統發送數據到BCD三個系統,通過接口調用發送。如果E系統也要這個數據呢?那如果C系統現在不需要了呢?A系統負責人幾乎崩潰A 系統跟其它各種亂七八糟的系統嚴重耦合,A系統產生一條比較關鍵的數據,很多系統都需要A系統將這個數據發送過來。如果使用MQ,A系統產生一條數據,發送到MQ里面去,哪個系統需要數據自己去MQ里面消費。如果新系統需要數據,直接從MQ里消費即可;如果某個系統不需要這條數據了,就取消對MQ消息的消費即可。這樣下來,A系統壓根兒不需要去考慮要給誰發送數據,不需要維護這個代碼,也不需要考慮人家是否調用成功、失敗超時等情況。
就是一個系統或者一個模塊,調用了多個系統或者模塊,互相之間的調用很復雜,維護起來很麻煩。但是其 實這個調用是不需要直接同步調用接口的,如果用MQ給它異步化解耦。
異步:A系統接收一個請求,需要在自己本地寫庫,還需要在BCD三個系統寫庫,自己本地寫庫要3ms,BCD三個系統分別寫庫要 300ms、450ms、200ms。最終請求總延時是3+300+450+200=953ms,接近1s,用戶感覺搞個什么東西,慢死了慢死了。用戶通過瀏覽器發起請求。
如果使用MQ,那么A系統連續發送3條消息到MQ隊列中,假如耗時5ms,A系統從接受一個請求到返回響應給用戶,總時長是3+5=8ms。
削峰:減少高峰時期對服務器壓力。
16、消息隊列有什么缺點?
答:
缺點有以下幾個:
系統可用性降低
本來系統運行好好的,現在你非要加入個消息隊列進去,那消息隊列掛了,你的系統不是呵呵了。因此,系統可用性會降低;
系統復雜度提高
加入了消息隊列,要多考慮很多方面的問題,比如:一致性問題、如何保證消息不被重復消費、如何保證消息可靠性傳輸等。因此,需要考慮的東西更多,復雜性增大。
一致性問題
A系統處理完了直接返回成功了,人都以為你這個請求就成功了;但是問題是,要是BCD三個系統那里,BD兩個系統寫庫成功了,結果C系統寫庫失敗了,咋整?你這數據就不一致了。
所以消息隊列實際是一種非常復雜的架構,你引入它有很多好處,但是也得針對它帶來的壞處做各種額外的技術方 案和架構來規避掉,做好之后,你會發現,媽呀,系統復雜度提升了一個數量級,也許是復雜了 10 倍。但是關 鍵時刻,用,還是得用的。
17、你們公司生產環境用的是什么消息中間件?
答:
這個首先你可以說下你們公司選用的是什么消息中間件,比如用的是RabbitMQ,然后可以初步給一些你對不同MQ中間件技術的選型分析。
舉個例子:比如說ActiveMQ是老牌的消息中間件,國內很多公司過去運用的還是非常廣泛的,功能很強大。
但是問題在于沒法確認ActiveMQ可以支撐互聯網公司的高并發、高負載以及高吞吐的復雜場景,在國內互聯網公司落地較少。而且使用較多的是一些傳統企業,用ActiveMQ做異步調用和系統解耦。
然后你可以說說RabbitMQ,他的好處在于可以支撐高并發、高吞吐、性能很高,同時有非常完善便捷的后臺管理界面可以使用。
另外,他還支持集群化、高可用部署架構、消息高可靠支持,功能較為完善。
而且經過調研,國內各大互聯網公司落地大規模RabbitMQ集群支撐自身業務的case較多,國內各種中小型互聯網公司使用RabbitMQ的實踐也比較多。
除此之外,RabbitMQ的開源社區很活躍,較高頻率的迭代版本,來修復發現的bug以及進行各種優化,因此綜合考慮過后,公司采取了RabbitMQ。
但是RabbitMQ也有一點缺陷,就是他自身是基于erlang語言開發的,所以導致較為難以分析里面的源碼,也較難進行深層次的源碼定制和改造,畢竟需要較為扎實的erlang語言功底才可以。
然后可以聊聊RocketMQ,是阿里開源的,經過阿里的生產環境的超高并發、高吞吐的考驗,性能卓越,同時還支持分布式事務等特殊場景。
而且RocketMQ是基于Java語言開發的,適合深入閱讀源碼,有需要可以站在源碼層面解決線上生產問題,包括源碼的二次開發和改造。
另外就是Kafka。Kafka提供的消息中間件的功能明顯較少一些,相對上述幾款MQ中間件要少很多。
但是Kafka的優勢在于專為超高吞吐量的實時日志采集、實時數據同步、實時數據計算等場景來設計。
因此Kafka在大數據領域中配合實時計算技術(比如Spark Streaming、Storm、Flink)使用的較多。但是在傳統的MQ中間件使用場景中較少采用。
18、Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么優缺點?
答:
綜上,各種對比之后,有如下建議:
一般的業務系統要引入MQ,最早大家都用ActiveMQ,但是現在確實大家用的不多了,沒經過大規模吞吐量場景的驗證,社區也不是很活躍,所以大家還是算了吧,我個人不推薦用這個了;
后來大家開始用RabbitMQ,但是確實erlang語言阻止了大量的Java工程師去深入研究和掌控它,對公司而言,幾乎處于不可控的狀態,但是確實人家是開源的,比較穩定的支持,活躍度也高;
不過現在確實越來越多的公司會去用RocketMQ,確實很不錯,畢竟是阿里出品,但社區可能有突然黃掉的風險(目前 RocketMQ已捐給Apache,但GitHub上的活躍度其實不算高)對自己公司技術實力有絕對自信的,推薦用RocketMQ,否則回去老老實實用RabbitMQ 吧,人家有活躍的開源社區,絕對不會黃。
所以中小型公司,技術實力較為一般,技術挑戰不是特別高,用RabbitMQ是不錯的選擇;大型公司,基礎架構研發實力較強,用 RocketMQ是很好的選擇。
如果是大數據領域的實時計算、日志采集等場景,用Kafka是業內標準的,絕對沒問題,社區活躍度很高,絕對不會黃,何況幾乎是全世界這個領域的事實性規范。
19、MQ有哪些常見問題?如何解決這些問題?
答:
MQ的常見問題有:
消息的順序問題
消息的重復問題
消息的順序問題
消息有序指的是可以按照消息的發送順序來消費。
假如生產者產生了2條消息:M1、M2,假定 M1 發送到S1,M2 發送到S2,如果要保證 M1先于M2被消費,怎么做?
解決方案:
保證生產者-MQServer-消費者是一對一對一的關系:
缺陷:
并行度就會成為消息系統的瓶頸(吞吐量不夠)
更多的異常處理,比如:只要消費端出現問題,就會導致整個處理流程阻塞,我們不得不花費更多的精力來解決阻塞的問題。 (2)通過合理的設計或者將問題分解來規避。
不關注亂序的應用實際大量存在
隊列無序并不意味著消息無序 所以從業務層面來保證消息的順序而不僅僅是依賴于消息系統,是一種更合理的方式。
消息的重復問題
造成消息重復的根本原因是:網絡不可達。
所以解決這個問題的辦法就是繞過這個問題。那么問題就變成了:如果消費端收到兩條一樣的消息,應該怎樣處理?
消費端處理消息的業務邏輯保持冪等性。只要保持冪等性,不管來多少條重復消息,最后處理的結果都一樣。保證每條消息都有唯一編號且保證消息處理成功與去重表的日志同時出現。利用一張日志表來記錄已經處理成功的消息的ID,如果新到的消息 ID已經在日志表中,那么就不再處理這條消息。
20、RabbitMQ基本概念。
答:
Broker:簡單來說就是消息隊列服務器實體
Exchange:消息交換機,它指定消息按什么規則,路由到哪個隊列
Queue:消息隊列載體,每個消息都會被投入到一個或多個隊列
Binding:綁定,它的作用就是把exchange和queue按照路由規則綁定起來
Routing Key: 路由關鍵字,exchange根據這個關鍵字進行消息投遞
VHost:vhost可以理解為虛擬broker ,即mini-RabbitMQ server。其內部均含有獨立的queue、exchange和binding等,但最最重要的是,其擁有獨立的權限系統,可以做到vhost范圍的用戶控制。當然,從RabbitMQ的全局角度,vhost可以作為不同權限隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。
Producer: 消息生產者,就是投遞消息的程序
Consumer:消息消費者,就是接受消息的程序
Channel:消息通道,在客戶端的每個連接里,可建立多個channel,每個channel代表一個會話任務由Exchange、Queue、RoutingKey三個才能決定一個從Exchange到Queue的唯一的線路。
21、RabbitMQ的工作模式。
答:
一.simple模式(即最簡單的收發模式)
消息產生消息,將消息放入隊列
消息的消費者(consumer) 監聽 消息隊列,如果隊列中有消息,就消費掉,消息被拿走后,自動從隊列中刪除(隱患 消息可能沒有被消費者正確處理,已經從隊列中消失了,造成消息的丟失,這里可以設置成手動的ack,但如果設置成手動ack,處理完后要及時發送ack消息給隊列,否則會造成內存溢出)。
二.work工作模式(資源的競爭)
3.消息產生者將消息放入隊列消費者可以有多個,消費者1,消費者2同時監聽同一個隊列,消息被消費。
4.C1 C2共同爭搶當前的消息隊列內容,誰先拿到誰負責消費消息(隱患:高并發情況下,默認會產生某一個消息被多個消費者共同使用,可以設置一個開關(syncronize) 保證一條消息只能被一個消費者使用)。
三.publish/subscribe發布訂閱(共享資源)
5.每個消費者監聽自己的隊列;
6.生產者將消息發給broker,由交換機將消息轉發到綁定此交換機的每個隊列,每個綁定交換機的隊列都將接收到消息。
四.routing路由模式
8. 消息生產者將消息發送給交換機按照路由判斷,路由是字符串(info) 當前產生的消息攜帶路由字符(對象的方法),交換機根據路由的key,只能匹配上路由key對應的消息隊列,對應的消費者才能消費消息;
9.根據業務功能定義路由字符串;
10.從系統的代碼邏輯中獲取對應的功能字符串,將消息任務扔到對應的隊列中。
11.業務場景:error通知;EXCEPTION;錯誤通知的功能;傳統意義的錯誤通知;客戶通知;利用key路由,可以將程序中的錯誤封裝成消息傳入到消息隊列中,開發者可以自定義消費者,實時接收錯誤; 五.topic 主題模式(路由模式的一種)
12. 星號井號代表通配符
13.星號代表多個單詞,井號代表一個單詞
14.路由功能添加模糊匹配
15.消息產生者產生消息,把消息交給交換機
16.交換機根據key的規則模糊匹配到對應的隊列,由隊列的監聽消費者接收消息消費(在我的理解看來就是routing查詢的一種模糊匹配,就類似sql的模糊查詢方式)
22、如何保證RabbitMQ消息的順序性?
答:
拆分多個queue(消息隊列),每個queue(消息隊列) 一個consumer(消費者),就是多一些queue(消息隊列)而已,確實是麻煩點;
或者就一個queue (消息隊列)但是對應一個consumer(消費者),然后這個consumer(消費者)內部用內存隊列做排隊,然后分發給底層不同的worker來處理。
23、消息如何分發?
答:
若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息并進行確認)。通過路由可實現多消費的功能。
24、消息怎么路由?
答:
消息提供方->路由->一至多個隊列消息發布到交換器時,消息將擁有一個路由鍵(routing key),在消息創建時設定。通過隊列路由鍵,可以把隊列綁定到交換器上。消息到達交換器后,RabbitMQ 會將消息的路由鍵與隊列的路由鍵進行匹配(針對不同的交換器有不同的路由規則);
常用的交換器主要分為一下三種:
fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上
direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列
topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用 topic 交換器時,可以使用通配符
25、消息基于什么傳輸?
答:
由于 TCP 連接的創建和銷毀開銷較大,且并發數受系統資源限制,會造成性能瓶頸。RabbitMQ使用信道的方式來傳輸數據。信道是建立在真實的 TCP 連接內的虛擬連接,且每條 TCP 連接上的信道數量沒有限制。
26、如何保證消息不被重復消費?或者說,如何保證消息消費時的冪等性?
答:
先說為什么會重復消費:正常情況下,消費者在消費消息的時候,消費完畢后,會發送一個確認消息給消息隊列,消息隊列就知道該消息被消費了,就會將該消息從消息隊列中刪除;
但是因為網絡傳輸等等故障,確認信息沒有傳送到消息隊列,導致消息隊列不知道自己已經消費過該消息了,再次將消息分發給其他的消費者。
針對以上問題,一個解決思路是:保證消息的唯一性,就算是多次傳輸,不要讓消息的多次消費帶來影響;保證消息等冪性;
比如:在寫入消息隊列的數據做唯一標示,消費消息時,根據唯一標識判斷是否消費過;
假設你有個系統,消費一條消息就往數據庫里插入一條數據,要是你一個消息重復兩次,你不就插入了兩條,這數據不就錯了?但是你要是消費到第二次的時候,自己判斷一下是否已經消費過了,若是就直接扔了,這樣不就保留了一條數據,從而保證了數據的正確性。
27、如何確保消息正確地發送至 RabbitMQ? 如何確保消息接收方消費了消息?
答:
發送方確認模式
將信道設置成confirm模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的ID。
一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一 ID)如果RabbitMQ發生內部錯誤從而導致消息丟失,會發送一條nack(notacknowledged,未確認)消息。
發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。
接收方確認機制消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確
認了消息,RabbitMQ才能安全地把消息從隊列中刪除。
這里并沒有用到超時機制,RabbitMQ僅通過Consumer的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ給了Consumer足夠長的時間來處理消息。保證數據的最終一致性;
下面羅列幾種特殊情況
如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ 會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。(可能存在消息重復消費的隱患,需要去重)如果消費者接收到消息卻沒有確認消息,連接也未斷開,則RabbitMQ認為該消費者繁忙,將不會給該消費者分發更多的消息。
28、如何保證RabbitMQ消息的可靠傳輸?
答:
消息不可靠的情況可能是消息丟失,劫持等原因;
丟失又分為:生產者丟失消息、消息列表丟失消息、消費者丟失消息;
生產者丟失消息:從生產者弄丟數據這個角度來看,RabbitMQ提供transaction和confirm模式來確保生產者不丟消息;
transaction機制就是說:發送消息前,開啟事務(channel.txSelect()),然后發送消息,如果發送過程中出現什么異常,事務就會回滾(channel.txRollback()),如果發送成功則提交事務(channel.txCommit())。然而,這種方式有個缺點:吞吐量下降;
confirm模式用的居多:一旦channel進入confirm模式,所有在該信道上發布的消息都將會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之后;
rabbitMQ就會發送一個ACK給生產者(包含消息的唯一ID),這就使得生產者知道消息已經正確到達目的隊列了;
如果rabbitMQ沒能處理該消息,則會發送一個Nack消息給你,你可以進行重試操作。
消息隊列丟數據:消息持久化。
處理消息隊列丟數據的情況,一般是開啟持久化磁盤的配置。
這個持久化配置可以和confirm機制配合使用,你可以在消息持久化磁盤后,再給生產者發送一個Ack信號。
這樣,如果消息持久化磁盤之前,rabbitMQ陣亡了,那么生產者收不到Ack信號,生產者會自動重發。
那么如何持久化呢?
這里順便說一下吧,其實也很容易,就下面兩步
將queue的持久化標識durable設置為true,則代表是一個持久的隊列
2.發送消息的時候將deliveryMode=2這樣設置以后,即使rabbitMQ掛了,重啟后也能恢復數據
3.消費者丟失消息:消費者丟數據一般是因為采用了自動確認消息模式,改為手動確認消息即可!
消費者在收到消息之后,處理消息之前,會自動回復RabbitMQ已收到消息;
如果這時處理消息失敗,就會丟失該消息;
解決方案:處理消息成功后,手動回復確認消息。
29、為什么不應該對所有的message都使用持久化機制?
答:
首先,必然導致性能的下降,因為寫磁盤比寫RAM慢的多,message的吞吐量可能有10倍的差距。
其次,message的持久化機制用在RabbitMQ的內置cluster方案時會出現“坑爹”問題。矛盾點在于,若message設置了persistent屬性,但queue未設置durable屬性,那么當該queue的owner node出現異常后,在未重建該queue前,發往該queue 的message將被 blackholed;若 message 設置了 persistent屬性,同時queue也設置了durable屬性,那么當queue的owner node異常且無法重啟的情況下,則該queue無法在其他node上重建,只能等待其owner node重啟后,才能恢復該 queue的使用,而在這段時間內發送給該queue的message將被 blackholed 。
所以,是否要對message進行持久化,需要綜合考慮性能需要,以及可能遇到的問題。若想達到100,000 條/秒以上的消息吞吐量(單RabbitMQ服務器),則要么使用其他的方式來確保message的可靠delivery ,要么使用非常快速的存儲系統以支持全持久化(例如使用SSD)。
另外一種處理原則是:僅對關鍵消息作持久化處理(根據業務重要程度),且應該保證關鍵消息的量不會導致性能瓶頸。
30、如何保證高可用的?RabbitMQ的集群?
答:
RabbitMQ是比較有代表性的,因為是基于主從(非分布式)做高可用性的,我們就以RabbitMQ為例子講解第一種MQ的高可用性怎么實現。RabbitMQ有三種模式:單機模式、普通集群模式、鏡像集群模式。
單機模式,就是Demo級別的,一般就是你本地啟動了玩玩兒的?,沒人生產用單機模式
普通集群模式:
意思就是在多臺機器上啟動多個RabbitMQ實例,每個機器啟動一個。
你創建的queue,只會放在一個RabbitMQ實例上,但是每個實例都同步queue的元數據(元數據可以認為是queue的一些配置信息,通過元數據,可以找到queue所在實例)。
你消費的時候,實際上如果連接到了另外一個實例,那么那個實例會從queue所在實例上拉取數據過來。這方案主要是提高吞吐量的,就是說讓集群中多個節點來服務某個queue的讀寫操作。
鏡像集群模式:
這種模式,才是所謂的RabbitMQ的高可用模式。跟普通集群模式不一樣的是,在鏡像集群模式下,你創建的queue,無論元數據還是 queue 里的消息都會存在于多個實例上,就是說,每個RabbitMQ節點都有這個queue的一個完整鏡像,包含queue的全部數據的意思。然后每次你寫消息到queue的時候,都會自動把消息同步到多個實例的queue上。
RabbitMQ有很好的管理控制臺,就是在后臺新增一個策略,這個策略是鏡像集群模式的策略,指定的時候是可以要求數據同步到所有節點的,也可以要求同步到指定數量的節點,再次創建queue的時候,應用這個策略,就會自動將數據同步到其他的節點上去了。
這樣的好處在于,你任何一個機器宕機了,沒事兒,其它機器(節點)還包含了這個queue的完整數據,別的consumer都可以到其它節點上去消費數據。壞處在于,第一,這個性能開銷也太大了吧,消息需要同步到所有機器上,導致網絡帶寬壓力和消耗很重!RabbitMQ一個queue的數據都是放在一個節點里的,鏡像集群下,也是每個節點都放這個queue的完整數據。
31、如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以后該怎么處理?有幾百萬消息持續積壓幾小時,怎么辦?
答:
消息積壓處理辦法:臨時緊急擴容:
先修復consumer的問題,確保其恢復消費速度,然后將現有cnosumer都停掉。
新建一個topic,partition是原來的10倍,臨時建立好原先10倍的queue數量。
然后寫一個臨時的分發數據的consumer程序,這個程序部署上去消費積壓的數據,消費之后不做耗時的處理,直接均勻輪詢寫入臨時建立好的10倍數量的queue。
接著臨時征用10倍的機器來部署consumer,每一批consumer消費一個臨時queue的數據。這種做法相當于是臨時將 queue 資源和consumer資源擴大10倍,以正常的10倍速度來消費數據。
等快速消費完積壓數據之后,得恢復原先部署的架構,重新用原先的consumer機器來消費消息。
MQ中消息失效:假設你用的是RabbitMQ,RabbtiMQ是可以設置過期時間的,也就是 TTL。如果消息在queue中積壓超過一定的時間就會被RabbitMQ給清理掉,這個數據就沒了。那這就是第二個坑了。
這就不是說數據會大量積壓在mq里,而是大量的數據會直接搞丟。我們可以采取一個方案,就是批量重導,這個我們之前線上也有類似的場景干過。就是大量積壓的時候,我們當時就直接丟棄數據了,然后等過了高峰期以后,比如大家一起喝咖啡熬夜到晚上12點以后,用戶都睡覺了。這個時候我們就開始寫程序,將丟失的那批數據,寫個臨時程序,一點一點的查出來,
然后重新灌入mq里面去,把白天丟的數據給他補回來。也只能是這樣了。假設1萬個訂單積壓在mq里面,沒有處理,其中 1000個訂單都丟了,你只能手動寫程序把那1000個訂單給查出來,手動發到mq里去再補一次。
mq消息隊列塊滿了:如果消息積壓在mq里,你很長時間都沒有處理掉,此時導致mq都快寫滿了,咋辦?這個還有別的辦法嗎?沒有,誰讓你第一個方案執行的太慢了,你臨時寫程序,接入數據來消費,消費一個丟棄一個,都不要了,快速消費掉所有的消息。然后走第二個方案,到了晚上再補數據吧。
32、設計MQ思路。
答:
比如說這個消息隊列系統,我們從以下幾個角度來考慮一下:
首先這個mq得支持可伸縮性吧,就是需要的時候快速擴容,就可以增加吞吐量和容量,那怎么搞?設計個分布式的系統唄,參照一下kafka的設計理念,broker->topic->partition,每個partition放一個機器,就存一部分數據。如果現在資源不夠了,簡單啊,給topic增加partition,然后做數據遷移,增加機器,不就可以存放更多數據,提供更高的吞吐量了?
其次你得考慮一下這個mq的數據要不要落地磁盤吧?那肯定要了,落磁盤才能保證別進程掛了數據就丟了。那落磁盤的時候怎么落啊?順序寫,這樣就沒有磁盤隨機讀寫的尋址開銷,磁盤順序讀寫的性能是很高的,這就是 kafka 的思路。
其次你考慮一下你的mq的可用性啊?這個事兒,具體參考之前可用性那個環節講解的kafka的高可用保障機制。多副本 -> leader&follower->broker掛了重新選舉 leader 即可對外服務。能不能支持數據0丟失啊?可以呀,有點復雜的。
總結
NAT RabbitMQ
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。