必知必會 - 使用kafka之前要掌握的知識

  • 2019 年 10 月 4 日
  • 筆記

前記

消息隊列是分散式系統架構中不可或缺的基礎組件,它主要負責服務間的消息通訊和數據傳輸。市面上有很多的開源消息隊列服務可以選擇,除了kafka,還有Activemq,Rocketmq等。對於要選擇哪一個服務需要根據的實際情況來定,今天主要介紹kafka。

kafka特性

大多數消息隊列服務的主要功能都是大同小異,都能完成基本的消息傳輸和保障機制,只是在具體的實現細節上會有所不同。而kafka也是有它獨特的特性,主要體現在如下幾個方面:

  • 文件存儲消息日誌
  • 支援高並發和大吞吐量
  • 支援消息持久化
  • 可以重複消費消息

除了這些之外的還有通用消息隊列服務的標配。比如:

  • 支援隊列和訂閱2種消息傳輸方式
  • 支援集群部署
  • 支援多機備份

kafka實現

相比於其它的消息隊列服務在記憶體中存儲消息而言,kafka最大的特點就是使用文件存儲消息日誌。並且這也沒有導致kafka的讀取性能和整體的吞吐量。 而之所以能達到這樣的效果,還要取決於它的設計原理,即保證了高速讀寫(read before|write behind),又保證了並發效率。

順序寫

kafka之所以能高速寫,是因為利用了磁碟的順序寫的特性。經測試發現磁碟的順序寫甚至比記憶體的隨機讀還要快很多,因此kafka在寫文件時會批量的寫入,並且追加到一個文件中。

高速讀

高速讀除了因為連續讀取,作業系統會有預讀的機制之外,還體現在它的文件結構的設計。kafka把消息按topic分類,topic又可以按分區讀寫,分區再按索引文件分割存取。

這樣當我們知道了topic、分區、offset之後,就可以通過O(1)的方式找到目標消息所在的位置。

概念介紹

kafka中有幾個重要的概念:

  • Topic
  • partition
  • Consumer Group
  • offset

Topic:定義一個消息分類,相關的生產者和消費者通過特定的Topic來進行聯通。

partition:Topic下的子概念,一個Topic通常可以分為1或多個partition,該Topic中的消息會分發到不同的partition中,也可以在程式碼中指定特定的partition。

Consumer Group:消費者組,它的作用的限定一組消費者,同組內的消費者在消費時是一種互斥模式;即同一個組內只有一個消費者可以消費到某個特定的消息。

offset:Topic中記錄某條消息位置的偏移量資訊,通常offset是消費者讀取消息的依據。

分區和分組

分區即一個Topic設置了多個partition(默認是1個),分區有如下的優勢:

  • 支援分散式
  • 支援負載並發請求
  • 支援容災備份
  • 保證分區內的消費順序

分組即把相關聯的消費者放在一個組內(kafka對每個消費者會分配一個默認分組,如果不指定的話),分組有如下優勢:

  • 組內多個消費者可以並發處理(提高消費效率的方式)
  • 消費者管理更加靈活

接著,在po一張分區和分組的關係圖。

從圖中可以看到的關係如下:

  • Topic下的消息會分發給所有的訂閱組
  • 組內的消費者會各自消費不同的分區(且在分區和組內消費者數不變的情況下,關係是固定的)
  • 一個消費者可以消費一或多個分區
  • 一個分區只能被同一個組內的一個消費者消費

這個是設計相對合理的分區和消費者數量,組內消費者數 = 分區數 * N。如果分區數和消費者數設置不合理,則會有消費者永遠拿不到數據。所以,分區、分組是kafka支援高並發處理的基礎。

隊列還是分發

跟其它消息隊列一樣,kafka的消息模式也支援隊列和分發訂閱兩種方式。

隊列模式也稱生產消費者模式,特點是同一個消息同時只能被一個消費者消費。其邏輯結構可以簡單的通過下面的示意圖來說明。

分發訂閱模式的特點是同一個消息同時可以被所有的消費者消費。(類似於廣播的形式)其邏輯結構的簡單示意如下:

kafka中默認會把同一個消息分發給所有的訂閱組(Consumer Group),即分發訂閱模式。

如果想要實現隊列模式,則把所有的消費者存放在一個Consumer Group內,且該Topic只有這一個組有訂閱。kafka不同消費模式的示意如下:

消費方式

消息的消費方式是很多初用者會忽略的,因為簡單場景下選擇任意一種都是可以正常工作的,而到了生成環境可能就會出問題了。 kafka的消費方式有三種:

  • At most once(消息最多被消費一次)
  • At least once(消息最少被消費一次)
  • Exactly once(消息剛好被消費一次)

前兩者所有版本的kafka都支援,可以通過是否自動提交offset來控制。 默認kafka是會自動提交offset的,即屬於第一種方式。如果設置為手動提交offset則屬於第二種方式。

另外如果需要剛好一次的消費語義,則需要0.11以上的kafka版本。 如果你的版本不是0.11之後的,則可以通過At least once配合下游應用的冪等機制來實現。

API

https://kafka-python.readthedocs.io/en/master/usage.html

Tags: