圖文詳解:Kafka到底有哪些秘密讓我對(duì)它情有獨(dú)鐘呢?
前言
好了,開始進(jìn)入正題。今天給大家?guī)淼牡氖顷P(guān)于我們的老朋友Kafka的來世今生。
隨著對(duì)實(shí)時(shí)性的要求越來越高,那么在龐大的數(shù)據(jù)的傳輸過程中怎么能保證數(shù)據(jù)的快速傳遞呢,由此,消息隊(duì)列產(chǎn)生了。
“消息”是在兩臺(tái)計(jì)算機(jī)間傳送的數(shù)據(jù)單位。消息可以非常簡(jiǎn)單,例如只包含文本字符串;也可以更復(fù)雜,可能包含嵌入對(duì)象。
消息被發(fā)送到隊(duì)列中。“消息隊(duì)列”是在消息的傳輸過程中保存消息的容器。Kafka是一個(gè)分布式消息隊(duì)列對(duì)我們來說掌握它是必不可少的。
本文對(duì) Kafka 的基本組件的實(shí)現(xiàn)細(xì)節(jié)及其基本應(yīng)用進(jìn)行了詳細(xì)介紹,同時(shí),也熬了幾天夜畫了圖解,希望能讓大家對(duì) Kafka 核心知識(shí)的有了更深刻的理解,最后也總結(jié)了 Kafka 在實(shí)際業(yè)務(wù)中的應(yīng)用。跟著小羽一起再來熟悉一下這些屬于Kafka的小秘密吧:
Kafka 概念
Kafka 是一種高吞吐量、分布式、基于發(fā)布/訂閱的消息系統(tǒng),最初由 LinkedIn 公司開發(fā),使用Scala 語言編寫,目前是 Apache 的開源項(xiàng)目。
Kafka 主要組件
- broker:Kafka 服務(wù)器,負(fù)責(zé)消息存儲(chǔ)和轉(zhuǎn)發(fā)
- topic:消息類別,Kafka 按照 topic 來分類消息
partition:topic 的分區(qū),一個(gè) topic 可以包含多個(gè) partition,topic 消息保存在各個(gè) partition 上
offset:消息在日志中的位置,可以理解是消息在 partition 上的偏移量,也是代表該消息的唯一序號(hào)
- Producer:消息生產(chǎn)者
- Consumer:消息消費(fèi)者
- Consumer Group:消費(fèi)者分組,每個(gè) Consumer 必須屬于一個(gè) group
- Zookeeper:保存著集群 broker、topic、partition 等 meta 數(shù)據(jù);另外,還負(fù)責(zé) broker 故障發(fā)現(xiàn),partition leader 選舉,負(fù)載均衡等功能
Kafka 優(yōu)點(diǎn)
- 解耦:消息系統(tǒng)在處理過程中間插入了一個(gè)隱含的、基于數(shù)據(jù)的接口層,兩邊的處理過程都要實(shí)現(xiàn)這一接口。這允許你獨(dú)立的擴(kuò)展或修改兩邊的處理過程,只要確保它們遵守同樣的接口約束。
- 冗余:消息隊(duì)列把數(shù)據(jù)進(jìn)行持久化直到它們已經(jīng)被完全處理,通過這一方式規(guī)避了數(shù)據(jù)丟失風(fēng)險(xiǎn)。許多消息隊(duì)列所采用的"插入-獲取-刪除"范式中,在把一個(gè)消息從隊(duì)列中刪除之前,需要你的處理系統(tǒng)明確的指出該消息已經(jīng)被處理完畢,從而確保你的數(shù)據(jù)被安全的保存直到你使用完畢。
- 擴(kuò)展性:因?yàn)橄㈥?duì)列解耦了你的處理過程,所以增大消息入隊(duì)和處理的頻率是很容易的,只要另外增加處理過程即可。不需要改變代碼、不需要調(diào)節(jié)參數(shù)。擴(kuò)展就像調(diào)大電力按鈕一樣簡(jiǎn)單。
- 靈活性 & 峰值處理能力:使用消息隊(duì)列能夠使關(guān)鍵組件頂住突發(fā)的訪問壓力,而不會(huì)因?yàn)橥话l(fā)的超負(fù)荷的請(qǐng)求而完全崩潰。
- 可恢復(fù)性:消息隊(duì)列降低了進(jìn)程間的耦合度,所以即使一個(gè)處理消息的進(jìn)程掛掉,加入隊(duì)列中的消息仍然可以在系統(tǒng)恢復(fù)后被處理。
- 順序保證:大部分消息隊(duì)列本來就是排序的,并且能保證數(shù)據(jù)會(huì)按照特定的順序來處理。Kafka保證一個(gè)Partition內(nèi)的消息的有序性。
- 緩沖:消息隊(duì)列通過一個(gè)緩沖層來幫助任務(wù)最高效率的執(zhí)行。寫入隊(duì)列的處理會(huì)盡可能的快速。該緩沖有助于控制和優(yōu)化數(shù)據(jù)流經(jīng)過系統(tǒng)的速度。
- 異步通信:消息隊(duì)列提供了異步處理機(jī)制,允許用戶把一個(gè)消息放入隊(duì)列,但并不立即處理它。想向隊(duì)列中放入多少消息就放多少,然后在需要的時(shí)候再去處理它們。
Kafka 應(yīng)用場(chǎng)景
- 活動(dòng)追蹤:跟蹤網(wǎng)站?用戶與前端應(yīng)?用程序發(fā)?生的交互,如:網(wǎng)站PV/UV分析
- 傳遞消息:系統(tǒng)間異步的信息交互,如:營銷活動(dòng)(注冊(cè)后發(fā)送券碼福利利)
- 日志收集:收集系統(tǒng)及應(yīng)?用程序的度量量指標(biāo)及?日志,如:應(yīng)用監(jiān)控和告警
- 提交日志:將數(shù)據(jù)庫的更更新發(fā)布到kafka上,如:交易統(tǒng)計(jì)
Kafka 數(shù)據(jù)存儲(chǔ)設(shè)計(jì)
partition 的數(shù)據(jù)文件
partition 中的每條 Message 包含三個(gè)屬性:offset,MessageSize,data,其中 offset 表 示 Message 在這個(gè) partition 中的偏移量,offset 不是該 Message 在 partition 數(shù)據(jù)文件中的實(shí)際存儲(chǔ)位置,而是邏輯上一個(gè)值,它唯一確定了 partition 中的一條 Message,可以認(rèn)為 offset 是 partition 中 Message 的 id;MessageSize 表示消息內(nèi)容 data 的大小;data 為 Message 的具體內(nèi)容。
數(shù)據(jù)文件分段 segment
partition 物理上由多個(gè) segment 文件組成,每個(gè) segment 大小相等,順序讀寫。每個(gè) segment數(shù)據(jù)文件以該段中最小的 offset 命名,文件擴(kuò)展名為.log。這樣在查找指定 offset 的 Message 的時(shí)候,用二分查找就可以定位到該 Message 在哪個(gè) segment 數(shù)據(jù)文件中。
數(shù)據(jù)文件索引
Kafka 為每個(gè)分段后的數(shù)據(jù)文件建立了索引文件,文件名與數(shù)據(jù)文件的名字是一樣的,只是文件擴(kuò)展名為.index。index 文件中并沒有為數(shù)據(jù)文件中的每條 Message 建立索引,而是采用了稀疏存儲(chǔ)的方式,每隔一定字節(jié)的數(shù)據(jù)建立一條索引。這樣避免了索引文件占用過多的空間,從而可以將索引文件保留在內(nèi)存中。
Zookeeper 在 kafka 的作用
無論是 kafka 集群,還是 producer 和 consumer 都依賴于 zookeeper 來保證系統(tǒng)可用性集群保存一些meta信息。
Kafka 使用 zookeeper 作為其分布式協(xié)調(diào)框架,很好的將消息生產(chǎn)、消息存儲(chǔ)、消息消費(fèi)的過程結(jié)合在一起。
同時(shí)借助 zookeeper,kafka 能夠生產(chǎn)者、消費(fèi)者和 broker 在內(nèi)的所以組件在無狀態(tài)的情況下,建立起生產(chǎn)者和消費(fèi)者的訂閱關(guān)系,并實(shí)現(xiàn)生產(chǎn)者與消費(fèi)者的負(fù)載均衡。
生產(chǎn)者設(shè)計(jì)
負(fù)載均衡
由于消息 topic 由多個(gè) partition 組成,且 partition 會(huì)均衡分布到不同 broker 上,因此,為了有效利用 broker 集群的性能,提高消息的吞吐量,producer 可以通過隨機(jī)或者 hash 等方式,將消息平均發(fā)送到多個(gè) partition 上,以實(shí)現(xiàn)負(fù)載均衡。
批量發(fā)送
是提高消息吞吐量重要的方式,Producer 端可以在內(nèi)存中合并多條消息后,以一次請(qǐng)求的方式發(fā)送了批量的消息給 broker,從而大大減少 broker 存儲(chǔ)消息的 IO 操作次數(shù)。但也一定程度上影響了消息的實(shí)時(shí)性,相當(dāng)于以時(shí)延代價(jià),換取更好的吞吐量。
壓縮
Kafka支持以集合(batch)為單位發(fā)送消息,在此基礎(chǔ)上,Kafka還支持對(duì)消息集合進(jìn)行壓縮,Producer 端可以通過 GZIP 或 Snappy 格式對(duì)消息集合進(jìn)行壓縮。Producer 端進(jìn)行壓縮之后,在Consumer 端需進(jìn)行解壓。壓縮的好處就是減少傳輸?shù)臄?shù)據(jù)量,減輕對(duì)網(wǎng)絡(luò)傳輸?shù)膲毫?,在?duì)大數(shù)據(jù)處理上,瓶頸往往體現(xiàn)在網(wǎng)絡(luò)上而不是 CPU(壓縮和解壓會(huì)耗掉部分 CPU 資源)。
那么如何區(qū)分消息是壓縮的還是未壓縮的呢,Kafka在消息頭部添加了一個(gè)描述壓縮屬性字節(jié),這個(gè)字節(jié)的后兩位表示消息的壓縮采用的編碼,如果后兩位為0,則表示消息未被壓縮。
消費(fèi)者設(shè)計(jì)
Consumer Group
同一 Consumer Group 中的多個(gè) Consumer 實(shí)例,不同時(shí)消費(fèi)同一個(gè) partition,等效于隊(duì)列模式。partition 內(nèi)消息是有序的,Consumer 通過 pull 方式消費(fèi)消息。Kafka 不刪除已消費(fèi)的消息對(duì)于 partition,順序讀寫磁盤數(shù)據(jù),以時(shí)間復(fù)雜度 O(1)方式提供消息持久化能力。
實(shí)踐應(yīng)用
Kafka 作為消息系統(tǒng)
kafka 通過在主題中具有并行性概念 - 分區(qū) - ,Kafka能夠在消費(fèi)者流程池中提供訂購保證和負(fù)載平衡。這是通過將主題中的分區(qū)分配給使用者組中的使用者來實(shí)現(xiàn)的,以便每個(gè)分區(qū)僅由該組中的一個(gè)使用者使用。通過這樣做,我們確保使用者是該分區(qū)的唯一讀者并按順序使用數(shù)據(jù)。由于有許多分區(qū),這仍然可以平衡許多消費(fèi)者實(shí)例的負(fù)載。但請(qǐng)注意,消費(fèi)者組中的消費(fèi)者實(shí)例不能超過分區(qū)。
Kafka 作為存儲(chǔ)系統(tǒng)
Kafka是一個(gè)非常好的存儲(chǔ)系統(tǒng)。寫入Kafka的數(shù)據(jù)將寫入磁盤并進(jìn)行復(fù)制以實(shí)現(xiàn)容錯(cuò)。Kafka允許生產(chǎn)者等待確認(rèn),以便在完全復(fù)制之前寫入不被認(rèn)為是完整的,并且即使寫入的服務(wù)器失敗也保證寫入仍然存在。
磁盤結(jié)構(gòu)Kafka很好地使用了規(guī)模 - 無論服務(wù)器上有50 KB還是50 TB的持久數(shù)據(jù),Kafka都會(huì)執(zhí)行相同的操作。
由于認(rèn)真對(duì)待存儲(chǔ)并允許客戶端控制其讀取位置,您可以將Kafka視為一種專用于高性能,低延遲提交日志存儲(chǔ),復(fù)制和傳播的專用分布式文件系統(tǒng)。
Kafka 用于流處理
對(duì)于復(fù)雜的轉(zhuǎn)換,Kafka提供了完全集成的Streams API。這允許構(gòu)建執(zhí)行非平凡處理的應(yīng)用程序,這些應(yīng)用程序可以計(jì)算流的聚合或?qū)⒘鬟B接在一起。
此工具有助于解決此類應(yīng)用程序面臨的難題:處理無序數(shù)據(jù),在代碼更改時(shí)重新處理輸入,執(zhí)行有狀態(tài)計(jì)算等。
流API構(gòu)建在Kafka提供的核心原理上:它使用生產(chǎn)者和消費(fèi)者API進(jìn)行輸入,使用Kafka進(jìn)行8有狀態(tài)存儲(chǔ),并在流處理器實(shí)例之間使用相同的組機(jī)制來實(shí)現(xiàn)容錯(cuò)*。