面試官問:Kafka為什么如此之快?
前言
天下武功,唯快不破。同樣的,kafka在消息隊列領(lǐng)域,也是非??斓?,這里的塊指的是kafka在單位時間搬運的數(shù)據(jù)量大小,也就是吞吐量,下圖是搬運網(wǎng)上的一個性能測試結(jié)果,在同步發(fā)送場景下,單機Kafka的吞吐量高達(dá)17.3w/s,不愧是高吞吐量消息中間件的行業(yè)老大。
那究竟是什么原因讓kafka如此之快呢?這也是面試官非常喜歡問的問題。
四個原因
原因一:磁盤順序讀寫
生產(chǎn)者發(fā)送數(shù)據(jù)到kafka集群中,最終會寫入到磁盤中,會采用順序?qū)懭氲姆绞?。消費者從kafka集群中獲取數(shù)據(jù)時,也是采用順序讀的方式。
無論是機械磁盤還是固態(tài)硬盤SSD,順序讀寫的速度都是遠(yuǎn)大于隨機讀寫的。因為對于機械磁盤順序讀寫省去了磁頭頻繁尋址和旋轉(zhuǎn)盤片的開銷。而固態(tài)硬盤就更加復(fù)雜,這里不展開闡述。
下圖是網(wǎng)上關(guān)于讀寫方式的性能比較。
- 機械磁盤順序讀寫 53M/s,隨讀寫 316k/s
- 固態(tài)硬盤順序讀寫 42M/s, 隨機讀寫 1000k/s
因而,由于kafka一般使用機械磁盤存儲消息,因為機械磁盤的價格遠(yuǎn)小于固態(tài)硬盤SSD。
原因二:PageCache頁緩存技術(shù)
前面提到了kafka采用順序讀寫寫入到磁盤中,難道是直接kafka到磁盤嗎,實際上不是的,中間多了一道操作系統(tǒng)的PageCache頁緩存,可以理解為內(nèi)存。
- 當(dāng)kafka有寫操作時,先將數(shù)據(jù)寫入PageCache中,然后在定時方式順序?qū)懭氲酱疟P中。
- 當(dāng)讀操作發(fā)生時,先從PageCache中查找,如果找不到,再去磁盤中讀取。
通過頁緩存技術(shù),更近一步的提高了讀寫的性能。
原因三:零拷貝技術(shù)
kafka之所以快的另外一個原因是采用了零拷貝技術(shù)。
首先我們來看下從磁盤讀取數(shù)據(jù)到網(wǎng)卡場景下,傳統(tǒng)IO的整個過程,如下圖所示:
傳統(tǒng)IO模型下,從磁盤讀取數(shù)據(jù),寫到網(wǎng)卡設(shè)備中,經(jīng)歷了4次用戶態(tài)和內(nèi)核態(tài)之間的切換,以及4次數(shù)據(jù)的拷貝,包括CPU拷貝和DMA拷貝。這些操作都是十分損耗性能。
DMA, Direct Memory Access, 直接內(nèi)存訪問是一些計算機總線架構(gòu)提供的功能,它能使數(shù)據(jù)從附加設(shè)備(如磁盤驅(qū)動器)直接發(fā)送到計算機主板的內(nèi)存上。
那能否減少這樣的切換和拷貝呢?答案是肯定的,不知道大家發(fā)下沒有,kafka的消息在應(yīng)用層做任何轉(zhuǎn)換,怎么存就怎么取,你看連序列化、反序列化都是在生產(chǎn)者和消費者做的。所以kafka采用了sendfile的零拷貝技術(shù)。
sendfile零拷貝技術(shù)在內(nèi)核態(tài)將數(shù)據(jù)從PageCache拷貝到了Socket緩沖區(qū),這樣就大大減少了不同形態(tài)的切換以及拷貝。
所謂的零拷貝技術(shù)不是指不發(fā)生拷貝,而是在用戶態(tài)沒有進(jìn)行拷貝。
原因四:kafka分區(qū)架構(gòu)和批量操作
一方面kafka的集群架構(gòu)采用了多分區(qū)技術(shù),并行度高。另外一方面,kafka采用了批量操作。生產(chǎn)者發(fā)送的消息先發(fā)送到一個隊列,然后有sender線程批量發(fā)送給kafka集群。
如何提高生產(chǎn)者的吞吐量?
kafka生產(chǎn)者提供的一些配置參數(shù)可以有助于提高生產(chǎn)者的吞吐量。
參數(shù)名稱 | 描述 |
buffer.memory | RecordAccumulator 緩沖區(qū)總大小,默認(rèn) 32m。適當(dāng)增加該值,可以提高吞吐量。 |
batch.size | 緩沖區(qū)一批數(shù)據(jù)最大值,默認(rèn) 16k。適當(dāng)增加該值,可以提高吞吐量,但是如果該值設(shè)置太大,會導(dǎo)致數(shù)據(jù)傳輸延遲增加。 |
linger.ms | 如果數(shù)據(jù)遲遲未達(dá)到 batch.size,sender線程等待 linger.time之后就會發(fā)送數(shù)據(jù)。單位 ms,默認(rèn)值是 0ms,表示沒有延遲。生產(chǎn)環(huán)境建議該值大小為 5-100ms 之間。 |
compression.type | 指定消息的壓縮方式,默認(rèn)值為“none ",即默認(rèn)情況下,消息不會被壓縮。該參數(shù)還可以配置為 "gzip","snappy" 和 "lz4"。對消息進(jìn)行壓縮可以極大地減少網(wǎng)絡(luò)傳輸、降低網(wǎng)絡(luò) I/O,從而提高整體的性能 。 |
如何提高消費者的吞吐量?
- 如果是Kafka消費能力不足,則可以考慮增加Topic的分區(qū)數(shù),并且同時提升消費組的消費者數(shù)量,消費者數(shù) = 分區(qū)數(shù),并發(fā)度最高。
- 如果是下游的數(shù)據(jù)處理不及時:提高每批次拉取的數(shù)量。批次拉取數(shù)據(jù)過少,使處理的數(shù)據(jù)小于生產(chǎn)的數(shù)據(jù),也會造成數(shù)據(jù)積壓。
- fetch.max.bytes:默認(rèn) Default: 52428800(50 m)。消費者獲取服務(wù)器端一批消息最大的字節(jié)數(shù)。如果服務(wù)器端一批次的數(shù)據(jù)大于該值(50m)仍然可以拉取回來這批數(shù)據(jù),因此,這不是一個絕、對最大值。一批次的大小受 message.max.bytes (broker config)or max.message.bytes (topic config)影響。
- max.poll.records:一次 poll 拉取數(shù)據(jù)返回消息的最大條數(shù),默認(rèn)是 500 條
- 優(yōu)化消費者代碼處理的邏輯
總結(jié)
本文總結(jié)了Kafka為什么快的原因,4個關(guān)鍵字,磁盤順序讀寫,頁緩存技術(shù),零拷貝技術(shù),Kafka本身分區(qū)機制和批量操作。我們抓住這4個關(guān)鍵字,有點到面地和面試官娓娓道來。
Kafka 在性能上確實是一騎絕塵,但在消息選型過程中,我們不僅僅要參考其性能,還有從功能性上來考慮,例如 RocketMQ 提供了豐富的消息檢索功能、事務(wù)消息、消息消費重試、定時消息等。
通常在大數(shù)據(jù)、流式處理場景基本選用 Kafka,業(yè)務(wù)處理相關(guān)選擇 RocketMQ更佳。