消息隊列面試題、RabbitMQ面試題、Kafka面試題、RocketMQ面試題 (史上最全、持續更新、吐血推薦)


文章很長,建議收藏起來,慢慢讀! 瘋狂創客圈為小伙伴奉上以下珍貴的學習資源:


推薦: 瘋狂創客圈 高質量 博文

高並發 必讀 的精彩博文
nacos 實戰(史上最全) sentinel (史上最全+入門教程)
Zookeeper 分布式鎖 (圖解+秒懂+史上最全) Webflux(史上最全)
SpringCloud gateway (史上最全) TCP/IP(圖解+秒懂+史上最全)
10分鍾看懂, Java NIO 底層原理 Feign原理 (圖解)
更多精彩博文 ..... 請參見【 瘋狂創客圈 高並發 總目錄

史上最全 Java 面試題 28 專題 總目錄

精心梳理、吐血推薦、史上最強、建議收藏 阿里、京東、美團、頭條.... 隨意挑、橫着走!!!
1.Java算法面試題(史上最強、持續更新、吐血推薦) 2.Java基礎面試題(史上最全、持續更新、吐血推薦)
3.JVM面試題(史上最強、持續更新、吐血推薦) 4、架構設計面試題 (史上最全、持續更新、吐血推薦)
5、Spring面試題 專題 6、SpringMVC面試題 專題
7.SpringBoot - 面試題(史上最強、持續更新) 8、Tomcat面試題 專題部分
9.網絡協議面試題(史上最全、持續更新、吐血推薦) 10、TCP/IP協議(圖解+秒懂+史上最全)
11.JUC並發包與容器 - 面試題(史上最強、持續更新) 12、設計模式面試題 (史上最全、持續更新、吐血推薦)
13.死鎖面試題(史上最強、持續更新) 15.Zookeeper 分布式鎖 (圖解+秒懂+史上最全)
14、Redis 面試題 - 收藏版(史上最強、持續更新) 16、Zookeeper 面試題(史上最強、持續更新)
17、分布式事務面試題 (史上最全、持續更新、吐血推薦) 18、一致性協議 (史上最全)
19、Zab協議 (史上最全) 20、Paxos 圖解 (秒懂)
21、raft 圖解 (秒懂) 26、消息隊列、RabbitMQ、Kafka、RocketMQ面試題 (史上最全、持續更新)
22.Linux面試題(史上最全、持續更新、吐血推薦) 23、Mysql 面試題(史上最強、持續更新)
24、SpringCloud 面試題 - 收藏版(史上最強、持續更新) 25、Netty 面試題 (史上最強、持續更新)
27、內存泄漏 內存溢出(史上最全) 28、JVM 內存溢出 實戰 (史上最全)

史上最全 Java 面試題:消息隊列 篇

MQ基礎

問:為什么使用MQ?MQ的優點

簡答

  • 異步處理 - 相比於傳統的串行、並行方式,提高了系統吞吐量。
  • 應用解耦 - 系統間通過消息通信,不用關心其他系統的處理。
  • 流量削鋒 - 可以通過消息隊列長度控制請求量;可以緩解短時間內的高並發請求。
  • 日志處理 - 解決大量日志傳輸。
  • 消息通訊 - 消息隊列一般都內置了高效的通信機制,因此也可以用在純的消息通訊。比如實現點對點消息隊列,或者聊天室等。

詳答

主要是:解耦、異步、削峰。

解耦: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。

削峰:減少高峰時期對服務器壓力。

問:消息隊列有什么優缺點?RabbitMQ有什么優缺點?

優點上面已經說了,就是在特殊場景下有其對應的好處解耦異步削峰

缺點有以下幾個:

系統可用性降低

本來系統運行好好的,現在你非要加入個消息隊列進去,那消息隊列掛了,你的系統不是呵呵了。因此,系統可用性會降低;

系統復雜度提高

加入了消息隊列,要多考慮很多方面的問題,比如:一致性問題、如何保證消息不被重復消費、如何保證消息可靠性傳輸等。因此,需要考慮的東西更多,復雜性增大。

一致性問題

A 系統處理完了直接返回成功了,人都以為你這個請求就成功了;但是問題是,要是 BCD 三個系統那里,BD 兩個系統寫庫成功了,結果 C 系統寫庫失敗了,咋整?你這數據就不一致了。

所以消息隊列實際是一種非常復雜的架構,你引入它有很多好處,但是也得針對它帶來的壞處做各種額外的技術方案和架構來規避掉,做好之后,你會發現,媽呀,系統復雜度提升了一個數量級,也許是復雜了 10 倍。但是關鍵時刻,用,還是得用的。

問:你們公司生產環境用的是什么消息中間件?

這個首先你可以說下你們公司選用的是什么消息中間件,比如用的是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中間件使用場景中較少采用。

問:Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么優缺點?

ActiveMQ RabbitMQ RocketMQ Kafka ZeroMQ
單機吞吐量 比RabbitMQ低 2.6w/s(消息做持久化) 11.6w/s 17.3w/s 29w/s
開發語言 Java Erlang Java Scala/Java C
主要維護者 Apache Mozilla/Spring Alibaba Apache iMatix,創始人已去世
成熟度 成熟 成熟 開源版本不夠成熟 比較成熟 只有C、PHP等版本成熟
訂閱形式 點對點(p2p)、廣播(發布-訂閱) 提供了4種:direct, topic ,Headers和fanout。fanout就是廣播模式 基於topic/messageTag以及按照消息類型、屬性進行正則匹配的發布訂閱模式 基於topic以及按照topic進行正則匹配的發布訂閱模式 點對點(p2p)
持久化 支持少量堆積 支持少量堆積 支持大量堆積 支持大量堆積 不支持
順序消息 不支持 不支持 支持 支持 不支持
性能穩定性 一般 較差 很好
集群方式 支持簡單集群模式,比如’主-備’,對高級集群模式支持不好。 支持簡單集群,'復制’模式,對高級集群模式支持不好。 常用 多對’Master-Slave’ 模式,開源版本需手動切換Slave變成Master 天然的‘Leader-Slave’無狀態集群,每台服務器既是Master也是Slave 不支持
管理界面 一般 較好 一般

綜上,各種對比之后,有如下建議:

一般的業務系統要引入 MQ,最早大家都用 ActiveMQ,但是現在確實大家用的不多了,沒經過大規模吞吐量場景的驗證,社區也不是很活躍,所以大家還是算了吧,我個人不推薦用這個了;

后來大家開始用 RabbitMQ,但是確實 erlang 語言阻止了大量的 Java 工程師去深入研究和掌控它,對公司而言,幾乎處於不可控的狀態,但是確實人家是開源的,比較穩定的支持,活躍度也高;

不過現在確實越來越多的公司會去用 RocketMQ,確實很不錯,畢竟是阿里出品,但社區可能有突然黃掉的風險(目前 RocketMQ 已捐給 Apache,但 GitHub 上的活躍度其實不算高)對自己公司技術實力有絕對自信的,推薦用 RocketMQ,否則回去老老實實用 RabbitMQ 吧,人家有活躍的開源社區,絕對不會黃。

所以中小型公司,技術實力較為一般,技術挑戰不是特別高,用 RabbitMQ 是不錯的選擇;大型公司,基礎架構研發實力較強,用 RocketMQ 是很好的選擇。

如果是大數據領域的實時計算、日志采集等場景,用 Kafka 是業內標准的,絕對沒問題,社區活躍度很高,絕對不會黃,何況幾乎是全世界這個領域的事實性規范。

問:MQ 有哪些常見問題?如何解決這些問題?

MQ 的常見問題有:

  1. 消息的順序問題
  2. 消息的重復問題

消息的順序問題

消息有序指的是可以按照消息的發送順序來消費。

假如生產者產生了 2 條消息:M1、M2,假定 M1 發送到 S1,M2 發送到 S2,如果要保證 M1 先於 M2 被消費,怎么做?

img

解決方案:

(1)保證生產者 - MQServer - 消費者是一對一對一的關系

img

缺陷:

  • 並行度就會成為消息系統的瓶頸(吞吐量不夠)
  • 更多的異常處理,比如:只要消費端出現問題,就會導致整個處理流程阻塞,我們不得不花費更多的精力來解決阻塞的問題。 (2)通過合理的設計或者將問題分解來規避。
  • 不關注亂序的應用實際大量存在
  • 隊列無序並不意味着消息無序 所以從業務層面來保證消息的順序而不僅僅是依賴於消息系統,是一種更合理的方式。

消息的重復問題

造成消息重復的根本原因是:網絡不可達。

所以解決這個問題的辦法就是繞過這個問題。那么問題就變成了:如果消費端收到兩條一樣的消息,應該怎樣處理?

消費端處理消息的業務邏輯保持冪等性。只要保持冪等性,不管來多少條重復消息,最后處理的結果都一樣。保證每條消息都有唯一編號且保證消息處理成功與去重表的日志同時出現。利用一張日志表來記錄已經處理成功的消息的 ID,如果新到的消息 ID 已經在日志表中,那么就不再處理這條消息。

問:說說設計MQ思路?

比如說這個消息隊列系統,我們從以下幾個角度來考慮一下:

首先這個 mq 得支持可伸縮性吧,就是需要的時候快速擴容,就可以增加吞吐量和容量,那怎么搞?設計個分布式的系統唄,參照一下 kafka 的設計理念,broker -> topic -> partition,每個 partition 放一個機器,就存一部分數據。如果現在資源不夠了,簡單啊,給 topic 增加 partition,然后做數據遷移,增加機器,不就可以存放更多數據,提供更高的吞吐量了?

其次你得考慮一下這個 mq 的數據要不要落地磁盤吧?那肯定要了,落磁盤才能保證別進程掛了數據就丟了。那落磁盤的時候怎么落啊?順序寫,這樣就沒有磁盤隨機讀寫的尋址開銷,磁盤順序讀寫的性能是很高的,這就是 kafka 的思路。

其次你考慮一下你的 mq 的可用性啊?這個事兒,具體參考之前可用性那個環節講解的 kafka 的高可用保障機制。多副本 -> leader & follower -> broker 掛了重新選舉 leader 即可對外服務。

能不能支持數據 0 丟失啊?可以的,參考我們之前說的那個 kafka 數據零丟失方案。

RabbitMQ

問:什么是RabbitMQ?

RabbitMQ是一款開源的,Erlang編寫的,基於AMQP協議的消息中間件

問:rabbitmq 的使用場景

(1)服務間異步通信

(2)順序消費

(3)定時任務

(4)請求削峰

問: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的唯一的線路。

問:RabbitMQ的工作模式

一.simple模式(即最簡單的收發模式)

img

1.消息產生消息,將消息放入隊列

2.消息的消費者(consumer) 監聽 消息隊列,如果隊列中有消息,就消費掉,消息被拿走后,自動從隊列中刪除(隱患 消息可能沒有被消費者正確處理,已經從隊列中消失了,造成消息的丟失,這里可以設置成手動的ack,但如果設置成手動ack,處理完后要及時發送ack消息給隊列,否則會造成內存溢出)。

二.work工作模式(資源的競爭)

img

1.消息產生者將消息放入隊列消費者可以有多個,消費者1,消費者2同時監聽同一個隊列,消息被消費。C1 C2共同爭搶當前的消息隊列內容,誰先拿到誰負責消費消息(隱患:高並發情況下,默認會產生某一個消息被多個消費者共同使用,可以設置一個開關(syncronize) 保證一條消息只能被一個消費者使用)。

三.publish/subscribe發布訂閱(共享資源)

img

1、每個消費者監聽自己的隊列;

2、生產者將消息發給broker,由交換機將消息轉發到綁定此交換機的每個隊列,每個綁定交換機的隊列都將接收到消息。

四.routing路由模式

img

1.消息生產者將消息發送給交換機按照路由判斷,路由是字符串(info) 當前產生的消息攜帶路由字符(對象的方法),交換機根據路由的key,只能匹配上路由key對應的消息隊列,對應的消費者才能消費消息;

2.根據業務功能定義路由字符串

3.從系統的代碼邏輯中獲取對應的功能字符串,將消息任務扔到對應的隊列中。

4.業務場景:error 通知;EXCEPTION;錯誤通知的功能;傳統意義的錯誤通知;客戶通知;利用key路由,可以將程序中的錯誤封裝成消息傳入到消息隊列中,開發者可以自定義消費者,實時接收錯誤;

五.topic 主題模式(路由模式的一種)

img

1.星號井號代表通配符

2.星號代表多個單詞,井號代表一個單詞

3.路由功能添加模糊匹配

4.消息產生者產生消息,把消息交給交換機

5.交換機根據key的規則模糊匹配到對應的隊列,由隊列的監聽消費者接收消息消費

(在我的理解看來就是routing查詢的一種模糊匹配,就類似sql的模糊查詢方式)

問:如何保證RabbitMQ消息的順序性?

拆分多個 queue,每個 queue 一個 consumer,就是多一些 queue 而已,確實是麻煩點;或者就一個 queue 但是對應一個 consumer,然后這個 consumer 內部用內存隊列做排隊,然后分發給底層不同的 worker 來處理。

問:消息如何分發?

若該隊列至少有一個消費者訂閱,消息將以循環(round-robin)的方式發送給消費者。每條消息只會分發給一個訂閱的消費者(前提是消費者能夠正常處理消息並進行確認)。通過路由可實現多消費的功能

問:消息怎么路由?

消息提供方->路由->一至多個隊列消息發布到交換器時,消息將擁有一個路由鍵(routing key),在消息創建時設定。通過隊列路由鍵,可以把隊列綁定到交換器上。消息到達交換器后,RabbitMQ 會將消息的路由鍵與隊列的路由鍵進行匹配(針對不同的交換器有不同的路由規則);

常用的交換器主要分為一下三種:

fanout:如果交換器收到消息,將會廣播到所有綁定的隊列上

direct:如果路由鍵完全匹配,消息就被投遞到相應的隊列

topic:可以使來自不同源頭的消息能夠到達同一個隊列。 使用 topic 交換器時,可以使用通配符

問:消息基於什么傳輸?

由於 TCP 連接的創建和銷毀開銷較大,且並發數受系統資源限制,會造成性能瓶頸。RabbitMQ 使用信道的方式來傳輸數據。信道是建立在真實的 TCP 連接內的虛擬連接,且每條 TCP 連接上的信道數量沒有限制。

問:如何保證消息不被重復消費?或者說,如何保證消息消費時的冪等性?

先說為什么會重復消費:正常情況下,消費者在消費消息的時候,消費完畢后,會發送一個確認消息給消息隊列,消息隊列就知道該消息被消費了,就會將該消息從消息隊列中刪除;

但是因為網絡傳輸等等故障,確認信息沒有傳送到消息隊列,導致消息隊列不知道自己已經消費過該消息了,再次將消息分發給其他的消費者。

針對以上問題,一個解決思路是:保證消息的唯一性,就算是多次傳輸,不要讓消息的多次消費帶來影響;保證消息等冪性;

比如:在寫入消息隊列的數據做唯一標示,消費消息時,根據唯一標識判斷是否消費過;

假設你有個系統,消費一條消息就往數據庫里插入一條數據,要是你一個消息重復兩次,你不就插入了兩條,這數據不就錯了?但是你要是消費到第二次的時候,自己判斷一下是否已經消費過了,若是就直接扔了,這樣不就保留了一條數據,從而保證了數據的正確性。

問:如何確保消息正確地發送至 RabbitMQ? 如何確保消息接收方消費了消息?

發送方確認模式

將信道設置成 confirm 模式(發送方確認模式),則所有在信道上發布的消息都會被指派一個唯一的 ID。

一旦消息被投遞到目的隊列后,或者消息被寫入磁盤后(可持久化的消息),信道會發送一個確認給生產者(包含消息唯一 ID)。

如果 RabbitMQ 發生內部錯誤從而導致消息丟失,會發送一條 nack(notacknowledged,未確認)消息。

發送方確認模式是異步的,生產者應用程序在等待確認的同時,可以繼續發送消息。當確認消息到達生產者應用程序,生產者應用程序的回調方法就會被觸發來處理確認消息。

接收方確認機制

消費者接收每一條消息后都必須進行確認(消息接收和消息確認是兩個不同操作)。只有消費者確認了消息,RabbitMQ 才能安全地把消息從隊列中刪除。

這里並沒有用到超時機制,RabbitMQ 僅通過 Consumer 的連接中斷來確認是否需要重新發送消息。也就是說,只要連接不中斷,RabbitMQ 給了 Consumer 足夠長的時間來處理消息。保證數據的最終一致性;

下面羅列幾種特殊情況

  • 如果消費者接收到消息,在確認之前斷開了連接或取消訂閱,RabbitMQ 會認為消息沒有被分發,然后重新分發給下一個訂閱的消費者。(可能存在消息重復消費的隱患,需要去重)
  • 如果消費者接收到消息卻沒有確認消息,連接也未斷開,則 RabbitMQ 認為該消費者繁忙,將不會給該消費者分發更多的消息。

問:如何保證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信號,生產者會自動重發。

那么如何持久化呢?

這里順便說一下吧,其實也很容易,就下面兩步

  1. 將queue的持久化標識durable設置為true,則代表是一個持久的隊列
  2. 發送消息的時候將deliveryMode=2

這樣設置以后,即使rabbitMQ掛了,重啟后也能恢復數據

消費者丟失消息:消費者丟數據一般是因為采用了自動確認消息模式,改為手動確認消息即可!

消費者在收到消息之后,處理消息之前,會自動回復RabbitMQ已收到消息;

如果這時處理消息失敗,就會丟失該消息;

解決方案:處理消息成功后,手動回復確認消息。

問:為什么不應該對所有的 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)。另外一種處理原則是:僅對關鍵消息作持久化處理(根據業務重要程度),且應該保證關鍵消息的量不會導致性能瓶頸。

問:如何保證高可用的?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 的完整數據。

問:如何解決消息隊列的延時以及過期失效問題?消息隊列滿了以后該怎么處理?有幾百萬消息持續積壓幾小時,說說怎么解決?

消息積壓處理辦法:臨時緊急擴容:

先修復 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 都快寫滿了,咋辦?這個還有別的辦法嗎?沒有,誰讓你第一個方案執行的太慢了,你臨時寫程序,接入數據來消費,消費一個丟棄一個,都不要了,快速消費掉所有的消息。然后走第二個方案,到了晚上再補數據吧。

Kafka

基礎題

問:1、Apache Kafka 是什么?

Apach Kafka 是一款分布式流處理框架,用於實時構建流處理應用。它有一個核心 的功能廣為人知,即作為企業級的消息引擎被廣泛使用。

你一定要先明確它的流處理框架地位,這樣能給面試官留 下一個很專業的印象。

問:2、什么是消費者組?

消費者組是 Kafka 獨有的概念,如果面試官問這 個,就說明他對此是有一定了解的。我先給出標准答案:
1、定義:即消費者組是 Kafka 提供的可擴展且具有容錯性的消費者機制。
2、原理:在 Kafka 中,消費者組是一個由多個消費者實例 構成的組。多個實例共同訂閱若干個主題,實現共同消費。同一個組下的每個實例都配置有 相同的組 ID,被分配不同的訂閱分區。當某個實例掛掉的時候,其他實例會自動地承擔起 它負責消費的分區。

此時,又有一個小技巧給到你:消費者組的題目,能夠幫你在某種程度上掌控下面的面試方
向。

  • 如果你擅長位移值原理,就不妨再提一下消費者組的位移提交機制;
  • 如果你擅長 Kafka Broker,可以提一下消費者組與 Broker 之間的交互;
  • 如果你擅長與消費者組完全不相關的 Producer,那么就可以這么說:“消費者組要消 費的數據完全來自於 Producer 端生產的消息,我對 Producer 還是比較熟悉的。”

問:3、在 Kafka 中,ZooKeeper 的作用是什么?

這是一道能夠幫助你脫穎而出的題目。碰到這個題目,請在心中暗笑三聲。

目前,Kafka 使用 ZooKeeper 存放集群元數據、成員管理、Controller 選舉,以及其他一些管理類任務。之后,等 KIP-500 提案完成后,Kafka 將完全不再依賴 於 ZooKeeper。

記住,一定要突出“目前”,以彰顯你非常了解社區的演進計划。“存放元數據”是指主題 分區的所有數據都保存在 ZooKeeper 中,且以它保存的數據為權威,其他“人”都要與它 保持對齊。“成員管理”是指 Broker 節點的注冊、注銷以及屬性變更,等 等。“Controller 選舉”是指選舉集群 Controller,而其他管理類任務包括但不限於主題 刪除、參數配置等。

不過,拋出 KIP-500 也可能是個雙刃劍。碰到非常資深的面試官,他可能會進一步追問你 KIP-500 是做的。一言以蔽之:KIP-500 思想,是使用社區自研的基於 Raft 的共識算法, 替代 ZooKeeper,實現 Controller 自選舉

問:4、解釋下 Kafka 中位移(offset)的作用

在 Kafka 中,每個 主題分區下的每條消息都被賦予了一個唯一的 ID 數值,用於標識它在分區中的位置。這個 ID 數值,就被稱為位移,或者叫偏移量。一旦消息被寫入到分區日志,它的位移值將不能 被修改。

答完這些之后,你還可以把整個面試方向轉移到你希望的地方。常見方法有以下 3 種:

  1. 如果你深諳 Broker 底層日志寫入的邏輯,可以強調下消息在日志中的存放格式;
  2. 如果你明白位移值一旦被確定不能修改,可以強調下“Log Cleaner 組件都不能影響位 移值”這件事情;
  3. 如果你對消費者的概念還算熟悉,可以再詳細說說位移值和消費者位移值之間的區別。

問:5、闡述下 Kafka 中的領導者副本(Leader Replica)和追隨者副本 (Follower Replica)的區別

這道題表面上是考核你對 Leader 和 Follower 區別的理解,但很容易引申到 Kafka 的同步 機制上。因此,我建議你主動出擊,一次性地把隱含的考點也答出來,也許能夠暫時把面試 官“唬住”,並體現你的專業性。

你可以這么回答:Kafka 副本當前分為領導者副本和追隨者副本。只有 Leader 副本才能 對外提供讀寫服務,響應 Clients 端的請求。Follower 副本只是采用拉(PULL)的方 式,被動地同步 Leader 副本中的數據,並且在 Leader 副本所在的 Broker 宕機后,隨時 准備應聘 Leader 副本。

通常來說,回答到這個程度,其實才只說了 60%,因此,我建議你再回答兩個額外的加分 項。

  • 強調 Follower 副本也能對外提供讀服務。自 Kafka 2.4 版本開始,社區通過引入新的 Broker 端參數,允許 Follower 副本有限度地提供讀服務。
  • 強調 Leader 和 Follower 的消息序列在實際場景中不一致。很多原因都可能造成 Leader 和 Follower 保存的消息序列不一致,比如程序 Bug、網絡問題等。這是很嚴重 的錯誤,必須要完全規避。你可以補充下,之前確保一致性的主要手段是高水位機制, 但高水位值無法保證 Leader 連續變更場景下的數據一致性,因此,社區引入了 Leader Epoch 機制,來修復高水位值的弊端。關於“Leader Epoch 機制”,國內的資料不是 很多,它的普及度遠不如高水位,不妨大膽地把這個概念秀出來,力求驚艷一把。

問:6、如何設置 Kafka 能接收的最大消息的大小?

這道題除了要回答消費者端的參數設置之外,一定要加上 Broker 端的設置,這樣才算完整。畢竟,如果 Producer 都不能向 Broker 端發送數據很大的消息,又何來消費一說呢? 因此,你需要同時設置 Broker 端參數和 Consumer 端參數。

  • Broker 端參數:message.max.bytes、max.message.bytes(主題級別)和 replica.fetch.max.bytes。
  • Consumer 端參數:fetch.message.max.bytes。

Broker 端的最后一個參數比較容易遺漏。我們必須調整 Follower 副本能夠接收的最大消 息的大小,否則,副本同步就會失敗。因此,把這個答出來的話,就是一個加分項。

問:7、監控 Kafka 的框架都有哪些?

面試官其實是在 考察你對監控框架的了解廣度,或者說,你是否知道很多能監控 Kafka 的框架或方法。下 面這些就是 Kafka 發展歷程上比較有名氣的監控系統。

  1. Kafka Manager:應該算是最有名的專屬 Kafka 監控框架了,是獨立的監控系統。
  2. Kafka Monitor:LinkedIn 開源的免費框架,支持對集群進行系統測試,並實時監控測
    試結果。
  3. CruiseControl:也是 LinkedIn 公司開源的監控框架,用於實時監測資源使用率,以及 提供常用運維操作等。無 UI 界面,只提供 REST API。
  4. JMX 監控:由於 Kafka 提供的監控指標都是基於 JMX 的,因此,市面上任何能夠集成 JMX 的框架都可以使用,比如 Zabbix 和 Prometheus。
  5. 已有大數據平台自己的監控體系:像 Cloudera 提供的 CDH 這類大數據平台,天然就提 供 Kafka 監控方案。
  6. JMXTool:社區提供的命令行工具,能夠實時監控 JMX 指標。答上這一條,屬於絕對 的加分項,因為知道的人很少,而且會給人一種你對 Kafka 工具非常熟悉的感覺。如果 你暫時不了解它的用法,可以在命令行以無參數方式執行一下kafka-run-class.sh kafka.tools.JmxTool,學習下它的用法。

問:8、Broker 的 Heap Size 如何設置?

如何設置 Heap Size 的問題,其實和 Kafka 關系不大,它是一類非常通用的面試題目。一 旦你應對不當,面試方向很有可能被引到 JVM 和 GC 上去,那樣的話,你被問住的幾率就 會增大。因此,我建議你簡單地介紹一下 Heap Size 的設置方法,並把重點放在 Kafka Broker 堆大小設置的最佳實踐上。

比如,你可以這樣回復:任何 Java 進程 JVM 堆大小的設置都需要仔細地進行考量和測 試。一個常見的做法是,以默認的初始 JVM 堆大小運行程序,當系統達到穩定狀態后,手動觸發一次 Full GC,然后通過 JVM 工具查看 GC 后的存活對象大小。之后,將堆大小設 置成存活對象總大小的 1.5~2 倍。對於 Kafka 而言,這個方法也是適用的。不過,業界有 個最佳實踐,那就是將 Broker 的 Heap Size 固定為 6GB。經過很多公司的驗證,這個大 小是足夠且良好的。

問:9、如何估算 Kafka 集群的機器數量?

這道題目考查的是機器數量和所用資源之間的關聯關系。所謂資源,也就是 CPU、內存、磁盤和帶寬。

通常來說,CPU 和內存資源的充足是比較容易保證的,因此,你需要從磁盤空間和帶寬占用兩個維度去評估機器數量。

在預估磁盤的占用時,你一定不要忘記計算副本同步的開銷。如果一條消息占用 1KB 的磁 盤空間,那么,在有 3 個副本的主題中,你就需要 3KB 的總空間來保存這條消息。顯式地 將這些考慮因素答出來,能夠彰顯你考慮問題的全面性,是一個難得的加分項。

對於評估帶寬來說,常見的帶寬有 1Gbps 和 10Gbps,但你要切記,這兩個數字僅僅是最大值。因此,你最好和面試官確認一下給定的帶寬是多少。然后,明確闡述出當帶寬占用接 近總帶寬的 90% 時,丟包情形就會發生。這樣能顯示出你的網絡基本功。

問:10、Leader 總是 -1,怎么破?

在生產環境中,你一定碰到過“某個主題分區不能工作了”的情形。使用命令行查看狀態的 話,會發現 Leader 是 -1,於是,你使用各種命令都無濟於事,最后只能用“重啟大 法”。

但是,有沒有什么辦法,可以不重啟集群,就能解決此事呢?這就是此題的由來。

參考答案:刪除 ZooKeeper 節點 /controller,觸發 Controller 重選舉。 Controller 重選舉能夠為所有主題分區重刷分區狀態,可以有效解決因不一致導致的 Leader 不可用問題。我幾乎可以斷定,當面試官問出此題時,要么就是他真的不知道怎么 解決在向你尋求答案,要么他就是在等你說出這個答案。所以,千萬別一上來就說“來個重 啟”之類的話。

提高題

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

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

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

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

Kafka 以集群的方式運行,可以由一個或多個服務組成,每個服務叫做一個 broker.

producers 通過網絡將消息發送到 Kafka 集群,集群向消費者提供消息

問:2.數據傳輸的事務定義有哪三種?

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

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

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

(3)精確的一次(Exactly once): 不會漏傳輸也不會重復傳輸,每個消息都傳輸被一次而

且僅僅被傳輸一次,這是大家所期望的

問:kafka事務。

分享一篇大佬講kafka事務的博客,這一篇講的更深入:http://matt33.com/2018/11/04/kafka-transaction/

同時分享一下這兩篇博文,感覺這篇博文講的更容易理解一些,面試我感覺看這兩篇就夠了:https://www.jianshu.com/p/64c93065473e,https://www.cnblogs.com/middleware/p/9477133.html

Kafka從0.11版本開始引入了事務支持。事務可以保證Kafka在Exactly Once語義的基礎上,生產和消費可以跨分區和會話,要么全部成功,要么全部失敗。

1)Producer事務

為了實現跨分區跨會話的事務,需要引入一個全局唯一的Transaction ID,並將Producer獲得的PID和Transaction ID綁定。這樣當Producer重啟后就可以通過正在進行的Transaction ID獲得原來的PID。

為了管理Transaction,Kafka引入了一個新的組件Transaction Coordinator。Producer就是通過和Transaction Coordinator交互獲得Transaction ID對應的任務狀態。Transaction Coordinator還負責將事務所有寫入Kafka的一個內部Topic,這樣即使整個服務重啟,由於事務狀態得到保存,進行中的事務狀態可以得到恢復,從而繼續進行。

2)Consumer事務

上述事務機制主要是從Producer方面考慮,對於Consumer而言,事務的保證就會相對較弱,尤其時無法保證Commit的信息被精確消費。這是由於Consumer可以通過offset訪問任意信息,而且不同的Segment File生命周期不同,同一事務的消息可能會出現重啟后被刪除的情況。

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

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

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

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

producer 直接將數據發送到 broker 的 leader(主節點),不需要在多個節點進行分發,為了

幫助 producer 做到這點,所有的 Kafka 節點都可以及時的告知:哪些節點是活動的,目標

topic 目標分區的 leader 在哪。這樣 producer 就可以直接將消息發送到目的地了

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

Kafa consumer 消費消息時,向 broker 發出"fetch"請求去消費特定分區的消息,consumer

指定消息在日志中的偏移量(offset),就可以消費從這個位置開始的消息,customer 擁有

了 offset 的控制權,可以向后回滾去重新消費之前的消息,這是很有意義的

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

Kafka 最初考慮的問題是,customer 應該從 brokes 拉取消息還是 brokers 將消息推送到

consumer,也就是 pull 還 push。在這方面,Kafka 遵循了一種大部分消息系統共同的傳統

的設計:producer 將消息推送到 broker,consumer 從 broker 拉取消息

一些消息系統比如 Scribe 和 Apache Flume 采用了 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 阻塞知道新消息到達

(當然也可以阻塞知道消息的數量達到某個特定的量這樣就可以批量Pull)

問:7.Kafka 存儲在硬盤上的消息格式是什么?

消息由一個固定長度的頭部和可變長度的字節數組組成。頭部包含了一個版本號和 CRC32

校驗碼。

消息長度: 4 bytes (value: 1+4+n)

版本號: 1 byte

CRC 校驗碼: 4 bytes

具體的消息: n bytes

問:8.Kafka 高效文件存儲設計特點:

(1).Kafka 把 topic 中一個 parition 大文件分成多個小文件段,通過多個小文件段,就容易定

期清除或刪除已經消費完文件,減少磁盤占用。

(2).通過索引信息可以快速定位 message 和確定 response 的最大大小。

(3).通過 index 元數據全部映射到 memory,可以避免 segment file 的 IO 磁盤操作。

(4).通過索引文件稀疏存儲,可以大幅降低 index 文件元數據占用空間大小。

問:9.Kafka 與傳統消息系統之間有三個關鍵區別

(1).Kafka 持久化日志,這些日志可以被重復讀取和無限期保留

(2).Kafka 是一個分布式系統:它以集群的方式運行,可以靈活伸縮,在內部通過復制數據

提升容錯能力和高可用性

(3).Kafka 支持實時的流式處理

10.Kafka 創建 Topic 時如何將分區放置到不同的 Broker 中

副本因子不能大於 Broker 的個數;

第一個分區(編號為 0)的第一個副本放置位置是隨機從 brokerList 選擇的;

其他分區的第一個副本放置位置相對於第 0 個分區依次往后移。也就是如果我們有 5 個

Broker,5 個分區,假設第一個分區放在第四個 Broker 上,那么第二個分區將會放在第五

個 Broker 上;第三個分區將會放在第一個 Broker 上;第四個分區將會放在第二個

Broker 上,依次類推;

剩余的副本相對於第一個副本放置位置其實是由 nextReplicaShift 決定的,而這個數也是

隨機產生的

問:11.Kafka 新建的分區會在哪個目錄下創建

在啟動 Kafka 集群之前,我們需要配置好 log.dirs 參數,其值是 Kafka 數據的存放目錄,

這個參數可以配置多個目錄,目錄之間使用逗號分隔,通常這些目錄是分布在不同的磁盤

上用於提高讀寫性能。

當然我們也可以配置 log.dir 參數,含義一樣。只需要設置其中一個即可。

如果 log.dirs 參數只配置了一個目錄,那么分配到各個 Broker 上的分區肯定只能在這個

目錄下創建文件夾用於存放數據。

但是如果 log.dirs 參數配置了多個目錄,那么 Kafka 會在哪個文件夾中創建分區目錄呢?

答案是:Kafka 會在含有分區目錄最少的文件夾中創建新的分區目錄,分區目錄名為 Topic

名+分區 ID。注意,是分區文件夾總數最少的目錄,而不是磁盤使用量最少的目錄!也就

是說,如果你給 log.dirs 參數新增了一個新的磁盤,新的分區目錄肯定是先在這個新的磁

盤上創建直到這個新的磁盤目錄擁有的分區目錄不是最少為止。

問:12.partition 的數據如何保存到硬盤

topic 中的多個 partition 以文件夾的形式保存到 broker,每個分區序號從 0 遞增,

且消息有序

Partition 文件下有多個 segment(xxx.index,xxx.log)

segment 文件里的 大小和配置文件大小一致可以根據要求修改 默認為 1g

如果大小大於 1g 時,會滾動一個新的 segment 並且以上一個 segment 最后一條消息的偏移

量命名

問:13.kafka 的 ack 機制

request.required.acks 有三個值 0 1 -1

0:生產者不會等待 broker 的 ack,這個延遲最低但是存儲的保證最弱當 server 掛掉的時候

就會丟數據

1:服務端會等待 ack 值 leader 副本確認接收到消息后發送 ack 但是如果 leader 掛掉后他

不確保是否復制完成新 leader 也會導致數據丟失

-1:同樣在 1 的基礎上 服務端會等所有的 follower 的副本受到數據后才會受到 leader 發出

的 ack,這樣數據不會丟失

問:14.Kafka 的消費者如何消費數據

消費者每次消費數據的時候,消費者都會記錄消費的物理偏移量(offset)的位置

等到下次消費時,他會接着上次位置繼續消費

問:15.消費者負載均衡策略

一個消費者組中的一個分片對應一個消費者成員,他能保證每個消費者成員都能訪問,如

果組中成員太多會有空閑的成員

問:16.數據有序

一個消費者組里它的內部是有序的

消費者組與消費者組之間是無序的

問:17.kafaka 生產數據時數據的分組策略

生產者決定數據產生到集群的哪個 partition 中

每一條消息都是以(key,value)格式

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

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

深度思考題

問:11、LEO、LSO、AR、ISR、HW 都表示什么含義?

  • LEO:Log End Offset。日志末端位移值或末端偏移量,表示日志下一條待插入消息的 位移值。舉個例子,如果日志有 10 條消息,位移值從 0 開始,那么,第 10 條消息的位 移值就是 9。此時,LEO = 10。
  • LSO:Log Stable Offset。這是 Kafka 事務的概念。如果你沒有使用到事務,那么這個 值不存在(其實也不是不存在,只是設置成一個無意義的值)。該值控制了事務型消費 者能夠看到的消息范圍。它經常與 Log Start Offset,即日志起始位移值相混淆,因為 有些人將后者縮寫成 LSO,這是不對的。在 Kafka 中,LSO 就是指代 Log Stable Offset。
  • AR:Assigned Replicas。AR 是主題被創建后,分區創建時被分配的副本集合,副本個 數由副本因子決定。
  • ISR:In-Sync Replicas。Kafka 中特別重要的概念,指代的是 AR 中那些與 Leader 保 持同步的副本集合。在 AR 中的副本可能不在 ISR 中,但 Leader 副本天然就包含在 ISR 中。關於 ISR,還有一個常見的面試題目是如何判斷副本是否應該屬於 ISR。目前的判斷 依據是:Follower 副本的 LEO 落后 Leader LEO 的時間,是否超過了 Broker 端參數 replica.lag.time.max.ms 值。如果超過了,副本就會被從 ISR 中移除。
  • HW:高水位值(High watermark)。這是控制消費者可讀取消息范圍的重要字段。一 個普通消費者只能“看到”Leader 副本上介於 Log Start Offset 和 HW(不含)之間的 所有消息。水位以上的消息是對消費者不可見的。關於 HW,問法有很多,我能想到的 最高級的問法,就是讓你完整地梳理下 Follower 副本拉取 Leader 副本、執行同步機制 的詳細步驟。這就是我們的第 20 道題的題目,一會兒我會給出答案和解析。

問:12、Kafka 能手動刪除消息嗎?

其實,Kafka 不需要用戶手動刪除消息。它本身提供了留存策略,能夠自動刪除過期消息。 當然,它是支持手動刪除消息的。因此,你最好從這兩個維度去回答。

  • 對於設置了 Key 且參數 cleanup.policy=compact 的主題而言,我們可以構造一條 <Key,null> 的消息發送給 Broker,依靠 Log Cleaner 組件提供的功能刪除掉該 Key 的消息。
  • 對於普通主題而言,我們可以使用 kafka-delete-records 命令,或編寫程序調用 Admin.deleteRecords 方法來刪除消息。這兩種方法殊途同歸,底層都是調用 Admin 的 deleteRecords 方法,通過將分區 Log Start Offset 值抬高的方式間接刪除消息。

問:13、__consumer_offsets 是做什么用的?

這是一個內部主題,公開的官網資料很少涉及到。因此,我認為,此題屬於面試官炫技一類 的題目。你要小心這里的考點:該主題有 3 個重要的知識點,你一定要全部答出來,才會顯得對這塊知識非常熟悉。

它是一個內部主題,無需手動干預,由 Kafka 自行管理。當然,我們可以創建該主題。

它的主要作用是負責注冊消費者以及保存位移值。可能你對保存位移值的功能很熟悉, 但其實該主題也是保存消費者元數據的地方。千萬記得把這一點也回答上。另外,這里 的消費者泛指消費者組和獨立消費者,而不僅僅是消費者組。

Kafka 的 GroupCoordinator 組件提供對該主題完整的管理功能,包括該主題的創建、 寫入、讀取和 Leader 維護等。

問:14、分區 Leader 選舉策略有幾種?

分區的 Leader 副本選舉對用戶是完全透明的,它是由 Controller 獨立完成的。你需要回答的是,在哪些場景下,需要執行分區 Leader 選舉。每一種場景對應於一種選舉策略。當前,Kafka 有 4 種分區 Leader 選舉策略。

  • OfflinePartition Leader 選舉:每當有分區上線時,就需要執行 Leader 選舉。所謂的分區上線,可能是創建了新分區,也可能是之前的下線分區重新上線。這是最常見的分區 Leader 選舉場景。
  • ReassignPartition Leader 選舉:當你手動運行 kafka-reassign-partitions 命令,或者是調用 Admin 的 alterPartitionReassignments 方法執行分區副本重分配時,可能觸發此類選舉。假設原來的 AR 是[1,2,3],Leader 是 1,當執行副本重分配后,副本集 合 AR 被設置成[4,5,6],顯然,Leader 必須要變更,此時會發生 Reassign Partition Leader 選舉。
  • PreferredReplicaPartition Leader 選舉:當你手動運行 kafka-preferred-replica- election 命令,或自動觸發了 Preferred Leader 選舉時,該類策略被激活。所謂的 Preferred Leader,指的是 AR 中的第一個副本。比如 AR 是[3,2,1],那么, Preferred Leader 就是 3。
  • ControlledShutdownPartition Leader 選舉:當 Broker 正常關閉時,該 Broker 上 的所有 Leader 副本都會下線,因此,需要為受影響的分區執行相應的 Leader 選舉。

這 4 類選舉策略的大致思想是類似的,即從 AR 中挑選首個在 ISR 中的副本,作為新 Leader。當然,個別策略有些微小差異。不過,回答到這種程度,應該足以應付面試官 了。畢竟,微小差別對選舉 Leader 這件事的影響很小。

問:Kafka中有那些地方需要選舉?這些地方的選舉策略又有哪些?

參考:https://blog.csdn.net/u013256816/article/details/89369160

控制器的選舉

  • Kafka Controller的選舉是依賴Zookeeper來實現的,在Kafka集群中哪個broker能夠成功創建/controller這個臨時(EPHEMERAL)節點他就可以成為Kafka Controller。

分區leader的選舉

消費者相關的選舉

  • 組協調器GroupCoordinator需要為消費組內的消費者選舉出一個消費組的leader,這個選舉的算法也很簡單,分兩種情況分析。如果消費組內還沒有leader,那么第一個加入消費組的消費者即為消費組的leader。如果某一時刻leader消費者由於某些原因退出了消費組,那么會重新選舉一個新的leader。

問:15、Kafka 的哪些場景中使用了零拷貝(Zero Copy)?

Zero Copy 是特別容易被問到的高階題目。在 Kafka 中,體現 Zero Copy 使用場景的地方有兩處:基於 mmap 的索引和日志文件讀寫所用的 TransportLayer

先說第一個。索引都是基於 MappedByteBuffer 的,也就是讓用戶態和內核態共享內核態 的數據緩沖區,此時,數據不需要復制到用戶態空間。不過,mmap 雖然避免了不必要的 拷貝,但不一定就能保證很高的性能。在不同的操作系統下,mmap 的創建和銷毀成本可 能是不一樣的。很高的創建和銷毀開銷會抵消 Zero Copy 帶來的性能優勢。由於這種不確 定性,在 Kafka 中,只有索引應用了 mmap,最核心的日志並未使用 mmap 機制。

再說第二個。TransportLayer 是 Kafka 傳輸層的接口。它的某個實現類使用了 FileChannel 的 transferTo 方法。該方法底層使用 sendfile 實現了 Zero Copy。對 Kafka 而言,如果 I/O 通道使用普通的 PLAINTEXT,那么,Kafka 就可以利用 Zero Copy 特 性,直接將頁緩存中的數據發送到網卡的 Buffer 中,避免中間的多次拷貝。相反,如果 I/O 通道啟用了 SSL,那么,Kafka 便無法利用 Zero Copy 特性了。

問:16、Kafka 為什么不支持讀寫分離?

這道題目考察的是你對 Leader/Follower 模型的思考。

Leader/Follower 模型並沒有規定 Follower 副本不可以對外提供讀服務。很多框架都是允 許這么做的,只是 Kafka 最初為了避免不一致性的問題,而采用了讓 Leader 統一提供服 務的方式。

不過,在開始回答這道題時,你可以率先亮出觀點:自 Kafka 2.4 之后,Kafka 提供了有限度的讀寫分離,也就是說,Follower 副本能夠對外提供讀服務

說完這些之后,你可以再給出之前的版本不支持讀寫分離的理由。

  • 場景不適用。讀寫分離適用於那種讀負載很大,而寫操作相對不頻繁的場景,可 Kafka 不屬於這樣的場景。
  • 同步機制。Kafka 采用 PULL 方式實現 Follower 的同步,因此,Follower 與 Leader 存 在不一致性窗口。如果允許讀 Follower 副本,就勢必要處理消息滯后(Lagging)的問題。

問:17、如何調優 Kafka?

回答任何調優問題的第一步,就是確定優化目標,並且定量給出目標!這點特別重要。對於 Kafka 而言,常見的優化目標是吞吐量、延時、持久性和可用性。每一個方向的優化思路都 是不同的,甚至是相反的。

確定了目標之后,還要明確優化的維度。有些調優屬於通用的優化思路,比如對操作系統、 JVM 等的優化;有些則是有針對性的,比如要優化 Kafka 的 TPS。我們需要從 3 個方向去考慮

  • Producer 端:增加 batch.size、linger.ms,啟用壓縮,關閉重試等。
  • Broker 端:增加 num.replica.fetchers,提升 Follower 同步 TPS,避免 Broker Full GC 等。
  • Consumer:增加 fetch.min.bytes 等

問:18、Controller 發生網絡分區(Network Partitioning)時,Kafka 會怎 么樣?

這道題目能夠誘發我們對分布式系統設計、CAP 理論、一致性等多方面的思考。不過,針 對故障定位和分析的這類問題,我建議你首先言明“實用至上”的觀點,即不論怎么進行理論分析,永遠都要以實際結果為准。一旦發生 Controller 網絡分區,那么,第一要務就是 查看集群是否出現“腦裂”,即同時出現兩個甚至是多個 Controller 組件。這可以根據 Broker 端監控指標 ActiveControllerCount 來判斷。

現在,我們分析下,一旦出現這種情況,Kafka 會怎么樣。

由於 Controller 會給 Broker 發送 3 類請求,即LeaderAndIsrRequest、 StopReplicaRequest 和 UpdateMetadataRequest,因此,一旦出現網絡分區,這些請求將不能順利到達 Broker 端。這將影響主題的創建、修改、刪除操作的信息同步,表現為 集群仿佛僵住了一樣,無法感知到后面的所有操作。因此,網絡分區通常都是非常嚴重的問 題,要趕快修復。

問:19、Java Consumer 為什么采用單線程來獲取消息?

在回答之前,如果先把這句話說出來,一定會加分:Java Consumer 是雙線程的設計。一 個線程是用戶主線程,負責獲取消息;另一個線程是心跳線程,負責向 Kafka 匯報消費者 存活情況。將心跳單獨放入專屬的線程,能夠有效地規避因消息處理速度慢而被視為下線 的“假死”情況。

單線程獲取消息的設計能夠避免阻塞式的消息獲取方式。單線程輪詢方式容易實現異步非阻塞式,這樣便於將消費者擴展成支持實時流處理的操作算子。因為很多實時流處理操作算子都不能是阻塞式的。另外一個可能的好處是,可以簡化代碼的開發。多線程交互的代碼是非常容易出錯的。

問:20、簡述 Follower 副本消息同步的完整流程

首先,Follower 發送 FETCH 請求給 Leader。接着,Leader 會讀取底層日志文件中的消 息數據,再更新它內存中的 Follower 副本的 LEO 值,更新為 FETCH 請求中的 fetchOffset 值。最后,嘗試更新分區高水位值。Follower 接收到 FETCH 響應之后,會把 消息寫入到底層日志,接着更新 LEO 和 HW 值。

Leader 和 Follower 的 HW 值更新時機是不同的,Follower 的 HW 更新永遠落后於 Leader 的 HW。這種時間上的錯配是造成各種不一致的原因。

重點:kafka如何實現高吞吐?

問:1、簡單說說:kafka如何實現高吞吐?

Kafka是分布式消息系統,需要處理海量的消息,Kafka的設計是把所有的消息都寫入速度低容量大的硬盤,以此來換取更強的存儲能力,但實際上,使用硬盤並沒有帶來過多的性能損失。kafka主要使用了以下幾個方式實現了超高的吞吐率:

    • 順序讀寫;

    • 零拷貝

    • 文件分段

    • 批量發送

    • 數據壓縮。

具體來說:

讀寫文件依賴OS文件系統的頁緩存,而不是在JVM內部緩存數據,利用OS來緩存,內存利用率高

sendfile技術(零拷貝),避免了傳統網絡IO四步流程

支持End-to-End的壓縮

順序IO以及常量時間get、put消息

Partition 可以很好的橫向擴展和提供高並發處理

問:2 Kafka如何實現每秒上百萬的超高並發寫入?掌握好面試給你打滿分

Kafka 是高吞吐低延遲的高並發、高性能的消息中間件,在大數據領域有極為廣泛的運用。配置良好的 Kafka 集群甚至可以做到每秒幾十萬、上百萬的超高並發寫入。

頁緩存技術 + 磁盤順序寫

首先 Kafka 每次接收到數據都會往磁盤上去寫,如下圖所示:

加粗樣式

那么在這里我們不禁有一個疑問了,如果把數據基於磁盤來存儲,頻繁的往磁盤文件里寫數據,這個性能會不會很差?大家肯定都覺得磁盤寫性能是極差的。

沒錯,要是真的跟上面那個圖那么簡單的話,那確實這個性能是比較差的。

但是實際上 Kafka 在這里有極為優秀和出色的設計,就是為了保證數據寫入性能,首先 Kafka 是基於操作系統的頁緩存來實現文件寫入的。

操作系統本身有一層緩存,叫做 Page Cache,是在內存里的緩存,我們也可以稱之為 OS Cache,意思就是操作系統自己管理的緩存。

你在寫入磁盤文件的時候,可以直接寫入這個 OS Cache 里,也就是僅僅寫入內存中,接下來由操作系統自己決定什么時候把 OS Cache 里的數據真的刷入磁盤文件中。

僅僅這一個步驟,就可以將磁盤文件寫性能提升很多了,因為其實這里相當於是在寫內存,不是在寫磁盤,大家看下圖:

在這里插入圖片描述

接着另外一個就是 kafka 寫數據的時候,非常關鍵的一點,它是以磁盤順序寫的方式來寫的。

也就是說,僅僅將數據追加到文件的末尾,不是在文件的隨機位置來修改數據。

普通的機械磁盤如果你要是隨機寫的話,確實性能極差,也就是隨便找到文件的某個位置來寫數據。

但是如果你是追加文件末尾按照順序的方式來寫數據的話,那么這種磁盤順序寫的性能基本上可以跟寫內存的性能本身也是差不多的。

所以大家就知道了,上面那個圖里,Kafka 在寫數據的時候,一方面基於 OS 層面的 Page Cache 來寫數據,所以性能很高,本質就是在寫內存罷了。

另外一個,它是采用磁盤順序寫的方式,所以即使數據刷入磁盤的時候,性能也是極高的,也跟寫內存是差不多的。

基於上面兩點,Kafka 就實現了寫入數據的超高性能。那么大家想想,假如說 Kafka 寫入一條數據要耗費 1 毫秒的時間,那么是不是每秒就是可以寫入 1000 條數據?

但是假如 Kafka 的性能極高,寫入一條數據僅僅耗費 0.01 毫秒呢?那么每秒是不是就可以寫入 10 萬條數據?

所以要保證每秒寫入幾萬甚至幾十萬條數據的核心點,就是盡最大可能提升每條數據寫入的性能,這樣就可以在單位時間內寫入更多的數據量,提升吞吐量。

零拷貝技術

說完了寫入這塊,再來談談消費這塊。

大家應該都知道,從 Kafka 里我們經常要消費數據,那么消費的時候實際上就是要從 Kafka 的磁盤文件里讀取某條數據然后發送給下游的消費者,如下圖所示:

在這里插入圖片描述

那么這里如果頻繁的從磁盤讀數據然后發給消費者,性能瓶頸在哪里呢?

假設要是 Kafka 什么優化都不做,就是很簡單的從磁盤讀數據發送給下游的消費者,那么大概過程如下所示:

先看看要讀的數據在不在 OS Cache 里,如果不在的話就從磁盤文件里讀取數據后放入 OS Cache。

接着從操作系統的 OS Cache 里拷貝數據到應用程序進程的緩存里,再從應用程序進程的緩存里拷貝數據到操作系統層面的 Socket 緩存里。

最后從 Socket 緩存里提取數據后發送到網卡,最后發送出去給下游消費。

整個過程,如下圖所示:

在這里插入圖片描述

大家看上圖,很明顯可以看到有兩次沒必要的拷貝吧!一次是從操作系統的 Cache 里拷貝到應用進程的緩存里,接着又從應用程序緩存里拷貝回操作系統的 Socket 緩存里。

而且為了進行這兩次拷貝,中間還發生了好幾次上下文切換,一會兒是應用程序在執行,一會兒上下文切換到操作系統來執行。

所以這種方式來讀取數據是比較消耗性能的。Kafka 為了解決這個問題,在讀數據的時候是引入零拷貝技術。

也就是說,直接讓操作系統的 Cache 中的數據發送到網卡后傳輸給下游的消費者,中間跳過了兩次拷貝數據的步驟,Socket 緩存中僅僅會拷貝一個描述符過去,不會拷貝數據到 Socket 緩存。

大家看下圖,體會一下這個精妙的過程:

在這里插入圖片描述

通過零拷貝技術,就不需要把 OS Cache 里的數據拷貝到應用緩存,再從應用緩存拷貝到 Socket 緩存了,兩次拷貝都省略了,所以叫做零拷貝。

對 Socket 緩存僅僅就是拷貝數據的描述符過去,然后數據就直接從 OS Cache 中發送到網卡上去了,這個過程大大的提升了數據消費時讀取文件數據的性能。

而且大家會注意到,在從磁盤讀數據的時候,會先看看 OS Cache 內存中是否有,如果有的話,其實讀數據都是直接讀內存的。

如果 Kafka 集群經過良好的調優,大家會發現大量的數據都是直接寫入 OS Cache 中,然后讀數據的時候也是從 OS Cache 中讀。

相當於是 Kafka 完全基於內存提供數據的寫和讀了,所以這個整體性能會極其的高。

RocketMQ

問:多個MQ如何選型?

RabbitMQ
erlang開發,對消息堆積的支持並不好,當大量消息積壓的時候,會導致 RabbitMQ 的性能急劇下降。每秒鍾可以處理幾萬到十幾萬條消息。

RocketMQ
java開發,面向互聯網集群化,功能豐富,對在線業務的響應時延做了很多的優化,大多數情況下可以做到毫秒級的響應,每秒鍾大概能處理幾十萬條消息。

Kafka
Scala開發,面向日志,功能豐富,性能最高。當你的業務場景中,每秒鍾消息數量沒有那么多的時候,Kafka 的時延反而會比較高。所以,Kafka 不太適合在線業務場景。

ActiveMQ
java開發,簡單,穩定,性能不如前面三個。不推薦。

基礎題

問:RocketMQ組成部分(角色)有哪些?

Nameserver
無狀態,動態列表;這也是和zookeeper的重要區別之一。zookeeper是有狀態的。

Producer
消息生產者,負責發消息到Broker。

Broker
就是MQ本身,負責收發消息、持久化消息等。

Consumer
消息消費者,負責從Broker上拉取消息進行消費,消費完進行ack。

問:RocketMQ消費模式有幾種?

集群消費

  • 一條消息只會被同Group中的一個Consumer消費
  • 多個Group同時消費一個Topic時,每個Group都會有一個Consumer消費到數據

廣播消費

  • 消息將對一個Consumer Group 下的各個 Consumer 實例都消費一遍。即即使這些 Consumer 屬於同一個Consumer Group ,消息也會被 Consumer Group 中的每個 Consumer 都消費一次。

問:消息重復消費如何解決?

出現原因
正常情況下在consumer真正消費完消息后應該發送ack,通知broker該消息已正常消費,從queue中剔除
當ack因為網絡原因無法發送到broker,broker會認為詞條消息沒有被消費,此后會開啟消息重投機制把消息再次投遞到consumer。

消費模式:在CLUSTERING模式下,消息在broker中會保證相同group的consumer消費一次,但是針對不同group的consumer會推送多次

解決方案

  • 數據庫表:處理消息前,使用消息主鍵在表中帶有約束的字段中insert
  • Map:單機時可以使用map做限制,消費時查詢當前消息id是不是已經存在
  • Redis:使用分布式鎖。

問:RocketMQ如何保證消息的順序消費?

首先多個queue只能保證單個queue里的順序,queue是典型的FIFO,天然順序。多個queue同時消費是無法絕對保證消息的有序性的。
可以使用同一topic,同一個QUEUE,發消息的時候一個線程去發送消息,消費的時候 一個線程去消費一個queue里的消息。

問:RocketMQ如何保證消息不丟失?

Producer端

采取send()同步發消息,發送結果是同步感知的。
發送失敗后可以重試,設置重試次數。默認3次。

Broker端
修改刷盤策略為同步刷盤。默認情況下是異步刷盤的。
集群部署

Consumer端
完全消費正常后在進行手動ack確認

問:RocketMQ 由哪些角色組成?

生產者(Producer):負責產生消息,生產者向消息服務器發送由業務應用程序系統生成的消息。

消費者(Consumer):負責消費消息,消費者從消息服務器拉取信息並將其輸入用戶應用程序。

消息服務器(Broker):是消息存儲中心,主要作用是接收來自 Producer 的消息並存儲, Consumer 從這里取得消息。

名稱服務器(NameServer):用來保存 Broker 相關 Topic 等元信息並給 Producer ,提供 Consumer 查找 Broker 信息。

問:RocketMQ執行流程

1、啟動 Namesrv,Namesrv起 來后監聽端口,等待 Broker、Producer、Consumer 連上來,相當於一個路由控制中心。

2、Broker 啟動,跟所有的 Namesrv 保持長連接,定時發送心跳包。

3、收發消息前,先創建 Topic 。創建 Topic 時,需要指定該 Topic 要存儲在 哪些 Broker上。也可以在發送消息時自動創建Topic。

4、Producer 發送消息。

5、Consumer 消費消息。

問:請說說你對 Producer 的了解?

1、獲得 Topic-Broker 的映射關系。

Producer 啟動時,也需要指定 Namesrv 的地址,從 Namesrv 集群中選一台建立長連接。

生產者每 30 秒從 Namesrv 獲取 Topic 跟 Broker 的映射關系,更新到本地內存中。然后再跟 Topic 涉及的所有 Broker 建立長連接,每隔 30 秒發一次心跳。

2、生產者端的負載均衡。

生產者發送時,會自動輪詢當前所有可發送的broker,一條消息發送成功,下次換另外一個broker發送,以達到消息平均落到所有的broker上。

問:說說你對 Consumer 的了解?

1、獲得 Topic-Broker 的映射關系。

Consumer 啟動時需要指定 Namesrv 地址,與其中一個 Namesrv 建立長連接。消費者每隔 30 秒從 Namesrv 獲取所有Topic 的最新隊列情況,

Consumer 跟 Broker 是長連接,會每隔 30 秒發心跳信息到Broker .

2、消費者端的負載均衡。根據消費者的消費模式不同,負載均衡方式也不同。

問:消費者消費模式有幾種?

消費者消費模式有兩種:集群消費和廣播消費。

  1. 集群消費

消費者的一種消費模式。一個 Consumer Group 中的各個 Consumer 實例分攤去消費消息,即一條消息只會投遞到一個 Consumer Group 下面的一個實例。

  1. 廣播消費

消費者的一種消費模式。消息將對一 個Consumer Group 下的各個 Consumer 實例都投遞一遍。即即使這些 Consumer 屬於同一個Consumer Group ,消息也會被 Consumer Group 中的每個 Consumer 都消費一次。

問:消費者獲取消息有幾種模式?

消費者獲取消息有兩種模式:推送模式和拉取模式。

  1. PushConsumer

推送模式(雖然 RocketMQ 使用的是長輪詢)的消費者。消息的能及時被消費。使用非常簡單,內部已處理如線程池消費、流控、負載均衡、異常處理等等的各種場景。

  1. PullConsumer

拉取模式的消費者。應用主動控制拉取的時機,怎么拉取,怎么消費等。主動權更高。但要自己處理各種場景。

問:什么是定時消息?如何實現?

定時消息,是指消息發到 Broker 后,不能立刻被 Consumer 消費,要到特定的時間點或者等待特定的時間后才能被消費。

提高題

問:RocketMQ如何實現分布式事務?

1、生產者向MQ服務器發送half消息。
2、half消息發送成功后,MQ服務器返回確認消息給生產者。
3、生產者開始執行本地事務。
4、根據本地事務執行的結果(UNKNOWcommitrollback)向MQ Server發送提交或回滾消息。
5、如果錯過了(可能因為網絡異常、生產者突然宕機等導致的異常情況)提交/回滾消息,則MQ服務器將向同一組中的每個生產者發送回查消息以獲取事務狀態。
6、回查生產者本地事物狀態。
7、生產者根據本地事務狀態發送提交/回滾消息。
8、MQ服務器將丟棄回滾的消息,但已提交(進行過二次確認的half消息)的消息將投遞給消費者進行消費。

Half Message:預處理消息,當broker收到此類消息后,會存儲到RMQ_SYS_TRANS_HALF_TOPIC的消息消費隊列中

檢查事務狀態:Broker會開啟一個定時任務,消費RMQ_SYS_TRANS_HALF_TOPIC隊列中的消息,每次執行任務會向消息發送者確認事務執行狀態(提交、回滾、未知),如果是未知,Broker會定時去回調在重新檢查。

超時:如果超過回查次數,默認回滾消息。
也就是他並未真正進入Topic的queue,而是用了臨時queue來放所謂的half message,等提交事務后才會真正的將half message轉移到topic下的queue。

問:RocketMQ的消息堆積如何處理?

1、如果可以添加消費者解決,就添加消費者的數據量
2、如果出現了queue,但是消費者多的情況。可以使用准備一個臨時的topic,同時創建一些queue,在臨時創建一個消費者來把這些消息轉移到topic中,讓消費者消費。


免責聲明!

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



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