消息中間件面試題31道RabbitMQ+ActiveMQ+Kafka


消息中間件面試題31道RabbitMQ+ActiveMQ+Kafka

前言

文章開始前,我們先了解一下什么是消息中間件?

什么是中間件?

非底層操作系統軟件,非業務應用軟件,不是直接給最終用戶使用的,不能直接給客戶帶來價值的軟件統稱為中間件。

什么是消息中間件?

是關注於數據的發送和接收,利用高效可靠的異步消息傳遞機制集成分布式系統

圖示:

 

消息中間件RabbitMQ+ActiveMQ+Kafka的對比

 

接下來就是消息中間件面試題RabbitMQ+ActiveMQ+Kafka

RabbitMQ消息中間件系列

1:RabbitMQ 中的 broker 是指什么?cluster 又是指什么?

答:broker 是指一個或多個 erlang node 的邏輯分組,且 node 上運行着 RabbitMQ 應用程序。cluster 是在 broker 的基礎之上,增加了 node 之間共享元數據的約束。

2:什么是元數據?元數據分為哪些類型?包括哪些內容?與 cluster 相關的元數據有哪些?元數據是如何保存的?元數據在 cluster 中是如何分布的?

答:在非 cluster 模式下,元數據主要分為 Queue 元數據(queue 名字和屬性等)、Exchange 元數據(exchange 名字、類型和屬性等)、Binding 元數據(存放路由關系的查找表)、Vhost 元數據(vhost 范圍內針對前三者的名字空間約束和安全屬性設置)。在cluster 模式下,還包括 cluster 中 node 位置信息和 node 關系信息。元數據按照 erlang node 的類型確定是僅保存於 RAM 中,還是同時保存在 RAM 和 disk 上。元數據在cluster 中是全 node 分布的。

3:RAM node 和 disk node 的區別?

答:RAM node 僅將 fabric(即 queue、exchange 和 binding 等 RabbitMQ 基礎構件)相關元數據保存到內存中,但 disk node 會在內存和磁盤中均進行存儲。RAM node 上唯一會存儲到磁盤上的元數據是 cluster 中使用的 disk node 的地址。要求在 RabbitMQ cluster 中至少存在一個 disk node 。

4:RabbitMQ 上的一個 queue 中存放的 message 是否有數量限制?

答:可以認為是無限制,因為限制取決於機器的內存,但是消息過多會導致處理效率的下降。

5:RabbitMQ 概念里的 channel、exchange 和 queue 這些東東是邏輯概念,還是對應着進程實體?這些東東分別起什么作用?

答:queue 具有自己的 erlang 進程;exchange 內部實現為保存 binding 關系的查找表; channel 是實際進行路由工作的實體,即負責按照 routing_key 將 message 投遞給queue 。由 AMQP 協議描述可知,channel 是真實 TCP 連接之上的虛擬連接,所有AMQP 命令都是通過 channel 發送的,且每一個 channel 有唯一的 ID。一個 channel 只能被單獨一個操作系統線程使用,故投遞到特定 channel 上的 message 是有順序的。但一個操作系統線程上允許使用多個 channel 。channel 號為 0 的 channel 用於處理所有對於當前 connection 全局有效的幀,而 1-65535 號 channel 用於處理和特定 channel 相關的幀。

其中每一個 channel 運行在一個獨立的線程上,多線程共享同一個 socket。

6:vhost 是什么?起什么作用?

答:vhost 可以理解為虛擬 broker ,即 mini-RabbitMQ server。其內部均含有獨立的

queue、exchange 和 binding 等,但最最重要的是,其擁有獨立的權限系統,可以做到vhost 范圍的用戶控制。當然,從 RabbitMQ 的全局角度,vhost 可以作為不同權限隔離的手段(一個典型的例子就是不同的應用可以跑在不同的 vhost 中)。

7:為什么 heavy RPC 的使用場景下不建議采用 disk node ?

答:heavy RPC 是指在業務邏輯中高頻調用 RabbitMQ 提供的 RPC 機制,導致不斷創建、銷毀 reply queue ,進而造成 disk node 的性能問題(因為會針對元數據不斷寫盤)。所以在使用 RPC 機制時需要考慮自身的業務場景。

8:向不存在的 exchange 發 publish 消息會發生什么?向不存在的 queue 執行consume 動作會發生什么?

答:都會收到 Channel.Close 信令告之不存在(內含原因 404 NOT_FOUND)。

問題十四:routing_key 和 binding_key 的最大長度是多少?

答:255 字節。

9:RabbitMQ 允許發送的 message 最大可達多大?

答:根據 AMQP 協議規定,消息體的大小由 64-bit 的值來指定,所以你就可以知道到底能發多大的數據了。

10:什么情況下 producer 不主動創建 queue 是安全的?

答:1.message是允許丟失的;2.實現了針對未處理消息的republish功能(例如采用Publisher Confirm 機制)。

11:“dead letter”queue 的用途?

答:當消息被 RabbitMQ server 投遞到 consumer 后,但 consumer 卻通過 Basic.Reject 進行了拒絕時(同時設置 requeue=false),那么該消息會被放入“dead letter”queue 中。該 queue 可用於排查 message 被 reject 或 undeliver 的原因。

12:為什么說保證 message 被可靠持久化的條件是 queue 和 exchange 具有durable 屬性,同時 message 具有 persistent 屬性才行?

答:binding 關系可以表示為 exchange – binding – queue 。從文檔中我們知道,若要求投遞的 message 能夠不丟失,要求 message 本身設置 persistent 屬性,要求 exchange 和 queue 都設置 durable 屬性。其實這問題可以這么想,若 exchange 或 queue 未設置durable 屬性,則在其 crash 之后就會無法恢復,那么即使 message 設置了 persistent 屬性,仍然存在 message 雖然能恢復但卻無處容身的問題;同理,若 message 本身未設置persistent 屬性,則 message 的持久化更無從談起。

13:什么情況下會出現 blackholed 問題?

答:blackholed 問題是指,向 exchange 投遞了 message ,而由於各種原因導致該message 丟失,但發送者卻不知道。可導致 blackholed 的情況:1.向未綁定 queue 的exchange 發送 message;2.exchange 以 binding_key key_A 綁定了 queue queue_A,但向該 exchange 發送 message 使用的 routing_key 卻是 key_B。

14:如何防止出現 blackholed 問題?

答:沒有特別好的辦法,只能在具體實踐中通過各種方式保證相關 fabric 的存在。另外, 如果在執行 Basic.Publish 時設置 mandatory=true ,則在遇到可能出現 blackholed 情況時,服務器會通過返回 Basic.Return 告之當前 message 無法被正確投遞(內含原因 312 NO_ROUTE)。

15:Consumer Cancellation Notification 機制用於什么場景?

答:用於保證當鏡像 queue 中 master 掛掉時,連接到 slave 上的 consumer 可以收到自身 consume 被取消的通知,進而可以重新執行 consume 動作從新選出的 master 出獲得消息。若不采用該機制,連接到 slave 上的 consumer 將不會感知 master 掛掉這個事情,導致后續無法再收到新 master 廣播出來的 message 。另外,因為在鏡像 queue 模式下,存在將 message 進行 requeue 的可能,所以實現 consumer 的邏輯時需要能夠正確處理出現重復 message 的情況。

 

ActiveMQ消息中間件系列

1.什么是 ActiveMQ?

activeMQ 是一種開源的,實現了 JMS1.1 規范的,面向消息(MOM)的中間件,為應用程序提供高效的、可擴展的、穩定的和安全的企業級消息通信

2.ActiveMQ 服務器宕機怎么辦?

這得從 ActiveMQ 的儲存機制說起。在通常的情況下,非持久化消息是存儲在內存中的,持久化消息是存儲在文件中的,它們的最大限制在配置文件的節點中配置。但是,在非持久化消息堆積到一定程度,內存告急的時候,ActiveMQ 會將內存中的非持久化消息寫入臨時文件中,以騰出內存。雖然都保存到了文件里,但它和持久化消息的區別是,重啟后持久化消息會從文件中恢復,非持久化的臨時文件會直接刪除。

那如果文件增大到達了配置中的最大限制的時候會發生什么?我做了以下實驗:

設置 2G 左右的持久化文件限制,大量生產持久化消息直到文件達到最大限制,此時生產者阻塞,但消費者可正常連接並消費消息,等消息消費掉一部分,文件刪除又騰出空間之后,生產者又可繼續發送消息, 服務自動恢復正常。

設置 2G 左右的臨時文件限制,大量生產非持久化消息並寫入臨時文件,在達到最大限制時,生產者阻塞,消費者可正常連接但不能消費消息,或者原本慢速消費的消費者,消費突然停止。整個系統可連接, 但是無法提供服務,就這樣掛了。

具體原因不詳,解決方案:盡量不要用非持久化消息,非要用的話,將臨時文件限制盡可能的調大。

3.丟消息怎么辦?

這得從 java 的 java.net.SocketException 異常說起。簡單點說就是當網絡發送方發送一堆數據,然后調用 close 關閉連接之后。這些發送的數據都在接收者的緩存里,接收者如果調用 read 方法仍舊能從緩存中讀取這些數據,盡管對方已經關閉了連接。但是當接收者嘗試發送數據時,由於此時連接已關閉,所以會發生異常,這個很好理解。不過需要注意的是,當發生 SocketException 后,原本緩存區中數據也作廢了,此時接收者再次調用 read 方法去讀取緩存中的數據,就會報 Software caused connection abort: recv failed 錯誤。

通過抓包得知,ActiveMQ 會每隔 10 秒發送一個心跳包,這個心跳包是服務器發送給客戶端的,用來判斷客戶端死沒死。如果你看過上面第一條,就會知道非持久化消息堆積到一定程度會寫到文件里,這個寫的過程會阻塞所有動作,而且會持續 20 到 30 秒,並且隨着內存的增大而增大。當客戶端發完消息調用connection.close()時,會期待服務器對於關閉連接的回答,如果超過 15 秒沒回答就直接調用 socket 層的 close 關閉 tcp 連接了。這時客戶端發出的消息其實還在服務器的緩存里等待處理,不過由於服務器心跳包的設置,導致發生了 java.net.SocketException 異常,把緩存里的數據作廢了,沒處理的消息全部丟失。

解決方案:用持久化消息,或者非持久化消息及時處理不要堆積,或者啟動事務,啟動事務后,

commit()方法會負責任的等待服務器的返回,也就不會關閉連接導致消息丟失了。

4.持久化消息非常慢。

默認的情況下,非持久化的消息是異步發送的,持久化的消息是同步發送的,遇到慢一點的硬盤,發送消息的速度是無法忍受的。但是在開啟事務的情況下,消息都是異步發送的,效率會有 2 個數量級的提升。所以在發送持久化消息時,請務必開啟事務模式。其實發送非持久化消息時也建議開啟事務,因為根本不會影響性能。

5.消息的不均勻消費。

有時在發送一些消息之后,開啟 2 個消費者去處理消息。會發現一個消費者處理了所有的消息,另一個消費者根本沒收到消息。原因在於 ActiveMQ 的 prefetch 機制。當消費者去獲取消息時,不會一條一條去獲取,而是一次性獲取一批,默認是 1000 條。這些預獲取的消息,在還沒確認消費之前,在管理控制台還是可以看見這些消息的,但是不會再分配給其他消費者,此時這些消息的狀態應該算作“已分配未消 費”,如果消息最后被消費,則會在服務器端被刪除,如果消費者崩潰,則這些消息會被重新分配給新的消費者。但是如果消費者既不消費確認,又不崩潰,那這些消息就永遠躺在消費者的緩存區里無法處理。更通常的情況是,消費這些消息非常耗時,你開了 10 個消費者去處理,結果發現只有一台機器吭哧吭哧

處理,另外 9 台啥事不干。

解決方案:將 prefetch 設為 1,每次處理 1 條消息,處理完再去取,這樣也慢不了多少。

6.死信隊列。

如果你想在消息處理失敗后,不被服務器刪除,還能被其他消費者處理或重試,可以關閉AUTO_ACKNOWLEDGE,將 ack 交由程序自己處理。那如果使用了 AUTO_ACKNOWLEDGE,消息是什么時候被確認的,還有沒有阻止消息確認的方法?有!

消費消息有 2 種方法,一種是調用 consumer.receive()方法,該方法將阻塞直到獲得並返回一條消息。這種情況下,消息返回給方法調用者之后就自動被確認了。另一種方法是采用 listener 回調函數,在有消息到達時,會調用 listener 接口的 onMessage 方法。在這種情況下,在 onMessage 方法執行完畢后, 消息才會被確認,此時只要在方法中拋出異常,該消息就不會被確認。那么問題來了,如果一條消息不能被處理,會被退回服務器重新分配,如果只有一個消費者,該消息又會重新被獲取,重新拋異常。就算有多個消費者,往往在一個服務器上不能處理的消息,在另外的服務器上依然不能被處理。難道就這么退回

–獲取–報錯死循環了嗎?

在重試 6 次后,ActiveMQ 認為這條消息是“有毒”的,將會把消息丟到死信隊列里。如果你的消息不見了,去 ActiveMQ.DLQ 里找找,說不定就躺在那里。

 

Kafka消息中間件系列

1.Kafka 的設計時什么樣的呢?

Kafka 將消息以 topic 為單位進行歸納

將向 Kafka topic 發布消息的程序成為 producers.

將預訂 topics 並消費消息的程序成為 consumer.

Kafka 以集群的方式運行,可以由一個或多個服務組成,每個服務叫做一個 broker. producers 通過網絡將消息發送到 Kafka 集群,集群向消費者提供消息

2.數據傳輸的事物定義有哪三種?

數據傳輸的事務定義通常有以下三種級別:

(1)最多一次: 消息不會被重復發送,最多被傳輸一次,但也有可能一次不傳輸

(2)最少一次: 消息不會被漏發送,最少被傳輸一次,但也有可能被重復傳輸.

(3)精確的一次(Exactly once):不會漏傳輸也不會重復傳輸,每個消息都傳輸被一次而且僅僅被傳輸一次,這是大家所期望的

3.Kafka 判斷一個節點是否還活着有那兩個條件?

(1)節點必須可以維護和 ZooKeeper 的連接,Zookeeper 通過心跳機制檢查每個節點的連接

(2)如果節點是個 follower,他必須能及時的同步 leader 的寫操作,延時不能太久

4.producer 是否直接將數據發送到 broker 的 leader(主節點)?

producer 直接將數據發送到 broker 的 leader(主節點),不需要在多個節點進行分發,為了幫助 producer 做到這點,所有的 Kafka 節點都可以及時的告知:哪些節點是活動的,目標topic 目標分區的 leader 在哪。這樣 producer 就可以直接將消息發送到目的地了

5、Kafa consumer 是否可以消費指定分區消息?

Kafaconsumer 消費消息時,向 broker 發出"fetch"請求去消費特定分區的消息,consumer 指定消息在日志中的偏移量(offset),就可以消費從這個位置開始的消息,customer 擁有了 offset 的控制權,可以向后回滾去重新消費之前的消息,這是很有意義的

6、Kafka 消息是采用 Pull 模式,還是 Push 模式?

Kafka 最初考慮的問題是,customer 應該從 brokes 拉取消息還是 brokers 將消息推送到consumer,也就是 pull 還 push。在這方面,Kafka 遵循了一種大部分消息系統共同的傳統的設計:producer 將消息推送到 broker,consumer 從 broker 拉取消息

一些消息系統比如 Scribe 和 ApacheFlume 采用了 push 模式,將消息推送到下游的consumer。這樣做有好處也有壞處:由 broker 決定消息推送的速率,對於不同消費速率的consumer 就不太好處理了。消息系統都致力於讓 consumer 以最大的速率最快速的消費消息,但不幸的是,push 模式下,當 broker 推送的速率遠大於 consumer 消費的速率時, consumer 恐怕就要崩潰了。最終 Kafka 還是選取了傳統的 pull 模式

Pull 模式的另外一個好處是 consumer 可以自主決定是否批量的從 broker 拉取數據。Push 模式必須在不知道下游 consumer 消費能力和消費策略的情況下決定是立即推送每條消息還是緩存之后批量推送。如果為了避免 consumer 崩潰而采用較低的推送速率,將可能導致一次只推送較少的消息而造成浪費。Pull 模式下,consumer 就可以根據自己的消費能力去決

定這些策略

Pull 有個缺點是,如果 broker 沒有可供消費的消息,將導致 consumer 不斷在循環中輪詢, 直到新消息到 t 達。為了避免這點,Kafka 有個參數可以讓 consumer 阻塞知道新消息到達(當然也可以阻塞知道消息的數量達到某個特定的量這樣就可以批量發

7.Kafka 的消費者如何消費數據

消費者每次消費數據的時候,消費者都會記錄消費的物理偏移量(offset)的位置等到下次消費時,他會接着上次位置繼續消費

8.消費者負載均衡策略

一個消費者組中的一個分片對應一個消費者成員,他能保證每個消費者成員都能訪問,如果組中成員太多會有空閑的成員

9數據有序

一個消費者組里它的內部是有序的消費者組與消費者組之間是無序的

10.kafaka 生產數據時數據的分組策略

生產者決定數據產生到集群的哪個 partition 中每一條消息都是以(key,value)格式

Key 是由生產者發送數據傳入

所以生產者(key)決定了數據產生到集群的哪個 partition

 

 

 

源地址為:https://www.jianshu.com/p/0a322b2bba2a


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM