Kafka高性能原因


概述

  簡單回顧下Kafka消息,Kafka中的消息以主題(Topic)為單位進行分類,主題是一個邏輯上的概念,主題還可以細分為一個或多個分區,一個分區只屬於單個主題,所以也可以把分區稱為主題分區(Topic-Partition)。同一個主題下的不同分區包含的消息是不同的,每個分區還可以有多個副本用於容災備份。分區在存儲層面可以看作一個可追加的日志(Log)文件,消息在被追加到分區日志文件的時候都會分配一個特定的偏移量(offset)。offset是消息在分區中的唯一標識,Kafka通過它來保證消息在分區內的順序性,不過offset並不跨越分區,也就是說,Kafka保證的是分區有序而不是主題有序。下圖表示了主題、分區、副本、日志之間的關系:一個主題包含至少一個分區,一個分區可以有一個或多個副本,每個副本對應一個日志(實際上是個目錄),每個日志里包含多個日志分段(是根據偏移量offset進行分段的),每個日志分段存儲日志文件、索引文件等。
      

  這里還要單獨提一下分區的副本。分區使用多副本機制來提升可靠性,每個分區的副本分為leader副本和follower副本,只有leader副本對外提供讀寫服務,follower副本只負責在內部進行消息同步。如果一個分區的leader副本不可用,Kafka就會從follower副本中選舉出一個新的leader副本。Kafka集群的一個broker最多只能有一個分區的一個副本。leader副本所在的broker節點可以稱為分區的leader節點,follower副本所在的broker節點就稱為分區的follower節點。如果以一個broker上面的擁有不同分區的leader副本太多,就意味着這個leader需要對外承載更大的讀寫請求,所以一般把不同分區的leader副本均勻地分配到Kafka集群的不同broker節點上。
  Kafka高性能的原因就在以下幾個方面:

  • 分區
  • 日志分段存儲
  • 消息順序追加
  • 頁緩存
  • 零拷貝

1. 分區

  生產者往Kafka發送消息時必須指定發往哪個主題,消費者需要訂閱某個主題才能進行消費。一個主題下的分區可以分布在集群的不同broker上面,也就是說,一個主題可以橫跨多個broker。這樣的話,生產者在指定主題(可以指定也可以不指定分區)發送消息的時候,Kafka會將消息分發至不同的分區,如果這些分區不在同一個broker上,就相當於並發的寫入多台broker,性能自然要比寫入單台broker要高。對於消費者,Kafka引入了消費組(Consumer Group)的概念,每個消費者都有一個對應的消費組。一個分區只能被一個消費組中的一個消費者消費,但是可以被不同消費組中的另一個消費者消費。可以在一個消費組里起多個消費者,每個消費者消費一個分區,這樣就提高了消費者的性能。需要注意的是,消費組里的消費者個數如果多於分區數的話,那些多出來的消費者就會處於空閑狀態,所以一個消費組里的消費者個數跟分區數相等就好了。下圖展示了消費者組與分區的關系。
        

  分區的設計使得Kafka消息的讀寫性能可以突破單台broker的I/O性能瓶頸,可以在創建主題的時候指定分區數,也可以在主題創建完成之后去修改分區數,通過增加分區數可以實現水平擴展,但是要注意,分區數也不是越多越好,一般達到某一個閾值之后,再增加分區數性能反而會下降,具體閾值需要對Kafka集群進行壓測才能確定。

2. 日志分段存儲

  為了防止日志(Log)過大,Kafka引入了日志分段(LogSegment)的概念,將日志切分成多個日志分段。在磁盤上,日志是一個目錄,每個日志分段對應於日志目錄下的日志文件、偏移量索引文件、時間戳索引文件(可能還有其他文件)。
  向日志中追加消息是順序寫入的,只有最后一個日志分段才能執行寫入操作,之前所有的日志分段都不能寫入數據。
  為了便於檢索,每個日志分段都有兩個索引文件:偏移量索引文件和時間戳索引文件。每個日志分段都有一個基准偏移量baseOffset,用來表示當前日志分段中第一條消息的offset。偏移量索引文件和時間戳索引文件是以稀疏索引的方式構造的,偏移量索引文件中的偏移量和時間戳索引文件中的時間戳都是嚴格單調遞增的。查詢指定偏移量(或時間戳)時,使用二分查找快速定位到偏移量(或時間戳)的位置。可見Kafka中對消息的查找速度還是非常快的。

3. 消息順序追加

  Kafka是通過文件追加的方式來寫入消息的,只能在日志文件的最后追加新的消息,並且不允許修改已經寫入的消息,這種方式就是順序寫磁盤,而順序寫磁盤的速度是非常快的。

4. 頁緩存

  頁緩存是操作系統實現的一種主要的磁盤緩存,以此用來減少對磁盤I/O的操作。具體來說,就是把磁盤中的數據緩存到內存中,把對磁盤的訪問變為對內存的訪問。
  Kafka中大量使用了頁緩存,消息都是先被寫入頁緩存,再由操作系統負責具體的刷盤任務(Kafka中也提供了同步刷盤和間斷性強制算盤的功能)。

5. 零拷貝

  零拷貝技術是一種避免CPU將數據從一塊存儲拷貝到另一塊存儲的技術。Kafka使用零拷貝技術將數據直接從磁盤復制到網卡設備緩沖區中,而不需要經過應用程序的轉發。
  通常應用程序將磁盤上的數據傳送至網卡需要經過4步:
    1. 調用read(),將數據從磁盤復制到內核模式的緩沖區;
    2. CPU會將數據從內核模式復制到用戶模式下的緩沖區;
    3. 調用write(),將數據從用戶模式下復制到內核模式下的Socket緩沖區;
    4. 將數據從內核模式的Socket緩沖區復制到網卡設備。
  上面的步驟中,第2、3步將數據從內核模式經過用戶模式再繞回內核模式,浪費了兩次復制過程。采用零拷貝技術,Kafka可以直接請求內核把磁盤中的數據復制到Socket緩沖區,而不用再經過用戶模式。

參考文獻

  1. 《深入理解Kafka:核心設計與實踐原理》


免責聲明!

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



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