Kafka 面試專題(2020.05整理)

1、Kafka 是什麼

Kafka 是一種高吞吐量、分佈式、基於發佈/訂閱的消息系統,最初由 LinkedIn 公司開發,使用Scala 語言編寫,目前是 Apache 的開源項目。

  1. broker: Kafka 服務器,負責消息存儲和轉發
  2. topic:消息類別, Kafka 按照 topic 來分類消息
  3. partition: topic 的分區,一個 topic 可以包含多個 partition, topic 消息保存在各個partition 上
  4. offset:消息在日誌中的位置,可以理解是消息在 partition 上的偏移量,也是代表該消息的唯一序號
  5. Producer:消息生產者
  6. Consumer:消息消費者
  7. Consumer Group:消費者分組,每個 Consumer 必須屬於一個 group
  8. Zookeeper:保存着集羣 broker、 topic、 partition 等 meta 數據;另外,還負責 broker 故障發現, partition leader 選舉,負載均衡等功能
    在這裏插入圖片描述

2、partition 的數據文件(offset, MessageSize, data)

partition 中的每條 Message 包含了以下三個屬性: offset, MessageSize, data, 其中 offset 表示 Message 在這個 partition 中的偏移量, offset 不是該 Message 在partition 數據文件中的實際存儲位置,而是邏輯上一個值,它唯一確定了 partition 中的一條 Message,可以認爲 offset 是partition 中 Message 的 id; MessageSize 表示消息內容 data 的大小; data 爲 Message 的具體內容。

3、數據文件分段 segment(順序讀寫、分段命令、二分查找)

Kafka 爲每個分段後的數據文件建立了索引文件,文件名與數據文件的名字是一樣的,只是文件擴展名爲.index。 index 文件中並沒有爲數據文件中的每條 Message 建立索引, 而是採用了稀疏存儲的方式,每隔一定字節的數據建立一條索引。這樣避免了索引文件佔用過多的空間,從而可以將索引文件保留在內存中。
在這裏插入圖片描述

4、負載均衡(partition 會均衡分佈到不同 broker 上)

由於消息 topic 由多個 partition 組成, 且 partition 會均衡分佈到不同 broker 上,因此,爲了有效利用 broker 集羣的性能,提高消息的吞吐量, producer 可以通過隨機或者hash 等方式,將消息平均發送到多個 partition 上,以實現負載均衡。
在這裏插入圖片描述

5、批量發送

是提高消息吞吐量重要的方式, Producer 端可以在內存中合併多條消息後, 以一次請求的方式發送了批量的消息給 broker,從而大大減少 broker 存儲消息的 IO 操作次數。但也一定程度上影響了消息的實時性,相當於以時延代價,換取更好的吞吐量。

6、壓縮(GZIP 或 Snappy)

Producer 端可以通過 GZIP 或 Snappy 格式對消息集合進行壓縮。 Producer 端進行壓縮之後,在Consumer 端需進行解壓。壓縮的好處就是減少傳輸的數據量,減輕對網絡傳輸的壓力,在對大數據處理上,瓶頸往往體現在網絡上而不是 CPU(壓縮和解壓會耗掉部分 CPU 資源)。

7、消費者設計

在這裏插入圖片描述

8、Consumer Group

同一 Consumer Group 中的多個 Consumer 實例,不同時消費同一個 partition,等效於隊列模式。 partition 內消息是有序的, Consumer 通過 pull 方式消費消息。 Kafka 不刪除已消費的消息對於 partition,順序讀寫磁盤數據,以時間複雜度 O(1)方式提供消息持久化能力。

9、如何獲取 topic 主題的列表

bin/kafka-topics.sh --list --zookeeper localhost:2181

10、生產者和消費者的命令行是什麼?

生產者在主題上發佈消息:

bin/kafka-console-producer.sh --broker-list 192.168.43.49:9092 --topic 
Hello-Kafa

注意這裏的 IP 是 server.properties 中的 listeners 的配置。接下來每個新行就是輸入一條新消息。消費者接受消息:

bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic 
Hello-Kafka --from-beginning

11、consumer 是推還是拉?

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阻塞知道新消息到達(當然也可以阻塞知道消息的數量達到某個特定的量這樣就可以批量發送)。

12、講講 kafka 維護消費狀態跟蹤的方法

大部分消息系統在 broker 端的維護消息被消費的記錄:一個消息被分發到consumer 後 broker 就馬上進行標記或者等待 customer 的通知後進行標記。這樣也可以在消息在消費後立馬就刪除以減少空間佔用。
但是這樣會不會有什麼問題呢?如果一條消息發送出去之後就立即被標記爲消費過的,一旦 consumer 處理消息時失敗了(比如程序崩潰)消息就丟失了。爲了解決這個問題, 很多消息系統提供了另外一個個功能:當消息被髮送出去之後僅僅被標記爲已發送狀態,當接到 consumer 已經消費成功的通知後才標記爲已被消費的狀態。這雖然解決了消息丟失的問題,但產生了新問題,首先如果 consumer處理消息成功了但是向 broker 發送響應時失敗了,這條消息將被消費兩次。第二個問題時,broker 必須維護每條消息的狀態,並且每次都要先鎖住消息然後更改狀態然後釋放鎖。這樣麻煩又來了,且不說要維護大量的狀態數據,比如如果消息發送出去但沒有收到消費成功的通知,這條消息將一直處於被鎖定的狀態,Kafka 採用了不同的策略。Topic 被分成了若干分區,每個分區在同一時間只被一個 consumer 消費。這意味着每個分區被消費的消息在日誌中的位置僅僅是一個簡單的整數:offset。這樣就很容易標記每個分區消費狀態就很容易了,僅僅需要一個整數而已。這樣消費狀態的跟蹤就很簡單了。這帶來了另外一個好處:consumer 可以把 offset 調成一個較老的值,去重新消費老的消息。這對傳統的消息系統來說看起來有些不可思議,但確實是非常有用的,誰規定了一條消息只能被消費一次呢?

13、講一下主從同步

https://blog.csdn.net/honglei915/article/details/37565289

14、爲什麼需要消息系統,mysql 不能滿足需求嗎?

1.解耦:
允許你獨立的擴展或修改兩邊的處理過程,只要確保它們遵守同樣的接口約束。
2.冗餘:
消息隊列把數據進行持久化直到它們已經被完全處理,通過這一方式規避了數據丟失風險。許多消息隊列所採用的”插入-獲取-刪除”範式中,在把一個消息從隊列中刪除之前,需要你的處理系統明確的指出該消息已經被處理完畢,從而確保你的數據被安全的保存直到你使用完畢。
3.擴展性:
因爲消息隊列解耦了你的處理過程,所以增大消息入隊和處理的頻率是很容易的,只要另外增加處理過程即可。
4.靈活性 & 峯值處理能力:
在訪問量劇增的情況下,應用仍然需要繼續發揮作用,但是這樣的突發流量並不常見。如果爲以能處理這類峯值訪問爲標準來投入資源隨時待命無疑是巨大的浪費。使用消息隊列能夠使關鍵組件頂住突發的訪問壓力,而不會因爲突發的超負荷的請求而完全崩潰。
5.可恢復性:
系統的一部分組件失效時,不會影響到整個系統。消息隊列降低了進程間的耦合度,所以即使一個處理消息的進程掛掉,加入隊列中的消息仍然可以在系統恢復後被處理。
6.順序保證:
在大多使用場景下,數據處理的順序都很重要。大部分消息隊列本來就是排序的,並且能保證數據會按照特定的順序來處理。(Kafka 保證一個 Partition 內的消息的有序性)
7.緩衝:
有助於控制和優化數據流經過系統的速度,解決生產消息和消費消息的處理速度不一致的情況。
8.異步通信:
很多時候,用戶不想也不需要立即處理消息。消息隊列提供了異步處理機制,允許用戶把一個消息放入隊列,但並不立即處理它。想向隊列中放入多少消息就放多少,然後在需要的時候再去處理它們。

15、Zookeeper 對於 Kafka 的作用是什麼?

Zookeeper 是一個開放源碼的、高性能的協調服務,它用於 Kafka 的分佈式應用。Zookeeper 主要用於在集羣中不同節點之間進行通信在 Kafka 中,它被用於提交偏移量,因此如果節點在任何情況下都失敗了,它都可以從之前提交的偏移量中獲取
除此之外,它還執行其他活動,如: leader 檢測、分佈式同步、配置管理、識別新節點何時離開或連接、集羣、節點實時狀態等等。

  • 數據傳輸的事務定義有哪三種? 和 MQTT 的事務定義一樣都是 3 種。
  1. 最多一次: 消息不會被重複發送,最多被傳輸一次,但也有可能一次不傳輸
  2. 最少一次: 消息不會被漏發送,最少被傳輸一次,但也有可能被重複傳輸.
  3. 精確的一次(Exactly once): 不會漏傳輸也不會重複傳輸,每個消息都傳輸被一次而且僅僅被傳輸一次,這是大家所期望的

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

  1. 節點必須可以維護和 ZooKeeper 的連接,Zookeeper 通過心跳機制檢查每個節點的連接
  2. 如果節點是個 follower,他必須能及時的同步 leader 的寫操作,延時不能太久

17、Kafka 與傳統 MQ 消息系統之間有三個關鍵區別

  1. Kafka 持久化日誌,這些日誌可以被重複讀取和無限期保留
  2. Kafka 是一個分佈式系統:它以集羣的方式運行,可以靈活伸縮,在內部通過複製數據提升容錯能力和高可用性
  3. Kafka 支持實時的流式處理

18、講一講 kafka 的 ack 的三種機制

request.required.acks 有三個值 0 1 -1(all)
0:生產者不會等待 broker 的 ack,這個延遲最低但是存儲的保證最弱當 server 掛掉的時候就會丟數據。
1:服務端會等待 ack 值 leader 副本確認接收到消息後發送 ack 但是如果 leader掛掉後他不確保是否複製完成新 leader 也會導致數據丟失。
-1(all):服務端會等所有的 follower 的副本受到數據後纔會受到 leader 發出的ack,這樣數據不會丟失

19、消費者如何不自動提交偏移量,由應用提交?

將 auto.commit.offset 設爲 false,然後在處理一批消息後 commitSync() 或者異步提交 commitAsync()
即:


ConsumerRecords<> records = consumer.poll(); 
	for (ConsumerRecord<> record : records){
		。。。
		tyr{ 
			consumer.commitSync()
		} 。
		。。
	}

20、消費者故障,出現活鎖問題如何解決?

出現 “活鎖 ” 的情 況, 是它 持續 的發 送心 跳, 但是 沒有 處理 。爲 了預 防消 費者 在這種 情況 下一 直持 有分 區,我們 使用 max.poll.interval.ms 活躍 檢測 機制 。 在此基礎上, 如果 你調 用的 poll 的頻 率大 於最 大間 隔, 則客 戶端 將主 動地 離開 組, 以便其 他消 費者 接管 該分 區。 發生 這種 情況 時, 你會 看到 offset 提交 失敗 (調 用
commitSync() 引發 的 CommitFailedException)。 這是 一種 安全 機制 ,保 障只有 活動 成員 能夠 提交 offset。所 以要 留在 組中 ,你 必須 持續 調用 poll。
消費者提供兩個配置設置來控制 poll 循環:
max.poll.interval.ms:增大 poll 的間 隔 ,可以 爲消 費者 提供 更多 的時 間去 處理 返回的 消息(調用 poll(long)返回 的消 息,通常 返回 的消 息都 是一 批)。缺點 是此 值越大 將會 延遲 組重 新平 衡。
max.poll.records:此 設置 限制 每次 調用 poll 返回 的消 息數 ,這 樣可 以更 容易 的預測 每次 poll 間隔 要處 理的 最大 值。通過 調整 此值 ,可以 減少 poll 間隔 ,減少 重新平衡分 組的

對於 消息 處理 時間 不可 預測 地的 情況 ,這些 選項 是不 夠的 。 處理 這種 情況 的推 薦方法 是將 消息 處理 移到 另一 個線 程中 ,讓消 費者 繼續 調用 poll。 但是 必須 注意確保已 提交 的 offset 不超 過實 際位 置。 另外 ,你 必須 禁用 自動 提交 ,並 只有 在線 程完成 處理 後才 爲記 錄手 動提 交偏 移量(取決 於你 )。 還要 注意 ,你需 要 pause 暫停分 區, 不會 從 poll 接收 到新 消息 ,讓 線程 處理 完之 前返 回的 消息 (如 果你 的處理能 力比 拉取 消息 的慢 ,那 創建 新線 程將 導致 你機 器內 存溢 出) 。

21、如何控制消費的位置

kafka 使用 seek(TopicPartition, long)指定新的消費位置。用於查找服務器保留的最早和最新的 offset 的特殊的方法也可用(seekToBeginning(Collection) 和
seekToEnd(Collection))

22、kafka 分佈式(不是單機)的情況下,如何保證消息的順序消費?

Kafka 分佈式的單位是 partition,同一個 partition 用一個 write ahead log 組織,所以可以保證 FIFO 的順序。不同 partition 之間不能保證順序。但是絕大多數用戶都可以通過
message key 來定義,因爲同一個 key 的 Message 可以保證只發送到同一個 partition。
Kafka 中發送 1 條消息的時候,可以指定(topic, partition, key) 3 個參數。partiton 和 key 是可選的。如果你指定了 partition,那就是所有消息發往同 1個 partition,就是有序的。並且在消費端,Kafka 保證,1 個 partition 只能被1 個 consumer 消費。或者你指定 key(比如 order id),具有同 1 個 key 的所有消息,會發往同 1 個 partition。

23、kafka 的高可用機制是什麼?

這個問題比較系統,回答出 kafka 的系統特點,leader 和 follower 的關係,消息讀寫的順序即可。
https://www.cnblogs.com/qingyunzong/p/9004703.html
https://www.tuicool.com/articles/BNRza2E
https://yq.aliyun.com/articles/64703

24、kafka 如何減少數據丟失

https://www.cnblogs.com/huxi2b/p/6056364.html

25、kafka 如何不消費重複數據?比如扣款,我們不能重複的扣。

其實還是得結合業務來思考,我這裏給幾個思路:
比如你拿個數據要寫庫,你先根據主鍵查一下,如果這數據都有了,你就別插入了,update 一下好吧。
比如你是寫 Redis,那沒問題了,反正每次都是 set,天然冪等性。
比如你不是上面兩個場景,那做的稍微複雜一點,你需要讓生產者發送每條數據的時候,裏面加一個全局唯一的 id,類似訂單 id 之類的東西,然後你這裏消費到了之後,先根據這個 id 去比如 Redis 裏查一下,之前消費過嗎?如果沒有消費過,你就處理,然後這個 id 寫 Redis。如果消費過了,那你就別處理了,保證別重複處理相同的消息即可。
比如基於數據庫的唯一鍵來保證重複數據不會重複插入多條。因爲有唯一鍵約束了,重複數據插入只會報錯,不會導致數據庫中出現髒數據

擴展連接:加粗樣式更多請點擊這裏

博主公衆號程序員小羊 只發面試相關推文
在這裏插入圖片描述

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