如今流行的 web 服務器裏面都提供 sendfile 選項用來提升服務器性能,那到底 sendfile 是什麼,怎麼影響性能的呢?linux
sendfile 其實是 Linux 2.0+ 之後的推出的一個系統調用,web 服務器能夠經過調整自身的配置來決定是否利用 sendfile 這個系統調用。web
先來看一下不用 sendfile 的傳統網絡傳輸過程:服務器
read(file, tmp_buf, len); write(socket, tmp_buf, len); 硬盤 >> kernel buffer >> user buffer >> kernel socket buffer >> 協議棧
通常來講一個網絡應用是經過讀硬盤數據,而後寫數據到 socket 來完成網絡傳輸的。網絡
上面2行用代碼解釋了這一點,不過上面2行簡單的代碼掩蓋了底層的不少操做。來看看底層是怎麼執行上面2行代碼的:socket
一、系統調用 read() 產生一個上下文切換:從 user mode 切換到 kernel mode,而後 DMA 執行拷貝,把文件數據從硬盤讀到一個 kernel buffer 裏。post
二、數據從 kernel buffer 拷貝到 user buffer,而後系統調用 read() 返回,這時又產生一個上下文切換:從kernel mode 切換到 user mode。性能
三、系統調用 write() 產生一個上下文切換:從 user mode 切換到 kernel mode,而後把步驟2讀到 user buffer 的數據拷貝到 kernel buffer(數據第2次拷貝到 kernel buffer),不過此次是個不一樣的 kernel buffer,這個 buffer 和 socket 相關聯。spa
四、系統調用 write() 返回,產生一個上下文切換:從 kernel mode 切換到 user mode(第4次切換了),而後 DMA 從 kernel buffer 拷貝數據到協議棧(第4次拷貝了)。code
上面4個步驟有4次上下文切換,有4次拷貝,咱們發現若是能減小切換次數和拷貝次數將會有效提高性能。orm
在kernel 2.0+ 版本中,系統調用 sendfile() 就是用來簡化上面步驟提高性能的。sendfile() 不但能減小切換次數並且還能減小拷貝次數。
再來看一下用 sendfile() 來進行網絡傳輸的過程:
sendfile(socket, file, len); 硬盤 >> kernel buffer (快速拷貝到kernel socket buffer) >> 協議棧
一、系統調用 sendfile() 經過 DMA 把硬盤數據拷貝到 kernel buffer,而後數據被 kernel 直接拷貝到另一個與 socket 相關的 kernel buffer。
這裏沒有 user mode 和 kernel mode 之間的切換,在 kernel 中直接完成了從一個 buffer 到另外一個 buffer 的拷貝。
二、DMA 把數據從 kernel buffer 直接拷貝給協議棧,沒有切換,也不須要數據從 user mode 拷貝到 kernel mode,由於數據就在 kernel 裏。
步驟減小了,切換減小了,拷貝減小了,天然性能就提高了。這就是爲何說在 Nginx 配置文件裏打開 sendfile on 選項能提升 web serve r性能的緣由。
原文連接:http://www.vpsee.com/2009/07/linux-sendfile-improve-performance/;
賜教!