[分散式][訊息中介軟體]訊息中介軟體如何實現每秒幾十萬的高併發寫入

加瓦一枚發表於2019-03-04

目錄

1、頁快取技術 + 磁碟順序寫

2、零拷貝技術

3、最後的總結

 

“ 這篇文章來聊一下Kafka的一些架構設計原理,這也是網際網路公司面試時非常高頻的技術考點。

 

Kafka是高吞吐低延遲的高併發、高效能的訊息中介軟體,在大資料領域有極為廣泛的運用。配置良好的Kafka叢集甚至可以做到每秒幾十萬、上百萬的超高併發寫入。

 

那麼Kafka到底是如何做到這麼高的吞吐量和效能的呢?這篇文章我們來一點一點說一下。

 

 

 

1、頁快取技術 + 磁碟順序寫

 

首先Kafka每次接收到資料都會往磁碟上去寫,如下圖所示。

 

那麼在這裡我們不禁有一個疑問了,如果把資料基於磁碟來儲存,頻繁的往磁碟檔案裡寫資料,這個效能會不會很差?大家肯定都覺得磁碟寫效能是極差的。

沒錯,要是真的跟上面那個圖那麼簡單的話,那確實這個效能是比較差的。

 

但是實際上Kafka在這裡有極為優秀和出色的設計,就是為了保證資料寫入效能,首先Kafka是基於作業系統的頁快取來實現檔案寫入的。

 

作業系統本身有一層快取,叫做page cache,是在記憶體裡的快取,我們也可以稱之為os cache,意思就是作業系統自己管理的快取。

 

你在寫入磁碟檔案的時候,可以直接寫入這個os cache裡,也就是僅僅寫入記憶體中,接下來由作業系統自己決定什麼時候把os cache裡的資料真的刷入磁碟檔案中。

 

僅僅這一個步驟,就可以將磁碟檔案寫效能提升很多了,因為其實這裡相當於是在寫記憶體,不是在寫磁碟,大家看下圖。

接著另外一個就是kafka寫資料的時候,非常關鍵的一點,他是以磁碟順序寫的方式來寫的。也就是說,僅僅將資料追加到檔案的末尾,不是在檔案的隨機位置來修改資料。

 

普通的機械磁碟如果你要是隨機寫的話,確實效能極差,也就是隨便找到檔案的某個位置來寫資料。

 

但是如果你是追加檔案末尾按照順序的方式來寫資料的話,那麼這種磁碟順序寫的效能基本上可以跟寫記憶體的效能本身也是差不多的。

 

所以大家就知道了,上面那個圖裡,Kafka在寫資料的時候,一方面基於了os層面的page cache來寫資料,所以效能很高,本質就是在寫記憶體罷了。

 

另外一個,他是採用磁碟順序寫的方式,所以即使資料刷入磁碟的時候,效能也是極高的,也跟寫記憶體是差不多的。

 

基於上面兩點,kafka就實現了寫入資料的超高效能。

 

那麼大家想想,假如說kafka寫入一條資料要耗費1毫秒的時間,那麼是不是每秒就是可以寫入1000條資料?

 

但是假如kafka的效能極高,寫入一條資料僅僅耗費0.01毫秒呢?那麼每秒是不是就可以寫入10萬條數?

 

所以要保證每秒寫入幾萬甚至幾十萬條資料的核心點,就是盡最大可能提升每條資料寫入的效能,這樣就可以在單位時間內寫入更多的資料量,提升吞吐量。

 

 

 

2、零拷貝技術

 

說完了寫入這塊,再來談談消費這塊。

 

大家應該都知道,從Kafka裡我們經常要消費資料,那麼消費的時候實際上就是要從kafka的磁碟檔案裡讀取某條資料然後傳送給下游的消費者,如下圖所示。

 

那麼這裡如果頻繁的從磁碟讀資料然後發給消費者,效能瓶頸在哪裡呢?

假設要是kafka什麼優化都不做,就是很簡單的從磁碟讀資料傳送給下游的消費者,那麼大概過程如下所示:

 

先看看要讀的資料在不在os cache裡,如果不在的話就從磁碟檔案裡讀取資料後放入os cache。

 

接著從作業系統的os cache裡拷貝資料到應用程式程式的快取裡,再從應用程式程式的快取裡拷貝資料到作業系統層面的Socket快取裡,最後從Socket快取裡提取資料後傳送到網路卡,最後傳送出去給下游消費。

 

整個過程,如下圖所示:

大家看上圖,很明顯可以看到有兩次沒必要的拷貝吧!

 

一次是從作業系統的cache裡拷貝到應用程式的快取裡,接著又從應用程式快取裡拷貝回作業系統的Socket快取裡。

 

而且為了進行這兩次拷貝,中間還發生了好幾次上下文切換,一會兒是應用程式在執行,一會兒上下文切換到作業系統來執行。

 

所以這種方式來讀取資料是比較消耗效能的。

 

Kafka為了解決這個問題,在讀資料的時候是引入零拷貝技術

 

也就是說,直接讓作業系統的cache中的資料傳送到網路卡後傳輸給下游的消費者,中間跳過了兩次拷貝資料的步驟,Socket快取中僅僅會拷貝一個描述符過去,不會拷貝資料到Socket快取。

 

大家看下圖,體會一下這個精妙的過程:

通過零拷貝技術,就不需要把os cache裡的資料拷貝到應用快取,再從應用快取拷貝到Socket快取了,兩次拷貝都省略了,所以叫做零拷貝。

 

對Socket快取僅僅就是拷貝資料的描述符過去,然後資料就直接從os cache中傳送到網路卡上去了,這個過程大大的提升了資料消費時讀取檔案資料的效能。

 

而且大家會注意到,在從磁碟讀資料的時候,會先看看os cache記憶體中是否有,如果有的話,其實讀資料都是直接讀記憶體的。

 

如果kafka叢集經過良好的調優,大家會發現大量的資料都是直接寫入os cache中,然後讀資料的時候也是從os cache中讀。

 

相當於是Kafka完全基於記憶體提供資料的寫和讀了,所以這個整體效能會極其的高。

 

說個題外話,下回有機會給大家說一下Elasticsearch的架構原理,其實ES底層也是大量基於os cache實現了海量資料的高效能檢索的,跟Kafka原理類似。

 

 

 

3、最後的總結

 

通過這篇文章對kafka底層的頁快取技術的使用,磁碟順序寫的思路,以及零拷貝技術的運用,大家應該就明白Kafka每臺機器在底層對資料進行寫和讀的時候採取的是什麼樣的思路,為什麼他的效能可以那麼高,做到每秒幾十萬的吞吐量。

 

這種設計思想對我們平時自己設計中介軟體的架構,或者是出去面試的時候,都有很大的幫助。

相關文章