(1)順序讀寫:基於磁盤的隨機讀寫確實很慢,但磁盤的順序讀寫性能卻很高,一些情況下磁盤順序讀寫性能甚至要高於內存隨機讀寫。(Kafka的message是不斷追加到本地磁盤文件末尾的,而不是隨機的寫入,這使得Kafka寫入吞吐量得到了顯著提升 。)
(2)Page Cache:為了優化讀寫性能,kafka利用了操作系統本身的page cache,就是利用操作系統自身的內存而不是JVM空間內存,這樣做的好處是:
1:避免Object消耗:如果是使用java堆,java對象的內存消耗比較大,通常是所存儲數據的兩倍甚至更多。
2:避免GC問題:隨着JVM中數據不斷增多,垃圾回收將會變得復雜與緩慢,使用系統緩存就不會存在GC問題。
通過操作系統的page cache,kafka的讀寫操作基本上是基於內存的,讀寫速度得到了極大的提升。
(3)零拷貝:(不使用的時候,數據在內核空間和用戶空間之間穿梭了兩次),使用零拷貝技術后避免了這種拷貝。通過這種 “零拷貝” 的機制,Page Cache 結合 sendfile 方法,Kafka消費端的性能也大幅提升。這也是為什么有時候消費端在不斷消費數據時,我們並沒有看到磁盤io比較高,此刻正是操作系統緩存在提供數據。
(4)分區分段+索引:topic 中的數據是按照一個一個的partition即分區存儲到不同broker節點的,每個partition對應了操作系統上的一個文件夾,partition實際上又是按照segment分段存儲的,這也非常符合分布式系統分區分桶的設計思想。kafka的message消息實際上是分布式存儲在一個一個segment中的,每次文件操作也是直接操作的segment。為了進一步的查詢優化,kafka又默認為分段后的數據文件建立了索引文件,就是文件系統上的.index文件.這種分區分段+索引的設計,不僅提升了數據讀取的效率,同時也提高了數據處理的並行度。
(5)批量讀寫:Kafka數據讀寫也是批量的而不是單條的。在向Kafka寫入數據時,可以啟用批次寫入,這樣可以避免在網絡上頻繁傳輸單個消息帶來的延遲和帶寬開銷。假設網絡帶寬為10MB/S,一次性傳輸10MB的消息比傳輸1KB的消息10000萬次顯然要快得多。
(6)批量壓縮:
在很多情況下,系統的瓶頸不是CPU或磁盤,而是網絡IO,對於需要在廣域網上的數據中心之間發送消息的數據流水線尤其如此。進行數據壓縮會消耗少量的CPU資源,不過對於kafka而言,網絡IO更應該需要考慮。
- 如果每個消息都壓縮,但是壓縮率相對很低,所以Kafka使用了批量壓縮,即將多個消息一起壓縮而不是單個消息壓縮
- Kafka允許使用遞歸的消息集合,批量的消息可以通過壓縮的形式傳輸並且在日志中也可以保持壓縮格式,直到被消費者解壓縮
- Kafka支持多種壓縮協議,包括Gzip和Snappy壓縮協議
Kafka速度的秘訣在於,它把所有的消息都變成一個批量的文件,並且進行合理的批量壓縮,減少網絡IO損耗,通過mmap提高I/O速度,寫入數據的時候由於單個Partion是末尾添加所以速度最優;讀取數據的時候配合sendfile直接暴力輸出。