最近一個學員去滴滴面試,在第二面的時候遇到了這個問題:
"請你簡單說一下Kafka的零拷貝原理"
然后那個學員努力在大腦里檢索了很久,沒有回答上來。
那么今天,我們基於這個問題來看看,普通人和高手是如何回答的!
普通人的回答:
零拷貝是一種減少數據拷貝的機制,能夠有效提升數據的效率
高手的回答:
在實際應用中,如果我們需要把磁盤中的某個文件內容發送到遠程服務器上,如圖
那么它必須要經過幾個拷貝的過程:
- 從磁盤中讀取目標文件內容拷貝到內核緩沖區
- CPU控制器再把內核緩沖區的數據賦值到用戶空間的緩沖區中
- 接着在應用程序中,調用
write()
方法,把用戶空間緩沖區中的數據拷貝到內核下的Socket Buffer中。 - 最后,把在內核模式下的SocketBuffer中的數據賦值到網卡緩沖區(NIC Buffer)
- 網卡緩沖區再把數據傳輸到目標服務器上。
在這個過程中我們可以發現,數據從磁盤到最終發送出去,要經歷4次拷貝,而在這四次拷貝過程中,有兩次拷貝是浪費的,分別是:
- 從內核空間賦值到用戶空間
- 從用戶空間再次復制到內核空間
除此之外,由於用戶空間和內核空間的切換會帶來CPU的上線文切換,對於CPU性能也會造成性能影響。
而零拷貝,就是把這兩次多於的拷貝省略掉,應用程序可以直接把磁盤中的數據從內核中直接傳輸給Socket,而不需要再經過應用程序所在的用戶空間,如下圖所示。
零拷貝通過DMA(Direct Memory Access)技術把文件內容復制到內核空間中的Read Buffer。
接着把包含數據位置和長度信息的文件描述符加載到Socket Buffer中,DMA引擎直接可以把數據從內核空間中傳遞給網卡設備。
在這個流程中,數據只經歷了兩次拷貝就發送到了網卡中,並且減少了2次cpu的上下文切換,對於效率有非常大的提高。
所以,所謂零拷貝,並不是完全沒有數據賦值,只是相對於用戶空間來說,不再需要進行數據拷貝。對於前面說的整個流程來說,零拷貝只是減少了不必要的拷貝次數而已。
在程序中如何實現零拷貝呢?
- 在Linux中,零拷貝技術依賴於底層的sendfile()方法實現
- 在Java中,FileChannal.transferTo() 方法的底層實現就是 sendfile() 方法。
除此之外,還有一個 mmap 的文件映射機制
它的原理是:將磁盤文件映射到內存, 用戶通過修改內存就能修改磁盤文件。使用這種方式可以獲取很大的I/O提升,省去了用戶空間到內核空間復制的開銷。
以上就是我對於Kafka中零拷貝原理的理解
總結
本期的普通人VS高手面試系列就到這里結束了。
本次的面試題涉及到一些計算機底層的原理,基本上也是業務程序員的知識盲區。
但我想提醒大家,做開發其實和建房子一樣,要想樓層更高更穩,首先地基要打牢固。
另外,如果你有任何面試相關的疑問,歡迎評論區給我留言。
我是Mic,一個工作了14年的Java程序員,咱們下篇文章再見。