成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Kafka 精妙的高性能設計之二

開發(fā) 架構 Kafka
在 上一篇文章 中,指出了高性能設計的兩個關鍵維度:計算和 IO,可以將它們理解成「道」。這篇文章將繼續(xù)對存儲消息和消費消息的 8 條高性能設計手段,逐個展開分析,廢話不多說,開始發(fā)車。

[[429455]]

大家好,我是武哥。

這是《吃透 MQ 系列》的連載:Kafka 高性能設計的下篇。在 上一篇文章 中,指出了高性能設計的兩個關鍵維度:計算和 IO,可以將它們理解成「道」。同時給出了 Kafka 高性能設計的全景圖,可以理解成「術」。

 

 

圖 1:Kafka 高性能設計的全景圖

這篇文章將繼續(xù)對存儲消息和消費消息的 8 條高性能設計手段,逐個展開分析,廢話不多說,開始發(fā)車。

一. 存儲消息的性能優(yōu)化手段

存儲消息屬于 Broker 端的核心功能,下面是它所采用的 4 條優(yōu)化手段。

 

 

1、IO 多路復用

對于 Kafka Broker 來說,要做到高性能,首先要考慮的是:設計出一個高效的網(wǎng)絡通信模型,用來處理它和 Producer 以及 Consumer 之間的消息傳遞問題。

先引用 Kafka 2.8.0 源碼里 SocketServer 類中一段很關鍵的注釋:

 

 

通過這段注釋,其實可以了解到 Kafka 采用的是:很典型的 Reactor 網(wǎng)絡通信模型,完整的網(wǎng)絡通信層框架圖如下所示:

 

 

圖 2:Kafka 網(wǎng)絡通信層的框架圖

通俗點記憶就是 1 + N + M:

  • 1:表示 1 個 Acceptor 線程,負責監(jiān)聽新的連接,然后將新連接交給 Processor 線程處理。
  • N:表示 N 個 Processor 線程,每個 Processor 都有自己的 selector,負責從 socket 中讀寫數(shù)據(jù)。
  • M:表示 M 個 KafkaRequestHandler 業(yè)務處理線程,它通過調用 KafkaApis 進行業(yè)務處理,然后生成 response,再交由給 Processor 線程。

對于 IO 有所研究的同學,應該清楚:Reactor 模式正是采用了很經典的 IO 多路復用技術,它可以復用一個線程去處理大量的 Socket 連接,從而保證高性能。Netty 和 Redis 為什么能做到十萬甚至百萬并發(fā)?它們其實都采用了 Reactor 網(wǎng)絡通信模型。

2、磁盤順序寫

通過 IO 多路復用搞定網(wǎng)絡通信后,Broker 下一步要考慮的是:如何將消息快速地存儲起來?在 Kafka 存儲選型的奧秘 一文中提到了:Kafka 選用的是「日志文件」來存儲消息,那這種寫磁盤文件的方式,又究竟是如何做到高性能的呢?這一切得益于磁盤順序寫,怎么理解呢?Kafka 作為消息隊列,本質上就是一個隊列,是先進先出的,而且消息一旦生產了就不可變。這種有序性和不可變性使得 Kafka 完全可以「順序寫」日志文件,也就是說,僅僅將消息追加到文件末尾即可。有了順序寫的前提,我們再來看一個對比實驗,從下圖中可以看到:磁盤順序寫的性能遠遠高于磁盤隨機寫,甚至高于內存隨機寫。

 

 

圖3:磁盤和內存的 IO 速度對比

原因很簡單:對于普通的機械磁盤,如果是隨機寫入,性能確實極差,也就是隨便找到文件的某個位置來寫數(shù)據(jù)。但如果是順序寫入,因為可大大節(jié)省磁盤尋道和盤片旋轉的時間,因此性能提升了 3 個數(shù)量級。

3、Page Cache

磁盤順序寫已經很快了,但是對比內存順序寫仍然慢了幾個數(shù)量級,那有沒有可能繼續(xù)優(yōu)化呢?答案是肯定的。

這里 Kafka 用到了 Page Cache 技術,簡單理解就是:利用了操作系統(tǒng)本身的緩存技術,在讀寫磁盤日志文件時,其實操作的都是內存,然后由操作系統(tǒng)決定什么時候將 Page Cache 里的數(shù)據(jù)真正刷入磁盤。通過下面這個示例圖便一目了然。

 

 

圖4:Kafka 的 Page Cache 原理

那 Page Cache 究竟什么時候會發(fā)揮最大的威力呢?這又不得不提 Page Cache 所用到的兩個經典原理。Page Cache 緩存的是最近會被使用的磁盤數(shù)據(jù),利用的是「時間局部性」原理,依據(jù)是:最近訪問的數(shù)據(jù)很可能接下來再訪問到。而預讀到 Page Cache 中的磁盤數(shù)據(jù),又利用了「空間局部性」原理,依據(jù)是:數(shù)據(jù)往往是連續(xù)訪問的。而 Kafka 作為消息隊列,消息先是順序寫入,而且立馬又會被消費者讀取到,無疑非常契合上述兩條局部性原理。因此,頁緩存可以說是 Kafka 做到高吞吐的重要因素之一。

除此之外,頁緩存還有一個巨大的優(yōu)勢。用過 Java 的人都知道:如果不用頁緩存,而是用 JVM 進程中的緩存,對象的內存開銷非常大(通常是真實數(shù)據(jù)大小的幾倍甚至更多),此外還需要進行垃圾回收,GC 所帶來的 Stop The World 問題也會帶來性能問題。可見,頁緩存確實優(yōu)勢明顯,而且極大地簡化了 Kafka 的代碼實現(xiàn)。

4、分區(qū)分段結構

磁盤順序寫加上頁緩存很好地解決了日志文件的高性能讀寫問題。但是如果一個 Topic 只對應一個日志文件,顯然只能存放在一臺 Broker 機器上。當面對海量消息時,單機的存儲容量和讀寫性能肯定有限,這樣又引出了又一個精妙的存儲設計:對數(shù)據(jù)進行分區(qū)存儲。我在 Kafka 架構設計的任督二脈 一文中詳細解釋了分區(qū)(Partition)的概念和作用,它是 Kafka 并發(fā)處理的最小粒度,很好地解決了存儲的擴展性問題。隨著分區(qū)數(shù)的增加,Kafka 的吞吐量得以進一步提升。其實在 Kafka 的存儲底層,在分區(qū)之下還有一層:那便是「分段」。簡單理解:分區(qū)對應的其實是文件夾,分段對應的才是真正的日志文件。

 

 

圖5:Kafka 的 分區(qū)分段存儲

每個 Partition 又被分成了多個 Segment,那為什么有了 Partition 之后,還需要 Segment 呢?

如果不引入 Segment,一個 Partition 只對應一個文件,那這個文件會一直增大,勢必造成單個 Partition 文件過大,查找和維護不方便。此外,在做歷史消息刪除時,必然需要將文件前面的內容刪除,只有一個文件顯然不符合 Kafka 順序寫的思路。而在引入 Segment 后,則只需將舊的 Segment 文件刪除即可,保證了每個 Segment 的順序寫。

二. 消費消息的性能優(yōu)化手段

Kafka 除了要做到百萬 TPS 的寫入性能,還要解決高性能的消息讀取問題,否則稱不上高吞吐。下面再來看看 Kafka 消費消息時所采用的 4 條優(yōu)化手段。

 

 

1、稀疏索引

如何提高讀性能,大家很容易想到的是:索引。Kafka 所面臨的查詢場景其實很簡單:能按照 offset 或者 timestamp 查到消息即可。如果采用 B Tree 類的索引結構來實現(xiàn),每次數(shù)據(jù)寫入時都需要維護索引(屬于隨機 IO 操作),而且還會引來「頁分裂」這種比較耗時的操作。而這些代價對于僅需要實現(xiàn)簡單查詢要求的 Kafka 來說,顯得非常重。所以,B Tree 類的索引并不適用于 Kafka。相反,哈希索引看起來卻非常合適。為了加快讀操作,如果只需要在內存中維護一個「從 offset 到日志文件偏移量」的映射關系即可,每次根據(jù) offset 查找消息時,從哈希表中得到偏移量,再去讀文件即可。(根據(jù) timestamp 查消息也可以采用同樣的思路)但是哈希索引常駐內存,顯然沒法處理數(shù)據(jù)量很大的情況,Kafka 每秒可能會有高達幾百萬的消息寫入,一定會將內存撐爆。可我們發(fā)現(xiàn)消息的 offset 完全可以設計成有序的(實際上是一個單調遞增 long 類型的字段),這樣消息在日志文件中本身就是有序存放的了,我們便沒必要為每個消息建 hash 索引了,完全可以將消息劃分成若干個 block,只索引每個 block 第一條消息的 offset 即可,先根據(jù)大小關系找到 block,然后在 block 中順序搜索,這便是 Kafka “稀疏索引” 的設計思想。

 

 

圖6:Kafka 的稀疏索引設計

采用 “稀疏索引”,可以認為是在磁盤空間、內存空間、查找性能等多方面的一個折中。有了稀疏索引,當給定一個 offset 時,Kafka 采用的是二分查找來高效定位不大于 offset 的物理位移,然后找到目標消息。

2、mmap

利用稀疏索引,已經基本解決了高效查詢的問題,但是這個過程中仍然有進一步的優(yōu)化空間,那便是通過 mmap(memory mapped files) 讀寫上面提到的稀疏索引文件,進一步提高查詢消息的速度。

  • 注意:mmap 和 page cache 是兩個概念,網(wǎng)上很多資料把它們混淆在一起。此外,還有資料談到 Kafka 在讀 log 文件時也用到了 mmap,通過對 2.8.0 版本的源碼分析,這個信息也是錯誤的,其實只有索引文件的讀寫才用到了 mmap.

究竟如何理解 mmap?前面提到,常規(guī)的文件操作為了提高讀寫性能,使用了 Page Cache 機制,但是由于頁緩存處在內核空間中,不能被用戶進程直接尋址,所以讀文件時還需要通過系統(tǒng)調用,將頁緩存中的數(shù)據(jù)再次拷貝到用戶空間中。而采用 mmap 后,它將磁盤文件與進程虛擬地址做了映射,并不會招致系統(tǒng)調用,以及額外的內存 copy 開銷,從而提高了文件讀取效率。

 

 

圖7:mmap 示意圖,引自《碼農的荒島求生》

關于 mmap,好友小風哥寫過一篇很通俗的文章: mmap 可以讓程序員解鎖哪些騷操作?大家可以參考。具體到 Kafka 的源碼層面,就是基于 JDK nio 包下的 MappedByteBuffer 的 map 函數(shù),將磁盤文件映射到內存中。至于為什么 log 文件不采用 mmap?其實是一個特別好的問題,這個問題社區(qū)并沒有給出官方答案,網(wǎng)上的答案只能揣測作者的意圖。個人比較認同 stackoverflow 上的這個答案:

mmap 有多少字節(jié)可以映射到內存中與地址空間有關,32 位的體系結構只能處理 4GB 甚至更小的文件。Kafka 日志通常足夠大,可能一次只能映射部分,因此讀取它們將變得非常復雜。然而,索引文件是稀疏的,它們相對較小。將它們映射到內存中可以加快查找過程,這是內存映射文件提供的主要好處。

3、零拷貝

消息借助稀疏索引被查詢到后,下一步便是:將消息從磁盤文件中讀出來,然后通過網(wǎng)卡發(fā)給消費者,那這一步又可以怎么優(yōu)化呢?Kafka 用到了零拷貝(Zero-Copy)技術來提升性能。所謂的零拷貝是指數(shù)據(jù)直接從磁盤文件復制到網(wǎng)卡設備,而無需經過應用程序,減少了內核和用戶模式之間的上下文切換。

下面這個過程是不采用零拷貝技術時,從磁盤中讀取文件然后通過網(wǎng)卡發(fā)送出去的流程,可以看到:經歷了 4 次拷貝,4 次上下文切換。

 

 

圖8:非零拷貝技術的流程圖,引自《艾小仙》

如果采用零拷貝技術(底層通過 sendfile 方法實現(xiàn)),流程將變成下面這樣。可以看到:只需 3 次拷貝以及 2 次上下文切換,顯然性能更高。

 

 

圖9:零拷貝技術的流程圖,引自《艾小仙》

4、批量拉取

和生產者批量發(fā)送消息類似,消息者也是批量拉取消息的,每次拉取一個消息集合,從而大大減少了網(wǎng)絡傳輸?shù)?overhead。另外,在 Kafka 精妙的高性能設計(上篇) 中介紹過,生產者其實在 Client 端對批量消息進行了壓縮,這批消息持久化到 Broker 時,仍然保持的是壓縮狀態(tài),最終在 Consumer 端再做解壓縮操作。

三. 寫在最后

以上就是 Kafka 12 條高性能設計手段的詳解,這兩篇文章先從 IO 和計算兩個維度進行宏觀上的切入,然后順著 MQ 一發(fā)一存一消費的脈絡,從微觀上解構了 Kafka 高性能的全景圖。可以說 Kafka 在高性能設計方面是教科書式的存在,它從 Prodcuer 、到 Broker、再到 Consumer,在掏空心思地優(yōu)化每一個細節(jié),最終才做到了單機每秒幾十萬 TPS 的極致性能。

最后,希望本文的分析技巧可以幫助你吃透其他高性能的中間件。我是武哥,我們下期見!

 

責任編輯:姜華 來源: 武哥漫談IT
相關推薦

2021-08-30 09:30:29

Kafka高性能設計

2019-10-17 09:23:49

Kafka高性能架構

2020-01-07 16:16:57

Kafka開源消息系統(tǒng)

2020-07-16 08:06:53

網(wǎng)關高性能

2024-09-02 18:10:20

2022-06-28 08:42:03

磁盤kafka高性能

2024-02-26 07:43:10

大語言模型LLM推理框架

2011-04-15 13:12:09

.NETMEF

2024-07-05 09:41:42

2013-12-02 10:34:32

虛擬化實戰(zhàn)Cluster

2014-01-03 13:56:00

手游用戶體驗設計啟動和停止

2012-08-20 09:22:32

2024-02-19 08:17:10

Kafka消息隊列收發(fā)消息

2023-05-08 14:56:00

Kafka高可靠高性能

2021-07-06 10:35:46

分布式KafkaLinux

2023-09-22 11:48:37

2016-09-28 15:02:39

數(shù)據(jù)庫防火墻高性能

2021-04-21 15:21:37

技術架構高并發(fā)基礎源碼解析

2024-11-12 08:13:09

2023-01-05 09:33:38

低代碼高性能引擎
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 精品一区在线免费观看 | 玖玖爱365| 欧美理伦片在线播放 | 日韩成人在线免费观看 | a欧美 | 久久久精品一区二区三区 | 99福利视频 | 91国内精品久久 | 91天堂网 | 亚洲免费在线视频 | 久久久久黄 | 国产91丝袜在线18 | 国产传媒视频在线观看 | 亚洲欧洲小视频 | 日本一区二区高清不卡 | 亚洲成网 | 日韩二区 | 99久久久久| 成人欧美一区二区 | 天天爽天天操 | 国产美女一区二区 | 国产 日韩 欧美 制服 另类 | 久草色视频 | 老外黄色一级片 | 999免费网站 | 免费在线观看成人av | www成年人视频 | 亚洲一区二区三区在线播放 | 欧美精品久久久久久 | 日韩精品一区二区三区中文在线 | 羞视频在线观看 | 日韩在线观看网站 | 九九久久久 | 日韩久久久久久久 | 国产色黄 | 久久新 | 国产精品久久久久久久久久免费看 | 日本福利视频免费观看 | 欧美三级三级三级爽爽爽 | av一区二区三区四区 | 欧美日韩精品一区二区三区四区 |