DMA,Direct IO和零複製

Linux的標準IO過程中,資料將快取在Page Cache中。也就是說,在讀取資料過程中,資料將首先被複制到核心緩衝區(Page Cache),之後再由核心緩衝區複製到使用者緩衝區中;在寫資料過程中,使用者緩衝區中的內容也將首先複製到核心緩衝區,進而被寫到磁碟或者透過socket傳送到網路。

採用Page Cache,在一定程度上實現了應用程式和物理裝置的分離,也減少了IO次數,提高了系統的效能。但在某些場景下,也需要其它最佳化措施。

DMA,Direct IO和零複製

標準IO網路傳送流程

DMA:外部裝置與記憶體資料互動最佳化

在將資料讀取到核心快取和從核心緩衝寫回的過程,都要CPU全程參與。由於這個過程可花費較長時間,就會導致CPU被IO佔用,極大地降低了CPU的利用率。因此,誕生了DMA技術。DMA技術是Direct Memory Access的縮寫,其意思是“儲存器直接訪問”。它是指一種高速的資料傳輸操作,允許在外部裝置和記憶體之間直接讀寫資料,既不透過CPU,也不需要CPU干預。

DMA是指外部裝置不透過CPU而直接與系統記憶體交換資料的介面技術。要把外設的資料讀入記憶體或把記憶體的資料傳送到外設,一般都要透過CPU控制完成,如CPU程式查詢或中斷方式。利用中斷進行資料傳送,可以大大提高CPU的利用率。但是採用中斷傳送有它的缺點,對於一個高速I/O裝置,以及批次交換資料的情況,只能採用DMA方式,才能解決效率和速度問題。DMA在外設與記憶體間直接進行資料交換,而不透過CPU,這樣資料傳送的速度就取決於儲存器和外設的工作速度。

Direct IO:繞過核心緩衝區

對於某些特殊的應用程式來說,其具有自己使用者空間的快取機制,並不需要核心中快取,比如資料庫管理系統就是這列應用的代表。這種情況下,就需要採用Direct IO。Direct IO避開了核心緩衝區,在使用者地址空間和磁碟之間傳輸資料,從而降低了系統級別管理對應用程式訪問資料的影響,獲取到更好的效能。除了應用程式已經實現了磁碟檔案的快取這種場景之外,高併發環境中大檔案的傳輸也需要用到Direct IO。大檔案難以命中 PageCache 快取,又帶來額外的記憶體複製,同時還擠佔了小檔案使用 PageCache 時需要的記憶體,因此,這時應該使用Direct IO。

Direct IO繞過記憶體緩衝區,減少了核心緩衝區和使用者資料複製次數,降低了檔案讀寫所帶來的CPU負載能力和記憶體頻寬的佔用率。然而,Direct IO並非沒有缺點。首先,不經過記憶體緩衝區直接進行磁碟讀寫操作,必然會引起阻塞,因而需要將Direct IO與非同步IO一起使用。然後,除了快取外,核心(IO 排程演算法)會試圖快取儘量多的連續 IO 在 PageCache 中,最後合併成一個更大的 IO 再發給磁碟,這樣可以減少磁碟的定址操作,核心也會預讀後續的 IO 放在 PageCache 中,減少磁碟操作。Direct IO 繞過了 PageCache,所以無法享受Page Cache所帶來的效能提升。

零複製技術:繞過使用者態,使用者緩衝區不參與資料複製

考慮伺服器檔案傳輸的場景,直接讀取檔案,然後透過網路傳送出去。假如使用上面所說的標準IO,資料就需要被copy到使用者緩衝區,再從使用者緩衝區copy到核心緩衝區中。然而,如果資料並沒有發生改變,經過使用者緩衝區就是一種浪費。為了避免核心態與使用者態之間資料的多餘copy,減少上下文切換,就需要採用零複製技術。

應用程式對檔案的訪問常用的訪問方式有兩種:一種是利用系統呼叫read()和write()進行定址訪問;另一種是透過系統呼叫mmap()建立直接訪問的虛擬地址空間對映。上文標準IO所示採用了read/write方式。如果應用程式呼叫mmap(),磁碟上的資料會透過DMA被複製的核心緩衝區,接著作業系統會把這段核心緩衝區與應用程式共享,這樣就不需要把核心緩衝區的內容往使用者空間複製。應用程式再呼叫write(),作業系統直接將核心緩衝區的內容複製到socket緩衝區中,這一切都發生在核心態,最後,socket緩衝區再把資料發到網絡卡去。使用mmap替代read很明顯減少了至少一次複製,但是仍舊會有使用者空間和核心空間的上下文切換。當複製資料量很大時,將大大提升效率。使用mmap時map一個檔案前,需要對檔案進行加鎖,否則當這個檔案被另一個程序截斷(truncate)時, write系統呼叫會因為訪問非法地址而被SIGBUS訊號終止。SIGBUS訊號預設會殺死應用程序併產生一個coredump,如果伺服器這樣被中止了,那會產生一筆損失。

Linux核心還提供了sendfile操作,使用sendfile不僅減少了資料複製的次數,還減少了上下文切換,資料傳送始終只發生在核心態中。

DMA,Direct IO和零複製

使用sendfile減少一次複製

如果網絡卡支援 SG-DMA(The Scatter-Gather Direct Memory Access)技術,還可以再去除 Socket 緩衝區的複製,這樣一共只有 2 次記憶體複製。

DMA,Direct IO和零複製

支援SG-DMA網絡卡,可以減少兩次複製

最後,簡單介紹下mmap 和 sendFile 的主要區別:

mmap 適合小資料量讀寫,sendFile 適合大檔案傳輸。

mmap 需要 4 次上下文切換,3 次資料複製;sendFile 需要 3 次上下文切換,最少 2 次資料複製。

sendFile 可以利用 DMA 方式,減少 CPU 複製,mmap則不能(必須從核心複製到 Socket 緩衝區)。

DMA,Direct IO和零複製

零複製相關思維導圖