sendfile優化文件拷貝

原文地址:http://www.vpsee.com/2009/07/linux-sendfile-improve-performance/

現在流行的 web 服務器裏面都提供 sendfile 選項用來提高服務器性能,那到底 sendfile 是什麼,怎麼影響性能的呢?sendfile 實際上是 Linux 2.0+ 以後的推出的一個系統調用,web 服務器可以通過調整自身的配置來決定是否利用 sendfile 這個系統調用。先來看一下不用 sendfile 的傳統網絡傳輸過程:

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

硬盤 >> kernel buffer >> user buffer >> kernel socket buffer >> 協議棧

一般來說一個網絡應用是通過讀硬盤數據,然後寫數據到 socket 來完成網絡傳輸的。上面2行用代碼解釋了這一點,不過上面2行簡單的代碼掩蓋了底層的很多操作。來看看底層是怎麼執行上面2行代碼的:

1、系統調用 read() 產生一個上下文切換:從 user mode 切換到 kernel mode,然後 DMA 執行拷貝,把文件數據從硬盤讀到一個 kernel buffer 裏。
2、數據從 kernel buffer 拷貝到 user buffer,然後系統調用 read() 返回,這時又產生一個上下文切換:從kernel mode 切換到 user mode。
3、系統調用 write() 產生一個上下文切換:從 user mode 切換到 kernel mode,然後把步驟2讀到 user buffer 的數據拷貝到 kernel buffer(數據第2次拷貝到 kernel buffer),不過這次是個不同的 kernel buffer,這個 buffer 和 socket 相關聯。
4、系統調用 write() 返回,產生一個上下文切換:從 kernel mode 切換到 user mode(第4次切換了),然後 DMA 從 kernel buffer 拷貝數據到協議棧(第4次拷貝了)。

上面4個步驟有4次上下文切換,有4次拷貝,我們發現如果能減少切換次數和拷貝次數將會有效提升性能。在kernel 2.0+ 版本中,系統調用 sendfile() 就是用來簡化上面步驟提升性能的。sendfile() 不但能減少切換次數而且還能減少拷貝次數。

再來看一下用 sendfile() 來進行網絡傳輸的過程:

sendfile(socket, file, len);

硬盤 >> kernel buffer (快速拷貝到kernel socket buffer) >> 協議棧

1、系統調用 sendfile() 通過 DMA 把硬盤數據拷貝到 kernel buffer,然後數據被 kernel 直接拷貝到另外一個與 socket 相關的 kernel buffer。這裏沒有 user mode 和 kernel mode 之間的切換,在 kernel 中直接完成了從一個 buffer 到另一個 buffer 的拷貝。
2、DMA 把數據從 kernel buffer 直接拷貝給協議棧,沒有切換,也不需要數據從 user mode 拷貝到 kernel mode,因爲數據就在 kernel 裏。

步驟減少了,切換減少了,拷貝減少了,自然性能就提升了。這就是爲什麼說在 Nginx 配置文件裏打開 sendfile on 選項能提高 web serve r性能的原因。(參見:64MB VPS 上優化Nginx

 

性能測試參考文章地址:

http://blog.csdn.net/crazyguang/archive/2008/05/09/2423708.aspx


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章