原文地址:http://www.vpsee.com/2009/07/linux-sendfile-improve-performance/
現在流行的 網頁伺服器裡面都提供 sendfile 選項用來提高伺服器效能,那到底 sendfile 是什麼,怎麼影響效能的呢。sendfile 實際上是 Linux 2.0+ 以後的推出的一個系統調用,網頁伺服器可以通過調整自身的配置來決定是否利用 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