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