Kafka是大數據領域無處不在的消息中間件,目前普遍使用在企業內部的實時數據管道,並幫助企業構建本身的流計算應用程序。Kafka雖然是基於磁盤作的數據存儲,但卻具備高性能、高吞吐、低延時的特色,其吞吐量動輒幾萬、幾十上百萬。可是不少使用過Kafka的人,常常會被問到這樣一個問題,Kafka爲何速度快,吞吐量大;大部分被問的人都是一會兒就懵了,或者是隻知道一些簡單的點,本文就簡單的介紹一下Kafka爲何速度快,吞吐量大。linux
衆所周知Kafka是將消息記錄持久化到本地磁盤中的,通常人會認爲磁盤讀寫性能差,可能會對Kafka性能如何保證提出質疑。實際上不論是內存仍是磁盤,快或慢關鍵在於尋址的方式,磁盤分爲順序讀寫與隨機讀寫,內存也同樣分爲順序讀寫與隨機讀寫。基於磁盤的隨機讀寫確實很慢,但磁盤的順序讀寫性能卻很高,通常而言要高出磁盤隨機讀寫三個數量級,一些狀況下磁盤順序讀寫性能甚至要高於內存隨機讀寫,這裏給出著名學術期刊 ACM Queue 上的一張性能對比圖:
緩存
磁盤的順序讀寫是磁盤使用模式中最有規律的,而且操做系統也對這種模式作了大量優化,Kafka就是使用了磁盤順序讀寫來提高的性能。Kafka的message是不斷追加到本地磁盤文件末尾的,而不是隨機的寫入,這使得Kafka寫入吞吐量獲得了顯著提高 。網絡
爲了優化讀寫性能,Kafka利用了操做系統自己的Page Cache,就是利用操做系統自身的內存而不是JVM空間內存。這樣作的好處有:數據結構
相比於使用JVM或in-memory cache等數據結構,利用操做系統的Page Cache更加簡單可靠。首先,操做系統層面的緩存利用率會更高,由於存儲的都是緊湊的字節結構而不是獨立的對象。其次,操做系統自己也對於Page Cache作了大量優化,提供了 write-behind、read-ahead以及flush等多種機制。再者,即便服務進程重啓,系統緩存依然不會消失,避免了in-process cache重建緩存的過程。socket
經過操做系統的Page Cache,Kafka的讀寫操做基本上是基於內存的,讀寫速度獲得了極大的提高。分佈式
這裏主要講的是Kafka利用 linux 操做系統的 「零拷貝(zero-copy)」 機制在消費端作的優化。首先來了解下數據從文件發送到socket網絡鏈接中的常規傳輸路徑:ide
這個過程包含4次copy操做和2次系統上下文切換,性能其實很是低效。linux操做系統 「零拷貝」 機制使用了sendfile方法, 容許操做系統將數據從Page Cache 直接發送到網絡,只須要最後一步的copy操做將數據複製到 NIC 緩衝區, 這樣避免從新複製數據 。示意圖以下:性能
經過這種 「零拷貝」 的機制,Page Cache 結合 sendfile 方法,Kafka消費端的性能也大幅提高。這也是爲何有時候消費端在不斷消費數據時,咱們並無看到磁盤io比較高,此刻正是操做系統緩存在提供數據。大數據
Kafka的message是按topic分類存儲的,topic中的數據又是按照一個一個的partition即分區存儲到不一樣broker節點。每一個partition對應了操做系統上的一個文件夾,partition實際上又是按照segment分段存儲的。這也很是符合分佈式系統分區分桶的設計思想。優化
經過這種分區分段的設計,Kafka的message消息其實是分佈式存儲在一個一個小的segment中的,每次文件操做也是直接操做的segment。爲了進一步的查詢優化,Kafka又默認爲分段後的數據文件創建了索引文件,就是文件系統上的.index文件。這種分區分段+索引的設計,不只提高了數據讀取的效率,同時也提升了數據操做的並行度。
Kafka採用順序讀寫、Page Cache、零拷貝以及分區分段等這些設計,再加上在索引方面作的優化,另外Kafka數據讀寫也是批量的而不是單條的,使得Kafka具備了高性能、高吞吐、低延時的特色。這樣,Kafka提供大容量的磁盤存儲也變成了一種優勢。