2023-07-16:講一講Kafka與RocketMQ中零拷貝技術(shù)的運(yùn)用?
2023-07-16:講一講Kafka與RocketMQ中零拷貝技術(shù)的運(yùn)用?
答案2023-07-16:
什么是零拷貝?
零拷貝(英語(yǔ): Zero-copy) 技術(shù)是指計(jì)算機(jī)執(zhí)行操作時(shí),CPU不需要先將數(shù)據(jù)從某處內(nèi)存復(fù)制到另一個(gè)特定區(qū)域。這種技術(shù)通常用于通過(guò)網(wǎng)絡(luò)傳輸文件時(shí)節(jié)省CPU周期和內(nèi)存帶寬。
?零拷貝技術(shù)可以減少數(shù)據(jù)拷貝和共享總線操作的次數(shù),消除傳輸數(shù)據(jù)在存儲(chǔ)器之間不必要的中間拷貝次數(shù),從而有效地提高數(shù)據(jù)傳輸效率
?零拷貝技術(shù)減少了用戶進(jìn)程地址空間和內(nèi)核地址空間之間因?yàn)樯?下文切換而帶來(lái)的開(kāi)銷
可以看出沒(méi)有說(shuō)不需要拷貝,只是說(shuō)減少冗余[不必要]的拷貝。
下面這些組件、框架中均使用了零拷貝技術(shù):Kafka、Netty、Rocketmq、Nginx、Apache。
傳統(tǒng)數(shù)據(jù)傳送機(jī)制
比如:讀取文件,再用socket發(fā)送出去,實(shí)際經(jīng)過(guò)四次copy。
偽碼實(shí)現(xiàn)如下:
buffer = File.read()
Socket.send(buffer)
1、第一次:將磁盤文件,讀取到操作系統(tǒng)內(nèi)核緩沖區(qū);
2、第二次:將內(nèi)核緩沖區(qū)的數(shù)據(jù),copy到應(yīng)用程序的buffer;
3、第三步:將application應(yīng)用程序buffer中的數(shù)據(jù),copy到socket網(wǎng)絡(luò)發(fā)送緩沖區(qū)(屬于操作系統(tǒng)內(nèi)核的緩沖區(qū));
4、第四次:將socket buffer的數(shù)據(jù),copy到網(wǎng)卡,由網(wǎng)卡進(jìn)行網(wǎng)絡(luò)傳輸。

分析上述的過(guò)程,雖然引入DMA來(lái)接管CPU的中斷請(qǐng)求,但四次copy是存在“不必要的拷貝”的。實(shí)際上并不需要第二個(gè)和第三個(gè)數(shù)據(jù)副本。應(yīng)用程序除了緩存數(shù)據(jù)并將其傳輸回套接字緩沖區(qū)之外什么都不做。相反,數(shù)據(jù)可以直接從讀緩沖區(qū)傳輸?shù)教捉幼志彌_區(qū)。
顯然,第二次和第三次數(shù)據(jù)copy 其實(shí)在這種場(chǎng)景下沒(méi)有什么幫助反而帶來(lái)開(kāi)銷(DMA拷貝速度一般比CPU拷貝速度快一個(gè)數(shù)量級(jí)),這也正是零拷貝出現(xiàn)的背景和意義。
打個(gè)比喻:200M的數(shù)據(jù),讀取文件,再用socket發(fā)送出去,實(shí)際經(jīng)過(guò)四次copy(2次cpu拷貝每次100ms ,2次DMS拷貝每次10ms)
傳統(tǒng)網(wǎng)絡(luò)傳輸?shù)脑挘汉嫌?jì)耗時(shí)將有220ms
mmap內(nèi)存映射(RocketMQ使用的)
硬盤上文件的位置和應(yīng)用程序緩沖區(qū)(application buffers)進(jìn)行映射(建立一種一一對(duì)應(yīng)關(guān)系),由于mmap()將文件直接映射到用戶空間,所以實(shí)際文件讀取時(shí)根據(jù)這個(gè)映射關(guān)系,直接將文件從硬盤拷貝到用戶空間,只進(jìn)行了一次數(shù)據(jù)拷貝,不再有文件內(nèi)容從硬盤拷貝到內(nèi)核空間的一個(gè)緩沖區(qū)。
mmap內(nèi)存映射將會(huì)經(jīng)歷:3次拷貝: 1次cpu copy,2次DMA copy;
打個(gè)比喻:200M的數(shù)據(jù),讀取文件,再用socket發(fā)送出去,如果是使用MMAP實(shí)際經(jīng)過(guò)三次copy(1次cpu拷貝每次100ms ,2次DMS拷貝每次10ms)合計(jì)只需要120ms
從數(shù)據(jù)拷貝的角度上來(lái)看,就比傳統(tǒng)的網(wǎng)絡(luò)傳輸,性能提升了近一倍。

RocketMQ源碼中的MMAP運(yùn)用
RocketMQ源碼中,使用MappedFile這個(gè)類類進(jìn)行MMAP的映射



Kafka中的零拷貝
Kafka兩個(gè)重要過(guò)程都使用了零拷貝技術(shù),且都是操作系統(tǒng)層面的狹義零拷貝,一是Producer生產(chǎn)的數(shù)據(jù)存到broker,二是 Consumer從broker讀取數(shù)據(jù)。
Producer生產(chǎn)的數(shù)據(jù)持久化到broker,采用mmap文件映射,實(shí)現(xiàn)順序的快速寫入;
Customer從broker讀取數(shù)據(jù),采用sendfile,將磁盤文件讀到OS內(nèi)核緩沖區(qū)后,直接轉(zhuǎn)到socket buffer進(jìn)行網(wǎng)絡(luò)發(fā)送。
sendfile
linux 2.1支持的sendfile
當(dāng)調(diào)用sendfile()時(shí),DMA將磁盤數(shù)據(jù)復(fù)制到kernel buffer,然后將內(nèi)核中的kernel buffer直接拷貝到socket buffer。在硬件支持的情況下,甚至數(shù)據(jù)都并不需要被真正復(fù)制到socket關(guān)聯(lián)的緩沖區(qū)內(nèi)。取而代之的是,只有記錄數(shù)據(jù)位置和長(zhǎng)度的描述符被加入到socket緩沖區(qū)中,DMA模塊將數(shù)據(jù)直接從內(nèi)核緩沖區(qū)傳遞給協(xié)議引擎,從而消除了遺留的最后一次復(fù)制。
一旦數(shù)據(jù)全都拷貝到socket buffer,sendfile()系統(tǒng)調(diào)用將會(huì)return、代表數(shù)據(jù)轉(zhuǎn)化的完成。socket buffer里的數(shù)據(jù)就能在網(wǎng)絡(luò)傳輸了。
sendfile會(huì)經(jīng)歷:3次拷貝,1次CPU copy ,2次DMA copy;硬件支持的情況下,則是2次拷貝,0次CPU copy, 2次DMA copy。
