Kafka 是一個優秀的分佈式消息中間件,許多系統中都會使用到 Kafka 來作消息通訊。對分佈式消息系統的瞭解和使用幾乎成爲一個後臺開發人員必備的技能。今天碼哥字節
就從常見的 Kafka 面試題入手,和你們聊聊 Kafka 的那些事兒。面試
分佈式消息是一種通訊機制,和 RPC、HTTP、RMI 等不同,消息中間件採用分佈式中間代理的方式進行通訊。如圖所示,採用了消息中間件以後,上游業務系統發送消息,先存儲在消息中間件,而後由消息中間件將消息分發到對應的業務模塊應用(分佈式生產者 - 消費者模式)。這種異步的方式,減小了服務之間的耦合程度。shell
定義消息中間件:數據庫
在系統架構中引用額外的組件,必然提升系統的架構複雜度和運維的難度,那麼在系統中使用分佈式消息中間件有什麼優點呢?消息中間件在系統中起的做用又是什麼呢?bootstrap
面試時,面試官常常會關心面試者對開源組件的選型能力,這既能夠考驗面試者知識的廣度,也能夠考驗面試者對某類系統的知識的認識深度,並且也能夠看出面試者對系統總體把握和系統架構設計的能力。開源分佈式消息系統有不少,不一樣的消息系統的特性也不同,選擇怎樣的消息系統,不只須要對各消息系統有必定的瞭解,也須要對自身系統需求有清晰的認識。緩存
下面是常見的幾種分佈式消息系統的對比:安全
Kafka 架構中的通常概念:性能優化
Kafka Topic Partitions Layout服務器
Kafka 將 Topic 進行分區,分區能夠併發讀寫。網絡
Kafka Consumer Offsetsession
Producer、Consumer、Consumer Group、Topic、Partition
Kafka Producer 向 Broker 發送消息使用 Push 模式,Consumer 消費採用的 Pull 模式。拉取模式,讓 consumer 本身管理 offset,能夠提供讀取性能
Consumer group
Topic 級別無序,Partition 有序
不支持,只有 Leader 對外提供讀寫服務
副本,ack,HW
集羣管理,元數據管理
0.11 後支持事務,能夠實現」exactly once「
不能夠,會丟失數據
Kafka 的命令行工具在 Kafka 包的/bin
目錄下,主要包括服務和集羣管理腳本,配置腳本,信息查看腳本,Topic 腳本,客戶端腳本等。
咱們一般可使用kafka-console-consumer.sh
和kafka-console-producer.sh
腳原本測試 Kafka 生產和消費,kafka-consumer-groups.sh
能夠查看和管理集羣中的 Topic,kafka-topics.sh
一般用於查看 Kafka 的消費組狀況。
Kafka producer 的正常生產邏輯包含如下幾個步驟:
Producer 發送消息的過程以下圖所示,須要通過攔截器
,序列化器
和分區器
,最終由累加器
批量發送至 Broker。
Kafka Producer 須要如下必要參數:
常見參數:
batch.num.messages
默認值:200,每次批量消息的數量,只對 asyc 起做用。
request.required.acks
默認值:0,0 表示 producer 毋須等待 leader 的確認,1 表明須要 leader 確認寫入它的本地 log 並當即確認,-1 表明全部的備份都完成後確認。 只對 async 模式起做用,這個參數的調整是數據不丟失和發送效率的 tradeoff,若是對數據丟失不敏感而在意效率的場景能夠考慮設置爲 0,這樣能夠大大提升 producer 發送數據的效率。
request.timeout.ms
默認值:10000,確認超時時間。
partitioner.class
默認值:kafka.producer.DefaultPartitioner,必須實現 kafka.producer.Partitioner,根據 Key 提供一個分區策略。有時候咱們須要相同類型的消息必須順序處理,這樣咱們就必須自定義分配策略,從而將相同類型的數據分配到同一個分區中。
producer.type
默認值:sync,指定消息發送是同步仍是異步。異步 asyc 成批發送用 kafka.producer.AyncProducer, 同步 sync 用 kafka.producer.SyncProducer。同步和異步發送也會影響消息生產的效率。
compression.topic
默認值:none,消息壓縮,默認不壓縮。其他壓縮方式還有,"gzip"、"snappy"和"lz4"。對消息的壓縮能夠極大地減小網絡傳輸量、下降網絡 IO,從而提升總體性能。
compressed.topics
默認值:null,在設置了壓縮的狀況下,能夠指定特定的 topic 壓縮,未指定則所有壓縮。
message.send.max.retries
默認值:3,消息發送最大嘗試次數。
retry.backoff.ms
默認值:300,每次嘗試增長的額外的間隔時間。
topic.metadata.refresh.interval.ms
默認值:600000,按期的獲取元數據的時間。當分區丟失,leader 不可用時 producer 也會主動獲取元數據,若是爲 0,則每次發送完消息就獲取元數據,不推薦。若是爲負值,則只有在失敗的狀況下獲取元數據。
queue.buffering.max.ms
默認值:5000,在 producer queue 的緩存的數據最大時間,僅僅 for asyc。
queue.buffering.max.message
默認值:10000,producer 緩存的消息的最大數量,僅僅 for asyc。
默認值:-1,0 當 queue 滿時丟掉,負值是 queue 滿時 block, 正值是 queue 滿時 block 相應的時間,僅僅 for asyc。
Kafka 有消費組的概念,每一個消費者只能消費所分配到的分區的消息,每個分區只能被一個消費組中的一個消費者所消費,因此同一個消費組中消費者的數量若是超過了分區的數量,將會出現有些消費者分配不到消費的分區。消費組與消費者關係以下圖所示:
Kafka Consumer Client 消費消息一般包含如下步驟:
由於 Kafka 的 Consumer 客戶端是線程不安全的,爲了保證線程安全,並提高消費性能,能夠在 Consumer 端採用相似 Reactor 的線程模型來消費數據。
host:port
格式。key.serializer
對應,key 的反序列化方式。value.serializer
對應,value 的反序列化方式。false
,則須要在程序中手動提交位移。對於精確到一次的語義,最好手動提交位移max.poll.records
條數據須要在在 session.timeout.ms 這個時間內處理完 。默認值爲 500rebalance 本質上是一種協議,規定了一個 consumer group 下的全部 consumer 如何達成一致來分配訂閱 topic 的每一個分區。好比某個 group 下有 20 個 consumer,它訂閱了一個具備 100 個分區的 topic。正常狀況下,Kafka 平均會爲每一個 consumer 分配 5 個分區。這個分配的過程就叫 rebalance。
何時 rebalance?
這也是常常被說起的一個問題。rebalance 的觸發條件有三種:
如何進行組內分區分配?
Kafka 默認提供了兩種分配策略:Range 和 Round-Robin。固然 Kafka 採用了可插拔式的分配策略,你能夠建立本身的分配器以實現不一樣的分配策略。
/bin
目錄,管理 kafka 集羣、管理 topic、生產和消費 kafka在分佈式數據系統中,一般使用分區來提升系統的處理能力,經過副原本保證數據的高可用性。多分區意味着併發處理的能力,這多個副本中,只有一個是 leader,而其餘的都是 follower 副本。僅有 leader 副本能夠對外提供服務。 多個 follower 副本一般存放在和 leader 副本不一樣的 broker 中。經過這樣的機制實現了高可用,當某臺機器掛掉後,其餘 follower 副本也能迅速」轉正「,開始對外提供服務。
爲何 follower 副本不提供讀服務?
這個問題本質上是對性能和一致性的取捨。試想一下,若是 follower 副本也對外提供服務那會怎麼樣呢?首先,性能是確定會有所提高的。但同時,會出現一系列問題。相似數據庫事務中的幻讀,髒讀。 好比你如今寫入一條數據到 kafka 主題 a,消費者 b 從主題 a 消費數據,卻發現消費不到,由於消費者 b 去讀取的那個分區副本中,最新消息還沒寫入。而這個時候,另外一個消費者 c 卻能夠消費到最新那條數據,由於它消費了 leader 副本。Kafka 經過 WH 和 Offset 的管理來決定 Consumer 能夠消費哪些數據,已經當前寫入的數據。
只有 Leader 能夠對外提供讀服務,那如何選舉 Leader
kafka 會將與 leader 副本保持同步的副本放到 ISR 副本集合中。固然,leader 副本是一直存在於 ISR 副本集合中的,在某些特殊狀況下,ISR 副本中甚至只有 leader 一個副本。 當 leader 掛掉時,kakfa 經過 zookeeper 感知到這一狀況,在 ISR 副本中選取新的副本成爲 leader,對外提供服務。 但這樣還有一個問題,前面提到過,有可能 ISR 副本集合中,只有 leader,當 leader 副本掛掉後,ISR 集合就爲空,這時候怎麼辦呢?這時候若是設置 unclean.leader.election.enable 參數爲 true,那麼 kafka 會在非同步,也就是不在 ISR 副本集合中的副本中,選取出副本成爲 leader。
副本的存在就會出現副本同步問題
Kafka 在全部分配的副本 (AR) 中維護一個可用的副本列表 (ISR),Producer 向 Broker 發送消息時會根據ack
配置來肯定須要等待幾個副本已經同步了消息才相應成功,Broker 內部會ReplicaManager
服務來管理 flower 與 leader 之間的數據同步。
一方面,因爲不一樣 Partition 可位於不一樣機器,所以能夠充分利用集羣優點,實現機器間的並行處理。另外一方面,因爲 Partition 在物理上對應一個文件夾,即便多個 Partition 位於同一個節點,也可經過配置讓同一節點上的不一樣 Partition 置於不一樣的 disk drive 上,從而實現磁盤間的並行處理,充分發揮多磁盤的優點。
Kafka 每個 partition 目錄下的文件被平均切割成大小相等(默認一個文件是 500 兆,能夠手動去設置)的數據文件,
每個數據文件都被稱爲一個段(segment file), 每一個 segment 都採用 append 的方式追加數據。
經過副原本保證數據的高可用,producer ack、重試、自動 Leader 選舉,Consumer 自平衡
交付語義通常有
at least once
、at most once
和exactly once
。kafka 經過 ack 的配置來實現前兩種。
實現數據的高可用
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 中移除。
Kafka 中的 HW 表明什麼?
高水位值 (High watermark)。這是控制消費者可讀取消息範圍的重要字段。一 個普通消費者只能「看到」Leader 副本上介於 Log Start Offset 和 HW(不含)之間的 全部消息。水位以上的消息是對消費者不可見的。
partition 併發、順序讀寫磁盤、page cache 壓縮、高性能序列化(二進制)、內存映射 無鎖 offset 管理、Java NIO 模型
本文並無深刻 Kafka 的實現細節和源碼分析,但 Kafka 確實是一個 優秀的開源系統,不少優雅的架構設計和源碼設計都值得咱們學習,十分建議感興趣的同窗更加深刻的去了解一下這個開源系統,對於自身架構設計能力,編碼能力,性能優化都會有很大的幫助。
如下幾篇文章閱讀量與讀者反饋都很好,推薦你們閱讀: