作者:源碼時代-Raymon老師
Kafka的高吞吐、低延時、高性能的實現原理
Kafka是大數據領域無處不在的消息中間件,目前廣泛使用在企業內部的實時數據管道,并幫助企業構建自己的流計算應用程序。Kafka雖然是基于磁盤做的數據存儲,但卻具有高性能、高吞吐、低延時的特點,其吞吐量動輒幾萬、幾十上百萬,這其中的原由值得我們一探究竟,讓我們一起掌握Kafka各種精巧的設計。
吞吐量:吞吐量是指在一定時間內通過系統、網絡或設備傳輸的數據量或處理的事務數量。它是衡量系統性能和效率的重要指標之一。
- 對于網絡,吞吐量可以指網絡連接的數據傳輸速率,單位可以是字節/秒或比特/秒
- 對于服務器或數據庫系統,吞吐量可以表示系統每秒能夠處理的事務或請求的數量
- 在存儲系統中,吞吐量可以表示系統每秒讀取或寫入的數據量。
較高的吞吐量意味著系統能夠更快地處理數據,而較低的吞吐量可能導致數據傳輸延遲和系統繁忙。
kafka,每毫秒可以處理1條數據,每秒可以處理1000條數據,這個單位時間內可以處理多少條數據,就叫做吞吐量,1000條數據,每條數據10kb,吞吐量相當于是每秒處理大概10mb的數據
低延遲:低延遲是指系統或應用在處理請求或傳輸數據時所需的時間盡可能地短。
如果來一條數據就處理一條數據,可能會導致每條數據要處理假設1毫秒,那么此時每秒可以處理1000條數據,這就是每秒的吞吐量,但是如果采用微批處理技術呢?比如說把10毫秒內的數據收集起來一共有1000條數據,接著一次性交給引擎來處理,1毫秒就把1000條數據給處理完了。那么1秒內就可以處理10萬條數據,吞吐量直接提升100倍。
這個就是所謂的流式計算采用的微批處理技術,你一條一條處理,每條數據都需要啟動新的計算資源,有網絡開銷,甚至是磁盤開銷。但是你一次性處理1000條,跟你一次性處理1條其實是差不多的。
接下來我們看看Kafka的高吞吐以及低延時實現的底層原理是什么。
1、頁緩存技術 + 磁盤順序寫
首先Kafka每次接收到數據都會往磁盤上去寫,如下圖所示:
如果把數據基于磁盤來存儲,頻繁的往磁盤文件里寫數據,這個性能會不會很差?大家肯定都覺得磁盤寫性能是極差的。
但是實際上Kafka在這里有極為優秀和出色的設計,就是為了保證數據寫入性能,首先Kafka是基于操作系統的頁緩存來實現文件寫入的。(操作系統本身有一層緩存,叫做page cache,是在內存里的緩存,我們也可以稱之為os cache,意思就是操作系統自己管理的緩存。)
在寫入磁盤文件的時候,可以直接寫入這個os cache里,也就是僅僅寫入內存中,接下來由操作系統自己決定什么時候把os cache里的數據真的刷入磁盤文件中。
僅僅這一個步驟,就可以將磁盤文件寫性能提升很多了,因為這里相當于是在寫內存,不是在寫磁盤,大家看下圖:
光有頁緩存這一點已經可以提升很多性能了,但是kafka在這里還使用到一個磁盤順序寫的技術,也就是說,僅僅將數據追加到文件的末尾,不是在文件的隨機位置來修改數據。
對于一塊硬盤,它有幾個重要指標:順序讀寫能力和隨機讀寫能力. 若把硬盤比作一個倉庫,硬盤中的數據比作倉庫中各種各樣的貨物. 硬盤的讀寫比作倉庫中一個工人的進貨和出貨. 這時如果一個工人需要取一個大電冰箱,雖然冰箱很大很重,但是工人卻能很快完成,這就是順序讀寫.
但如果一個工作需要同時取一瓶水,一個文具盒、一包面包、一個鼠標、一管牙膏等,雖然它們很小很輕,但工作必須跑遍整個倉庫才能拿到它們. 因此,工人往往會做的更慢,這就是隨機讀寫.
小結:
頁緩存+磁盤順序寫的方式讓kafka的寫性能極高,最大程度減少了每條數據處理的時間開銷,反過來就大幅度提升了每秒處理數據的吞吐量,一般kafka部署在物理機上,單機每秒寫入幾萬到幾十萬條消息是沒問題的。
這種方式同時也兼顧了低延遲和高吞吐兩個要求,盡量把每條消息的寫入性能壓榨到極致,就可以實現低延遲的寫入,同時對應的每秒的吞吐量自然就提升了,這也是kafka非常核心的一個底層機制。
2、零拷貝實現高性能讀取
那么在消費數據的時候,需要從磁盤文件里讀取數據后通過網絡發送出去,這個時候怎么提升性能呢?
首先就是利用了page cache技術,之前說過,kafka寫入數據到磁盤文件的時候,實際上是寫入page cache的,沒有直接發生磁盤IO,所以寫入的數據大部分都是停留在os層的page cache里的(這個本質其實跟elasticsearch的實現原理是類似的)
然后在讀取的時候,如果正常情況下從磁盤讀取數據,先嘗試從page cache讀,讀不到才從磁盤IO讀,讀到數據以后先會放在os層的一個page cache里,接著會發生上下文切換到系統那邊,把os的讀緩存數據拷貝到應用緩存里。
接著再次發生上下文切換到os層,把應用緩存的數據拷貝到os的socket緩存中,最后數據再發送到網卡上:【非零拷貝的實現方案】
這個過程里,發生了好幾次上下文切換,而且還涉及到了好幾次數據拷貝,如果不考慮跟硬件之間的交互,起碼是從os cache到用戶緩存,從用戶緩存到socket緩存,有兩次拷貝是絕對沒必要的。
但是如果用零拷貝技術,就是linux的sendfile,就可以直接把操作交給os,os看page cache里是否有數據,如果沒有就從磁盤上讀取,如果有的話直接把os cache里的數據拷貝給網卡了,中間不用走那么多步驟了:【零拷貝技術】
跟上圖一對比是不是零拷貝技術就快多了?所以呢,通過零拷貝技術來讀取磁盤上的數據,還有page cahce的幫助,這個性能就非常高了。