(轉)Nginx中sendfile的做用

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

版權聲明:本文爲博主原創文章,遵循 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);socket

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


標題
一個基於socket的服務,首先讀硬盤數據,而後寫數據到socket 來完成網絡傳輸的。上面2行用代碼解釋了這一點,不過上面2行簡單的代碼掩蓋了底層的不少操做。來看看底層是怎麼執行上面2行代碼的:性能

一、系統調用 read()產生一個上下文切換:從 user mode 切換到 kernel mode,而後 DMA 執行拷貝,把文件數據從硬盤讀到一個 kernel buffer 裏。.net

二、數據從 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相關聯。blog

四、系統調用 write()返回,產生一個上下文切換:從 kernel mode 切換到 user mode ,而後 DMA 從 kernel buffer拷貝數據到協議棧。接口

上面4個步驟有4次上下文切換,有4次拷貝,咱們發現若是能減小切換次數和拷貝次數將會有效提高性能。在kernel2.0+ 版本中,系統調用 sendfile() 就是用來簡化上面步驟提高性能的。sendfile() 不但能減小切換次數並且還能減小拷貝次數。

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

sendfile(socket,file, len);

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

一、 系統調用sendfile()經過 DMA把硬盤數據拷貝到 kernel buffer,而後數據被 kernel直接拷貝到另一個與 socket相關的 kernel buffer。這裏沒有 user mode和 kernel mode之間的切換,在 kernel中直接完成了從一個 buffer到另外一個 buffer的拷貝。

二、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 函數的參數要求了。

相關文章
相關標籤/搜索