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

前言

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

什麼是中間件?

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

什麼是消息中間件?

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

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

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

消息中間件面試題31道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)。

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 的情況。

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

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 裏找找,說不定就躺在那裏。
消息中間件面試題31道RabbitMQ+ActiveMQ+Kafka

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章