五、pagecache 有什麼作用?
六、大檔案傳輸用什麼方式實現?
七、總結
磁碟可以說是計算機系統最慢的硬體之一,讀寫速度相差記憶體 10 倍以上,所以針對優化磁碟的技術非常的多,比如零拷貝、直接 i/o、非同步 i/o 等等,這些優化的目的就是為了提高系統的吞吐量,另外作業系統核心中的磁碟快取記憶體區,可以有效的減少磁碟的訪問次數
。
為了方便你理解,我畫了一副圖:
那使用 dma 控制器進行資料傳輸的過程究竟是什麼樣的呢?
;所以,要想減少上下文切換到次數,就要減少系統呼叫的次數
。
下面就談一談,它們是如何減少「上下文切換」和「資料拷貝」的次數
。
所以,總體來看,零拷貝技術可以把檔案傳輸的效能提高至少一倍以上
這兩個做法,將大大提高讀寫磁碟的效能。那針對大檔案的傳輸,我們應該使用什麼方式呢?
我們先來看看最初的例子,當呼叫 read 方法讀取檔案時,程序實際上會阻塞在 read 方法呼叫,因為要等待磁碟資料的返回,如下圖:
對於阻塞的問題,可以用非同步 i/o
來解決,它工作方式如下圖:
而且,我們可以發現,非同步 i/o 並沒有涉及到 pagecache,所以使用非同步 i/o 就意味著要繞開 pagecache。
繞開 pagecache 的 i/o 叫直接 i/o,使用 pagecache 的 i/o 則叫快取 i/o。通常,對於磁碟,非同步 i/o 只支援直接 i/o。
前面也提到,大檔案的傳輸不應該使用 pagecache,因為可能由於 pagecache 被大檔案佔據,而導致「熱點」小檔案無法利用到 pagecache。
於是,傳輸大檔案的時候,使用「非同步 i/o + 直接 i/o」了,就可以無阻塞地讀取檔案了。
早期 i/o 操作,記憶體與磁碟的資料傳輸的工作都是由 cpu 完成的,而此時 cpu 不能執行其他任務,會特別浪費 cpu 資源
。
於是,為了解決這一問題,dma 技術就出現了,每個 i/o 裝置都有自己的 dma 控制器,通過這個 dma 控制器,cpu 只需要告訴 dma 控制器,我們要傳輸什麼資料,從**來,到**去,就可以放心離開了。後續的實際資料傳輸工作,都會由 dma 控制器來完成,cpu 不需要參與資料傳輸的工作
。
傳統 io 的工作方式,從硬碟讀取資料,然後再通過網絡卡向外傳送,我們需要進行 4 上下文切換,和 4 次資料拷貝,其中 2 次資料拷貝發生在記憶體裡的緩衝區和對應的硬體裝置之間,這個是由 dma 完成,另外 2 次則發生在核心態和使用者態之間,這個資料搬移工作是由 cpu 完成的。
為了提高檔案傳輸的效能,於是就出現了零拷貝技術,它通過一次系統呼叫(sendfile 方法)合併了磁碟讀取與網路傳送兩個操作,降低了上下文切換次數。另外,拷貝資料都是發生在核心中的,天然就降低了資料拷貝的次數。
kafka 和 nginx 都有實現零拷貝技術,這將大大提高檔案傳輸的效能。
零拷貝技術是基於 pagecache 的,pagecache 會快取最近訪問的資料,提公升了訪問快取資料的效能,同時,為了解決機械硬碟定址慢的問題,它還協助 i/o 排程演算法實現了 io 合併與預讀,這也是順序讀比隨機讀效能好的原因。這些優勢,進一步提公升了零拷貝的效能
。
需要注意的是,零拷貝技術是不允許程序對檔案內容作進一步的加工
的,比如壓縮資料再傳送。
另外,當傳輸大檔案時,不能使用零拷貝,因為可能由於 pagecache 被大檔案佔據,而導致「熱點」小檔案無法利用到 pagecache,並且大檔案的快取命中率不高,這時就需要使用「非同步 io + 直接 io 」的方式。
在 nginx 裡,可以通過配置,設定乙個檔案大小閾值,針對大檔案使用非同步 io 和直接 io,而對小檔案使用零拷貝。
零拷貝 高效地傳輸檔案
基於使用者緩衝區傳輸檔案時,過多的記憶體拷貝與上下文切換次數會降低效能。零拷貝技術在核心中完成記憶體拷貝,天然降低了記憶體拷貝次數。它通過一次系統呼叫合併了磁碟讀取與網路傳送兩個操作,降低了上下文切換次數。尤其是,由於拷貝在核心中完成,它可以最大化使用 socket 緩衝區的可用空間,從而提高了一次...
如何高效傳輸檔案之零拷貝
pagecache 磁碟快取記憶體 大檔案零拷貝下的問題 非同步io 直接io 總結磁碟是主機中最慢的硬體,往往是效能的瓶頸,優化它能獲得立竿見影的效果。針對磁碟的優化技術有零拷貝 直接io 非同步io等 主要目的是為了降低時延 提公升作業系統的吞吐量,圍繞著核心的磁碟快取記憶體 pagecache...
零拷貝 如何高效的通過網路傳輸檔案
假如要傳輸320mb的檔案,那麼你可能會在應用程式分配32kb的記憶體空間,然後呼叫read函式從檔案中讀出32位元組,最後呼叫write函式通過網路發生出去,其流程如下圖所示。這種方式非常低效,主要有如下的原因 1 至少經歷了4萬次使用者態與核心態的上下文切換。因為每處理32kb的訊息,就需要一次...