Kafka效率、吞吐量為什么這么高?


背景

在公司做的數據同步過程中,大部分是需要使用到Kafka做消息中間件,來實時做同步的,以及最近在做的實時消息推送給數倉,數倉需要准實時拿到數據進行分析,這些都離不開Kafka,但為什么我們第一時間就是想到了Kafka了,這么好用的原因是什么呢?我們就來分析一下吧,我自己也算做一個歸納總結。

優勢1. 順序讀寫

首先要明確一點,Kafka的數據是持久化保存在本地磁盤的,有的人一想?咦?持久化本地磁盤,讀取起來不是很慢的嗎???為什么Kafka還這么的快!問題的原因就在於Kafka是順序讀取磁盤的,我們都知道計算機讀取信息的地方有兩個,一個是內存,另外一個就是本地化磁盤,而讀取的方式又有順序讀取和隨機讀取,這里我總結一下其效率:內存順序讀取 > 磁盤順序讀取 > 內存隨機讀取 > 磁盤隨機讀取,這里就可以知道 他磁盤順序讀取的效率是比內存隨機讀取要高的。至於高多少,具體我本人是沒有親自測試過的,但有些書籍上是寫到二到三個數量級。

磁盤的順序讀寫是磁盤使用模式中最有規律的,並且操作系統也對這種模式做了大量優化,Kafka就是使用了磁盤順序讀寫來提升的性能。Kafka的message是不斷追加到本地磁盤文件末尾的,而不是隨機的寫入,這使得Kafka寫入吞吐量得到了顯著提升 。

這里就會有一個問題,文件的數據是不斷往后添加的,那如果要刪數據呢?嘿, 是不可能刪除數據的,因為Kafka不支持刪數據,它會把所有的數據都保存下來,然后每個消費者(Consumer)對每個Topic都有一個offset用來表示 讀取到了第幾條數據。比如說A消費者訂閱了topic1和topic2 那么,消費者A 就會在topic1和topic2中各有一個offset下標來表明,他消費到了topic1和topic2中的哪一個數據,還有哪些數據是沒有消費到的

這個offset是由客戶端SDK負責保存的,Kafka的Broker完全無視這個東西的存在;一般情況下SDK會把它保存到zookeeper里面。(所以需要給Consumer提供zookeeper的地址)。

當然我們往極限的情況去思考,既然消費者沒有辦法去刪數據,就是跳過數據,那又是磁盤本地化的存儲數據,如果硬盤被存滿了怎么辦?是的,會有這樣的情況,所有Kafka提供了兩種策略去刪除本地化的數據,一個是基於時間的,一個是基於文件大小的。

優勢2. 頁緩存

為了優化讀寫性能,Kafka利用了操作系統本身的Page Cache,就是利用操作系統自身的內存而不是JVM空間內存。這樣做的好處有:

  • 避免Object消耗:如果是使用 Java 堆,Java對象的內存消耗比較大,通常是所存儲數據的兩倍甚至更多。
  • 避免GC問題:隨着JVM中數據不斷增多,垃圾回收將會變得復雜與緩慢,使用系統緩存就不會存在GC問題

相比於使用JVM或in-memory cache等數據結構,利用操作系統的Page Cache更加簡單可靠。首先,操作系統層面的緩存利用率會更高,因為存儲的都是緊湊的字節結構而不是獨立的對象。其次,操作系統本身也對於Page Cache做了大量優化,提供了 write-behind、read-ahead以及flush等多種機制。再者,即使服務進程重啟,系統緩存依然不會消失,避免了in-process cache重建緩存的過程。

通過操作系統的Page Cache,Kafka的讀寫操作基本上是基於內存的,讀寫速度得到了極大的提升。

優勢3. 分區分段+索引

Kafka的message是按topic分類存儲的,topic中的數據又是按照一個一個的partition即分區存儲到不同broker節點。每個partition對應了操作系統上的一個文件夾,partition實際上又是按照segment分段存儲的。這也非常符合分布式系統分區分桶的設計思想。

通過這種分區分段的設計,Kafka的message消息實際上是分布式存儲在一個一個小的segment中的,每次文件操作也是直接操作的segment。為了進一步的查詢優化,Kafka又默認為分段后的數據文件建立了索引文件,就是文件系統上的.index文件。這種分區分段+索引的設計,不僅提升了數據讀取的效率,同時也提高了數據操作的並行度。

優勢4. 批量讀寫

一些Kafka底層設計的說完,就到了上一層,使用的層面,使用的時候,Kafka也是批量進行讀寫的,而非單條單條進行讀寫,這樣進一步的增加了Kafka的吞吐速度。

在向Kafka寫入數據時,可以啟用批次寫入,這樣可以避免在網絡上頻繁傳輸單個消息帶來的延遲和帶寬開銷。假設網絡帶寬為10MB/S,一次性傳輸10MB的消息比傳輸1KB的消息10000萬次顯然要快得多。

優勢5. 批量壓縮

在很多情況下,系統的瓶頸不是CPU或磁盤,而是網絡IO,對於需要在廣域網上的數據中心之間發送消息的數據流水線尤其如此。比如A應用和B應用要數據實時同步,應用A在上海,應用B在深圳,那么這么距離的網絡肯定會收到限制,進行數據壓縮會消耗少量的CPU資源,不過對於kafka而言,網絡IO更應該需要考慮。所以就要進行壓縮需要傳輸的數據。

  1. 如果每個消息都壓縮,Kafka的壓縮率相對是很低,所以Kafka使用了批量壓縮,即將多個消息一起壓縮而不是單個消息壓縮,這里的思想與批量讀寫一致

  2. Kafka允許使用遞歸的消息集合,批量的消息可以通過壓縮的形式傳輸並且在日志中也可以保持壓縮格式,直到被消費者解壓縮

  3. Kafka支持多種壓縮協議,包括Gzip和Snappy壓縮協議

總結

Kafka速度的秘訣在於,它把所有的消息都變成一個批量的文件,並且進行合理的批量壓縮,減少網絡IO損耗,通過mmap提高I/O速度,寫入數據的時候由於單個Partion是末尾添加所以速度最優;讀取數據的時候配合sendfile直接暴力輸出。

參考文獻:Kafka相關書籍以及一些技術公眾號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM