(轉)Nginx中sendfile的作用


原文:https://blog.csdn.net/zhusixun/article/details/81702380

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
本文鏈接:https://blog.csdn.net/zhusixun/article/details/81702380
那么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 函數的參數要求了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM