天天看點

kafka如何保證每秒上百萬的超高并發寫入

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

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

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

歡迎大家關注我,需要更多Java面試資料和學習幹貨可以關注我的專欄【Tom貓的Java屋本專欄會長期更新java架構技術以及心得等精彩文章!

頁緩存技術 + 磁盤順序寫

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

kafka如何保證每秒上百萬的超高并發寫入

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

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

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

作業系統本身有一層緩存,叫做 Page Cache,是在記憶體裡的緩存,我們也可以稱之為 OS Cache,意思就是作業系統自己管理的緩存。對大資料以及人工智能概念都是模糊不清的,該按照什麼線路去學習,學完往哪方面發展,想深入了解,想學習的同學歡迎加入大資料學習扣群:資料515—269+數字485,有大量幹貨(零基礎以及進階的經典實戰)分享給大家,并且有清華大學畢業的資深大資料講師給大家免費授課,給大家分享目前國内最完整的大資料高端實戰實用學習流程體系 。從java和linux入手,其後逐漸的深入到HADOOP-hive-oozie-web-flume-python-hbase-kafka-scala-SPARK等相關知識一一分享!

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

僅僅這一個步驟,就可以将磁盤檔案寫性能提升很多了,因為其實這裡相當于是在寫記憶體,不是在寫磁盤,大家看下圖:

kafka如何保證每秒上百萬的超高并發寫入

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

也就是說,僅僅将資料追加到檔案的末尾,不是在檔案的随機位置來修改資料。

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

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

是以大家就知道了,上面那個圖裡,Kafka 在寫資料的時候,一方面基于 OS 層面的 Page Cache 來寫資料,是以性能很高,本質就是在寫記憶體罷了。

另外一個,它是采用磁盤順序寫的方式,是以即使資料刷入磁盤的時候,性能也是極高的,也跟寫記憶體是差不多的。

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

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

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

零拷貝技術

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

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

kafka如何保證每秒上百萬的超高并發寫入

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

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

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

接着從作業系統的 OS Cache 裡拷貝資料到應用程式程序的緩存裡,再從應用程式程序的緩存裡拷貝資料到作業系統層面的 Socket 緩存裡。

最後從 Socket 緩存裡提取資料後發送到網卡,最後發送出去給下遊消費。

整個過程,如下圖所示:

kafka如何保證每秒上百萬的超高并發寫入

大家看上圖,很明顯可以看到有兩次沒必要的拷貝吧!一次是從作業系統的 Cache 裡拷貝到應用程序的緩存裡,接着又從應用程式緩存裡拷貝回作業系統的 Socket 緩存裡。

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

是以這種方式來讀取資料是比較消耗性能的。Kafka 為了解決這個問題,在讀資料的時候是引入零拷貝技術。

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

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

kafka如何保證每秒上百萬的超高并發寫入
kafka如何保證每秒上百萬的超高并發寫入

通過零拷貝技術,就不需要把 OS Cache 裡的資料拷貝到應用緩存,再從應用緩存拷貝到 Socket 緩存了,兩次拷貝都省略了,是以叫做零拷貝。

對 Socket 緩存僅僅就是拷貝資料的描述符過去,然後資料就直接從 OS Cache 中發送到網卡上去了,這個過程大大的提升了資料消費時讀取檔案資料的性能。

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

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

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

總結

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

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