Kafka 作為一款基于磁盤存儲(chǔ)的高吞吐消息中間件,常作為 log、event 等流式數(shù)據(jù)的通道,在流式計(jì)算領(lǐng)域也有豐富應(yīng)用,下面簡(jiǎn)單分析其高吞吐、高性能的幾點(diǎn)原因
零拷貝
普通的數(shù)據(jù)傳輸一般涉及 read、write 兩個(gè)系統(tǒng)調(diào)用,而 kafka 的 broker 傳遞數(shù)據(jù)給消費(fèi)者使用零拷貝的技術(shù),底層使用了 sendfile 的系統(tǒng)調(diào)用,減少了用戶態(tài)與內(nèi)核態(tài)的上下文切換和數(shù)據(jù)拷貝的次數(shù),read、write 兩次系統(tǒng)調(diào)用涉及 4 次的上下文切換和 4 次的數(shù)據(jù)拷貝才能從一端到另一端,而 sendfile 系統(tǒng)調(diào)用只需要 2 次的上下文切換和 3 次的數(shù)據(jù)拷貝,減少了兩次的上下文切換和一次拷貝動(dòng)作,善用零拷貝可以優(yōu)化基于磁盤的分布式系統(tǒng)的數(shù)據(jù)傳輸-
順序?qū)?+ page cache
普通磁盤的隨機(jī)寫性能較低,順序?qū)懙男阅軇t好很多,kafka 的存儲(chǔ)模型就是一個(gè) FIFO 的隊(duì)列模型,不斷地追加寫文件,直到達(dá)到配置的大小限制(默認(rèn)1GB)后進(jìn)行翻滾,而當(dāng) kafka 的 partition 增多后,每個(gè)磁盤的隨機(jī)寫會(huì)增加,kafka 本身寫入邏輯非常簡(jiǎn)單,使用普通的 java api,所以其完全依賴 linux 系統(tǒng)本身的 page cache,寫到 page cache 后不是立刻寫入磁盤,而要等待系統(tǒng)的 pdflush 線程進(jìn)行刷盤操作,官方文檔描述了 3 點(diǎn)使用 page cache 相對(duì)應(yīng)用層緩存的優(yōu)點(diǎn):- 多次連續(xù)寫入能批量匯聚成一次的物理寫提高吞吐量
- 寫入重排最小化磁頭移動(dòng)的次數(shù),優(yōu)化寫入性能
- 自動(dòng)使用系統(tǒng)的剩余內(nèi)存
分區(qū)(partition)
partiton 是 topic 的子概念,一個(gè) topic 可以分成多個(gè) partition,partition 是 kafka 橫向擴(kuò)展和并行化的基礎(chǔ),每個(gè) partition 都可以并行寫入與讀取,一般會(huì)預(yù)估數(shù)據(jù)的量級(jí),選擇合適的 partition 數(shù)量進(jìn)行 topic 的創(chuàng)建,某種程度上而言,partition 越多意味著讀寫的吞吐量越大,當(dāng)然不是絕對(duì)的,分區(qū)越多對(duì)于磁盤的順序?qū)懹绊懺酱?,更容易產(chǎn)生隨機(jī)寫降低性能。關(guān)于分區(qū)基本上所有分布式(存儲(chǔ)、計(jì)算)系統(tǒng)都有類似抽象,基本都是依托其作為水平擴(kuò)展的基礎(chǔ)reactor 網(wǎng)絡(luò)模型
Kafka 的網(wǎng)絡(luò)層使用 reactor 的線程模型,單個(gè) acceptor 線程負(fù)責(zé)處理所有客戶端的連接,建立連接后將 socket 的輪詢分發(fā)給多個(gè) processor 線程處理讀寫請(qǐng)求,processor 只負(fù)責(zé)數(shù)據(jù)的接收和發(fā)送,其后還有多個(gè) handler 線程進(jìn)行具體的邏輯操作,通過(guò)這樣的異步線程模型,kafka 能夠與成千上萬(wàn)的客戶端交互而毫無(wú)壓力