大家好,我是樹哥。
相信大家在面試的時(shí)候會(huì)被問到:Kafka 為啥會(huì)這么快?其中我們都會(huì)說是因?yàn)?zero-copy 的緣故,但 zero-copy 中其實(shí)有很多種實(shí)現(xiàn)方式,例如:mmap + write、sendfile 等等。這其中的 mmap 到底是咋回事呢?今天我們就來講講 mmap 技術(shù)。
mmap 是一種內(nèi)存映射文件的方法,即將一個(gè)文件或者其它對(duì)象映射到進(jìn)程的地址空間,實(shí)現(xiàn)文件磁盤地址和進(jìn)程虛擬地址空間中一段虛擬地址的一一對(duì)映關(guān)系。
那么 mmap 技術(shù)有啥用呢?
答案是:減少數(shù)據(jù)文件復(fù)制,提高效率。
想一下我們讀取文件,然后將其通過網(wǎng)卡發(fā)送出去的流程,其整體流程如下所示:
圖片來自知乎博主艾小仙
上述數(shù)據(jù)讀取和發(fā)送過程發(fā)生了 4 次用戶態(tài)和內(nèi)核態(tài)的上下文切換和 4 次拷貝,具體流程如下:
- 用戶進(jìn)程通過 read () 方法向操作系統(tǒng)發(fā)起調(diào)用,此時(shí)進(jìn)程從用戶態(tài)轉(zhuǎn)向內(nèi)核態(tài)。
- DMA 控制器把數(shù)據(jù)從硬盤中拷貝到讀緩沖區(qū)。
- CPU 把讀緩沖區(qū)數(shù)據(jù)拷貝到應(yīng)用緩沖區(qū),上下文從內(nèi)核態(tài)轉(zhuǎn)為用戶態(tài),read () 返回
- 用戶進(jìn)程通過 write () 方法發(fā)起調(diào)用,上下文從用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài)
- CPU 將應(yīng)用緩沖區(qū)中數(shù)據(jù)拷貝到 socket 緩沖區(qū)
- DMA 控制器把數(shù)據(jù)從 socket 緩沖區(qū)拷貝到網(wǎng)卡,上下文從內(nèi)核態(tài)切換回用戶態(tài),write () 返回
可以看到數(shù)據(jù)要從內(nèi)核空間的讀緩沖區(qū)讀取到用戶空間的用戶緩沖區(qū),再拷貝到內(nèi)核空間的 socket 緩沖區(qū),這個(gè)過程其實(shí)是很浪費(fèi)時(shí)間的。而 mmap 技術(shù)的出現(xiàn),就是為了提高這個(gè)效率。 使用 mmap 技術(shù)進(jìn)行文件讀寫操作的過程如下圖所示:
圖片來自知乎博主艾小仙
整個(gè)過程發(fā)生了 4 次用戶態(tài)和內(nèi)核態(tài)的上下文切換和 3 次拷貝,具體流程如下:
- 用戶進(jìn)程通過 mmap () 方法向操作系統(tǒng)發(fā)起調(diào)用,上下文從用戶態(tài)轉(zhuǎn)向內(nèi)核態(tài)
- DMA 控制器把數(shù)據(jù)從硬盤中拷貝到讀緩沖區(qū)
- 上下文從內(nèi)核態(tài)轉(zhuǎn)為用戶態(tài),mmap 調(diào)用返回
- 用戶進(jìn)程通過 write () 方法發(fā)起調(diào)用,上下文從用戶態(tài)轉(zhuǎn)為內(nèi)核態(tài)
- CPU 將讀緩沖區(qū)中數(shù)據(jù)拷貝到 socket 緩沖區(qū)
- DMA 控制器把數(shù)據(jù)從 socket 緩沖區(qū)拷貝到網(wǎng)卡,上下文從內(nèi)核態(tài)切換回用戶態(tài),write () 返回
使用了 mmap 方式的文件讀寫節(jié)省了一次 CPU 拷貝,我們不需要再次從內(nèi)核空間拷貝到用戶空間,然后再從用戶空間拷貝到內(nèi)核空間。
此時(shí)我們會(huì)想:那這到底是怎么實(shí)現(xiàn)的呢?
其實(shí)這一切的背后都是操作系統(tǒng)的功勞。操作系統(tǒng)在這背后為我們做好了所有的映射和回寫工作。當(dāng)我們對(duì)內(nèi)存特定區(qū)域進(jìn)行讀寫時(shí),操作系統(tǒng)便會(huì)檢測到這一操作,然后根據(jù)不同場景去做讀磁盤或者寫磁盤的操作。
看到這里,對(duì)于 mmap 的理解基本上足夠我們應(yīng)用開發(fā)人員使用了。