ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
![](http://tinywan-develop.oss-cn-hangzhou.aliyuncs.com/18-9-3/68162193.jpg) ## sendfile()对nginx性能的提升 Linux kernel 2.2之前,(如图)读写数据基本都是使用read系统调用和write系调用. 以nginx来说如果一个请求建立,从磁盘的文件到网络连接之间会通过硬件(DMA)---内核层---用户层多次读写系统来完成文件数据的复制传输:从内核层用read系统调用读到用户层,再从用户层用write系统调用写到内核层,每一次用户层到内核层的进行一次上下文转换,这种代价是非常昂贵的,甚至在没有数据变化时这种复制尤其显得多余。 如果nginx接受大量并发请求,这种系统调用就会非常频繁,服务器的性能就会下降。 ![](http://tinywan-develop.oss-cn-hangzhou.aliyuncs.com/18-9-3/79634632.jpg) 在Linux kernel2.2版本之后出现了一种叫做“零拷贝(zero-copy)”系统调用机制,目前很多应用服务器如apache、samba、nginx都支持sendfile。注意:sendfile系统调用是一种文件传输的系统调用和kernel系统调用关系不大。 ![](http://tinywan-develop.oss-cn-hangzhou.aliyuncs.com/18-9-3/45931953.jpg) > 如图所示,nginx在支持了sendfile系统调用后,避免了内核层与用户层的上线文切换(content swith)工作,大大减少了系统性能的开销。 ## 如何使用 **配置示例** ``` http { # other directives sendfile on; # other directives } ``` **指令说明** 语法:` sendfile on | off;` 默认值:` sendfile off;` 上下文:` http,server,location,if in location` 指定是否使用sendfile系统调用来传输文件。 > sendfile系统调用在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了数据在内核缓冲区和用户缓冲区之间的拷贝,操作效率很高,被称之为零拷贝。 原理解释:`read/write`在传统的文件传输方式(read、write/send方式),具体流程细节如下: 1、调用read函数,文件数据拷贝到内核缓冲区 2、read函数返回,数据从内核缓冲区拷贝到用户缓冲区 3、调用write/send函数,将数据从用户缓冲区拷贝到内核socket缓冲区 4、数据从内核socket缓冲区拷贝到协议引擎中 5、在这个过程当中,文件数据实际上是经过了四次拷贝操作: > 硬盘—>内核缓冲区—>用户缓冲区—>内核socket缓冲区—>协议引擎 ### sendfile sendfile系统调用则提供了一种减少拷贝次数,提升文件传输性能的方法。 * sendfile系统调用利用DMA引擎将文件数据拷贝到内核缓冲区,之后数据被拷贝到内核socket缓冲区中   * DMA引擎将数据从内核socket缓冲区拷贝到协议引擎中 这里没有用户态和内核态之间的切换,也没有内核缓冲区和用户缓冲区之间的拷贝,大大提升了传输性能。 这个过程数据经历的拷贝操作如下: > 硬盘—>内核缓冲区—>内核socket缓冲区—>协议引擎