前言:? Kafka雖然是基于磁盤做的數(shù)據(jù)存儲(chǔ),但卻具有高性能、高吞吐、低延時(shí)的特點(diǎn),其吞吐量動(dòng)輒幾萬(wàn)、幾十上百萬(wàn)??偨Y(jié)起來(lái)大致就5個(gè)原因,順序讀寫、零拷貝、分區(qū)、批量發(fā)送、數(shù)據(jù)壓縮。
1、順序讀寫
????眾所周知Kafka是將消息記錄持久化到本地磁盤中的,一般人會(huì)認(rèn)為磁盤讀寫性能差,可能會(huì)對(duì)Kafka性能如何保證提出質(zhì)疑。實(shí)際上不管是內(nèi)存還是磁盤,快或慢關(guān)鍵在于尋址的方式,磁盤分為順序讀寫與隨機(jī)讀寫,內(nèi)存也一樣分為順序讀寫與隨機(jī)讀寫?;诖疟P的隨機(jī)讀寫確實(shí)很慢,但磁盤的順序讀寫性能卻很高,一般而言要高出磁盤隨機(jī)讀寫三個(gè)數(shù)量級(jí),一些情況下磁盤順序讀寫性能甚至要高于內(nèi)存隨機(jī)讀寫。
? ??Kafka的message是不斷追加到本地磁盤文件末尾的,而不是隨機(jī)的寫入,這使得Kafka寫入吞吐量得到了顯著提升。?

? ??這種方法有一個(gè)缺陷—— 沒(méi)有辦法刪除數(shù)據(jù) ,所以Kafka是不會(huì)刪除數(shù)據(jù)的,它會(huì)把所有的數(shù)據(jù)都保留下來(lái),每個(gè)消費(fèi)者(Consumer)對(duì)每個(gè)Topic都有一個(gè)offset用來(lái)表示 讀取到了第幾條數(shù)據(jù) 。
2、零拷貝
????linux操作系統(tǒng) “零拷貝” 機(jī)制使用了sendfile方法, 允許操作系統(tǒng)將數(shù)據(jù)從Page Cache 直接發(fā)送到網(wǎng)絡(luò),只需要最后一步的copy操作將數(shù)據(jù)復(fù)制到 NIC 緩沖區(qū), 這樣避免重新復(fù)制數(shù)據(jù) 。示意圖如下:

? ??通過(guò)這種 “零拷貝” 的機(jī)制,Page Cache 結(jié)合 sendfile 方法,Kafka消費(fèi)端的性能也大幅提升。這也是為什么有時(shí)候消費(fèi)端在不斷消費(fèi)數(shù)據(jù)時(shí),我們并沒(méi)有看到磁盤io比較高,此刻正是操作系統(tǒng)緩存在提供數(shù)據(jù)。
3、分區(qū)
????Kafka的message是按topic分類存儲(chǔ)的,topic中的數(shù)據(jù)又是按照一個(gè)一個(gè)的partition即分區(qū)存儲(chǔ)到不同broker節(jié)點(diǎn)。每個(gè)partition對(duì)應(yīng)了操作系統(tǒng)上的一個(gè)文件夾,partition實(shí)際上又是按照segment分段存儲(chǔ)的。這也非常符合分布式系統(tǒng)分區(qū)分桶的設(shè)計(jì)思想。
? ? 通過(guò)這種分區(qū)分段的設(shè)計(jì),Kafka的message消息實(shí)際上是分布式存儲(chǔ)在一個(gè)一個(gè)小的segment中的,每次文件操作也是直接操作的segment。為了進(jìn)一步的查詢優(yōu)化,Kafka又默認(rèn)為分段后的數(shù)據(jù)文件建立了索引文件,就是文件系統(tǒng)上的.index文件。這種分區(qū)分段+索引的設(shè)計(jì),不僅提升了數(shù)據(jù)讀取的效率,同時(shí)也提高了數(shù)據(jù)操作的并行度。
4、批量讀寫
????Kafka數(shù)據(jù)讀寫也是批量的而不是單條的。
? ? 除了利用底層的技術(shù)外,Kafka還在應(yīng)用程序?qū)用嫣峁┝艘恍┦侄蝸?lái)提升性能。最明顯的就是使用批次。在向Kafka寫入數(shù)據(jù)時(shí),可以啟用批次寫入,這樣可以避免在網(wǎng)絡(luò)上頻繁傳輸單個(gè)消息帶來(lái)的延遲和帶寬開(kāi)銷。假設(shè)網(wǎng)絡(luò)帶寬為10MB/S,一次性傳輸10MB的消息比傳輸1KB的消息10000萬(wàn)次顯然要快得多。
5、批量壓縮
? ???在很多情況下,系統(tǒng)的瓶頸不是CPU或磁盤,而是網(wǎng)絡(luò)IO,對(duì)于需要在廣域網(wǎng)上的數(shù)據(jù)中心之間發(fā)送消息的數(shù)據(jù)流水線尤其如此。進(jìn)行數(shù)據(jù)壓縮會(huì)消耗少量的CPU資源,不過(guò)對(duì)于kafka而言,網(wǎng)絡(luò)IO更應(yīng)該需要考慮。
? ? 1)如果每個(gè)消息都?jí)嚎s,但是壓縮率相對(duì)很低,所以Kafka使用了批量壓縮,即將多個(gè)消息一起壓縮而不是單個(gè)消息壓縮
? ? 2)Kafka允許使用遞歸的消息集合,批量的消息可以通過(guò)壓縮的形式傳輸并且在日志中也可以保持壓縮格式,直到被消費(fèi)者解壓縮
? ? 3)Kafka支持多種壓縮協(xié)議,包括Gzip和Snappy壓縮協(xié)議
總結(jié):Kafka速度的秘訣在于,它把所有的消息都變成一個(gè)批量的文件,并且進(jìn)行合理的批量壓縮,減少網(wǎng)絡(luò)IO損耗,通過(guò)mmap提高I/O速度,寫入數(shù)據(jù)的時(shí)候由于單個(gè)Partion是末尾添加所以速度最優(yōu);讀取數(shù)據(jù)的時(shí)候配合sendfile直接暴力輸出。