支持百萬級TPS,Kafka是怎麼作到的?答案藏在這10張圖裏

本文 github/JavaMap 已收錄,有Java程序員進階技術知識地圖以及個人系列文章,歡迎你們Star。java

談到大數據傳輸都會想到 Kafka,Kafka 號稱大數據的殺手鐗,在業界有不少成熟的應用場景而且被主流公司承認。這款爲大數據而生的消息中間件,以其百萬級TPS的吞吐量名聲大噪,迅速成爲大數據領域的寵兒,在數據採集、傳輸、存儲的過程當中發揮着舉足輕重的做用。git

在業界已經有不少成熟的消息中間件如:RabbitMQ, RocketMQ, ActiveMQ, ZeroMQ,爲何 Kafka 在衆多的敵手中依然能有一席之地,固然靠的是其強悍的吞吐量。下面帶領你們來揭祕。程序員

Kafka 如何作到支持百萬級 TPS ?

先用一張思惟導圖直接告訴你答案:github

Kafka支持百萬TPS的祕密
Kafka支持百萬TPS的祕密

順序讀寫磁盤

生產者寫入數據和消費者讀取數據都是順序讀寫的,先來一張圖直觀感覺一下順序讀寫和隨機讀寫的速度:面試

順序寫 VS 隨機寫
順序寫 VS 隨機寫

從圖中能夠看出傳統硬盤或者SSD的順序讀寫甚至超過了內存的隨機讀寫,固然與內存的順序讀寫對比差距仍是很大。微信

因此Kafka選擇順序讀寫磁盤也不足爲奇了。markdown

下面以傳統機械磁盤爲例詳細介紹一下什麼是順序讀寫和隨機讀寫。網絡

盤片和**盤面:**一塊硬盤通常有多塊盤片,盤片分爲上下兩面,其中有效面稱爲盤面,通常上下都有效,也就是說:盤面數 = 盤片數 * 2。架構

磁頭:磁頭切換磁道讀寫數據時是經過機械設備實現的,通常速度較慢;而磁頭切換盤面讀寫數據是經過電子設備實現的,通常速度較快,所以磁頭通常是先讀寫完柱面後纔開始尋道的(不用切換磁道),這樣磁盤讀寫效率更快。app

傳統機械磁盤
傳統機械磁盤

磁道:磁道就是以中間軸爲圓心的圓環,一個盤面有多個磁道,磁道之間有間隙,磁道也就是磁盤存儲數據的介質。磁道上布有一層磁介質,經過磁頭可使磁介質的極性轉換爲數據信號,即磁盤的讀,磁盤寫恰好與之相反。

柱面:磁盤中不一樣盤面中半徑相同的磁道組成的,也就是說柱面總數 = 某個盤面的磁道數。

扇區:單個磁道就是多個弧形扇區組成的,盤面上的每一個磁道擁有的扇區數量是相等。扇區是最小存儲單元,通常扇區大小爲512bytes。

單盤示意圖
單盤示意圖

若是系統每次只讀取一個扇區,那恐怕效率過低了,因此出現了block(塊)的概念。文件讀取的最小單位是block,根據不一樣操做系統一個block通常由多個扇區組成。

有了磁盤的背景知識咱們就能夠很容易理解順序讀寫和隨機讀寫了。

插播維基百科定義: 順序讀寫:是一種按記錄的邏輯順序進行讀、寫操做的存取方法 ,即按照信息在存儲器中的實際位置所決定的順序使用信息。 隨機讀寫:指的是當存儲器中的消息被讀取或寫入時,所須要的時間與這段信息所在的位置無關。

當讀取第一個block時,要經歷尋道、旋轉延遲、傳輸三個步驟才能讀取完這個block的數據。而對於下一個block,若是它在磁盤的其餘任意位置,訪問它會一樣經歷尋道、旋轉、延時、傳輸才能讀取完這個block的數據,咱們把這種方式叫作隨機讀寫。可是若是這個block的起始扇區恰好在剛纔訪問的block的後面,磁頭就能馬上遇到,不需等待直接傳輸,這種就叫順序讀寫

好,咱們再回到 Kafka,詳細介紹Kafka如何實現順序讀寫入數據。

Kafka 寫入數據是順序的,下面每個Partition 均可以當作一個文件,每次接收到新數據後Kafka會把數據插入到文件末尾,虛框部分表明文件尾。

順序寫
順序寫

這種方法有一個問題就是刪除數據不方便,因此 Kafka 通常會把全部的數據都保留下來,每一個消費者(Consumer)對每一個Topic都有一個 offset 用來記錄讀取進度或者叫座標。

順序讀
順序讀

Memory Mapped Files(MMAP)

在文章開頭咱們看到硬盤的順序讀寫基本能與內存隨機讀寫速度媲美,可是與內存順序讀寫相比仍是太慢了,那 Kafka 若是有追求想進一步提高效率怎麼辦?可使用現代操做系統分頁存儲來充分利用內存提升I/O效率,這也是下面要介紹的 MMAP 技術。

MMAP也就是內存映射文件,在64位操做系統中通常能夠表示 20G 的數據文件,它的工做原理是直接利用操做系統的 Page 來實現文件到物理內存的直接映射,完成映射以後對物理內存的操做會被同步到硬盤上。

MMAP原理
MMAP原理

經過MMAP技術進程能夠像讀寫硬盤同樣讀寫內存(邏輯內存),沒必要關心內存的大小,由於有虛擬內存兜底。這種方式能夠獲取很大的I/O提高,省去了用戶空間到內核空間複製的開銷。

也有一個很明顯的缺陷,寫到MMAP中的數據並無被真正的寫到硬盤,操做系統會在程序主動調用 flush 的時候才把數據真正的寫到硬盤。

Kafka提供了一個參數:producer.type 來控制是否是主動 flush,若是Kafka寫入到MMAP以後就當即flush而後再返回Producer叫同步(sync);寫入MMAP以後當即返回Producer不調用flush叫異步(async)。

Zero Copy(零拷貝)

Kafka 另一個黑技術就是使用了零拷貝,要想深入理解零拷貝必須得知道什麼是DMA。

什麼是DMA?

衆所周知 CPU 的速度與磁盤 IO 的速度比起來相差幾個數量級,能夠用烏龜和火箭作比喻。

通常來講 IO 操做都是由 CPU 發出指令,而後等待 IO 設備完成操做後返回,那CPU會有大量的時間都在等待IO操做。

可是CPU 的等待在不少時候並無太多的實際意義,咱們對於 I/O 設備的大量操做其實都只是把內存裏面的數據傳輸到 I/O 設備而已。好比進行大文件複製,若是全部數據都要通過 CPU,實在是有點兒太浪費時間了。

基於此就有了DMA技術,翻譯過來也就是直接內存訪問(Direct Memory Access),有了這個能夠減小 CPU 的等待時間。

Kafka 零拷貝原理

若是不使用零拷貝技術,消費者(consumer)從Kafka消費數據,Kafka從磁盤讀數據而後發送到網絡上去,數據一共發生了四次傳輸的過程。其中兩次是 DMA 的傳輸,另外兩次,則是經過 CPU 控制的傳輸。

四次傳輸過程
四次傳輸過程

第一次傳輸:從硬盤上將數據讀到操做系統內核的緩衝區裏,這個傳輸是經過 DMA 搬運的。

第二次傳輸:從內核緩衝區裏面的數據複製到分配的內存裏面,這個傳輸是經過 CPU 搬運的。

第三次傳輸:從分配的內存裏面再寫到操做系統的 Socket 的緩衝區裏面去,這個傳輸是由 CPU 搬運的。

第四次傳輸:從 Socket 的緩衝區裏面寫到網卡的緩衝區裏面去,這個傳輸是經過 DMA 搬運的。

實際上在kafka中只進行了兩次數據傳輸,以下圖:

兩次傳輸,零拷貝技術
兩次傳輸,零拷貝技術

第一次傳輸:經過 DMA從硬盤直接讀到操做系統內核的讀緩衝區裏面。

第二次傳輸:根據 Socket 的描述符信息直接從讀緩衝區裏面寫入到網卡的緩衝區裏面。

咱們能夠看到同一份數據的傳輸次數從四次變成了兩次,而且沒有經過 CPU 來進行數據搬運,全部的數據都是經過 DMA 來進行傳輸的。沒有在內存層面去複製(Copy)數據,這個方法稱之爲零拷貝(Zero-Copy)。

不管傳輸數據量的大小,傳輸一樣的數據使用了零拷貝可以縮短 65% 的時間,大幅度提高了機器傳輸數據的吞吐量,這也是Kafka可以支持百萬TPS的一個重要緣由。

Batch Data(數據批量處理)

當消費者(consumer)須要消費數據時,首先想到的是消費者須要一條,kafka發送一條,消費者再要一條kafka再發送一條。但實際上 Kafka 不是這樣作的,Kafka 耍小聰明瞭。

Kafka 把全部的消息都存放在一個一個的文件中,當消費者須要數據的時候 Kafka 直接把文件發送給消費者。好比說100萬條消息放在一個文件中多是10M的數據量,若是消費者和Kafka之間網絡良好,10MB大概1秒就能發送完,既100萬TPS,Kafka每秒處理了10萬條消息。

看到這裏你能夠有疑問了,消費者只須要一條消息啊,kafka把整個文件都發送過來了,文件裏面剩餘的消息怎麼辦?不要忘了消費者能夠經過offset記錄消費進度。

發送文件還有一個好處就是能夠對文件進行批量壓縮,減小網絡IO損耗。

總結

最後再總結一下 Kafka 支持百萬級 TPS 的祕密:

(1)順序寫入數據,在 Partition 末尾追加,因此速度最優。

(2)使用 MMAP 技術將磁盤文件與內存映射,Kafka 能夠像操做磁盤同樣操做內存。

(3)經過 DMA 技術實現零拷貝,減小數據傳輸次數。

(4)讀取數據時配合sendfile直接暴力輸出,批量壓縮把全部消息變成一個批量文件,合理減小網絡IO損耗。

-- END --

平常厚臉皮求贊:你好技術人,先贊後看養成習慣,你的贊對於我很是重要。

做者簡介:

☕讀過幾年書:華中科技大學碩士畢業;

😂浪過幾個大廠:華爲、網易、百度……

😘一直堅信技術能改變生活,願保持初心,加油技術人!

微信搜索公衆號【愛笑的架構師】,關注這個對技術和生活有追求的技術人。

文章持續更新,在 github/JavaMap 中能夠看到我歸檔的系列文章,有面試經驗和技術乾貨,歡迎Star。

相關文章
相關標籤/搜索