1. 程式人生 > 其它 >【轉】Nginx中sendfile的作用

【轉】Nginx中sendfile的作用

那麼sendfile是什麼東西,他是怎麼影響效能的… … sendfile實際上是 Linux2.0+以後的推出的一個系統呼叫,web伺服器可以通過調整自身的配置來決定是否利用 sendfile這個系統呼叫。先來看一下不用 sendfile的傳統網路傳輸過程:

read(file,tmp_buf, len);

write(socket,tmp_buf, len);

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

 

 


標題
一個基於socket的服務,首先讀硬碟資料,然後寫資料到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 ,然後 DMA 從 kernel buffer拷貝資料到協議棧。

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

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

sendfile(socket,file, len);

硬碟 >> kernel buffer (快速拷貝到kernelsocket buffer) >>協議棧

1、 系統呼叫sendfile()通過 DMA把硬碟資料拷貝到 kernel buffer,然後資料被 kernel直接拷貝到另外一個與 socket相關的 kernel buffer。這裡沒有 user mode和 kernel mode之間的切換,在 kernel中直接完成了從一個 buffer到另一個 buffer的拷貝。

2、DMA 把資料從 kernelbuffer 直接拷貝給協議棧,沒有切換,也不需要資料從 user mode 拷貝到 kernel mode,因為資料就在 kernel 裡。

簡單說,sendfile是個比 read 和 write 更高效能的系統介面, 不過需要注意的是,sendfile 是將 in_fd 的內容傳送到 out_fd 。而 in_fd 不能是 socket , 也就是隻能檔案控制代碼。 所以當 Nginx 是一個靜態檔案伺服器的時候,開啟 SENDFILE 配置項能大大提高 Nginx 的效能。 但是當 Nginx 是作為一個反向代理來使用的時候,SENDFILE 則沒什麼用了,因為 Nginx 是反向代理的時候。 in_fd 就不是檔案控制代碼而是 socket,此時就不符合 sendfile 函式的引數要求了。


from:https://blog.csdn.net/zhusixun/article/details/81702380