微信公眾號:moon聊技術
關注選擇“ 星標 ”, 重磅干貨,第一 時間送達!
[如果你覺得文章對你有幫助,歡迎關注,在看,點贊,轉發]

大家好,我是moon,最新一篇面試八股文系列 kafka 篇也出爐了,大家還不卷起來嗎?
- 1.什么是消息中間件?
- 2.kafka 是什么?有什么作用?
- 3.kafka 的架構是怎么樣的?
- 4.Kafka Replicas是怎么管理的?
- 5.如何確定當前能讀到哪一條消息?
- 6.生產者發送消息有哪些模式?
- 7.發送消息的分區策略有哪些?
- 8.Kafka 支持讀寫分離嗎?為什么?
- 9.那 Kafka 是怎么去實現負載均衡的?
- 10.Kafka 的負責均衡會有什么問題呢?
- 11.Kafka 的可靠性是怎么保證的?
- 12.Kafka 的消息消費方式有哪些?
- 13.分區再分配是做什么的?解決了什么問題?
- 14.副本 leader 是怎么選舉的?
- 15.分區數越多越好嗎?吞吐量就會越高嗎?
- 16.如何增強消費者的消費能力?
- 17.消費者與 topic 的分區分配策略有哪些?
- 18.kafka 控制器是什么?有什么作用
- 19.kafka 控制器是怎么進行選舉的?
- 20.kafka 為什么這么快?
- 21.什么情況下 kafka 會丟失消息?
1.什么是消息中間件?
消息中間件是基於隊列與消息傳遞技術,在網絡環境中為應用系統提供同步或異步、可靠的消息傳輸的支撐性軟件系統。
消息中間件利用高效可靠的消息傳遞機制進行平台無關的數據交流,並基於數據通信來進行分布式系統的集成。通過提供消息傳遞和消息排隊模型,它可以在分布式環境下擴展進程間的通信。
2.kafka 是什么?有什么作用?
Kafka 是一個分布式的流式處理平台,它以高吞吐、可持久化、可水平擴展、支持流數據處理等多種特性而被廣泛使用

主要功能體現於三點:
-
消息系統:kafka與傳統的消息中間件都具備 系統解耦、冗余存儲、流量削峰、緩沖、異步通信、擴展性、可恢復性等功能。與此同時,kafka還提供了大多數消息系統難以實現的消息順序性保障及回溯性消費的功能。 -
存儲系統:kafka把 消息持久化到磁盤,相比於其他基於內存存儲的系統而言,有效的降低了消息丟失的風險。這得益於其消息持久化和多副本機制。也可以將kafka作為長期的存儲系統來使用,只需要把對應的數據保留策略設置為“永久”或啟用主題日志壓縮功能。 -
流式處理平台:kafka為流行的流式處理框架提供了可靠的數據來源,還提供了一個完整的流式處理框架,比如窗口、連接、變換和聚合等各類操作。
3.kafka 的架構是怎么樣的?

一個典型的 kafka 體系架構包括若干 Producer、若干 Consumer、以及一個 Zookeeper 集群(在2.8.0版本中移,除了 Zookeeper,通過 KRaft 進行自己的集群管理)
Producer 將消息發送到 Broker,Broker 負責將受到的消息存儲到磁盤中,而 Consumer 負責從 Broker 訂閱並消費消息。
Kafka 基本概念:
-
Producer :生產者,負責將消息發送到 Broker -
Consumer :消費者,從 Broker 接收消息 -
Consumer Group :消費者組,由 多個 Consumer 組成。消費者組內每個消費者負責消費不同分區的數據, 一個分區只能由一個組內消費者消費;消費者組之間互不影響。所有的消費者都屬於某個消費者組,即消費者組是邏輯上的一個訂閱者。 -
Broker :可以看做一個獨立的 Kafka 服務節點或 Kafka 服務實例。如果一台服務器上只部署了一個 Kafka 實例,那么我們也可以將 Broker 看做一台 Kafka 服務器。 -
Topic :一個邏輯上的概念,包含很多 Partition, 同一個 Topic 下的 Partiton 的消息內容是不相同的。 -
Partition :為了實現擴展性,一個非常大的 topic 可以分布到多個 broker 上,一個 topic 可以分為多個 partition,每個 partition 是一個有序的隊列。 -
Replica :副本, 同一分區的不同副本保存的是相同的消息,為保證集群中的某個節點發生故障時,該節點上的 partition 數據不丟失,且 kafka 仍然能夠繼續工作,kafka 提供了副本機制,一個 topic 的每個分區都有若干個副本,一個 leader 和若干個 follower。 -
Leader :每個分區的多個副本中的"主副本", 生產者以及消費者只與 Leader 交互。 -
Follower :每個分區的多個副本中的"從副本", 負責實時從 Leader 中同步數據,保持和 Leader 數據的同步。Leader 發生故障時,從 Follower 副本中重新選舉新的 Leader 副本對外提供服務。
4.Kafka Replicas是怎么管理的?

-
AR:分區中的 所有 Replica 統稱為 AR -
ISR:所有與 Leader 副本 保持一定程度同步的Replica(包括 Leader 副本在內)組成 ISR -
OSR:與 Leader 副本 同步滯后過多的 Replica 組成了 OSR
Leader 負責維護和跟蹤 ISR 集合中所有 Follower 副本的滯后狀態,當 Follower 副本落后過多時,就會將其放入 OSR 集合,當 Follower 副本追上了 Leader 的進度時,就會將其放入 ISR 集合。
默認情況下,只有 ISR 中的副本才有資格晉升為 Leader。
5.如何確定當前能讀到哪一條消息?
分區相當於一個日志文件,我們先簡單介紹幾個概念

如上圖是一個分區日志文件
-
標識 共有7條消息,offset (消息偏移量)分別是0~6 -
0 代表這個日志文件的 開始 -
HW(High Watermark) 為4,0~3 代表這個日志文件 可以消費的區間,消費者只能消費到這四條消息 -
LEO 代表即將要寫入消息的偏移量 offset
分區 ISR 集合中的每個副本都會維護自己的 LEO,而 ISR 集合中最小的LEO 即為分區的 HW

如上圖: 三個分區副本都是 ISR集合當中的,最小的 LEO 為 3,就代表分區的 HW 為3,所以當前分區只能消費到 0~2 之間的三條數據,如下圖

6.生產者發送消息有哪些模式?
總共有三種模式
-
1. 發后即忘(fire-and-forget) -
它只管往 Kafka 里面發送消息,但是 不關心消息是否正確到達,這種方式的效率最高,但是可靠性也最差,比如當發生某些不可充實異常的時候會造成消息的丟失
-
-
2. 同步(sync) -
producer.send()返回一個Future對象,調用get()方法變回進行同步等待,就知道消息是否發送成功, 發送一條消息需要等上個消息發送成功后才可以繼續發送
-
-
3. 異步(async) -
Kafka支持 producer.send() 傳入一個回調函數,消息不管成功或者失敗都會調用這個回調函數,這樣就算是異步發送,我們也知道消息的發送情況,然后再回調函數中選擇記錄日志還是重試都取決於調用方
-
7.發送消息的分區策略有哪些?

-
1.輪詢: 依次將消息發送該topic下的所有分區,如果在創建消息的時候 key 為 null,Kafka 默認采用這種策略。 -
2.key 指定分區:在創建消息是 key 不為空,並且使用默認分區器,Kafka 會將 key 進行 hash,然后 根據hash值映射到指定的分區上。這樣的好處是 key 相同的消息會在一個分區下,Kafka 並不能保證全局有序,但是在每個分區下的消息是有序的,按照順序存儲,按照順序消費。在保證同一個 key 的消息是有序的,這樣基本能滿足消息的順序性的需求。但是 如果 partation 數量發生變化,那就很難保證 key 與分區之間的映射關系了。 -
3.自定義策略:實現 Partitioner 接口就能自定義分區策略。 -
4.指定 Partiton 發送
8.Kafka 支持讀寫分離嗎?為什么?
Kafka 是不支持讀寫分離的,那么讀寫分離的好處是什么?主要就是讓一個節點去承擔另一個節點的負載壓力,也就是能做到一定程度的負載均衡,而且 Kafka 不通過讀寫分離也可以一定程度上去實現負載均衡。
但是對於 Kafka 的架構來說,讀寫分離有兩個很大的缺點

-
1.數據不一致的問題:讀寫分離必然涉及到數據的同步,只要是 不同節點之間的數據同步,必然 會有數據不一致的問題存在。 -
2.延時問題:由於 Kafka 獨特的數據處理方式,導致如果將數據從一個節點同步到另一個節點必然會經過 主節點磁盤和從節點磁盤,對一些延時性要求較高的應用來說,並不太適用
9.那 Kafka 是怎么去實現負載均衡的?
Kafka 的負責均衡主要是通過分區來實現的,我們知道 Kafka 是主寫主讀的架構,如下圖:

共三個 broker ,里面各有三個副本,總共有三個 partation, 深色的是 leader,淺色的是 follower,上下灰色分別代表生產者和消費者,虛線代表 follower 從 leader 拉取消息。
我們從這張圖就可以很明顯的看出來,每個 broker 都有消費者拉取消息,每個 broker 也都有生產者發送消息,每個 broker 上的讀寫負載都是一樣的,這也說明了 kafka 獨特的架構方式可以通過主寫主讀來實現負載均衡。
10.Kafka 的負責均衡會有什么問題呢?
kafka的負載均衡在絕對理想的狀況下可以實現,但是會有某些情況出現一定程度上的負載不均衡
-
1. broker 端分配不均:當創建 topic 的時候可能會出現某些 broker 分配到的分區數多,而有些 broker 分配的分區少,這就導致了 leader 多副本不均。 -
2. 生產者寫入消息不均:生產者可能只對某些 broker 中的 leader 副本進行大量的寫入操作,而對其他的 leader 副本不聞不問。 -
3. 消費者消費不均:消費者可能只對某些 broker 中的 leader 副本進行大量的拉取操作,而對其他的 leader 副本不聞不問。 -
4. leader 副本切換不均:當主從副本切換或者分區副本進行了重分配后,可能會導致各個 broker 中的 leader 副本分配不均勻。
11.Kafka 的可靠性是怎么保證的?

1.acks
這個參數用來指定分區中有多少個副本收到這條消息,生產者才認為這條消息是寫入成功的,這個參數有三個值:
-
1.acks = 1,默認為1。生產者發送消息, 只要 leader 副本成功寫入消息,就代表成功。這種方案的問題在於,當返回成功后,如果 leader 副本和 follower 副本還 沒有來得及同步,leader 就崩潰了,那么在選舉后新的 leader 就沒有這條 消息,也就丟失了。 -
2.acks = 0。生產者發送消息后直接算寫入成功,不需要等待響應。這個方案的問題很明顯, 只要服務端寫消息時出現任何問題,都會導致消息丟失。 -
3.acks = -1 或 acks = all。生產者發送消息后,需要等待 ISR 中的所有副本都成功寫入消息后才能收到服務端的響應。毫無疑問這種方案的 可靠性是最高的,但是如果 ISR 中只有leader 副本,那么就和 acks = 1 毫無差別了。
2.消息發送的方式
第6問中我們提到了生產者發送消息有三種方式,發完即忘,同步和異步。我們可以通過同步或者異步獲取響應結果,失敗做重試來保證消息的可靠性。
3.手動提交位移
默認情況下,當消費者消費到消息后,就會自動提交位移。但是如果消費者消費出錯,沒有進入真正的業務處理,那么就可能會導致這條消息消費失敗,從而丟失。我們可以開啟手動提交位移,等待業務正常處理完成后,再提交offset。
4.通過副本 LEO 來確定分區 HW
可參考第五問
12.Kafka 的消息消費方式有哪些?
一般消息消費有兩種模式,推和拉。Kafka的消費是屬於拉模式的,而此模式的消息消費方式有兩種,點對點和發布訂閱。
-
1. 點對點:如果所有消費者屬於同一個消費組,那么所有的消息都會被均勻的投遞給每一個消費者, 每條消息只會被其中一個消費者消費。

-
2. 發布訂閱:如果所有消費者屬於不同的消費組,那么所有的消息都會被投遞給每一個消費者, 每個消費者都會收到該消息。
13.分區再分配是做什么的?解決了什么問題?
分區再分配主要是用來維護 kafka 集群的負載均衡
既然是分區再分配,那么 kafka 分區有什么問題呢?

-
問題1:當集群中的一個節點下線了 -
如果該節點的分區是單副本的,那么分區將會變得不可用 -
如果是多副本的,就會進行 leader 選舉,在其他機器上選舉出新的 leader
-
kafka 並不會將這些失效的分區遷移到其他可用的 broker 上,這樣就會影響集群的負載均衡,甚至也會影響服務的可靠性和可用性

-
問題2:當集群新增 broker 時,只有新的主題分區會分配在該 broker 上,而老的主題分區不會分配在該 broker 上,就造成了 老節點和新節點之間的負載不均衡。
為了解決該問題就出現了分區再分配,它可以在集群擴容,broker 失效的場景下進行分區遷移。
分區再分配的原理就是通化控制器給分區新增新的副本,然后通過網絡把舊的副本數據復制到新的副本上,在復制完成后,將舊副本清除。 當然,為了不影響集群正常的性能,在此復制期間還會有一些列保證性能的操作,比如復制限流。
14.副本 leader 是怎么選舉的?
當分區 leader 節點崩潰時,其中一個 follower 節點會成為新的 leader 節點,這樣會導致集群的負載不均衡,從而影響服務的健壯性和穩定性。
如下:
Topic: test Partation:0 Leader:1 Replicas:1,2,0 Isr:1,2,0
Topic: test Partation:1 Leader:2 Replicas:2,0,1 Isr:2,0,1
Topic: test Partation:2 Leader:0 Replicas:0,1,2 Isr:0,1,2
我們可以看到
-
0 分區有 1 個 leader -
1 分區有 2 個 leader -
2 分區有 0 個 leader
如果此時中間的節點重啟
Topic: test Partation:0 Leader:1 Replicas:1,2,0 Isr:1,0,2
Topic: test Partation:1 Leader:0 Replicas:2,0,1 Isr:0,1,2
Topic: test Partation:2 Leader:0 Replicas:0,1,2 Isr:0,1,2
我們又可以看到:
-
0 分區有 1 個 leader -
1 分區有 0 個 leader -
2 分區有 0 個 leader
我們會發現,原本 1 分區有兩個 ledaer,經過重啟后 leader 都消失了,如此就負載不均衡了。
為了解決這種問題,就引入了優先副本的概念
優先副本就是說在 AR 集合中的第一個副本。比如分區 2 的 AR 為 0,1,2,那么分區 2 的優先副本就為0。理想情況下優先副本就是 leader 副本。優先副本選舉就是促使優先副本成為 leader 副本,從而維護集群的負載均衡。
15.分區數越多越好嗎?吞吐量就會越高嗎?
一般類似於這種問題的答案,都是持否定態度的。
但是可以說,在一定條件下,分區數的數量是和吞吐量成正比的,分區數和性能也是成正比的。
那么為什么說超過了一定限度,就會對性能造成影響呢?原因如下:

1.客戶端/服務器端需要使用的內存就越多
-
服務端在很多組件中都維護了分區級別的緩存,分區數越大, 緩存成本也就越大。 -
消費端的消費線程數是和分區數掛鈎的,分區數越大消費線程數也就越多, 線程的開銷成本也就越大 -
生產者發送消息有緩存的概念,會為每個分區緩存消息,當積累到一定程度或者時間時會將消息發送到分區, 分區越多,這部分的緩存也就越大
2.文件句柄的開銷
每個 partition 都會對應磁盤文件系統的一個目錄。在 Kafka 的數據日志文件目錄中,每個日志數據段都會分配兩個文件,一個索引文件和一個數據文件。每個 broker 會為每個日志段文件打開一個 index 文件句柄和一個數據文件句柄。因此,隨着 partition 的增多,所需要保持打開狀態的文件句柄數也就越多,最終可能超過底層操作系統配置的文件句柄數量限制。
3.越多的分區可能增加端對端的延遲
Kafka 會將分區 HW 之前的消息暴露給消費者。分區越多則副本之間的同步數量就越多,在默認情況下,每個 broker 從其他 broker 節點進行數據副本復制時,該 broker 節點只會為此工作分配一個線程,該線程需要完成該 broker 所有 partition 數據的復制。
4.降低高可用性
在第 13 問我們提到了分區再分配,會將數據復制到另一份副本當中,分區數量越多,那么恢復時間也就越長,而如果發生宕機的 broker 恰好是 controller 節點時:在這種情況下,新 leader 節點的選舉過程在 controller 節點恢復到新的 broker 之前不會啟動。controller 節點的錯誤恢復將會自動地進行,但是新的 controller 節點需要從 zookeeper 中讀取每一個 partition 的元數據信息用於初始化數據。例如,假設一個Kafka 集群存在 10000個partition,從 zookeeper 中恢復元數據時每個 partition 大約花費 2 ms,則 controller 的恢復將會增加約 20 秒的不可用時間窗口。
16.如何增強消費者的消費能力?
-
1.可以考慮增加 topic 的分區數,並且同時提升消費組的消費者數量,消費者數=分區數。 -
2.如果是消費者消費不及時,可以采用多線程的方式進行消費,並且優化業務方法流程,同樣的分區數,為什么人家並發那么高,你的就不行??
17.消費者與 topic 的分區分配策略有哪些?

1.RangeAssignor 分配策略
該分配策略是按照消費者總數和分區總數進行整除運算來獲得一個跨度,然后分區按照跨度來進行平均分配,盡可能保證分區均勻的分配給所有的消費者。
對於每個 topic,該策略會講消費者組內所有訂閱這個主題的消費者按照名稱的字典順序排序,然后為每個消費者划分固定過的區域,如果不夠平均分配,那么字典排序考前的就會多分配一個分區。
比如 2 個消費者屬於一個消費者組,有 2 個 topic t1,t2,每個 topic 都有 3 個分區,p1,p2,p3,那么分配的情況如下:
消費者A:t0-p0,t0-p1,t1-p0,t1-p1,
消費者B:t0-p2,t1-p2
這樣就會出現非配不均勻的情況
2.RoundRobinAssignor 分配策略
該分配策略是按將消費者組內所有消費者及消費者訂閱的所有主題的分區按照字典排序,然后通過輪詢的方式分配給每個消費者。
比如有 3 個消費者 A,B,C,訂閱了 3 個 topic ,t0,t1,t2,每個 topic 各有 3 個分區 p0,p1,p2。 如果 A 訂閱了 t0,B 訂閱了 t0 和 t1,C 訂閱了 t0,t1,t2,那么分配的情況如下:
消費者A:t0-p0
消費者B:t1-p0
消費者C:t1-p1,t2-p0,t2-p1,t2-p2
這樣也會出現分配不均勻的情況,按照訂閱情況來講完全可以吧 t1p1 分配給消費者B
3.StickyAssignor分配策略
這種分配策略有兩個目的
-
1.分區的分配要盡可能的均勻 -
2.分區的分配盡可能的與上次分配的保持相同。
當兩者發生沖突時,第一個目標優先於第二個目標。
假設消費組內有3個消費者:C0、C1、C2
它們都訂閱了4個主題:t0、t1、t2、t3
並且每個主題有2個分區,也就是說整個消費組訂閱了,t0p0、t0p1、t1p0、t1p1、t2p0、t2p1、t3p0、t3p1 這8個分區
最終的分配結果如下:
消費者C0:t0p0、t1p1、t3p0
消費者C1:t0p1、t2p0、t3p1
消費者C2:t1p0、t2p1
這樣初看上去似乎與采用RoundRobinAssignor策略所分配的結果相同
此時假設消費者C1脫離了消費組,那么消費組就會執行再平衡操作,進而消費分區會重新分配。如果采用RoundRobinAssignor策略,那么此時的分配結果如下:
消費者C0:t0p0、t1p0、t2p0、t3p0
消費者C2:t0p1、t1p1、t2p1、t3p1
如分配結果所示,RoundRobinAssignor策略會按照消費者C0和C2進行重新輪詢分配。而如果此時使用的是StickyAssignor策略,那么分配結果為:
消費者C0:t0p0、t1p1、t3p0、t2p0
消費者C2:t1p0、t2p1、t0p1、t3p1
可以看到分配結果中保留了上一次分配中對於消費者C0和C2的所有分配結果,並將原來消費者C1的“負擔”分配給了剩余的兩個消費者C0和C2,最終C0和C2的分配還保持了均衡。
如果發生分區重分配,那么對於同一個分區而言有可能之前的消費者和新指派的消費者不是同一個,對於之前消費者進行到一半的處理還要在新指派的消費者中再次復現一遍,這顯然很浪費系統資源。StickyAssignor策略如同其名稱中的“sticky”一樣,讓分配策略具備一定的“粘性”,盡可能地讓前后兩次分配相同,進而減少系統資源的損耗以及其它異常情況的發生。
到目前為止所分析的都是消費者的訂閱信息都是相同的情況,我們來看一下訂閱信息不同的情況下的處理。
舉例: 同樣消費組內有3個消費者:C0、C1、C2
集群中有3個主題 t0、t1、t2
這3個主題分別有 1、2、3個分區
也就是說集群中有 t0p0、t1p0、t1p1、t2p0、t2p1、t2p2 這6個分區
消費者C0訂閱了主題t0,消費者C1訂閱了主題t0和t1,消費者C2訂閱了主題t0、t1和t2
如果此時采用RoundRobinAssignor策略:
消費者C0:t0p0
消費者C1:t1p0
消費者C2:t1p1、t2p0、t2p1、t2p2
如果此時采用的是StickyAssignor策略:
消費者C0:t0p0
消費者C1:t1p0、t1p1
消費者C2:t2p0、t2p1、t2p2
此時消費者C0脫離了消費組,那么RoundRobinAssignor策略的分配結果為:
消費者C1:t0p0、t1p1
消費者C2:t1p0、t2p0、t2p1、t2p2
StickyAssignor策略,那么分配結果為:
消費者C1:t1p0、t1p1、t0p0
消費者C2:t2p0、t2p1、t2p2
可以看到StickyAssignor策略保留了消費者C1和C2中原有的5個分區的分配:
t1p0、t1p1、t2p0、t2p1、t2p2。
從結果上看StickyAssignor策略比另外兩者分配策略而言顯得更加的優異,這個策略的代碼實現也是異常復雜。
4.自定義分區分配策略
可以通過實現 org.apache.kafka.clients.consumer.internals.PartitionAssignor 接口來實現
18.kafka 控制器是什么?有什么作用
在 Kafka 集群中會有一個或多個 broker,其中有一個 broker 會被選舉為控制器,它負責管理整個集群中所有分區和副本的狀態,kafka 集群中只能有一個控制器。
-
當某個分區的 leader 副本出現故障時,由控制器負責 為該分區選舉新的 leader 副本。 -
當檢測到某個分區的ISR集合發生變化時,由控制器負責 通知所有 broker 更新其元數據信息。 -
當為某個 topic 增加分區數量時,由控制器 負責分區的重新分配。
19.kafka 控制器是怎么進行選舉的?
kafka 中的控制器選舉工作依賴於 Zookeeper,成功競選成為控制器的 broker 會在Zookeeper中創建/controller臨時節點。
每個 broker 啟動的時候會去嘗試讀取/controller 節點的 brokerid的值
-
如果讀取到的 brokerid 的值不為-1,表示已經有其他broker 節點成功競選為控制器,所以當前 broker 就會放棄競選;
如果Zookeeper中不存在/controller 節點,或者這個節點的數據異常,那么就會嘗試去創建/controller 節點,創建成功的那個 broker 就會成為控制器。
每個 broker 都會在內存中保存當前控制器的 brokerid 值,這個值可以標識為 activeControllerId。
Zookeeper 中還有一個與控制器有關的/controller_epoch 節點,這個節點是持久節點,節點中存放的是一個整型的 controller_epoch 值。controller_epoch 值用於記錄控制器發生變更的次數。
controller_epoch 的初始值為1,即集群中的第一個控制器的紀元為1,當控制器發生變更時,每選出一個新的控制器就將該字段值加1。
每個和控制器交互的請求都會攜帶 controller_epoch 這個字段,
-
如果請求的 controller_epoch 值小於 內存中的 controller_epoch值, 則認為這個請求是向已經過期的控制器發送的請求,那么這個請求會 被認定為無效的請求。 -
如果請求的 controller_epoch 值 大於內存中的 controller_epoch值,那么說明 已經有新的控制器當選了
20.kafka 為什么這么快?

-
1.順序讀寫
磁盤分為順序讀寫與隨機讀寫,基於磁盤的隨機讀寫確實很慢,但磁盤的順序讀寫性能卻很高,kafka 這里采用的就是順序讀寫。
-
2.Page Cache
為了優化讀寫性能,Kafka 利用了操作系統本身的 Page Cache,就是利用操作系統自身的內存而不是JVM空間內存。
-
3.零拷貝
Kafka使用了零拷貝技術,也就是直接將數據從內核空間的讀緩沖區直接拷貝到內核空間的 socket 緩沖區,然后再寫入到 NIC 緩沖區,避免了在內核空間和用戶空間之間穿梭。
-
4.分區分段+索引
Kafka 的 message 是按 topic分 類存儲的,topic 中的數據又是按照一個一個的 partition 即分區存儲到不同 broker 節點。每個 partition 對應了操作系統上的一個文件夾,partition 實際上又是按照segment分段存儲的。
通過這種分區分段的設計,Kafka 的 message 消息實際上是分布式存儲在一個一個小的 segment 中的,每次文件操作也是直接操作的 segment。為了進一步的查詢優化,Kafka 又默認為分段后的數據文件建立了索引文件,就是文件系統上的.index文件。這種分區分段+索引的設計,不僅提升了數據讀取的效率,同時也提高了數據操作的並行度。
-
5.批量讀寫
Kafka 數據讀寫也是批量的而不是單條的,這樣可以避免在網絡上頻繁傳輸單個消息帶來的延遲和帶寬開銷。假設網絡帶寬為10MB/S,一次性傳輸10MB的消息比傳輸1KB的消息10000萬次顯然要快得多。
-
6.批量壓縮
Kafka 把所有的消息都變成一個批量的文件,並且進行合理的批量壓縮,減少網絡 IO 損耗,通過 mmap 提高 I/O 速度,寫入數據的時候由於單個Partion是末尾添加所以速度最優;讀取數據的時候配合 sendfile 進行直接讀取。
21.什么情況下 kafka 會丟失消息?
Kafka 有三次消息傳遞的過程: 生產者發消息給 Broker,Broker 同步消息和持久化消息,Broker 將消息傳遞給消費者。

這其中每一步都有可能丟失消息.
-
1.生產者發送數據: 在第 11 問中的 acks中有說到
-
當 acks 為 0, 只要服務端寫消息時出現任何問題,都會導致消息丟失。 -
當 acks 配置為 1 時,生產者發送消息,只要 leader 副本成功寫入消息,就代表成功。這種方案的問題在於,當返回成功后, 如果 leader 副本和 follower 副本還沒有來得及同步,leader 就崩潰了,那么在選舉后新的 leader 就沒有這條消息,也就丟失了。
-
-
2.Broker 存儲數據:kafka 通過 Page Cache 將數據寫入磁盤。
-
Page Cache 就是當往磁盤文件寫入的時候,系統會先將數據流寫入緩存中,但是 什么時候將緩存的數據寫入文件中是由操作系統自行決定。所以 如果此時機器突然掛了,也是會丟失消息的。
-
-
3.消費者消費數據:在開啟自動提交 offset 時,只要消費者消費到消息,那么就會自動提交偏移量,如果業務還沒有來得及處理,那么消息就會丟失。