這篇文章來聊一下 Kafka 的一些架構設計原理,這也是網際網路公司面試時非常高頻的技術考點。
Kafka 是高吞吐低延遲的高併發、高效能的訊息中介軟體,在大資料領域有極為廣泛的運用。配置良好的 Kafka 叢集甚至可以做到每秒幾十萬、上百萬的超高併發寫入。
那麼 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 在寫資料的時候,一方面基於 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 每臺機器在底層對資料進行寫和讀的時候採取的是什麼樣的思路,為什麼它的效能可以那麼高,做到每秒幾十萬的吞吐量。
這種設計思想對我們平時自己設計中介軟體的架構,或者是出去面試的時候,都有很大的幫助。
看到最後的都是真愛了,感覺文章不錯的記得給小編點個贊哦,關注小編,以後會有更多的精品文章輸出哦。
作者福利:
給大家推薦一個架構技術交流群:714827309 ,裡面會分享一些資深架構師錄製的視訊錄影:有Spring,MyBatis,Netty原始碼分析
,高併發、高效能、分散式、微服務架構的原理,JVM效能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,相信對於已經工作
和遇到技術瓶頸的碼友,在這個群裡會有你需要的內容。
點選連結加入群聊【JAVA高階架構技術交流】:jq.qq.com/?_wv=1027&a…