如果你瞭解過 Kafka,那麼它用到的一個效能最佳化技術可能會引起你的注意 -- 作業系統的零複製(zero-copy)最佳化。
零複製操作可以避免對資料的非必要複製,當然,並非是說完全沒有複製。
在 Kafka 的場景下,作業系統可以從 page cache 複製資料到 socket buffer,直接繞過 Kafka broker 這個 Java 程式。這可以節省一些額外的複製,節省一些使用者態和核心態的切換。讓我們看一個例子。
傳統複製
如果您的應用程式要從磁碟讀取檔案並透過網路傳送它,則可能會進行一堆不必要的複製,以及使用者態/核心態的切換。
一些術語:
- read buffer: 讀緩衝區,作業系統的 page cache
- socket buffer: 套接字緩衝區,OS 用於管理資料包的位元組緩衝區
- NIC buffer: 網路卡中的位元組緩衝區
- DMA copy: DMA 是 Direct Memory Access 的縮寫,是記憶體控制器的一個功能,可以避免 CPU 的干預,允許硬體(圖形卡、音效卡、網路卡等)直接訪問記憶體 (RAM) 裡的某些資料
在這個例子中,我們有 4 次模式切換(使用者態和核心態之間的切換)和 4 次資料複製。
- 應用程式(這裡指 Kafka)利用 DMA copy 從磁碟 load 資料到 read buffer(
使用者態->核心態
) - read buffer 到應用程式的快取區(
核心態->使用者態
) - 應用程式要發資料到網路上,實際是先寫到 socket buffer(
使用者態->核心態
) - socket buffer 到 NIC buffer(響應資料寫完之後,由核心態返回使用者態)
零複製
為了減少複製,把資料從磁碟直接發向網路,那 Kafka 在儲存資料的時候,就要保證儲存的資料格式和將要發出的 response 格式一致。
在傳統複製模式下,第二步、第三步沒啥意義,因為 Kafka 沒有對資料做額外處理,只是簡單轉發。那能否從磁碟直接發向網路呢?答案是肯定的。透過零複製技術,磁碟上的資料還是要先進入 read buffer,然後不用再複製到應用程式的快取區,而是直接複製到 NIC buffer,圖上的步驟 2:Appends just file descriptors,只是把檔案描述符交給了 Socket buffer,實際資料並沒有複製給 Socket buffer。這就是所謂的 scatter-gather 操作(也稱為 Vectorized I/O),scatter-gather 是僅將 read buffer 資料指標儲存在 socket buffer 中,並讓 DMA 直接從記憶體讀取資料的行為。
最終結果如何呢?
- 4 次模式切換變成了 2 次
- 2 次 DMA 複製,仍然是 2 次
- 1 次微小的指標複製
在 Kafka 中
你可能聽過 Kafka 因為零複製實現了高效能,但是理想很豐滿現實很骨感,零複製技術在大部分 Kafka 叢集中並沒有那麼大的影響力。
- CPU 很少成為瓶頸。網路飽和的速度要快得多,因此在大多數情況下,記憶體中副本的缺失並不會帶來多大的影響。
- 啟用加密和 SSL/TLS 已經禁止 Kafka 使用零複製
原文:https://2minutestreaming.beehiiv.com/p/apache-kafka-zero-copy-operating-system-optimization
譯者:巴輝特,極客時間專欄《運維監控系統實戰筆記》作者,Open-Falcon、Nightingale 開源專案發起人,目前創業中,作為 Flashcat 聯合創始人,專攻監控/可觀測性方向。歡迎和我一起探討監控/可觀測性相關技術和產品。