Kafka通過使用“long polling”等待模式的方式解決了這個問題。簡而言之,如果分區上沒有數據,Kafka 不會返回空響應。相反,broker保持連接并等待數據進入,然后再將其返回給消費者。
前言
Kafka 一開始是LinkedIn這家公司研發的技術,它是一種高吞吐量的分布式發布訂閱消息系統,現在已成為大多數公司使用的技術,我們公司也不例外。那么你對kafka的了解有多少呢?那么本文就帶你過一過kafka中的一些關鍵要點。
為什么我們需要Kafka?
訂單發生時通知其他服務
在我們深入研究之前,有必要重新審視一下 Kafka 最初被發明的原因。
想象一下為一家電子商務公司維護一組微服務。
下訂單時,訂單服務要通知很多服務,如下:
- 錢包服務從用戶賬戶中扣除金額
- 倉庫服務扣除物品的庫存數量
- 物流服務發貨
當訂單服務要通知更多的服務時,復雜度就要進一步提高。
訂單服務器需要做以下事情:
- 跟蹤都通知了誰
- 確保所有其他服務確實收到并處理
- 和其他服務建立直接的連接和處理不同的響應
發現沒有,這很難擴展,如果接入更多的系統,訂單系統的開發天天996了。
因此,Kafka就很好的解決這樣的問題。
消息隊列與發布訂閱
訂單服務器只是將消息發布到 Pub-Sub/Message Queue
消息隊列和發布訂閱系統都是解決上述問題的關鍵。
也就是說,不是讓訂單服務維護直接和各種系統打交道,而是將事件發布或者推送到中間隊列中,對隊列感興趣的服務器(通常稱為消費者)訂閱隊列并相應地消費事件。
那么消息隊列和發布訂閱系統有什么區別呢?
消息隊列
消息隊列是一種類似隊列的結構,其中消息被發布并且僅被消費一次。這對于非冪等的進程很方便,事件應該只由一個消費者處理,RabbitMQ 最初被設計成一個消息隊列。
發布-訂閱系統
另一方面,發布訂閱系統允許多個消費者多次使用一條消息。訂單事件被多個系統訂閱消費,所以更適合發布訂閱系統模式。Kafka 被設計為既是消息隊列又是發布訂閱系統。
Kafka組件
為了充分理解 Kafka 的工作原理,讓我們剖析 下Kafka 的各個組件。
Kafka Broker 和集群
Kafka 代理和集群
Kafka 只不過是一個管理數據發布和消費的服務。
一個Kafka Broker就是一個Kafka服務。維護同一組主題的一組Broker稱為 Kafka 集群。
發布者Publisher
發布者發布到 Kafka 代理
將數據發布到 Kafka Broker的服務稱為發布者。我們之前提到的Order服務是發布者的一個例子。
消費者Consumer
消費者從 Kafka 代理消費
另一方面,消費者是訂閱和消費來自 Kafka 主題的數據的服務。
在我們前面的示例中,Wallet服務器、Warehouse服務器和Logistic服務器充當Order主題的消費者。
主題Topic
Kafka 代理中的不同主題
Kafka 代理維護不同類型的事件,例如:
- 訂單創建事件
- 訂單取消事件
- 缺貨事件
這些事件中的每一個都是大量的數據流。主題只是一種事件或數據流。
發布到 Kafka 時,發布者指定消息應發布到的主題。
主題是一個只能追加的日志。將消息附加到主題類似于將數據附加到隊列,它需要 O(1) 常數時間,因此速度非常快。
分區Partition
主題被分片成分區
主題是存儲在 Kafka Broker上的追加的日志。
隨著消息數量的增加,Broker在特定主題上存儲的數據量是有限的,那怎么辦呢?
可以將一個主題拆分為多個分區,而不是將所有數據一直追加到同一個主體日志中,而是每個分區存儲特定主題的一部分數據,這類似于數據庫分片。
主題基于分區進行分片。同一主題的分區可以存儲在相同或不同的 Kafka Broker上。這使得 Kafka 具有高度可擴展性。
發布者在發布之前指定消息的主題和分區。因此,發布者有責任確保分區邏輯不會導致熱分區。
偏移量offset
分區中的偏移量
偏移量是分區中消息的唯一索引。
當 Kafka 將數據推送給消費者時,它會增加并跟蹤當前的偏移量。
有兩種類型的偏移量值得強調:
- 當前偏移量:保存在Consumer客戶端中,它表示Consumer希望收到的下一條消息的序號。
- 提交的偏移量: 保存在Broker上,它表示Consumer已經確認消費過的消息的序號。
消費者組
如前所述,Kafka 既是消息隊列又是發布訂閱系統。這是通過消費者群體優雅地設計的。
Consumer可以消費多個partition,但是每個partition只能被同組的一個consumer消費
消費者組由一組消費相同主題的消費者組成。
一個消費者一次可以消費多個分區。但是,每個分區只能由同一組中的一個且只有一個消費者使用。
一個分區可以被來自不同消費者組的多個消費者消費
消費者組是相互獨立的,不同的組可以同時使用同一主題并使用不同的偏移量。
通過將所有消費者放在同一組中來實現隊列,同一分區中的消息不會被來自相似組的不同消費者并發消費。
在分區級別實現隊列。因此,如果想要保證順序處理數據流,發布者必須確保數據始終被推送到同一個分區。
另一方面,發布訂閱系統是通過多個消費者組實現的。消費者群體彼此之間一無所知,并使用單獨的偏移量消費數據。
在前面的例子中,Wallet服務器和Logistic服務器分別屬于不同的消費者組,分別消費數據。
重新平衡和分區分配
當新消費者加入時,Kafka 會重新平衡
如果一組中只有一個消費者,則該消費者將負責消費所有可用分區。
當一個新的consumer加入group時,比如增加了一個新的server實例,Kafka會進行rebalancing,將一部分partitions分配給新的consumer。
這確保了每個消費者共享相同數量的工作,從而使 Kafka 具有可擴展性。
Kafka 使用自己的重新平衡策略進行分區重新分配,這值得另一篇單獨的文章來介紹。
復制Replica
副本在分區級別創建,可以存儲在相同/不同的代理中
單點故障是每個分布式系統的噩夢,Kafka也不例外。
如果Broker出現故障,存儲在代理上的分區可能不可用。因此,副本是在分區級別創建的。
為每個分區創建副本,并存儲在不同的 Kafka 代理上。為每個分區選舉一個領導者來為發布者和消費者服務。
副本不斷從leader同步數據。當 leader 宕機時,Zookeeper 會加入進來幫助進行 leader 的選舉。
Zookeeper
正如您可能正在思考的那樣,我們的難題中缺少一些部分。
- 我們如何知道每個分區的領導者?
- 如何知道每個主題的分區數?
- 我們如何知道每個消費者組的最新偏移量?
- 我們如何知道每個消費者組中有多少消費者?
這就是Zookeeper發揮作用的地方。它是一個分布式協調服務系統,用于存儲元數據并協調 Kafka 中的分布式系統。
主要涉及以下方面:
- 領導者選舉——確保每個分區都有一個領導者
- 集群成員資格——跟蹤集群中的所有功能代理
- 主題配置——跟蹤所有可用主題、分區及其副本
- 訪問控制列表——跟蹤每個組中消費者的數量及其訪問權限
- 配額——跟蹤每個客戶端可以讀取和寫入的數據量
長輪詢
Kafka 如何向消費者推送消息?
RabbitMQ 采用推送模型。代理與消費者保持持久的 TCP 連接,并在有可用數據時將數據推送給他們。
然而,推送模型可能會淹沒消費者。如果代理推送數據的速度快于消費者處理數據的速度,消費者可能會落后。RabbitMQ 確實有一個解決方案,這邊就不展開討論了。
長輪詢等待方式方法
Kafka 使用拉模型,也就是長輪詢。消費者定期從代理拉取數據。因此,消費者只有在準備好時才能拉取數據。但是,如果分區上沒有數據,來自消費者的定期輪詢可能會導致資源浪費。
Kafka通過使用“long polling”等待模式的方式解決了這個問題。簡而言之,如果分區上沒有數據,Kafka 不會返回空響應。相反,broker保持連接并等待數據進入,然后再將其返回給消費者。
這減輕了當分區上沒有數據時消費者頻繁輪詢并防止資源浪費。
總結
本文總結了Kafka這個組件的基礎知識,希望讓大家對Kafka有一個宏觀的認識,感興趣的再深入分析底層的實現機制。