溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

為什么Kafka這么厲害

發(fā)布時間:2021-10-19 15:11:56 來源:億速云 閱讀:125 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“為什么Kafka這么厲害”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“為什么Kafka這么厲害”吧!

1 Kafka 簡介

1.1 Kafka 概述

為什么Kafka這么厲害

Kafka架構(gòu)

Kafka 是一個分布式的基于發(fā)布/訂閱模式的消息隊(duì)列,依靠其強(qiáng)悍的吞吐量,Kafka  主要應(yīng)用于大數(shù)據(jù)實(shí)時處理領(lǐng)域。在數(shù)據(jù)采集、傳輸、存儲的過程中發(fā)揮著舉足輕重的作用。

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. Apache Kafka 由 Scala  寫成,是由Apache軟件基金會開發(fā)的一個開源消息系統(tǒng)項(xiàng)目。該項(xiàng)目的目標(biāo)是為處理實(shí)時數(shù)據(jù)提供一個統(tǒng)一、高通量、低等待的平臺。

  3. Kafka 是一個分布式消息隊(duì)列,Kafka 對消息保存時根據(jù) Topic 進(jìn)行歸類,Kafka 集群有多個 Kafka實(shí)例組成,每個實(shí)例 Server  稱為 broker。

  4. 無論是 Kafka 集群還是 Consumer 都依賴于 ZooKeeper 集群保存一些 meta 信息,來保證系統(tǒng)可用性

1.2 Kafka 優(yōu)點(diǎn)

  1. 支持多個生產(chǎn)者和消費(fèi)者。

  2. 支持broker的橫向拓展。

  3. 副本集機(jī)制,實(shí)現(xiàn)數(shù)據(jù)冗余,保證數(shù)據(jù)不丟失。

  4. 通過 topic 將數(shù)據(jù)進(jìn)行分類。

  5. 通過分批發(fā)送壓縮數(shù)據(jù)的方式,減少數(shù)據(jù)傳輸開銷,提高吞高量。

  6. 支持多種模式的消息,消息是基于磁盤實(shí)現(xiàn)數(shù)據(jù)的持久化。

  7. 高性能的處理信息,在大數(shù)據(jù)的情況下,可以保證亞秒級的消息延遲。

  8. 一個消費(fèi)者可以支持多種 topic 的消息。

  9. 對CPU、內(nèi)存、網(wǎng)絡(luò)的消耗比較小。

  10. 支持跨數(shù)據(jù)中心的數(shù)據(jù)復(fù)制跟鏡像集群。

1.3 Kafka 缺點(diǎn)

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 由于是批量發(fā)送,所以數(shù)據(jù)達(dá)不到真正的實(shí)時。

  3. 只能支持統(tǒng)一分區(qū)內(nèi)消息有序,無法實(shí)現(xiàn)全局消息有序。

  4. 監(jiān)控不完善,需要安裝插件。

  5. 會丟失數(shù)據(jù),并且不支持事務(wù)。

  6. 可能會重復(fù)消費(fèi)數(shù)據(jù),消息會亂序,可用保證一個固定的partition內(nèi)部的消息是有序的,但是一個topic有多個partition的話,就不能保證有序了,需要zookeeper的支持,topic一般需要人工創(chuàng)建,部署和維護(hù)一般都比mq高。

1.4 Kafka 架構(gòu)

為什么Kafka這么厲害

  1. Broker:一臺 kafka 服務(wù)器就是一個broker。一個集群由多個broker組成。一個broker可以容納多個topic。

  2. Producer :消息生產(chǎn)者,就是向 Kafka broker 發(fā)消息的客戶端。

  3. Consumer :消息消費(fèi)者,向 Kafka broker 拉取消息來消費(fèi)。可以根據(jù) Consumer 的消費(fèi)能力以適當(dāng)?shù)乃俾氏M(fèi)消息。

  4. Topic :可以理解為一個隊(duì)列,生產(chǎn)者和消費(fèi)者面向的都是一個topic。

  5. Partition:為了實(shí)現(xiàn)擴(kuò)展性,一個非常大的 topic 可以分布到多個broker上,一個 topic 可以分為多個partition,每個  partition 是一個有序的隊(duì)列,有點(diǎn)平衡分?jǐn)偵a(chǎn)者機(jī)制。

  6. Replication:為保證集群中的某個節(jié)點(diǎn)發(fā)生故障時,該節(jié)點(diǎn)上的partition數(shù)據(jù)不丟失,且kafka仍然能夠繼續(xù)工作,kafka提供了副本機(jī)制,一個topic的每個分區(qū)都有若干個副本,一個leader和若干個follower。

  7. leader:一個分區(qū)有一個Leader,生產(chǎn)者發(fā)送數(shù)據(jù)的對象,以及消費(fèi)者消費(fèi)數(shù)據(jù)的對象都是leader。

  8. follower:一個分區(qū)有一個Follower,實(shí)時從 leader 中同步數(shù)據(jù),保持和 leader 數(shù)據(jù)的同步。leader 發(fā)生故障時,某個  follower 會成為新的 follower。注意Kafka中 副本數(shù)不能超過Broker數(shù)!

  9. Consumer Group :消費(fèi)者組由多個 consumer  組成。組內(nèi)每個消費(fèi)者負(fù)責(zé)消費(fèi)不同分區(qū)的數(shù)據(jù),一個分區(qū)只能由一個組內(nèi)消費(fèi)者消費(fèi);消費(fèi)者組之間互不影響。所有的消費(fèi)者都屬于某個消費(fèi)者組,即消費(fèi)者組是邏輯上的一個訂閱者。

  10. offset:消費(fèi)者在具體消費(fèi)某個 topic 中的消息時,可以指定起始偏移量。

1.5 ZooKeeper 作用

ZooKeeper 在 Kafka 中有舉足輕重的地位,一般提供如下功能:

1.5.1 Broker 注冊

Broker 是分布式部署并且相互之間相互獨(dú)立,但是需要有一個注冊系統(tǒng)能夠?qū)⒄麄€集群中的Broker管理起來,比如用ZooKeeper。

1.5.2 Topic注冊

在 Kafka 中同一個 Topic 的消息會被分成多個 Partition 并將其分布在多個 Broker 上,這些 Partition 信息及與  Broker 的對應(yīng)關(guān)系也都是由 Zookeeper 在維護(hù),由專門的節(jié)點(diǎn)來記錄。

1.5.3 生產(chǎn)者負(fù)載均衡

同一個Topic消息會被分區(qū)并將其分布在多個Broker上,因此,生產(chǎn)者需要將消息合理地發(fā)送到這些分布式的Broker上。

老式的四層負(fù)載均衡,根據(jù)生產(chǎn)者的IP地址和端口來為其確定一個相關(guān)聯(lián)的Broker。一般一個生產(chǎn)者只會對應(yīng)單個Broker,但實(shí)際系統(tǒng)中的每個生產(chǎn)者產(chǎn)生的消息量及每個Broker的消息存儲量都是不一樣的。

使用 Zookeeper  進(jìn)行負(fù)載均衡,由于每個Broker啟動時,都會完成Broker注冊過程,生產(chǎn)者會通過該節(jié)點(diǎn)的變化來動態(tài)地感知到Broker服務(wù)器列表的變更,這樣就可以實(shí)現(xiàn)動態(tài)的負(fù)載均衡機(jī)制。

1.5.4 消費(fèi)者負(fù)載均衡

Kafka 中的消費(fèi)者同樣需要進(jìn)行負(fù)載均衡來實(shí)現(xiàn)多個消費(fèi)者合理地從對應(yīng)的 Broker  服務(wù)器上接收消息,每個消費(fèi)者分組包含若干消費(fèi)者,每條消息都只會發(fā)送給分組中的一個消費(fèi)者,不同的消費(fèi)者分組消費(fèi)自己特定的Topic下面的消息,互不干擾。

1.5.5 分區(qū) 與 消費(fèi)者 的關(guān)系

Kafka 會為每個 Consumer Group 分配個全局唯一 Group ID,Group 內(nèi)的 Consumer 共享該 ID,Kafka規(guī)定  每個partition信息只能被同組的一個Consumer 消費(fèi),在Zk中記錄partition 跟  Consumer關(guān)系,每個消費(fèi)者一旦確定了對一個消息分區(qū)的消費(fèi)權(quán)力,需要將其Consumer ID 寫入到 Zookeeper  對應(yīng)消息分區(qū)的臨時節(jié)點(diǎn)上。

1.5.6 消息消費(fèi)進(jìn)度 Offset 記錄

Consumer 對指定消息分區(qū)進(jìn)行消費(fèi)的過程中,需要定時地將分區(qū)消息的消費(fèi)進(jìn)度 Offset 記錄到 Zookeeper 上,以便在該 Consumer  進(jìn)行重啟或者其他 Consumer 重新接管該消息分區(qū)的消息消費(fèi)后,能夠從之前的進(jìn)度開始繼續(xù)進(jìn)行消息消費(fèi)。

1.5 7 消費(fèi)者注冊

為讓同一個 Topic 下不同分區(qū)的消息盡量均衡地被多個 Consumer 消費(fèi)而進(jìn)行 Consumer 與消息分區(qū)分配的過程。

Consumer 啟動后在ZK下創(chuàng)建個節(jié)點(diǎn),并且每個 Consumer 會對 Consumer Group 中的 Consumer  的變化注冊監(jiān)聽,目的是為了保證 Consumer 負(fù)載均衡。

Consumer 會對Broker列表監(jiān)聽,發(fā)生變化會進(jìn)行 Consumer 負(fù)載均衡。

2 Kafka 生成過程

2.1 寫入方式

producer采用 push 模式將消息發(fā)布到 broker,每條消息都被 append 到 patition 中,屬于 順序?qū)懘疟P  ,順序?qū)懕入S機(jī)寫要起碼提速3個數(shù)量級!

2.2 分區(qū) Partition

2.2.1 Partition 簡介

消息發(fā)送時都被發(fā)送到一個topic,其本質(zhì)就是一個目錄,而topic是由一些 分區(qū)日志 Partition Logs 組成,其組織結(jié)構(gòu)如下圖所示:

為什么Kafka這么厲害

Partition發(fā)生

可以看到每個 Partition 中的消息都是有序的,生產(chǎn)的消息被不斷追加到 Partition log 上,其中的每一個消息都被賦予了一個唯一的  offset 值。

為什么Kafka這么厲害

消費(fèi)者

通過分區(qū)可以 方便在集群中擴(kuò)展,可以提高并發(fā)。

形象理解:

Kafka  的設(shè)計(jì)源自生活,好比為公路運(yùn)輸,不同的起始點(diǎn)和目的地需要修不同高速公路(主題),高速公路上可以提供多條車道(分區(qū)),流量大的公路(主題)多修幾條車道(分區(qū))保證暢通,流量小的公路少修幾條車道避免浪費(fèi)。收費(fèi)站好比消費(fèi)者,車多的時候多開幾個一起收費(fèi)避免堵在路上,車少的時候開幾個讓汽車并道就好了。

2.2.2 分區(qū)原則

我們需要將producer發(fā)送的數(shù)據(jù)封裝成一個ProducerRecord對象。

為什么Kafka這么厲害

數(shù)據(jù)封裝

  1. 指明 partition 的情況下,直接將指明的值直接作為 partiton 值。

  2. 沒有指明 partition 值但有 key 的情況下,將 key 的 hash 值與 topic 的 partition 數(shù)進(jìn)行取余得到  partition 值。

  3. 既沒有 partition 值又沒有 key 值的情況下,第一次調(diào)用時隨機(jī)生成一個整數(shù)(后面每次調(diào)用在這個整數(shù)上自增),將這個值與 topic 可用的  partition 總數(shù)取余得到 partition 值,也就是常說的 round-robin 算法。

2.3 Kafka 文件存儲機(jī)制

為什么Kafka這么厲害

Kafka存儲結(jié)構(gòu)

  1. Kafka 中消息是以 topic 進(jìn)行分類的,生產(chǎn)者跟消費(fèi)者都是面向 topic 的,topic 只是邏輯上的概念,而 Partition  是物理上的概念,每個 Partition 對應(yīng)個 log 文件,每個分區(qū)用  .index`存放數(shù)據(jù)索引,`.log存儲數(shù)據(jù)。index文件中的元數(shù)據(jù)指向?qū)?yīng)log文件中Message的物理偏移地址(參考  kaldi、Neo4j)。

  2. 為防止 log 文件過大導(dǎo)致數(shù)據(jù)定位效率低下,Kafka采取了分片和索引機(jī)制,將每個partition分為多個segment。每個 segment  對應(yīng).index`跟`.log。這些文件位于一個文件夾下,該文件夾的命名規(guī)則為:topic名稱 + 分區(qū)序號。例如 first 這個 topic  有三個分區(qū),則其對應(yīng)的文件夾為first-0、first-1、first-2。

100000000000000000000.index 200000000000000000000.log 300000000000000170410.index 400000000000000170410.log 500000000000000239430.index 600000000000000239430.log

注意:index 和 log 文件以當(dāng)前segment的第一條消息的 offset 命名。

為什么Kafka這么厲害

數(shù)據(jù)查找過程

2.4 如何保證消息順序執(zhí)行

2.4.1 順序錯亂

Kafka 一個 topic,一個 partition,一個 Consumer,但是 Consumer  內(nèi)部進(jìn)行多線程消費(fèi),這樣數(shù)據(jù)也會出現(xiàn)順序錯亂問題。

為什么Kafka這么厲害

多線程消費(fèi)

數(shù)據(jù)有順序的數(shù)據(jù)寫入到了不同的 partition 里面,不同的消費(fèi)者去消費(fèi),但是每個 Consumer 的執(zhí)行時間是不固定的,無法保證先讀到消息的  Consumer 一定先完成操作,這樣就會出現(xiàn)消息并沒有按照順序執(zhí)行,造成數(shù)據(jù)順序錯誤。

為什么Kafka這么厲害

多個消費(fèi)者

2.4.2 解決辦法

確保同一個消息發(fā)送到同一個 partition,一個topic,一個partition,一個consumer,內(nèi)部單線程消費(fèi)。

  • 寫入同一個Partition的信息一定有序。

  • 給信息指定一個key,key相同則一定寫入同一個partition。

  • 從同一個Partition讀取信息一定有序。

為什么Kafka這么厲害

單線程消費(fèi)

在1的基礎(chǔ)上,在一個 Consumer 上根據(jù)信息ID映射到不同隊(duì)列,以此加速消費(fèi)。

為什么Kafka這么厲害

內(nèi)存隊(duì)列

4 數(shù)據(jù)可靠性

4.1 消息傳遞語義

消息傳遞語義 message delivery semantic ,Kafka 為確保消息在 producer 和 consumer  之間傳輸。有以下三種傳輸保障(delivery guarantee):

  1. at most once:最多一次,消息可能會丟,但絕不會重復(fù)傳輸。

  2. at least once:至少一次,消息絕不會丟,但可能會重復(fù)傳輸。

  3. exactly once:精確傳遞一次。消息被處理且只會被處理一次。不丟失不重復(fù)就一次。

理想情況下肯定希望系統(tǒng)的消息傳遞是嚴(yán)格 exactly once,但很難做到。接下來會按照 消息的傳播流程大致說下。

4.2 信息從生產(chǎn)者到 Broker

4.2.1 生產(chǎn)者信息發(fā)送至Broker

大致步驟如下:

  1. producer 從 ZK 找到目標(biāo) Partition 的 Leader 元數(shù)據(jù)。

  2. producer 發(fā)送消息給 Leader。

  3. Leader 接受消息持久化,然后根據(jù)acks配置選擇如何同步Follower。

  4. Followder 按照前面說的同步數(shù)據(jù)后給Leader回復(fù)ack。

  5. Leader 跟 Follower 同步完畢后 Leader 給 producer 回復(fù) ack。

對于Leader回復(fù) ack,Kafka 為用戶提供了三種可靠性級別,用戶根據(jù)對可靠性和延遲的要求進(jìn)行權(quán)衡。

  • request.required.acks = 0

producer不等待 broker 的ack,提供了一個最低的延遲,broker接收到還沒有寫入磁盤就已經(jīng)返回,當(dāng)broker故障時有可能丟失數(shù)據(jù),對應(yīng)  At Most Once 模式。

但凡沒落盤成功信息就丟失了,一般生產(chǎn)不用。

  • request.required.acks = 1

此乃默認(rèn)值,producer 等待 broker 的 ack,partition  的leader落盤成功后返回ack,如果在follower同步成功之前l(fā)eader故障,那么將會丟失數(shù)據(jù);認(rèn)為leader返回 信息就成功了。

  • request.required.acks = -1 / all

producer 等待 broker 的 ack,partition 的 leader 和 follower (ISR中的)全部落盤成功后才返回  ack。

但如果在 leader 收到信息返回ok,follower 收到信息但是發(fā)送 ack 時 leader 故障,此時生產(chǎn)者會重新給follower  發(fā)送個信息。

對應(yīng) At Least Once 模式。

4.2.2 如何保證冪等性

如果業(yè)務(wù)需要數(shù)據(jù) Exactly Once,在早期的 Kafka 版本中  只能在下游去重,現(xiàn)在引入了個冪等性,意思就是無論生產(chǎn)者發(fā)送多少個重復(fù)消息,Server端只會持久化一條數(shù)據(jù),

At Least Once + 冪等性 = Exactly Once

啟動冪等性,在生產(chǎn)者參數(shù)中 enable.idompotence=  true,開啟冪等性的生產(chǎn)者在初始化時候會被分配一個PID,發(fā)送同一個Partition的消息會附帶Sequence  Number,Broker會對做緩存,以此來判斷唯一性。但是如果PID重啟就會發(fā)生變化,同時不同partition也具有不同的主鍵,冪等性無法保證跨分區(qū)會話的  Exactly Once。

4.3 Kafka Broker 信息落磁盤

為什么Kafka這么厲害

數(shù)據(jù)落盤過程

Kafka Broker 收到信息后,如何落盤是通過 producer.type 來設(shè)定的,一般兩個值。

sync,默認(rèn)模式,數(shù)據(jù)必須最終落盤才算OK。

async,異步模式,數(shù)據(jù)刷新到OS的 Page Cache就返回,此時如果機(jī)器突然出問題,信息就丟失了。

4.4 消費(fèi)者從 Kafka Broker 消費(fèi)數(shù)據(jù)

為什么Kafka這么厲害

消費(fèi)數(shù)據(jù)

Consumer 是以 Consumer Group  消費(fèi)者組的方式工作,由一個或者多個消費(fèi)者組成一個組,共同消費(fèi)一個topic。每個分區(qū)在同一時間只能由group中的一個消費(fèi)者讀取,但是多個group可以同時消費(fèi)這個partition。如果一個消費(fèi)者失敗了,那么其他的  group 成員會自動負(fù)載均衡讀取之前失敗的消費(fèi)者讀取的分區(qū)。Consumer Group 從 Broker 拉取消息來消費(fèi)主要分為兩個階段:

獲得數(shù)據(jù),提交 Offset。

開始處理數(shù)據(jù)。

如果你先提交 offset 再處理數(shù)據(jù)可能在處理數(shù)據(jù)時出現(xiàn)異常導(dǎo)致數(shù)據(jù)丟失。而如果你先處理數(shù)據(jù)再提交 offset, 如果提交 offset  失敗可能導(dǎo)致信息重復(fù)消費(fèi)。

PS:

pull 模式不足之處是,如果 kafka 沒有數(shù)據(jù),消費(fèi)者可能會陷入循環(huán)中,一直返回空數(shù)據(jù)。針對這一點(diǎn),Kafka的消費(fèi)者在消費(fèi)數(shù)據(jù)時會傳入一個時長參數(shù)  timeout,如果當(dāng)前沒有數(shù)據(jù)可供消費(fèi),consumer會等待一段時間之后再返回,這段時長即為 timeout。

5 Kafka 分區(qū)分配策略

同一個 group.id 中的消費(fèi)者,對于一個 topic 中的多個 partition 中的消息消費(fèi),存在著一定的分區(qū)分配策略。

在 Kafka 中存在著兩種分區(qū)分配策略,通過 partition.assignment.strategy 來設(shè)置。

  • RangeAssignor 范圍分區(qū)策略,也是默認(rèn)模式。

  • RoundRobinAssignor 分配策略,輪詢分區(qū)模式。

5.1 RangeAssignor 范圍分區(qū)策略

Range 范圍分區(qū)策略是對每個 topic 而言的。首先對同一個 topic 里面的分區(qū)按照序號進(jìn)行排序,并對消費(fèi)者按照字母順序進(jìn)行排序。假如現(xiàn)在有  10 個分區(qū),3 個消費(fèi)者,排序后的分區(qū)將會是p0~p9。消費(fèi)者排序完之后將會是C1-0、C2-0、C3-0。通過 Partitions數(shù) /  Consumer數(shù) 來決定每個消費(fèi)者應(yīng)該消費(fèi)幾個分區(qū)。如果除不盡,那么前面幾個消費(fèi)者將會多消費(fèi) 1 個分區(qū)。

消費(fèi)者消費(fèi)的分區(qū)
C1-0消費(fèi) p0、1、2、3分區(qū)
C2-0消費(fèi) 4、5、6分區(qū)
C3-0消費(fèi) 7、8、9分區(qū)

Range 范圍分區(qū)的弊端:

如上只是針對 1 個 topic 而言,C1-0 消費(fèi)者多消費(fèi)1個分區(qū)影響不是很大。如果有 N 多個 topic,那么針對每個 topic,消費(fèi)者  C1-0 都將多消費(fèi) 1 個分區(qū),topic越多,C1-0 消費(fèi)的分區(qū)會比其他消費(fèi)者明顯多消費(fèi) N 個分區(qū)。這就是 Range  范圍分區(qū)的一個很明顯的弊端了.

5.2 RoundRobinAssignor 輪詢分區(qū)策略

RoundRobin 輪詢分區(qū)策略是把所有的 partition 和所有的 consumer 都列出來,然后按照 hascode  進(jìn)行排序,最后通過輪詢算法來分配 partition 給到各個消費(fèi)者。輪詢分區(qū)分為如下兩種情況:

  • 同一個 Consumer Group 內(nèi) Consumer 訂閱信息相同

  • 同一個 Consumer Group 內(nèi) Consumer 訂閱信息不相同

5.2.1 Consumer Group 內(nèi) Consumer 訂閱信息相同

如果同一消費(fèi)組內(nèi),所有的消費(fèi)者訂閱的消息都是相同的,那么 RoundRobin 策略的分區(qū)分配會是均勻的。

例如同一消費(fèi)者組中,有 3 個消費(fèi)者C0、C1和C2,都訂閱了 2 個主題 t0 和 t1,并且每個主題都有 3  個分區(qū)(p0、p1、p2),那么所訂閱的所以分區(qū)可以標(biāo)識為t0p0、t0p1、t0p2、t1p0、t1p1、t1p2。最終分區(qū)分配結(jié)果如下:

消費(fèi)者消費(fèi)的分區(qū)
C0消費(fèi) t0p0、t1p0 分區(qū)
C1消費(fèi) t0p1、t1p1 分區(qū)
C2消費(fèi) t0p2、t1p2 分區(qū)

5.2.1 Consumer Group 內(nèi) Consumer 訂閱信息不相同

同一消費(fèi)者組內(nèi),所訂閱的消息是不相同的,那么分區(qū)分配就不是完全的輪詢分配,有可能會導(dǎo)致分區(qū)分配的不均勻。如果某個消費(fèi)者沒有訂閱消費(fèi)組內(nèi)的某個  topic,那么在分配分區(qū)的時候,此消費(fèi)者將不會分配到這個 topic 的任何分區(qū)。

例如同一消費(fèi)者組中有3個消費(fèi)者C0、C1、C2,他們共訂閱了 3 個主題t0、t1、t2,這 3 個主題分別有 1、2、3  個分區(qū)(即t0有1個分區(qū)(p0),t1有2個分區(qū)(p0、p1),t2有3個分區(qū)(p0、p1、p2)),即整個消費(fèi)者所訂閱的所有分區(qū)可以標(biāo)識為  t0p0、t1p0、t1p1、t2p0、t2p1、t2p2。然后消費(fèi)者 C0  訂閱的是主題t0,消費(fèi)者C1訂閱的是主題t0和t1,消費(fèi)者C2訂閱的是主題t0、t1和t2,最終分區(qū)分配結(jié)果如下:

消費(fèi)者消費(fèi)的分區(qū)
C0消費(fèi) t0p0 分區(qū)
C1消費(fèi) t1p0 分區(qū)
C2消費(fèi) t1p1、 t2p0、 t2p1、 t2p2 分區(qū)

6 Kafka 高效讀寫

Kafka 可支持百萬 TPS 跟如下幾個特性有關(guān)。

6.1 順序讀寫數(shù)據(jù)

信息存儲在硬盤中,硬盤由很多盤片組成,顯微鏡觀察盤片會看見盤片表面凹凸不平,凸起的地方被磁化代表數(shù)字1,凹的地方是沒有被磁化代表數(shù)字0,因此硬盤可以以二進(jìn)制來存儲表示文字、圖片等信息。

為什么Kafka這么厲害

磁盤平面圖

上圖是硬盤的實(shí)際圖,可能無法理解內(nèi)部構(gòu)造,我們來看個形象的圖:

為什么Kafka這么厲害

磁盤內(nèi)部圖

  1. 系統(tǒng)通過磁頭從盤面讀取數(shù)據(jù),磁頭在盤面上的飛行高度只是人類頭發(fā)直徑的千分之一。

  2. 硬盤里的盤片跟CD光盤的長相類似,一個盤片有上下兩個盤面,每個盤面都可以存儲數(shù)據(jù)。

  3. 每個盤面會被劃分出超級多的同心圓磁道,同心圓的半徑是不同的。

  4. 所有磁盤上的同一磁道構(gòu)成一個柱面,相同磁道的同一個扇區(qū)被稱為簇。數(shù)據(jù)的讀寫按照柱面從上到下進(jìn)行,一個柱面寫滿后,才移到下一個扇區(qū)開始寫數(shù)據(jù)。

  5. 一個磁道是被劃分成一段段的圓弧(扇區(qū)),每個扇區(qū)用來存儲 512個字節(jié)跟其他信息。由于同心圓的扇區(qū)弧度相同而半徑不同所以外圈線速度比內(nèi)圈線速度大。

  6. 系統(tǒng)每次讀取一個扇區(qū)效率太低,所以操作系統(tǒng)是按照block來進(jìn)行讀取數(shù)據(jù)的,一個block(塊)一般有多個扇區(qū)組成。在每塊的大小是 4~64KB。

  7. 頁page,默認(rèn)4KB,操作系統(tǒng)經(jīng)常與內(nèi)存和硬盤這兩種存儲設(shè)備進(jìn)行通信,類似于塊的概念,都需要一種虛擬的基本單位。所以與內(nèi)存操作,是虛擬一個頁的概念來作為最小單位。與硬盤打交道,就是以塊為最小單位。

扇區(qū):硬盤的最小讀寫單元

塊/簇:是操作系統(tǒng)針對硬盤讀寫的最小單元

page:是內(nèi)存與操作系統(tǒng)之間操作的最小單元。

一次訪盤的讀/寫請求完成過程由三個動作組成:

  1. 尋道:磁頭從開始移動到數(shù)據(jù)所在磁道所需要的時間,平均10ms左右。

  2. 旋轉(zhuǎn)延遲:盤片旋轉(zhuǎn)將請求數(shù)據(jù)所在扇區(qū)移至讀寫磁頭下方所需要的時間,旋轉(zhuǎn)延遲取決于磁盤轉(zhuǎn)速。如果是 5400 轉(zhuǎn)每分鐘的磁盤,平均大概為 5 ms。

  3. 數(shù)據(jù)傳輸:磁頭位從目標(biāo)扇區(qū)第一個位置,到訪問完所有數(shù)據(jù)的耗時。假如5400轉(zhuǎn)的磁道有400個扇區(qū),我只訪問一個則耗時 0.0278ms。

可以發(fā)現(xiàn)讀取主要耗時是在前兩個,如果我順序讀取則尋道跟旋轉(zhuǎn)延遲只用一次即可。而如果隨機(jī)讀取呢則可能經(jīng)歷多次尋道跟旋轉(zhuǎn)延遲,兩者相差幾乎  3個數(shù)量級。

為什么Kafka這么厲害

隨機(jī)跟順序讀寫在磁盤跟內(nèi)存中

6.2 Memory Mapped Files 內(nèi)存映射文件

  1. 虛擬內(nèi)存系統(tǒng) 通過將虛擬內(nèi)存分割為稱作虛擬頁(Virtual  Page,VP)大小固定的塊,一般情況下,每個虛擬頁的大小默認(rèn)是4KB。同樣的,物理內(nèi)存也被分割為物理頁(Physical  Page,PP),也為4KB。

  2. 服務(wù)器可直接用 操作系統(tǒng)的 Page  來實(shí)現(xiàn)物理內(nèi)存到文件的映射,用戶操作讀寫數(shù)據(jù)會直接到Page中,操作系統(tǒng)會根據(jù)映射自動的將對物理內(nèi)存的操作同步到硬盤上。實(shí)現(xiàn)類似順序讀寫內(nèi)存的功能。

  3. 缺點(diǎn)在Broker信息落盤時候也說了,落的不是真正磁盤可能導(dǎo)致數(shù)據(jù)丟失。

為什么Kafka這么厲害

內(nèi)存映射

6.3 Zero Copy

6.3.1 直接內(nèi)存存取 DMA

CPU 發(fā)出指令操作 IO 來進(jìn)行讀寫操作,大部分情況下其實(shí)只是把數(shù)據(jù)讀取到內(nèi)存,然后從內(nèi)存?zhèn)鞯絀O即可,所以數(shù)據(jù)其實(shí)可以不經(jīng)過CPU的。

Direct Memory Access 的出現(xiàn)就是為批量數(shù)據(jù)的輸入/輸出而提速的。DMA  是指外部設(shè)備不通過CPU而直接與系統(tǒng)內(nèi)存交換數(shù)據(jù)的接口技術(shù)。這樣數(shù)據(jù)的傳送速度就取決于存儲器和外設(shè)的工作速度。

如果數(shù)據(jù)傳輸?shù)臅r候只用到了 DMA 傳輸而沒經(jīng)過 CPU 復(fù)制數(shù)據(jù),則我們稱之為零拷貝 Zero Copy。用了 Zero Copy  技術(shù)耗時性能起碼減半。

6.3.2 Kafka 讀寫對比

為什么Kafka這么厲害

零拷貝

如上黑色流程是沒用 Zero Copy 技術(shù)流程:

  1. DMA傳輸,磁盤讀取數(shù)據(jù)到操作系統(tǒng)內(nèi)存 Page Cache 區(qū)。

  2. CPU搬運(yùn),數(shù)據(jù)從 Page Cache 區(qū)數(shù)據(jù)復(fù)制到用戶內(nèi)存區(qū)。

  3. CPU搬運(yùn),數(shù)據(jù)從用戶內(nèi)存區(qū)到 Socket Cache 區(qū)。

  4. DMA傳輸,數(shù)據(jù)從 Socket Cache 區(qū)傳輸?shù)?NIC網(wǎng)卡緩存區(qū)。

紅色流程是用 Zero Copy 技術(shù)流程:

  1. DMA傳輸,磁盤讀取數(shù)據(jù)到操作系統(tǒng)內(nèi)存 Page Cache 區(qū)。

  2. DMA傳輸,數(shù)據(jù)從 系統(tǒng)內(nèi)存 Page Cache 區(qū)傳輸?shù)?NIC網(wǎng)卡緩存區(qū)。

6.4 Batch Deal

消費(fèi)者拉取數(shù)據(jù)的時候,Kafka  不是一個一個的來送數(shù)據(jù)的,而是批量發(fā)送來處理的,這樣可以節(jié)省網(wǎng)絡(luò)傳輸,增大系統(tǒng)的TPS,不過也有個缺點(diǎn)就是,我們的數(shù)據(jù)不是真正的實(shí)時處理的,而真正的實(shí)時還是要看  Flink。

感謝各位的閱讀,以上就是“為什么Kafka這么厲害”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對為什么Kafka這么厲害這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI