必知必會 - 使用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