Linux kernel 2.2之前,(如圖)讀寫數據基本都是使用read系統調用和write系調用,以nginx來說如果一個請求建立,從磁盤的文件到網絡連接之間會通過硬件(DMA)---內核層---用戶層多次讀寫系統來完成文件數據的複製傳輸:從內核層用read系統調用讀到用戶層,再從用戶層用write系統調用寫到內核層,每一次用戶層到內核層的進行一次上下文轉換,這種代價是非常昂貴的。甚至在沒有數據變化時這種複製尤其顯得多餘。如果nginx接受大量併發請求,這種系統調用就會非常頻繁,服務器的性能就會下降。
在Linux kernel2.2版本之後出現了一種叫做“零拷貝(zero-copy)”系統調用機制,目前很多應用服務器如apache、samba、nginx都支持sendfile。注意:sendfile系統調用是一種文件傳輸的系統調用和kernel系統調用關係不大。
如圖所示,nginx在支持了sendfile系統調用後,避免了內核層與用戶層的上線文切換(content swith)工作,大大減少了系統性能的開銷。
可以使用man 8 sendfile 進一步瞭解sendfile系統調用。
以下是對參數解釋
out_fd a file descriptor, open for writing, for the data to be written in_fd a file descriptor, open for reading, for the data to be read offset the offset in the input file to start transfer (e.g. a value of 0 indicates the beginning of the file). This is passed into the function and updated when the function returns. count the number of bytes to be transferred
正常情況下函數會返回被寫入的字節數,如果出錯就返回-1
我們都知道在linux系統裏文件描述符fd,可以是一個真實的文件或者是一個設備,例如一個網絡socket,(當然linux世界裏一切皆文件,這裏只是具體區別一下。)senfile需要輸入的文件描述符是一個支持mmap的真實文件或者設備,那麼socket就不能作爲輸入的fd,而輸出的fd是可以的。
具體在nginx的使用中可以通過在配置文件nginx.conf中增加參數使用sendfile
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
...........................
}