1.1 Kafka 概述
Kafka架構(gòu)
Kafka 是一個 分布式的基于 發(fā)布/訂閱模式的消息隊列,依靠其強悍的吞吐量,Kafka 主要應用于大數(shù)據(jù)實時處理領(lǐng)域。在數(shù)據(jù)采集、傳輸、存儲的過程中發(fā)揮著舉足輕重的作用。
-
Apache Kafka 由 Scala 寫成,是由Apache軟件基金會開發(fā)的一個開源消息系統(tǒng)項目。該項目的目標是為處理實時數(shù)據(jù)提供一個統(tǒng)一、高通量、低等待的平臺。
-
Kafka 是一個分布式消息隊列,Kafka 對消息保存時根據(jù) Topic 進行歸類,Kafka 集群有多個 Kafka實例組成,每個實例 Server 稱為 broker。
-
無論是 Kafka 集群還是 Consumer 都依賴于 ZooKeeper 集群保存一些 meta 信息,來保證系統(tǒng)可用性
1.2 Kafka 優(yōu)點
-
支持多個生產(chǎn)者和消費者。
-
支持broker的橫向拓展。
-
副本集機制,實現(xiàn)數(shù)據(jù)冗余,保證數(shù)據(jù)不丟失。
-
通過 topic 將數(shù)據(jù)進行分類。
-
通過分批發(fā)送壓縮數(shù)據(jù)的方式,減少數(shù)據(jù)傳輸開銷,提高吞高量。
-
支持多種模式的消息,消息是基于磁盤實現(xiàn)數(shù)據(jù)的持久化。
-
高性能的處理信息,在大數(shù)據(jù)的情況下,可以保證亞秒級的消息延遲。
-
一個消費者可以支持多種 topic 的消息。
-
對CPU、內(nèi)存、網(wǎng)絡的消耗比較小。
-
支持跨數(shù)據(jù)中心的數(shù)據(jù)復制跟鏡像集群。
1.3 Kafka 缺點
-
由于是批量發(fā)送,所以數(shù)據(jù)達不到真正的實時。
-
只能支持統(tǒng)一分區(qū)內(nèi)消息有序,無法實現(xiàn)全局消息有序。
-
監(jiān)控不完善,需要安裝插件。
-
會丟失數(shù)據(jù),并且不支持事務。
-
可能會重復消費數(shù)據(jù),消息會亂序,可用保證一個固定的partition內(nèi)部的消息是有序的,但是一個topic有多個partition的話,就不能保證有序了,需要zookeeper的支持,topic一般需要人工創(chuàng)建,部署和維護一般都比mq高。
1.4 Kafka 架構(gòu)
-
Broker:一臺 kafka 服務器就是一個broker。一個集群由多個broker組成。一個broker可以容納多個topic。
-
Producer :消息生產(chǎn)者,就是向 Kafka broker 發(fā)消息的客戶端。
-
Consumer :消息消費者,向 Kafka broker 拉取消息來消費??梢愿鶕?jù) Consumer 的消費能力以適當?shù)乃俾氏M消息。
-
Topic :可以理解為一個隊列,生產(chǎn)者和消費者面向的都是一個topic。
-
Partition:為了實現(xiàn)擴展性,一個非常大的 topic 可以分布到多個broker上,一個 topic 可以分為多個partition,每個 partition 是一個有序的隊列,有點平衡分攤生產(chǎn)者機制。
-
Replication:為保證集群中的某個節(jié)點發(fā)生故障時,該節(jié)點上的partition數(shù)據(jù)不丟失,且kafka仍然能夠繼續(xù)工作,kafka提供了副本機制,一個topic的每個分區(qū)都有若干個副本,一個leader和若干個follower。
-
leader:一個分區(qū)有一個Leader,生產(chǎn)者發(fā)送數(shù)據(jù)的對象,以及消費者消費數(shù)據(jù)的對象都是leader。
-
follower:一個分區(qū)有一個Follower,實時從 leader 中同步數(shù)據(jù),保持和 leader 數(shù)據(jù)的同步。leader 發(fā)生故障時,某個 follower 會成為新的 follower。注意Kafka中 副本數(shù)不能超過Broker數(shù)!
-
Consumer Group :消費者組由多個 consumer 組成。組內(nèi)每個消費者負責消費不同分區(qū)的數(shù)據(jù),一個分區(qū)只能由一個組內(nèi)消費者消費;消費者組之間互不影響。所有的消費者都屬于某個消費者組,即消費者組是邏輯上的一個訂閱者。
-
offset:消費者在具體消費某個 topic 中的消息時,可以指定起始偏移量。
1.5 ZooKeeper 作用
ZooKeeper 在 Kafka 中有舉足輕重的地位,一般提供如下功能:
1.5.1 Broker 注冊
Broker 是分布式部署并且相互之間相互獨立,但是需要有一個注冊系統(tǒng)能夠?qū)⒄麄€集群中的Broker管理起來,比如用ZooKeeper。
1.5.2 Topic注冊
在 Kafka 中同一個 Topic 的消息會被分成多個 Partition 并將其分布在多個 Broker 上,這些 Partition 信息及與 Broker 的對應關(guān)系也都是由 Zookeeper 在維護,由專門的節(jié)點來記錄。
1.5.3 生產(chǎn)者負載均衡
同一個Topic消息會被分區(qū)并將其分布在多個Broker上,因此,生產(chǎn)者需要將消息合理地發(fā)送到這些分布式的Broker上。
-
老式的四層負載均衡,根據(jù)生產(chǎn)者的IP地址和端口來為其確定一個相關(guān)聯(lián)的Broker。一般一個生產(chǎn)者只會對應單個Broker,但實際系統(tǒng)中的每個生產(chǎn)者產(chǎn)生的消息量及每個Broker的消息存儲量都是不一樣的。
-
使用 Zookeeper 進行負載均衡,由于每個Broker啟動時,都會完成Broker注冊過程,生產(chǎn)者會通過該節(jié)點的變化來動態(tài)地感知到Broker服務器列表的變更,這樣就可以實現(xiàn)動態(tài)的負載均衡機制。
1.5.4 消費者負載均衡
Kafka 中的消費者同樣需要進行負載均衡來實現(xiàn)多個消費者合理地從對應的 Broker 服務器上接收消息,每個消費者分組包含若干消費者,每條消息都只會發(fā)送給分組中的一個消費者,不同的消費者分組消費自己特定的Topic下面的消息,互不干擾。
1.5.5 分區(qū) 與 消費者 的關(guān)系
Kafka 會為每個 Consumer Group 分配個全局唯一 Group ID,Group 內(nèi)的 Consumer 共享該 ID,Kafka規(guī)定 每個partition信息只能被同組的一個Consumer 消費,在Zk中記錄partition 跟 Consumer關(guān)系,每個消費者一旦確定了對一個消息分區(qū)的消費權(quán)力,需要將其Consumer ID 寫入到 Zookeeper 對應消息分區(qū)的臨時節(jié)點上。
1.5.6 消息消費進度 Offset 記錄
Consumer 對指定消息分區(qū)進行消費的過程中,需要定時地將分區(qū)消息的消費進度 Offset 記錄到 Zookeeper 上,以便在該 Consumer 進行重啟或者其他 Consumer 重新接管該消息分區(qū)的消息消費后,能夠從之前的進度開始繼續(xù)進行消息消費。
1.5 7 消費者注冊
為讓同一個 Topic 下不同分區(qū)的消息盡量均衡地被多個 Consumer 消費而進行 Consumer 與消息分區(qū)分配的過程。
-
Consumer 啟動后在ZK下創(chuàng)建個節(jié)點,并且每個 Consumer 會對 Consumer Group 中的 Consumer 的變化注冊監(jiān)聽,目的是為了保證 Consumer 負載均衡。
-
Consumer 會對Broker列表監(jiān)聽,發(fā)生變化會進行 Consumer 負載均衡。
2 Kafka 生成過程
2.1 寫入方式
producer采用 push 模式將消息發(fā)布到 broker,每條消息都被 append 到 patition 中,屬于 順序?qū)懘疟P ,順序?qū)懕入S機寫要起碼提速3個數(shù)量級!
2.2 分區(qū) Partition
2.2.1 Partition 簡介
消息發(fā)送時都被發(fā)送到一個topic,其本質(zhì)就是一個目錄,而topic是由一些 分區(qū)日志 Partition Logs 組成,其組織結(jié)構(gòu)如下圖所示:
Partition發(fā)生
可以看到每個 Partition 中的消息都是有序的,生產(chǎn)的消息被不斷追加到 Partition log 上,其中的每一個消息都被賦予了一個唯一的 offset 值。
消費者
通過分區(qū)可以 方便在集群中擴展,可以提高并發(fā)。
形象理解:
Kafka 的設計源自生活,好比為公路運輸,不同的起始點和目的地需要修不同高速公路(主題),高速公路上可以提供多條車道(分區(qū)),流量大的公路(主題)多修幾條車道(分區(qū))保證暢通,流量小的公路少修幾條車道避免浪費。收費站好比消費者,車多的時候多開幾個一起收費避免堵在路上,車少的時候開幾個讓汽車并道就好了。
2.2.2 分區(qū)原則
我們需要將producer發(fā)送的數(shù)據(jù)封裝成一個ProducerRecord對象。
數(shù)據(jù)封裝
-
指明 partition 的情況下,直接將指明的值直接作為 partiton 值。
-
沒有指明 partition 值但有 key 的情況下,將 key 的 hash 值與 topic 的 partition 數(shù)進行取余得到 partition 值。
-
既沒有 partition 值又沒有 key 值的情況下,第一次調(diào)用時隨機生成一個整數(shù)(后面每次調(diào)用在這個整數(shù)上自增),將這個值與 topic 可用的 partition 總數(shù)取余得到 partition 值,也就是常說的 round-robin 算法。
2.3 Kafka 文件存儲機制
Kafka存儲結(jié)構(gòu)
-
Kafka 中消息是以 topic 進行分類的,生產(chǎn)者跟消費者都是面向 topic 的,topic 只是邏輯上的概念,而 Partition 是物理上的概念,每個 Partition 對應個 log 文件,每個分區(qū)用.index`存放數(shù)據(jù)索引,`.log存儲數(shù)據(jù)。index文件中的元數(shù)據(jù)指向?qū)猯og文件中Message的物理偏移地址(參考 kaldi、Neo4j)。
-
為防止 log 文件過大導致數(shù)據(jù)定位效率低下,Kafka采取了分片和索引機制,將每個partition分為多個segment。每個 segment 對應.index`跟`.log。這些文件位于一個文件夾下,該文件夾的命名規(guī)則為:topic名稱 + 分區(qū)序號。例如 first 這個 topic 有三個分區(qū),則其對應的文件夾為first-0、first-1、first-2。
100000000000000000000.index 200000000000000000000.log 300000000000000170410.index 400000000000000170410.log 500000000000000239430.index 600000000000000239430.log
注意:index 和 log 文件以當前segment的第一條消息的 offset 命名。
數(shù)據(jù)查找過程
2.4 如何保證消息順序執(zhí)行
2.4.1 順序錯亂
-
Kafka 一個 topic,一個 partition,一個 Consumer,但是 Consumer 內(nèi)部進行多線程消費,這樣數(shù)據(jù)也會出現(xiàn)順序錯亂問題。
- 多線程消費
-
數(shù)據(jù)有順序的數(shù)據(jù)寫入到了不同的 partition 里面,不同的消費者去消費,但是每個 Consumer 的執(zhí)行時間是不固定的,無法保證先讀到消息的 Consumer 一定先完成操作,這樣就會出現(xiàn)消息并沒有按照順序執(zhí)行,造成數(shù)據(jù)順序錯誤。
多個消費者
2.4.2 解決辦法
-
確保同一個消息發(fā)送到同一個 partition,一個topic,一個partition,一個consumer,內(nèi)部單線程消費。
寫入同一個Partition的信息一定有序。
給信息指定一個key,key相同則一定寫入同一個partition。
從同一個Partition讀取信息一定有序。
單線程消費
-
在1的基礎上,在一個 Consumer 上根據(jù)信息ID映射到不同隊列,以此加速消費。
內(nèi)存隊列
4 數(shù)據(jù)可靠性
4.1 消息傳遞語義
消息傳遞語義 message delivery semantic ,Kafka 為確保消息在 producer 和 consumer 之間傳輸。有以下三種傳輸保障(delivery guarantee):
-
at most once:最多一次,消息可能會丟,但絕不會重復傳輸。
-
at least once:至少一次,消息絕不會丟,但可能會重復傳輸。
-
exactly once:精確傳遞一次。消息被處理且只會被處理一次。不丟失不重復就一次。
理想情況下肯定希望系統(tǒng)的消息傳遞是嚴格 exactly once,但很難做到。接下來會按照 消息的傳播流程大致說下。
4.2 信息從生產(chǎn)者到 Broker
4.2.1 生產(chǎn)者信息發(fā)送至Broker
大致步驟如下:
-
producer 從 ZK 找到目標 Partition 的 Leader 元數(shù)據(jù)。
-
producer 發(fā)送消息給 Leader。
-
Leader 接受消息持久化,然后根據(jù)acks配置選擇如何同步Follower。
-
Followder 按照前面說的同步數(shù)據(jù)后給Leader回復ack。
-
Leader 跟 Follower 同步完畢后 Leader 給 producer 回復 ack。
對于Leader回復 ack,Kafka 為用戶提供了三種可靠性級別,用戶根據(jù)對可靠性和延遲的要求進行權(quán)衡。
-
request.required.acks = 0
producer不等待broker 的ack,提供了一個最低的延遲,broker接收到還沒有寫入磁盤就已經(jīng)返回,當broker故障時有可能丟失數(shù)據(jù),對應 At Most Once 模式。
但凡沒落盤成功信息就丟失了,一般生產(chǎn)不用。
-
request.required.acks = 1
此乃默認值,producer 等待 broker 的 ack,partition 的leader落盤成功后返回ack,如果在follower同步成功之前l(fā)eader故障,那么將會丟失數(shù)據(jù);認為leader返回 信息就成功了。
-
request.required.acks = -1 / all
producer 等待 broker 的 ack,partition 的 leader 和 follower (ISR中的)全部落盤成功后才返回 ack。
但如果在 leader 收到信息返回ok,follower 收到信息但是發(fā)送 ack 時 leader 故障,此時生產(chǎn)者會重新給follower 發(fā)送個信息。
對應 At Least Once 模式。
4.2.2 如何保證冪等性
如果業(yè)務需要數(shù)據(jù) Exactly Once,在早期的 Kafka 版本中 只能在下游去重,現(xiàn)在引入了個冪等性,意思就是無論生產(chǎn)者發(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 信息落磁盤
數(shù)據(jù)落盤過程
Kafka Broker 收到信息后,如何落盤是通過 producer.type 來設定的,一般兩個值。
-
sync,默認模式,數(shù)據(jù)必須最終落盤才算OK。
-
async,異步模式,數(shù)據(jù)刷新到OS的 Page Cache就返回,此時如果機器突然出問題,信息就丟失了。
4.4 消費者從 Kafka Broker 消費數(shù)據(jù)
消費數(shù)據(jù)
Consumer 是以 Consumer Group 消費者組的方式工作,由一個或者多個消費者組成一個組,共同消費一個topic。每個分區(qū)在同一時間只能由group中的一個消費者讀取,但是多個group可以同時消費這個partition。如果一個消費者失敗了,那么其他的 group 成員會自動負載均衡讀取之前失敗的消費者讀取的分區(qū)。Consumer Group 從 Broker 拉取消息來消費主要分為兩個階段:
-
獲得數(shù)據(jù),提交 Offset。
-
開始處理數(shù)據(jù)。
如果你先提交 offset 再處理數(shù)據(jù)可能在處理數(shù)據(jù)時出現(xiàn)異常導致數(shù)據(jù)丟失。而如果你先處理數(shù)據(jù)再提交 offset, 如果提交 offset 失敗可能導致信息重復消費。
PS:
pull 模式不足之處是,如果 kafka 沒有數(shù)據(jù),消費者可能會陷入循環(huán)中,一直返回空數(shù)據(jù)。針對這一點,Kafka的消費者在消費數(shù)據(jù)時會傳入一個時長參數(shù) timeout,如果當前沒有數(shù)據(jù)可供消費,consumer會等待一段時間之后再返回,這段時長即為 timeout。
5 Kafka 分區(qū)分配策略
同一個 group.id 中的消費者,對于一個 topic 中的多個 partition 中的消息消費,存在著一定的分區(qū)分配策略。
在 Kafka 中存在著兩種分區(qū)分配策略,通過 partition.assignment.strategy 來設置。
-
RangeAssignor 范圍分區(qū)策略,也是默認模式。
-
RoundRobinAssignor 分配策略,輪詢分區(qū)模式。
5.1 RangeAssignor 范圍分區(qū)策略
Range 范圍分區(qū)策略是對每個 topic 而言的。首先對同一個 topic 里面的分區(qū)按照序號進行排序,并對消費者按照字母順序進行排序。假如現(xiàn)在有 10 個分區(qū),3 個消費者,排序后的分區(qū)將會是p0~p9。消費者排序完之后將會是C1-0、C2-0、C3-0。通過 Partitions數(shù) / Consumer數(shù) 來決定每個消費者應該消費幾個分區(qū)。如果除不盡,那么前面幾個消費者將會多消費 1 個分區(qū)。
消費者 | 消費的分區(qū) |
---|---|
C1-0 | 消費 p0、1、2、3分區(qū) |
C2-0 | 消費 4、5、6分區(qū) |
C3-0 | 消費 7、8、9分區(qū) |
Range 范圍分區(qū)的弊端:
如上只是針對 1 個 topic 而言,C1-0 消費者多消費1個分區(qū)影響不是很大。如果有 N 多個 topic,那么針對每個 topic,消費者 C1-0 都將多消費 1 個分區(qū),topic越多,C1-0 消費的分區(qū)會比其他消費者明顯多消費 N 個分區(qū)。這就是 Range 范圍分區(qū)的一個很明顯的弊端了.
5.2 RoundRobinAssignor 輪詢分區(qū)策略
RoundRobin 輪詢分區(qū)策略是把所有的 partition 和所有的 consumer 都列出來,然后按照 hascode 進行排序,最后通過輪詢算法來分配 partition 給到各個消費者。輪詢分區(qū)分為如下兩種情況:
-
同一個 Consumer Group 內(nèi) Consumer 訂閱信息相同
-
同一個 Consumer Group 內(nèi) Consumer 訂閱信息不相同
5.2.1 Consumer Group 內(nèi) Consumer 訂閱信息相同
如果同一消費組內(nèi),所有的消費者訂閱的消息都是相同的,那么 RoundRobin 策略的分區(qū)分配會是均勻的。
例如同一消費者組中,有 3 個消費者C0、C1和C2,都訂閱了 2 個主題 t0 和 t1,并且每個主題都有 3 個分區(qū)(p0、p1、p2),那么所訂閱的所以分區(qū)可以標識為t0p0、t0p1、t0p2、t1p0、t1p1、t1p2。最終分區(qū)分配結(jié)果如下:
消費者 | 消費的分區(qū) |
---|---|
C0 | 消費 t0p0、t1p0 分區(qū) |
C1 | 消費 t0p1、t1p1 分區(qū) |
C2 | 消費 t0p2、t1p2 分區(qū) |
5.2.1 Consumer Group 內(nèi) Consumer 訂閱信息不相同
同一消費者組內(nèi),所訂閱的消息是不相同的,那么分區(qū)分配就不是完全的輪詢分配,有可能會導致分區(qū)分配的不均勻。如果某個消費者沒有訂閱消費組內(nèi)的某個 topic,那么在分配分區(qū)的時候,此消費者將不會分配到這個 topic 的任何分區(qū)。
例如同一消費者組中有3個消費者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)),即整個消費者所訂閱的所有分區(qū)可以標識為 t0p0、t1p0、t1p1、t2p0、t2p1、t2p2。然后消費者 C0 訂閱的是主題t0,消費者C1訂閱的是主題t0和t1,消費者C2訂閱的是主題t0、t1和t2,最終分區(qū)分配結(jié)果如下:
消費者 | 消費的分區(qū) |
---|---|
C0 | 消費 t0p0 分區(qū) |
C1 | 消費 t1p0 分區(qū) |
C2 | 消費 t1p1、 t2p0、 t2p1、 t2p2 分區(qū) |
6 Kafka 高效讀寫
Kafka 可支持百萬 TPS 跟如下幾個特性有關(guān)。
6.1 順序讀寫數(shù)據(jù)
信息存儲在硬盤中,硬盤由很多盤片組成,顯微鏡觀察盤片會看見盤片表面凹凸不平,凸起的地方被磁化代表數(shù)字1,凹的地方是沒有被磁化代表數(shù)字0,因此硬盤可以以二進制來存儲表示文字、圖片等信息。
磁盤平面圖
上圖是硬盤的實際圖,可能無法理解內(nèi)部構(gòu)造,我們來看個形象的圖:
磁盤內(nèi)部圖
-
系統(tǒng)通過磁頭從盤面讀取數(shù)據(jù),磁頭在盤面上的飛行高度只是人類頭發(fā)直徑的千分之一。
-
硬盤里的盤片跟CD光盤的長相類似,一個盤片有上下兩個盤面,每個盤面都可以存儲數(shù)據(jù)。
-
每個盤面會被劃分出超級多的同心圓磁道,同心圓的半徑是不同的。
-
所有磁盤上的同一磁道構(gòu)成一個柱面,相同磁道的同一個扇區(qū)被稱為簇。數(shù)據(jù)的讀寫按照柱面從上到下進行,一個柱面寫滿后,才移到下一個扇區(qū)開始寫數(shù)據(jù)。
-
一個磁道是被劃分成一段段的圓弧(扇區(qū)),每個扇區(qū)用來存儲 512個字節(jié)跟其他信息。由于同心圓的扇區(qū)弧度相同而半徑不同所以外圈線速度比內(nèi)圈線速度大。
-
系統(tǒng)每次讀取一個扇區(qū)效率太低,所以操作系統(tǒng)是按照block來進行讀取數(shù)據(jù)的,一個block(塊)一般有多個扇區(qū)組成。在每塊的大小是 4~64KB。
-
頁page,默認4KB,操作系統(tǒng)經(jīng)常與內(nèi)存和硬盤這兩種存儲設備進行通信,類似于塊的概念,都需要一種虛擬的基本單位。所以與內(nèi)存操作,是虛擬一個頁的概念來作為最小單位。與硬盤打交道,就是以塊為最小單位。
扇區(qū):硬盤的最小讀寫單元
塊/簇:是操作系統(tǒng)針對硬盤讀寫的最小單元
page:是內(nèi)存與操作系統(tǒng)之間操作的最小單元。
一次訪盤的讀/寫請求完成過程由三個動作組成:
-
尋道:磁頭從開始移動到數(shù)據(jù)所在磁道所需要的時間,平均10ms左右。
-
旋轉(zhuǎn)延遲:盤片旋轉(zhuǎn)將請求數(shù)據(jù)所在扇區(qū)移至讀寫磁頭下方所需要的時間,旋轉(zhuǎn)延遲取決于磁盤轉(zhuǎn)速。如果是 5400 轉(zhuǎn)每分鐘的磁盤,平均大概為 5 ms。
-
數(shù)據(jù)傳輸:磁頭位從目標扇區(qū)第一個位置,到訪問完所有數(shù)據(jù)的耗時。假如5400轉(zhuǎn)的磁道有400個扇區(qū),我只訪問一個則耗時 0.0278ms。
可以發(fā)現(xiàn)讀取主要耗時是在前兩個,如果我順序讀取則尋道跟旋轉(zhuǎn)延遲只用一次即可。而如果隨機讀取呢則可能經(jīng)歷多次尋道跟旋轉(zhuǎn)延遲,兩者相差幾乎 3個數(shù)量級。
隨機跟順序讀寫在磁盤跟內(nèi)存中
6.2 Memory Mapped Files 內(nèi)存映射文件
-
虛擬內(nèi)存系統(tǒng) 通過將虛擬內(nèi)存分割為稱作虛擬頁(Virtual Page,VP)大小固定的塊,一般情況下,每個虛擬頁的大小默認是4KB。同樣的,物理內(nèi)存也被分割為物理頁(Physical Page,PP),也為4KB。
-
服務器可直接用 操作系統(tǒng)的 Page 來實現(xiàn)物理內(nèi)存到文件的映射,用戶操作讀寫數(shù)據(jù)會直接到Page中,操作系統(tǒng)會根據(jù)映射自動的將對物理內(nèi)存的操作同步到硬盤上。實現(xiàn)類似順序讀寫內(nèi)存的功能。
-
缺點在Broker信息落盤時候也說了,落的不是真正磁盤可能導致數(shù)據(jù)丟失。
內(nèi)存映射
6.3 Zero Copy
6.3.1 直接內(nèi)存存取 DMA
CPU 發(fā)出指令操作 IO 來進行讀寫操作,大部分情況下其實只是把數(shù)據(jù)讀取到內(nèi)存,然后從內(nèi)存?zhèn)鞯絀O即可,所以數(shù)據(jù)其實可以不經(jīng)過CPU的。
Direct Memory Access的出現(xiàn)就是為批量數(shù)據(jù)的輸入/輸出而提速的。DMA 是指外部設備不通過CPU而直接與系統(tǒng)內(nèi)存交換數(shù)據(jù)的接口技術(shù)。這樣數(shù)據(jù)的傳送速度就取決于存儲器和外設的工作速度。
如果數(shù)據(jù)傳輸?shù)臅r候只用到了 DMA 傳輸而沒經(jīng)過 CPU 復制數(shù)據(jù),則我們稱之為零拷貝 Zero Copy。用了 Zero Copy 技術(shù)耗時性能起碼減半。
6.3.2 Kafka 讀寫對比
零拷貝
如上黑色流程是沒用Zero Copy技術(shù)流程:
-
DMA傳輸,磁盤讀取數(shù)據(jù)到操作系統(tǒng)內(nèi)存 Page Cache 區(qū)。
-
CPU搬運,數(shù)據(jù)從 Page Cache 區(qū)數(shù)據(jù)復制到用戶內(nèi)存區(qū)。
-
CPU搬運,數(shù)據(jù)從用戶內(nèi)存區(qū)到 Socket Cache 區(qū)。
-
DMA傳輸,數(shù)據(jù)從 Socket Cache 區(qū)傳輸?shù)?NIC網(wǎng)卡緩存區(qū)。
紅色流程是用Zero Copy技術(shù)流程:
-
DMA傳輸,磁盤讀取數(shù)據(jù)到操作系統(tǒng)內(nèi)存 Page Cache 區(qū)。
-
DMA傳輸,數(shù)據(jù)從 系統(tǒng)內(nèi)存 Page Cache 區(qū)傳輸?shù)?NIC網(wǎng)卡緩存區(qū)。
6.4 Batch Deal
消費者拉取數(shù)據(jù)的時候,Kafka 不是一個一個的來送數(shù)據(jù)的,而是批量發(fā)送來處理的,這樣可以節(jié)省網(wǎng)絡傳輸,增大系統(tǒng)的TPS,不過也有個缺點就是,我們的數(shù)據(jù)不是真正的實時處理的,而真正的實時還是要看Flink。
7 參考
Kafka 為什么要分區(qū) :https://www.zhihu.com/question/28925721
關(guān)于磁盤讀?。篽ttps://blog.csdn.net/holybin/article/details/21175781
Kafka百萬TPS:https://mp.weixin.qq.com/s/Fb1cW0oN7xYeb1oI2ixtgQ
免責聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!