1. 程式人生 > >kafka系列 -- 基礎概念

kafka系列 -- 基礎概念

指定 comm 一個人 讓我 所在 每一個 rod .com partition

kafka是一個分布式的、分區化、可復制提交的發布訂閱消息系統
傳統的消息傳遞方法包括兩種:

  • 排隊:在隊列中,一組用戶可以從服務器中讀取消息,每條消息都發送給其中一個人。
  • 發布-訂閱:在這個模型中,消息被廣播給所有的用戶。
    kafka與傳統的消息傳遞技術相比優勢之處在於:
  • 快速:單一的Kafka代理可以處理成千上萬的客戶端,每秒處理數兆字節的讀寫操作。
  • 可伸縮:在一組機器上對數據進行分區和簡化,以支持更大的數據
  • 持久:消息是持久性的,並在集群中進行復制,以防止數據丟失。
  • 設計:它提供了容錯保證和持久性

基本概念

  1. Topic(話題):Kafka中用於區分不同類別信息的類別名稱。由producer指定
  2. Producer(生產者):將消息發布到Kafka特定的Topic的對象(過程)
  3. Consumers(消費者):訂閱並處理特定的Topic中的消息的對象(過程)
  4. Broker(Kafka服務集群):已發布的消息保存在一組服務器中,稱之為Kafka集群。集群中的每一個服務器都是一個代理(Broker). 消費者可以訂閱一個或多個話題,並從Broker拉數據,從而消費這些已發布的消息。
  5. Partition(分區)Topic物理上的分組,一個topic可以分為多個partition,每個partition是一個有序的隊列。partition中的每條消息都會被分配一個有序的id(offset)
  6. Message:消息,是通信的基本單位,每個producer可以向一個topic(主題)發送一些消息。

Log(日誌)

日誌是一個只能增加的,完全按照時間排序的一系列記錄。我們可以給日誌的末尾添加記錄,並且可以從左到右讀取日誌記錄。每一條記錄都指定了一個唯一的有一定順序的日誌記錄編號。

每個日誌文件都是“log entries”序列,每一個log entry包含一個4字節整型數(值為N),其後跟N個字節的消息體。每條消息都有一個當前partition下唯一的64字節的offset,它指明了這條消息的起始位置

這個“log entries”並非由一個文件構成,而是分成多個segment,每個segment名為該segment第一條消息的offset和“.kafka”組成。另外會有一個索引文件,它標明了每個segment下包含的log entry的offset範圍。

技術分享圖片

Topic & Partition

技術分享圖片
談到kafka的存儲,就不得不提到分區。
創建一個topic時,同時可以指定分區數目,分區數越多,其吞吐量也越大,但是需要的資源也越多,同時也會導致更高的不可用性,kafka在接收到生產者發送的消息之後,會根據均衡策略將消息存儲到不同的分區中。

為了使得Kafka的吞吐率可以水平擴展,物理上把topic分成一個或多個partition,每個partition在物理上對應一個文件夾,該文件夾下存儲這個partition的所有消息和索引文件。

消息以順序存儲:每一個分區都是一個順序的、不可變的消息隊列, 並且可以持續的添加,,最晚接收的的消息會最後被消費。
分區中的消息都被分配了一個序列號,稱之為偏移量(64字節的offset),在每個分區中此偏移量都是唯一的。
因為每條消息都被append到該partition中,是順序寫磁盤,因此效率非常高(經驗證,順序寫磁盤效率比隨機寫內存還要高,這是Kafka高吞吐率的一個很重要的保證)

與生產者的交互

生產者在向kafka集群發送消息的時候,可以通過指定分區來發送到指定的分區中
也可以通過指定均衡策略來將消息發送到不同的分區中
如果不指定,就會采用默認的隨機均衡策略,將消息隨機的存儲到不同的分區中

每一條消息被發送到broker時,會根據paritition規則選擇被存儲到哪一個partition
如果partition規則設置的合理,所有消息可以均勻分布到不同的partition裏,這樣就實現了水平擴展。(如果一個topic對應一個文件,那這個文件所在的機器I/O將會成為這個topic的性能瓶頸,而partition解決了這個問題)。

在發送一條消息時,可以指定這條消息的key,producer根據這個key和partition機制來判斷將這條消息發送到哪個parition。
paritition機制可以通過指定producer的paritition. class這一參數來指定,該class必須實現kafka.producer.Partitioner接口。
本例中如果key可以被解析為整數則將對應的整數與partition總數取余,該消息會被發送到該數對應的partition。(每個parition都會有個序號)

與消費者交互

在消費者消費消息時,kafka使用offset來記錄當前消費的位置
在kafka的設計中,可以有多個不同的group來同時消費同一個topic下的消息
兩個不同的group同時消費,他們的的消費的記錄位置offset各不項目,不互相幹擾。

對於一個group而言,消費者的數量不應該多余分區的數量
因為每個分區至多只能自動發送消息到一個group中的一個消費者上,即一個消費者可以消費多個分區,一個分區只能給同一個組的一個消費者消費
因此,若一個group中的消費者數量大於分區數量的話,多余的消費者將不會收到任何消息
技術分享圖片

offset偏移量

  1. 在每個分區中此偏移量都是唯一的。
  2. 消費者所持有的僅有的元數據就是這個偏移量,也就是消費者在這個log中的位置。
  3. 偏移量由消費者控制。正常情況當消費者消費消息的時候,偏移量也線性的的增加。消費者可以將偏移量重置為更老的一個偏移量,重新讀取消息。
  4. 一個消費者的操作不會影響其它消費者對此log的處理
  5. 一個topic中有100條數據,我消費了50條並且提交了,那麽此時的kafka服務端記錄提交的offset就是49(offset從0開始),那麽下次消費的時候offset就從50開始消費。

手動控制Offest

自動提交是在kafka拉取到數據完就直接提交數據偏移量。

而業務系統中,消費數據還伴隨著一些邏輯業務處理,插入數據庫等。
這事務過程,需要完成才提交。不然還沒插進數據庫,新的數據又來了。
加入插入數據庫還失敗了,就沒法再消費一次失敗的數據了。

所以要嚴格的不丟數據,需要手動控制offest。

  1. 手動commit offset,並針對partition_num啟同樣數目的consumer進程,這樣就能保證一個consumer進程占有一個partition,commit offset的時候不會影響別的 partition 的 offset。但這個方法比較局限,因為partition和consumer進程的數目必須嚴格對應。
  2. 另一個方法同樣需要手動commit offset,另外在consumer端再將所有fetch到的數據緩存到queue裏,當把queue裏所有的數據處理完之後,再批量提交offset,這樣就能保證只有處理完的數據才被commit。

官網還說:
手動控制offest讓我們能精確控制消息被消費(能實現 提交了offest的不再消費,沒提交過offest的數據會再次消費)。
但這一過程可能在 數據插入數據庫後,但是還沒commit offset到kafka時 失敗了。
那麽下一次消費將還是從上次消費的起點取到數據,會重復插入數據庫。
kafka提供的是 "at-least once delivery" 保證, 每個消息會被傳遞至少一次,然而在失敗的時候會造成重復。

kafka系列 -- 基礎概念