1. 深入理解零拷貝技術(shù)

        共 6843字,需瀏覽 14分鐘

         ·

        2021-09-01 14:58


        注意事項:除了 Direct I/O,與磁盤相關(guān)的文件讀寫操作都有使用到 page cache 技術(shù)。
        數(shù)據(jù)的四次拷貝與四次上下文切換


        很多應(yīng)用程序在面臨客戶端請求時,可以等價為進(jìn)行如下的系統(tǒng)調(diào)用:

        1. File.read(file, buf, len);

        2. Socket.send(socket, buf, len);


        例如消息中間件 Kafka 就是這個應(yīng)用場景,從磁盤中讀取一批消息后原封不動地寫入網(wǎng)卡(NIC,Network interface controller)進(jìn)行發(fā)送。

        在沒有任何優(yōu)化技術(shù)使用的背景下,操作系統(tǒng)為此會進(jìn)行 4 次數(shù)據(jù)拷貝,以及 4 次上下文切換,如下圖所示:


        如果沒有優(yōu)化,讀取磁盤數(shù)據(jù),再通過網(wǎng)卡傳輸?shù)膱鼍靶阅鼙容^差:

        4 次 copy:

        1. CPU 負(fù)責(zé)將數(shù)據(jù)從磁盤搬運到內(nèi)核空間的 Page Cache 中;

        2. CPU 負(fù)責(zé)將數(shù)據(jù)從內(nèi)核空間的 Socket 緩沖區(qū)搬運到的網(wǎng)絡(luò)中;

        3. CPU 負(fù)責(zé)將數(shù)據(jù)從內(nèi)核空間的 Page Cache 搬運到用戶空間的緩沖區(qū);

        4. CPU 負(fù)責(zé)將數(shù)據(jù)從用戶空間的緩沖區(qū)搬運到內(nèi)核空間的 Socket 緩沖區(qū)中。


        4 次上下文切換:

        1. read 系統(tǒng)調(diào)用時:用戶態(tài)切換到內(nèi)核態(tài);

        2. read 系統(tǒng)調(diào)用完畢:內(nèi)核態(tài)切換回用戶態(tài);

        3. write 系統(tǒng)調(diào)用時:用戶態(tài)切換到內(nèi)核態(tài);

        4. write 系統(tǒng)調(diào)用完畢:內(nèi)核態(tài)切換回用戶態(tài)。


        我們不免發(fā)出抱怨:

        1. CPU 全程負(fù)責(zé)內(nèi)存內(nèi)的數(shù)據(jù)拷貝還可以接受,因為效率還算可以接受,但是如果要全程負(fù)責(zé)內(nèi)存與磁盤、網(wǎng)絡(luò)的數(shù)據(jù)拷貝,這將難以接受,因為磁盤、網(wǎng)卡的速度遠(yuǎn)小于內(nèi)存,內(nèi)存又遠(yuǎn)遠(yuǎn)小于 CPU;

        2. 4 次 copy 太多了,4 次上下文切換也太頻繁了。


        DMA 參與下的數(shù)據(jù)四次拷貝


        DMA 技術(shù)很容易理解,本質(zhì)上,DMA 技術(shù)就是我們在主板上放一塊獨立的芯片。在進(jìn)行內(nèi)存和 I/O 設(shè)備的數(shù)據(jù)傳輸?shù)臅r候,我們不再通過 CPU 來控制數(shù)據(jù)傳輸,而直接通過 DMA 控制器(DMA Controller,簡稱 DMAC)。這塊芯片,我們可以認(rèn)為它其實就是一個協(xié)處理器(Co-Processor)。

        DMAC 最有價值的地方體現(xiàn)在,當(dāng)我們要傳輸?shù)臄?shù)據(jù)特別大、速度特別快,或者傳輸?shù)臄?shù)據(jù)特別小、速度特別慢的時候。

        比如說,我們用千兆網(wǎng)卡或者硬盤傳輸大量數(shù)據(jù)的時候,如果都用 CPU 來搬運的話,肯定忙不過來,所以可以選擇 DMAC。而當(dāng)數(shù)據(jù)傳輸很慢的時候,DMAC 可以等數(shù)據(jù)到齊了,再發(fā)送信號,給到 CPU 去處理,而不是讓 CPU 在那里忙等待。

        注意,這里面的“協(xié)”字。DMAC 是在“協(xié)助”CPU,完成對應(yīng)的數(shù)據(jù)傳輸工作。在 DMAC 控制數(shù)據(jù)傳輸?shù)倪^程中,我們還是需要 CPU 的進(jìn)行控制,但是具體數(shù)據(jù)的拷貝不再由 CPU 來完成。

        原本,計算機(jī)所有組件之間的數(shù)據(jù)拷貝(流動)必須經(jīng)過 CPU,如下圖所示:


        現(xiàn)在,DMA 代替了 CPU 負(fù)責(zé)內(nèi)存與磁盤以及內(nèi)存與網(wǎng)卡之間的數(shù)據(jù)搬運,CPU 作為 DMA 的控制者,如下圖所示:


        但是 DMA 有其局限性,DMA 僅僅能用于設(shè)備之間交換數(shù)據(jù)時進(jìn)行數(shù)據(jù)拷貝,但是設(shè)備內(nèi)部的數(shù)據(jù)拷貝還需要 CPU 進(jìn)行,例如 CPU 需要負(fù)責(zé)內(nèi)核空間數(shù)據(jù)與用戶空間數(shù)據(jù)之間的拷貝(內(nèi)存內(nèi)部的拷貝),如下圖所示:


        上圖中的 read buffer 也就是 page cache,socket buffer 也就是 Socket 緩沖區(qū)。


        零拷貝技術(shù)


        什么是零拷貝技術(shù)?

        零拷貝技術(shù)是一個思想,指的是指計算機(jī)執(zhí)行操作時,CPU 不需要先將數(shù)據(jù)從某處內(nèi)存復(fù)制到另一個特定區(qū)域。

        可見,零拷貝的特點是 CPU 不全程負(fù)責(zé)內(nèi)存中的數(shù)據(jù)寫入其他組件,CPU 僅僅起到管理的作用。但注意,零拷貝不是不進(jìn)行拷貝,而是 CPU 不再全程負(fù)責(zé)數(shù)據(jù)拷貝時的搬運工作。如果數(shù)據(jù)本身不在內(nèi)存中,那么必須先通過某種方式拷貝到內(nèi)存中(這個過程 CPU 可以不參與),因為數(shù)據(jù)只有在內(nèi)存中,才能被轉(zhuǎn)移,才能被 CPU 直接讀取計算。

        零拷貝技術(shù)的具體實現(xiàn)方式有很多,例如:

        • sendfile

        • mmap

        • splice

        • 直接 Direct I/O


        不同的零拷貝技術(shù)適用于不同的應(yīng)用場景,下面依次進(jìn)行 sendfile、mmap、Direct I/O 的分析。

        不過出于總結(jié)性的目的,我們在這里先對下面的技術(shù)做一個前瞻性的總結(jié)。

        • DMA 技術(shù)回顧:DMA 負(fù)責(zé)內(nèi)存與其他組件之間的數(shù)據(jù)拷貝,CPU 僅需負(fù)責(zé)管理,而無需負(fù)責(zé)全程的數(shù)據(jù)拷貝;

        • 使用 page cache 的 zero copy:

          • sendfile:一次代替 read/write 系統(tǒng)調(diào)用,通過使用 DMA 技術(shù)以及傳遞文件描述符,實現(xiàn)了 zero copy

          • mmap:僅代替 read 系統(tǒng)調(diào)用,將內(nèi)核空間地址映射為用戶空間地址,write 操作直接作用于內(nèi)核空間。通過 DMA 技術(shù)以及地址映射技術(shù),用戶空間與內(nèi)核空間無須數(shù)據(jù)拷貝,實現(xiàn)了 zero copy


        • 不使用 page cache 的 Direct I/O:讀寫操作直接在磁盤上進(jìn)行,不使用 page cache 機(jī)制,通常結(jié)合用戶空間的用戶緩存使用。通過 DMA 技術(shù)直接與磁盤/網(wǎng)卡進(jìn)行數(shù)據(jù)交互,實現(xiàn)了 zero copy


        sendfile

        snedfile 的應(yīng)用場景是:用戶從磁盤讀取一些文件數(shù)據(jù)后不需要經(jīng)過任何計算與處理就通過網(wǎng)絡(luò)傳輸出去。此場景的典型應(yīng)用是消息隊列。

        在傳統(tǒng) I/O 下,正如第一節(jié)所示,上述應(yīng)用場景的一次數(shù)據(jù)傳輸需要四次 CPU 全權(quán)負(fù)責(zé)的拷貝與四次上下文切換,正如本文第一節(jié)所述。

        sendfile 主要使用到了兩個技術(shù):

        1. DMA 技術(shù);

        2. 傳遞文件描述符代替數(shù)據(jù)拷貝。


        下面依次講解這兩個技術(shù)的作用。

        利用 DMA 技術(shù)

        sendfile 依賴于 DMA 技術(shù),將四次 CPU 全程負(fù)責(zé)的拷貝與四次上下文切換減少到兩次,如下圖所示:

        利用 DMA 技術(shù)減少 2 次 CPU 全程參與的拷貝

        DMA 負(fù)責(zé)磁盤到內(nèi)核空間中的 Page cache(read buffer)的數(shù)據(jù)拷貝以及從內(nèi)核空間中的 socket buffer 到網(wǎng)卡的數(shù)據(jù)拷貝。

        傳遞文件描述符代替數(shù)據(jù)拷貝

        傳遞文件描述可以代替數(shù)據(jù)拷貝,這是由于兩個原因:

        • page cache 以及 socket buffer 都在內(nèi)核空間中;

        • 數(shù)據(jù)傳輸過程前后沒有任何寫操作。


        利用傳遞文件描述符代替內(nèi)核中的數(shù)據(jù)拷貝

        注意事項:只有網(wǎng)卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技術(shù)才可以通過傳遞文件描述符的方式避免內(nèi)核空間內(nèi)的一次 CPU 拷貝。這意味著此優(yōu)化取決于 Linux 系統(tǒng)的物理網(wǎng)卡是否支持(Linux 在內(nèi)核 2.4 版本里引入了 DMA 的 scatter/gather -- 分散/收集功能,只要確保 Linux 版本高于 2.4 即可)。

        一次系統(tǒng)調(diào)用代替兩次系統(tǒng)調(diào)用

        由于 sendfile 僅僅對應(yīng)一次系統(tǒng)調(diào)用,而傳統(tǒng)文件操作則需要使用 read 以及 write 兩個系統(tǒng)調(diào)用。

        正因為如此,sendfile 能夠?qū)⒂脩魬B(tài)與內(nèi)核態(tài)之間的上下文切換從 4 次講到 2 次。

        sendfile 系統(tǒng)調(diào)用僅僅需要兩次上下文切換

        另一方面,我們需要注意 sendfile 系統(tǒng)調(diào)用的局限性。如果應(yīng)用程序需要對從磁盤讀取的數(shù)據(jù)進(jìn)行寫操作,例如解密或加密,那么 sendfile 系統(tǒng)調(diào)用就完全沒法用。這是因為用戶線程根本就不能夠通過 sendfile 系統(tǒng)調(diào)用得到傳輸?shù)臄?shù)據(jù)。

        mmap

        mmap 技術(shù)在這篇文章[1]中單獨展開,請移步閱讀。

        Direct I/O

        Direct I/O 即直接 I/O。其名字中的“直接”二字用于區(qū)分使用 page cache 機(jī)制的緩存 I/O。

        • 緩存文件 I/O:用戶空間要讀寫一個文件并不直接與磁盤交互,而是中間夾了一層緩存,即 page cache;

        • 直接文件 I/O:用戶空間讀取的文件直接與磁盤交互,沒有中間 page cache 層。


        “直接”在這里還有另一層語義:其他所有技術(shù)中,數(shù)據(jù)至少需要在內(nèi)核空間存儲一份,但是在 Direct I/O 技術(shù)中,數(shù)據(jù)直接存儲在用戶空間中,繞過了內(nèi)核。

        Direct I/O 模式如下圖所示:

        Direct I/O 示意圖

        此時用戶空間直接通過 DMA 的方式與磁盤以及網(wǎng)卡進(jìn)行數(shù)據(jù)拷貝。

        Direct I/O 的讀寫非常有特點:

        • Write 操作:由于其不使用 page cache,所以其進(jìn)行寫文件,如果返回成功,數(shù)據(jù)就真的落盤了(不考慮磁盤自帶的緩存);

        • Read 操作:由于其不使用 page cache,每次讀操作是真的從磁盤中讀取,不會從文件系統(tǒng)的緩存中讀取。


        事實上,即使 Direct I/O 還是可能需要使用操作系統(tǒng)的 fsync 系統(tǒng)調(diào)用。為什么?

        這是因為雖然文件的數(shù)據(jù)本身沒有使用任何緩存,但是文件的元數(shù)據(jù)仍然需要緩存,包括 VFS 中的 inode cache 和 dentry cache 等。

        在部分操作系統(tǒng)中,在 Direct I/O 模式下進(jìn)行 write 系統(tǒng)調(diào)用能夠確保文件數(shù)據(jù)落盤,但是文件元數(shù)據(jù)不一定落盤。如果在此類操作系統(tǒng)上,那么還需要執(zhí)行一次 fsync 系統(tǒng)調(diào)用確保文件元數(shù)據(jù)也落盤。否則,可能會導(dǎo)致文件異常、元數(shù)據(jù)確實等情況。MySQL 的 O_DIRECT 與 O_DIRECT_NO_FSYNC 配置是一個具體案例。

        Direct I/O 的優(yōu)缺點:

        優(yōu)點:

        1. Linux 中的直接 I/O 技術(shù)省略掉緩存 I/O 技術(shù)中操作系統(tǒng)內(nèi)核緩沖區(qū)的使用,數(shù)據(jù)直接在應(yīng)用程序地址空間和磁盤之間進(jìn)行傳輸,從而使得自緩存應(yīng)用程序可以省略掉復(fù)雜的系統(tǒng)級別的緩存結(jié)構(gòu),而執(zhí)行程序自己定義的數(shù)據(jù)讀寫管理,從而降低系統(tǒng)級別的管理對應(yīng)用程序訪問數(shù)據(jù)的影響。

        2. 與其他零拷貝技術(shù)一樣,避免了內(nèi)核空間到用戶空間的數(shù)據(jù)拷貝,如果要傳輸?shù)臄?shù)據(jù)量很大,使用直接 I/O 的方式進(jìn)行數(shù)據(jù)傳輸,而不需要操作系統(tǒng)內(nèi)核地址空間拷貝數(shù)據(jù)操作的參與,這將會大大提高性能。


        缺點:

        1. 由于設(shè)備之間的數(shù)據(jù)傳輸是通過 DMA 完成的,因此用戶空間的數(shù)據(jù)緩沖區(qū)內(nèi)存頁必須進(jìn)行 page pinning(頁鎖定),這是為了防止其物理頁框地址被交換到磁盤或者被移動到新的地址而導(dǎo)致 DMA 去拷貝數(shù)據(jù)的時候在指定的地址找不到內(nèi)存頁從而引發(fā)缺頁錯誤,而頁鎖定的開銷并不比 CPU 拷貝小,所以為了避免頻繁的頁鎖定系統(tǒng)調(diào)用,應(yīng)用程序必須分配和注冊一個持久的內(nèi)存池,用于數(shù)據(jù)緩沖。

        2. 如果訪問的數(shù)據(jù)不在應(yīng)用程序緩存中,那么每次數(shù)據(jù)都會直接從磁盤進(jìn)行加載,這種直接加載會非常緩慢。

        3. 在應(yīng)用層引入直接 I/O 需要應(yīng)用層自己管理,這帶來了額外的系統(tǒng)復(fù)雜性。


        誰會使用 Direct I/O?

        IBM的一篇文章[2]指出,自緩存應(yīng)用程序( self-caching applications)可以選擇使用 Direct I/O。
        自緩存應(yīng)用程序

        對于某些應(yīng)用程序來說,它會有它自己的數(shù)據(jù)緩存機(jī)制,比如,它會將數(shù)據(jù)緩存在應(yīng)用程序地址空間,這類應(yīng)用程序完全不需要使用操作系統(tǒng)內(nèi)核中的高速緩沖存儲器,這類應(yīng)用程序就被稱作是自緩存應(yīng)用程序( self-caching applications )。


        例如,應(yīng)用內(nèi)部維護(hù)一個緩存空間,當(dāng)有讀操作時,首先讀取應(yīng)用層的緩存數(shù)據(jù),如果沒有,那么就通過 Direct I/O 直接通過磁盤 I/O 來讀取數(shù)據(jù)。緩存仍然在應(yīng)用,只不過應(yīng)用覺得自己實現(xiàn)一個緩存比操作系統(tǒng)的緩存更高效。


        數(shù)據(jù)庫管理系統(tǒng)是這類應(yīng)用程序的一個代表。自緩存應(yīng)用程序傾向于使用數(shù)據(jù)的邏輯表達(dá)方式,而非物理表達(dá)方式;當(dāng)系統(tǒng)內(nèi)存較低的時候,自緩存應(yīng)用程序會讓這種數(shù)據(jù)的邏輯緩存被換出,而并非是磁盤上實際的數(shù)據(jù)被換出。自緩存應(yīng)用程序?qū)σ僮鞯臄?shù)據(jù)的語義了如指掌,所以它可以采用更加高效的緩存替換算法。自緩存應(yīng)用程序有可能會在多臺主機(jī)之間共享一塊內(nèi)存,那么自緩存應(yīng)用程序就需要提供一種能夠有效地將用戶地址空間的緩存數(shù)據(jù)置為無效的機(jī)制,從而確保應(yīng)用程序地址空間緩存數(shù)據(jù)的一致性。

        另一方面,目前 Linux 上的異步 IO 庫,其依賴于文件使用 O_DIRECT 模式打開,它們通常一起配合使用。

        如何使用 Direct I/O?

        用戶應(yīng)用需要實現(xiàn)用戶空間內(nèi)的緩存區(qū),讀/寫操作應(yīng)當(dāng)盡量通過此緩存區(qū)提供。如果有性能上的考慮,那么盡量避免頻繁地基于 Direct I/O 進(jìn)行讀/寫操作。


        典型案例


        Kakfa

        Kafka 作為一個消息隊列,涉及到磁盤 I/O 主要有兩個操作:

        • Provider 向 Kakfa 發(fā)送消息,Kakfa 負(fù)責(zé)將消息以日志的方式持久化落盤;

        • Consumer 向 Kakfa 進(jìn)行拉取消息,Kafka 負(fù)責(zé)從磁盤中讀取一批日志消息,然后再通過網(wǎng)卡發(fā)送。


        Kakfa 服務(wù)端接收 Provider 的消息并持久化的場景下使用 mmap 機(jī)制,能夠基于順序磁盤 I/O 提供高效的持久化能力,使用的 Java 類為 java.nio.MappedByteBuffer。

        Kakfa 服務(wù)端向 Consumer 發(fā)送消息的場景下使用 sendfile 機(jī)制,這種機(jī)制主要兩個好處:

        • sendfile 避免了內(nèi)核空間到用戶空間的 CPU 全程負(fù)責(zé)的數(shù)據(jù)移動;

        • sendfile 基于 Page Cache 實現(xiàn),因此如果有多個 Consumer 在同時消費一個主題的消息,那么由于消息一直在 page cache 中進(jìn)行了緩存,因此只需一次磁盤 I/O,就可以服務(wù)于多個 Consumer。

        使用 mmap 來對接收到的數(shù)據(jù)進(jìn)行持久化,使用 sendfile 從持久化介質(zhì)中讀取數(shù)據(jù)然后對外發(fā)送是一對常用的組合。但是注意,你無法利用 sendfile 來持久化數(shù)據(jù),利用 mmap 來實現(xiàn) CPU 全程不參與數(shù)據(jù)搬運的數(shù)據(jù)拷貝。MySQL

        MySQL 的具體實現(xiàn)比 Kakfa 復(fù)雜很多,這是因為支持 SQL 查詢的數(shù)據(jù)庫本身比消息隊列對復(fù)雜很多。

        MySQL

        的零拷貝技術(shù)使用方式請移步我的另一篇文章[3]。

        總結(jié)


        DMA 技術(shù)的推出使得內(nèi)存與其他組件,例如磁盤、網(wǎng)卡進(jìn)行數(shù)據(jù)拷貝時,CPU 僅僅需要發(fā)出控制信號,而拷貝數(shù)據(jù)的過程則由 DMA 負(fù)責(zé)完成。

        Linux 的零拷貝技術(shù)有多種實現(xiàn)策略,但根據(jù)策略可以分為如下幾種類型:

        • 減少甚至避免用戶空間和內(nèi)核空間之間的數(shù)據(jù)拷貝:在一些場景下,用戶進(jìn)程在數(shù)據(jù)傳輸過程中并不需要對數(shù)據(jù)進(jìn)行訪問和處理,那么數(shù)據(jù)在 Linux 的 Page Cache 和用戶進(jìn)程的緩沖區(qū)之間的傳輸就完全可以避免,讓數(shù)據(jù)拷貝完全在內(nèi)核里進(jìn)行,甚至可以通過更巧妙的方式避免在內(nèi)核里的數(shù)據(jù)拷貝。這一類實現(xiàn)一般是是通過增加新的系統(tǒng)調(diào)用來完成的,比如 Linux 中的 mmap(),sendfile() 以及 splice() 等。

        • 繞過內(nèi)核的直接 I/O:允許在用戶態(tài)進(jìn)程繞過內(nèi)核直接和硬件進(jìn)行數(shù)據(jù)傳輸,內(nèi)核在傳輸過程中只負(fù)責(zé)一些管理和輔助的工作。這種方式其實和第一種有點類似,也是試圖避免用戶空間和內(nèi)核空間之間的數(shù)據(jù)傳輸,只是第一種方式是把數(shù)據(jù)傳輸過程放在內(nèi)核態(tài)完成,而這種方式則是直接繞過內(nèi)核和硬件通信,效果類似但原理完全不同。

        • 內(nèi)核緩沖區(qū)和用戶緩沖區(qū)之間的傳輸優(yōu)化:這種方式側(cè)重于在用戶進(jìn)程的緩沖區(qū)和操作系統(tǒng)的頁緩存之間的 CPU 拷貝的優(yōu)化。這種方法延續(xù)了以往那種傳統(tǒng)的通信方式,但更靈活。


        相關(guān)鏈接:

        1. https://spongecaptain.cool/SimpleClearFileIO/3.%20mmap.html

        2. https://www.ibm.com/developerworks/cn/linux/l-cn-directio/

        3. https://spongecaptain.cool/zerocopyofmysql


        原文鏈接:https://github.com/Spongecaptain/SimpleClearFileIO/blob/main/2.%20DMA%20與零拷貝技術(shù).md


        推薦閱讀:

        世界的真實格局分析,地球人類社會底層運行原理

        不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

        企業(yè)IT技術(shù)架構(gòu)規(guī)劃方案

        論數(shù)字化轉(zhuǎn)型——轉(zhuǎn)什么,如何轉(zhuǎn)?

        華為干部與人才發(fā)展手冊(附PPT)

        企業(yè)10大管理流程圖,數(shù)字化轉(zhuǎn)型從業(yè)者必備!

        【中臺實踐】華為大數(shù)據(jù)中臺架構(gòu)分享.pdf

        華為的數(shù)字化轉(zhuǎn)型方法論

        華為如何實施數(shù)字化轉(zhuǎn)型(附PPT)

        超詳細(xì)280頁Docker實戰(zhàn)文檔!開放下載

        華為大數(shù)據(jù)解決方案(PPT)


        瀏覽 24
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
          
          

            1. av中文网 | 国产乱子轮XXX农村 | AA片在线观看视频在线播放 | 草草视频在线播放 | 性做久久久久久免费观看 |