Kafka技術知識總結之七——Kafka磁盤存儲

接上篇《Kafka技術知識總結之六——Kafka負載均衡策略》

七. 磁盤存儲

參考地址:
《Kafka如何實現每秒上百萬的高併發寫入》
《深入理解 Kafka:核心設計與實踐原理》5.5 章節

Kafka 在大數據領域有極爲廣泛的運用,配置良好的 Kafka 集羣甚至可以做到每秒幾十萬、上百萬的超高併發寫入。通常磁盤寫入是一種非常緩慢的操作,Kafka 的高併發寫入主要是依靠頁緩存零拷貝兩種技術實現的。

7.1 頁緩存

操作系統本身有一層緩存,叫做頁緩存 (Page Cache),又被稱爲 OS Cache,即爲操作系統自己管理的緩存。頁緩存可以將磁盤中的數據緩存到內存中,將對磁盤的訪問轉換爲對內存的訪問。
Kafka 大量使用了頁緩存,Kafka 在準備將消息寫入磁盤中時,可以直接寫入頁緩存中,接下來操作系統自己決定什麼時候將頁緩存中的數據真正刷入磁盤中。這樣的設計使得 Kafka 將消息寫入磁盤的效率大幅提升。
Kafka頁緩存

此外 Kafka 寫入數據時採用了文件追加的方式寫入消息,在日誌文件的尾部追加新消息,屬於典型的順序寫盤的操作,它依賴於硬盤來存儲和緩存消息。通常來說,內存的讀寫效率要高於磁盤,但磁盤的順序讀寫效率也是非常高的,順序寫磁盤的速度甚至高於隨機寫內存的速率。所以 Kafka 使用了順序寫磁盤的方式做持久化工作。

7.2 零拷貝 (Zero-Copy)

頁緩存技術主要用於消息寫入 Kafka Broker 端的磁盤,零拷貝技術用於 Kafka Broker 將消息推送給下游消費者。

7.2.1 傳統 IO

Kafka Broker 將消息發送給下游的消費者,如果在什麼優化都不做的情況下,應該是如下流程:

  1. Kafka Broker 從磁盤中讀取消息數據到系統內存;(內核模式)
  2. 系統內存拷貝數據到 Kafka Server 服務的緩存中(內核模式 -> 應用模式)
  3. Kafka Server 服務將緩存中的消息數據複製到操作系統的 Socket 緩存中(應用模式 -> 內核模式)
  4. Socket 緩存將消息數據通過網卡發送出去(內核模式)

上面未優化的過程中,步驟 2 與步驟 3 是沒有必要的,這兩個步驟中間發生了兩次沒有必要的上下文切換,而上下文切換是十分消耗性能的。上下文切換狀態如下圖所示:
傳統IO上下文切換

注:傳統的拷貝方法爲:

  1. 當設備接收到數據,向 CPU 報告中斷;
  2. CPU 處理中斷;
  3. CPU 將數據從設備寄存器數據讀到內存;

傳統拷貝方法的步驟 2, 3 是先等待 CPU 中斷處理完畢後,再將數據讀入內存。而每次的 IO 中斷都會帶來 CPU 的上下文切換
在現代操作系統中引入了直接內存訪問 (DMA, Direct Memory Access) 技術,它允許不同速度的硬件裝置溝通,不需要依賴 CPU 的大量中斷負載,數據的讀寫請求由 DMA 控制器接管,減少了 CPU 的負擔。

7.2.2 零拷貝技術

參考地址:
《零拷貝簡述》
高性能IO背後原理—零拷貝技術概述

Kafka 爲了解決這個問題,在讀消息時引入了零拷貝技術。零拷貝技術跳過了步驟 2 與步驟 3,跳過了兩個上下文切換的步驟,將內核中的數據直接傳輸給 Socket 緩存,如下圖所示。
無描述符零拷貝
上圖中的 transferTo() 方法調用過程中的步驟如下:

  1. transferTo() 方法觸發 DMA 引擎,將文件內容拷貝到一個讀取緩衝區;(內核模式)
  2. 內核將數據拷貝到 Socket 緩衝區;(內核模式)
  3. DMA 引擎將數據從 Socket 緩衝傳到網卡設備。(內核模式)

這樣就將上下文切換次數減少到兩次,即只留下必須的兩次切換。但依舊還有優化的內容。因爲步驟 2 中的拷貝過程屬於重複拷貝,可以將該步驟進行優化。步驟如下:

  1. transferTo() 方法觸發 DMA 引擎,將文件內容拷貝到內核緩衝區;(內核模式)
  2. 關於數據的位置和長度的信息的描述符被追加到了 Socket 緩衝;
  3. DMA 引擎將數據從 Socket 緩衝傳到網卡設備。(內核模式)

通過使用拷貝描述符的方法取代了拷貝數據,消除了剩下的最後一次 CPU 拷貝。

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