Kafka如何實現每秒上百萬的超高併發寫入?掌握好面試給你打滿分!

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

Kafka 是高吞吐低延遲的高併發、高性能的消息中間件,在大數據領域有極爲廣泛的運用。配置良好的 Kafka 集羣甚至可以做到每秒幾十萬、上百萬的超高併發寫入。

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

頁緩存技術 + 磁盤順序寫

首先 Kafka 每次接收到數據都會往磁盤上去寫,如下圖所示:

 

 

那麼在這裏我們不禁有一個疑問了,如果把數據基於磁盤來存儲,頻繁的往磁盤文件裏寫數據,這個性能會不會很差?大家肯定都覺得磁盤寫性能是極差的。

對大數據以及人工智能概念都是模糊不清的,該按照什麼線路去學習,學完往哪方面發展,想深入瞭解,想學習的同學歡迎加入大數據學習qq羣:515269485,有大量乾貨(零基礎以及進階的經典實戰)分享給大家,並且有清華大學畢業的資深大數據講師給大家免費授課,給大家分享目前國內最完整的大數據高端實戰實用學習流程體系 。從java和linux入手,其後逐步的深入到HADOOP-hive-oozie-web-flume-python-hbase-kafka-scala-SPARK等相關知識一一分享!

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

但是實際上 Kafka 在這裏有極爲優秀和出色的設計,就是爲了保證數據寫入性能,首先 Kafka 是基於操作系統的頁緩存來實現文件寫入的。

操作系統本身有一層緩存,叫做 Page Cache,是在內存裏的緩存,我們也可以稱之爲 OS Cache,意思就是操作系統自己管理的緩存。

你在寫入磁盤文件的時候,可以直接寫入這個 OS Cache 裏,也就是僅僅寫入內存中,接下來由操作系統自己決定什麼時候把 OS Cache 裏的數據真的刷入磁盤文件中。

僅僅這一個步驟,就可以將磁盤文件寫性能提升很多了,因爲其實這裏相當於是在寫內存,不是在寫磁盤,大家看下圖:

 

 

接着另外一個就是 kafka 寫數據的時候,非常關鍵的一點,它是以磁盤順序寫的方式來寫的。

也就是說,僅僅將數據追加到文件的末尾,不是在文件的隨機位置來修改數據。

普通的機械磁盤如果你要是隨機寫的話,確實性能極差,也就是隨便找到文件的某個位置來寫數據。

但是如果你是追加文件末尾按照順序的方式來寫數據的話,那麼這種磁盤順序寫的性能基本上可以跟寫內存的性能本身也是差不多的。

所以大家就知道了,上面那個圖裏,Kafka 在寫數據的時候,一方面基於 OS 層面的 Page Cache 來寫數據,所以性能很高,本質就是在寫內存罷了。

另外一個,它是採用磁盤順序寫的方式,所以即使數據刷入磁盤的時候,性能也是極高的,也跟寫內存是差不多的。

基於上面兩點,Kafka 就實現了寫入數據的超高性能。那麼大家想想,假如說 Kafka 寫入一條數據要耗費 1 毫秒的時間,那麼是不是每秒就是可以寫入 1000 條數據?

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

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

零拷貝技術

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

大家應該都知道,從 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 原理類似。

總結

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

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章