自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

《吃透 MQ 系列》之 Kafka 存儲選型的奧秘

存儲 存儲軟件 Kafka
從這篇文章開始,我將從微觀角度切入,深入分析 Kafka 的設(shè)計(jì)原理。本文要講的是 Kafka 最具代表性的:存儲設(shè)計(jì)。

[[405722]]

大家好,我是武哥。這是《吃透 MQ 系列》之 Kafka 的第 3 篇,錯(cuò)過前兩篇文章的,建議再溫習(xí)下:

扒開 Kafka 的神秘面紗

Kafka 架構(gòu)設(shè)計(jì)的任督二脈

從這篇文章開始,我將從微觀角度切入,深入分析 Kafka 的設(shè)計(jì)原理。本文要講的是 Kafka 最具代表性的:存儲設(shè)計(jì)。

談到 Kafka 的存儲設(shè)計(jì),了解不多的同學(xué),可能會有這樣的疑惑:為什么 Kafka 會采用 Logging(日志文件)這種很原始的方式來存儲消息,而沒考慮用數(shù)據(jù)庫或者 KV 來做存儲?

而對 Kafka 有所了解的同學(xué),應(yīng)該能快速說出一些 知識點(diǎn):比如 Append Only、Linear Scans、磁盤順序?qū)?、頁緩存、零拷貝、稀疏索引、二分查找等等?/p>

我計(jì)劃寫兩篇文章,除了解釋清楚上面的疑惑,同時(shí)還會給出一個(gè)脈絡(luò),幫助大家迅速切中 Kafka 存儲設(shè)計(jì)的要點(diǎn),然后將上面這些零散的知識點(diǎn)串聯(lián)起來。

此外,也希望大家在了解了 Kafka 的存儲設(shè)計(jì)后,能對 Append Only Data Structures 這一經(jīng)典的底層存儲原理認(rèn)識更加深刻,因?yàn)樗?qū)動了業(yè)界太多極具影響力的存儲系統(tǒng)走向成功,比如 HBase、Cassandra、RocksDB 等等。

1. Kafka 的存儲難點(diǎn)是什么?

為什么說存儲設(shè)計(jì)是 Kafka 的精華所在?之前這篇文章做過分析,Kafka 通過簡化消息模型,將自己退化成了一個(gè)海量消息的存儲系統(tǒng)。

既然 Kafka 在其他功能特性上做了減法,必然會在存儲上下功夫,做到其他 MQ 無法企及的性能表現(xiàn)。

圖1:Kafka 的消息模型

但是在講解 Kafka 的存儲方案之前,我們有必要去嘗試分析下:為什么 Kafka 會采用 Logging(日志文件)的存儲方式?它的選型依據(jù)到底是什么?

這也是本系列希望做到的,思考力勝過記憶力,多問 why,而不是死記 what。

Kafka 的存儲選型邏輯,我認(rèn)為跟我們開發(fā)業(yè)務(wù)需求的思路類似,到底用 MySQL、Redis 還是其他存儲方案?一定取決于具體的業(yè)務(wù)場景。

我們試著從以下兩個(gè)維度來分析下:

1、功能性需求:存的是什么數(shù)據(jù)?量級如何?需要存多久?CRUD 的場景都有哪些?

2、非功能性需求:性能和穩(wěn)定性的要求是什么樣的?是否要考慮擴(kuò)展性?

再回到 Kafka 來看,它的功能性需求至少包括以下幾點(diǎn):

1、存的數(shù)據(jù)主要是消息流:消息可以是最簡單的文本字符串,也可以是自定義的復(fù)雜格式。

但是對于 Broker 來說,它只需處理好消息的投遞即可,無需關(guān)注消息內(nèi)容本身。

2、數(shù)據(jù)量級非常大:因?yàn)?Kafka 作為 Linkedin 的孵化項(xiàng)目誕生,用作實(shí)時(shí)日志流處理(運(yùn)營活動中的埋點(diǎn)、運(yùn)維監(jiān)控指標(biāo)等),按 Linkedin 當(dāng)初的業(yè)務(wù)規(guī)模來看,每天要處理的消息量預(yù)計(jì)在千億級規(guī)模。

3、CRUD 場景足夠簡單:因?yàn)橄㈥?duì)列最核心的功能就是數(shù)據(jù)管道,它僅提供轉(zhuǎn)儲能力,因此 CRUD 操作確實(shí)很簡單。

首先,消息等同于通知事件,都是追加寫入的,根本無需考慮 update。其次,對于 Consumer 端來說,Broker 提供按 offset(消費(fèi)位移)或者 timestamp(時(shí)間戳)查詢消息的能力就行。再次,長時(shí)間未消費(fèi)的消息(比如 7 天前的),Broker 做好定期刪除即可。

接著,我們再來看看非功能性需求:

1、性能要求:之前的文章交代過,Linkedin 最初嘗試過用 ActiveMQ 來解決數(shù)據(jù)傳輸問題,但是性能無法滿足要求,然后才決定自研 Kafka。ActiveMQ 的單機(jī)吞吐量大約是萬級 TPS,Kafka 顯然要比 ActiveMQ 的性能高一個(gè)量級才行。

2、穩(wěn)定性要求:消息的持久化(確保機(jī)器重啟后歷史數(shù)據(jù)不丟失)、單臺 Broker 宕機(jī)后如何快速故障轉(zhuǎn)移繼續(xù)對外提供服務(wù),這兩個(gè)能力也是 Kafka 必須要考慮的。

3、擴(kuò)展性要求:Kafka 面對的是海量數(shù)據(jù)的存儲問題,必然要考慮存儲的擴(kuò)展性。

再簡單總結(jié)下,Kafka 的存儲需求如下:

1、功能性需求:其實(shí)足夠簡單,追加寫、無需update、能根據(jù)消費(fèi)位移和時(shí)間戳查詢消息、能定期刪除過期的消息。

2、非功能性需求:是難點(diǎn)所在,因?yàn)?Kafka 本身就是一個(gè)高并發(fā)系統(tǒng),必然會遇到典型的高性能、高可用和高擴(kuò)展這三方面的挑戰(zhàn)。

2. Kafka 的存儲選型分析

有了上面的需求梳理,我們繼續(xù)往下分析。

為什么 Kafka 最終會選用 logging(日志文件)來存儲消息呢?而不是用我們最常見的關(guān)系型數(shù)據(jù)庫或者 key-value 數(shù)據(jù)庫呢?

2.1 存儲領(lǐng)域的基礎(chǔ)知識

先普及幾點(diǎn)存儲領(lǐng)域的基礎(chǔ)知識,這是我們進(jìn)一步分析的理論依據(jù)。

1、內(nèi)存的存取速度快,但是容量小、價(jià)格昂貴,不適用于要長期保存的數(shù)據(jù)。

2、磁盤的存取速度相對較慢,但是廉價(jià)、而且可以持久化存儲。

3、一次磁盤 IO 的耗時(shí)主要取決于:尋道時(shí)間和盤片旋轉(zhuǎn)時(shí)間,提高磁盤 IO 性能最有效的方法就是:減少隨機(jī) IO,增加順序 IO。

4、磁盤的 IO 速度其實(shí)不一定比內(nèi)存慢,取決于我們?nèi)绾问褂盟?/p>

關(guān)于磁盤和內(nèi)存的 IO 速度,有很多這方面的對比測試,結(jié)果表明:磁盤順序?qū)懭胨俣瓤梢赃_(dá)到幾百兆/s,而隨機(jī)寫入速度只有幾百KB/s,相差上千倍。此外,磁盤順序 IO 訪問甚至可以超過內(nèi)存隨機(jī) IO 的性能。

圖2:磁盤和內(nèi)存的 IO 速度對比

再看數(shù)據(jù)存儲領(lǐng)域,有兩個(gè) “極端” 發(fā)展方向:

1、加快讀:通過索引( B+ 樹、二份查找樹等方式),提高查詢速度,但是寫入數(shù)據(jù)時(shí)要維護(hù)索引,因此會降低寫入效率。

2、加快寫:純?nèi)罩拘停瑪?shù)據(jù)以 append 追加的方式順序?qū)懭?,不加索引,使得寫入速度非常?理論上可接近磁盤的寫入速度),但是缺乏索引支持,因此查詢性能低。

基于這兩個(gè)極端,又衍生出來了 3 類最具代表性的底層索引結(jié)構(gòu):

1、哈希索引:通過哈希函數(shù)將 key 映射成數(shù)據(jù)的存儲地址,適用于等值查詢等簡單場景,對于比較查詢、范圍查詢等復(fù)雜場景無能為力。

2、B/B+ Tree 索引:最常見的索引類型,重點(diǎn)考慮的是讀性能,它是很多傳統(tǒng)關(guān)系型數(shù)據(jù)庫,比如 MySQL、Oracle 的底層結(jié)構(gòu)。

3、 LSM Tree 索引:數(shù)據(jù)以 Append 方式追加寫入日志文件,優(yōu)化了寫但是又沒顯著降低讀性能,眾多 NoSQL 存儲系統(tǒng)比如 BigTable,HBase,Cassandra,RocksDB 的底層結(jié)構(gòu)。

2.2 Kafka 的存儲選型考慮

有了上面這些理論基礎(chǔ),我們繼續(xù)回到 Kafka 的存儲需求上進(jìn)行思考。

Kafka 所處業(yè)務(wù)場景的特點(diǎn)是:

1、寫入操作:并發(fā)非常高,百萬級 TPS,但都是順序?qū)懭?,無需考慮更新

2、查詢操作:需求簡單,能按照 offset 或者 timestamp 查詢消息即可

如果單純滿足 Kafka 百萬級 TPS 的寫入操作需求,采用 Append 追加寫日志文件的方式顯然是最理想的,前面講過磁盤順序?qū)懙男阅芡耆强梢詽M足要求的。

剩下的就是如何解決高效查詢的問題。如果采用 B Tree 類的索引結(jié)構(gòu)來實(shí)現(xiàn),每次數(shù)據(jù)寫入時(shí)都需要維護(hù)索引(屬于隨機(jī) IO 操作),而且還會引來“頁分裂”等比較耗時(shí)的操作。而這些代價(jià)對于僅需要實(shí)現(xiàn)簡單查詢要求的 Kafka 來說,顯得非常重。所以,B Tree 類的索引并不適用于 Kafka。

相反,哈希索引看起來卻非常合適。為了加快讀操作,如果只需要在內(nèi)存中維護(hù)一個(gè)「從 offset 到日志文件偏移量」的映射關(guān)系即可,每次根據(jù) offset 查找消息時(shí),從哈希表中得到偏移量,再去讀文件即可。(根據(jù) timestamp 查消息也可以采用同樣的思路)

但是哈希索引常駐內(nèi)存,顯然沒法處理數(shù)據(jù)量很大的情況,Kafka 每秒可能會有高達(dá)幾百萬的消息寫入,一定會將內(nèi)存撐爆。

可我們發(fā)現(xiàn)消息的 offset 完全可以設(shè)計(jì)成有序的(實(shí)際上是一個(gè)單調(diào)遞增 long 類型的字段),這樣消息在日志文件中本身就是有序存放的了,我們便沒必要為每個(gè)消息建 hash 索引了,完全可以將消息劃分成若干個(gè) block,只索引每個(gè) block 第一條消息的 offset 即可,先根據(jù)大小關(guān)系找到 block,然后在 block 中順序搜索,這便是 Kafka “稀疏索引” 的來源。

圖3:Kafka 的稀疏索引示意圖

最終我們發(fā)現(xiàn):Append 追加寫日志 + 稀疏的哈希索引,形成了 Kafka 最終的存儲方案。而這不就是 LSM Tree 的設(shè)計(jì)思想嗎?

也許會有人會反駁 Kafka 的方案跟 LSM Tree 不一樣,并沒有用到樹型索引以及 Memtable 這一層。但我個(gè)人認(rèn)為,從「設(shè)計(jì)思想」從這個(gè)角度來看,完全可以將 Kafka 視為 LSM Tree 的極端應(yīng)用。

此外,關(guān)于 Append Only Data Structures 和 LSM Tree,推薦 Ben Stopford (Kafka 母公司的一位技術(shù)專家) 于 2017 年 QCon 上做的一個(gè)視頻分享,演講非常精彩,值得一看。

https://www.infoq.com/presentations/lsm-append-data-structures/

3. Kafka 的存儲設(shè)計(jì)

了解了 Kafka 存儲選型的來龍去脈后,最后我們再看下它具體的存儲結(jié)構(gòu)。

圖4:Kafka 的存儲結(jié)構(gòu)

可以看到,Kafka 是一個(gè)「分區(qū) + 分段 + 索引」的三層結(jié)構(gòu):

1、每個(gè) Topic 被分成多個(gè) Partition,Partition 從物理上可以理解成一個(gè)文件夾。

之前的文章解釋過:Partition 主要是為了解決 Kafka 存儲上的水平擴(kuò)展問題,如果一個(gè) Topic 的所有消息都只存在一個(gè) Broker,這個(gè) Broker 必然會成為瓶頸。因此,將 Topic 內(nèi)的數(shù)據(jù)分成多個(gè) Partition,然后分布到整個(gè)集群是很自然的設(shè)計(jì)方式。

2、每個(gè) Partition 又被分成了多個(gè) Segment,Segment 從物理上可以理解成一個(gè)「數(shù)據(jù)文件 + 索引文件」,這兩者是一一對應(yīng)的。

一定有讀者會有疑問:有了 Partition 之后,為什么還需要 Segment?

如果不引入 Segment,一個(gè) Partition 只對應(yīng)一個(gè)文件,那這個(gè)文件會一直增大,勢必造成單個(gè) Partition 文件過大,查找和維護(hù)不方便。

此外,在做歷史消息刪除時(shí),必然需要將文件前面的內(nèi)容刪除,不符合 Kafka 順序?qū)懙乃悸?。而在引?Segment 后,則只需將舊的 Segment 文件刪除即可,保證了每個(gè) Segment 的順序?qū)憽?/p>

4. 寫在最后

本文從需求分析、到選型對比、再到具體的存儲方案,一步步撥開了 Kafka 選用 logging(日志文件)這一存儲方案的奧秘。

也是希望大家能去主動思考 Kafka 在存儲選型時(shí)的難點(diǎn),把它當(dāng)做一個(gè)系統(tǒng)設(shè)計(jì)題去思考,而不僅僅記住它用了日志存儲。

另外一個(gè)觀點(diǎn):越底層越通用,你每次多往下研究深一點(diǎn),會發(fā)現(xiàn)這些知識在很多優(yōu)秀的開源系統(tǒng)里都是相通的。

下篇文章我將結(jié)合 Kafka 的源碼,分析它在存儲數(shù)據(jù)時(shí)的各個(gè)性能優(yōu)化手段,我們下期見!

本文轉(zhuǎn)載自微信公眾號「武哥漫談IT」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系武哥漫談IT公眾號。

 

責(zé)任編輯:武曉燕 來源: 武哥漫談IT
相關(guān)推薦

2021-03-28 20:44:34

Kafka中間件MQ

2021-04-20 19:20:57

Kafka架構(gòu)設(shè)計(jì)

2021-03-02 12:36:49

MQKafkaRocketMQ

2021-06-10 07:49:27

Kafka 架構(gòu)設(shè)計(jì)

2011-07-08 15:41:43

oracle job

2024-05-31 08:05:29

2018-01-25 08:29:28

Kafka源碼存儲

2023-11-17 09:00:00

Kafka開發(fā)

2019-12-11 10:14:23

Kafka吞吐量架構(gòu)

2022-05-31 08:21:07

MQ使用場景消費(fèi)消息

2013-10-11 15:25:43

華為存儲華為

2018-05-14 09:28:24

RAID磁盤存儲

2018-05-22 09:11:27

塊存儲LUN文件系統(tǒng)

2024-06-07 13:42:41

2019-01-15 08:50:12

Apache FlinKafka分布式

2013-04-23 10:42:55

JavaScriptthis

2021-07-13 10:00:00

微服務(wù)SleuthElasticSear

2018-11-26 07:04:59

神經(jīng)網(wǎng)絡(luò)優(yōu)化函數(shù)

2022-07-19 10:26:44

監(jiān)控系統(tǒng)

2012-02-13 16:00:35

內(nèi)網(wǎng)安全技術(shù)選型安全產(chǎn)品
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號