nginx AIO机制与sendfile机制

nginx AIO机制与sendfile机制

从0.8.11版本开始, nginx 开始支持Linux native aio,如何在nginx里配置使用这套机制是本文介绍的重点。在下面的示例配置中,几个重要相关选项的具体含义如下: aio:

Syntax: aio on | off | sendfile
Default: off

在linux下aio可以设置为on或off(在freebsd还可以设置为sendfile),但需要2.6.22及以后版本的内核,原因在前面文章已经提到过,nginx使用的eventfd有这个 要求 。

directio:

Syntax: directio size | off
Default: off

directio选项可以设置为off或一个大小值,表示当文件大小大于等于这个值时启用directio。

sendfile:

Syntax: sendfile on | off
Default: off

是否启用sendfile()。

[root@www nginx-1.2.0]# uname -a
Linux www.t1.com 2.6.38.8 #2 SMP Wed Nov 2 07:52:53 CST 2011 x86_64 x86_64 x86_64 GNU/Linux
[root@www nginx-1.2.0]# cat /etc/issue
CentOS Linux release 6.0 (Final)
Kernel \r on an \m

[root@www nginx-1.2.0]# ./configure --with-file-aio
[root@www nginx-1.2.0]# make
[root@www nginx-1.2.0]# make install
[root@www nginx-1.2.0]# cat /usr/local/nginx/conf/nginx.conf
...
http {
...
server {
...
location / {
aio on;
directio 512k;
sendfile on;
output_buffers 1 128k;
...

要使aio生效需把directio设置为打开状况,并且如果aio生效,那么将自动不使用sendfile(),这在linux下这是显然的,要么利用aio读到缓存区,要么利用sendfile()直接发送出去,两者不可兼用,而对于freebsd系统下aio和sendfile并用的情况,我并不了解,所以也就不妄加评论;

可以看到directio是针对每个请求的文件大小而决定是否开启directio的,因此对于上面的整个示例配置,也就会针对每个请求的不同而不同: 如果某处请求的文件大于等于512k,那么将启用directio,从而aio生效,进而sendfile不生效; 如果某处请求的文件小于512k,那么将禁用directio,从而aio也就不生效,转而使用sendfile(),即sendfile生效;

这种设计貌似刚好把linux下aio和sendfile两种机制的优点很好的结合起来使用。对于大文件采用aio,节省cpu,而对于小文件,采用sendfile,减少拷贝;并且对于大文件aio采用directio,避免挤占文件系统缓存,让文件系统缓存更多的小文件。 从理论上来看,这种配置比较适合系统内存有限、小文件请求比较多、间隔有几个大文件请求的Web环境;如果内存足够大,那么应该充分利用文件系统缓存,而directio使得aio无法使用缓存是衡量最终是否需要采用aio的一个需要仔细考虑的因素;网上有人总结说nginx+aio很好,也有人说其很差,其实根据特定的系统环境和应用场景来做配置调节,才能达到性能的最优,nginx提供的 AIO 只是一套工具,没有固定的好与差之分,就看你能否恰当的用好它,但据nginx官网论坛来看,在linux系统的大部分场景下,目前因使用aio功能附加的限制而带来的实际效果估计并不太理想:

nginx supports file AIO only in 0.8.11+, but the file AIO is functional
on FreeBSD only. On Linux AIO is supported by nginx only on kerenl
2.6.22+ (although, CentOS 5.5 has backported the required AIO features).
Anyway, on Linux AIO works only if file offset and size are aligned
to a disk block size (usually 512 bytes) and this data can not be cached
in OS VM cache (Linux AIO requires DIRECTIO that bypass OS VM cache).
I believe a cause of so strange AIO implementaion is that AIO in Linux
was developed mainly for databases by Oracle and IBM.

示例:

location /video/ {
sendfile on;
sendfile_max_chunk 256k; 
aio threads;
directio 512k;
output_buffers 1 128k;
}

启用aio时会自动启用directio,小于directio定义的大小的文件则采用sendfile进行发送,超过或等于directio定义的大小的文件,将采用aio线程池进行发送,也就是说aio和directio适合大文件下载.因为大文件不适合进入操作系统的buffers/cache,这样会浪费内存,而且Linux AIO(异步磁盘IO)也要求使用directio的形式.

sendfilemaxchunk可以减少阻塞调用sendfile()所花费的最长时间.因为Nginx不会尝试一次将整个文件发送出去,而是每次发送大小为256KB的块数据.

注意,Nginx从1.7.11开始为AIO引入了线程池支持,能够使用多线程读取和发送文件,以免工人进程被阻塞.要启用多线程支持,configure时需要显式加入–with-threads选项.

sendfile机制:

在apache,nginx,lighttpd等web服务器当中,都有一项sendfile相关的配置,在一些网上的资料都有谈到sendfile会提升文件传输性能,那sendfile到底是什么呢?它的原理又是如何呢?

在传统的文件传输里面(read/write方式),在实现上其实是比较复杂的,需要经过多次上下文的切换,我们看一下如下两行代码: Java代码 收藏代码

read(file, tmp_buf, len);      
       write(socket, tmp_buf, len);      


    以上两行代码是传统的read/write方式进行文件到socket的传输。

当需要对一个文件进行传输的时候,其具体流程细节如下: 1、调用read函数,文件数据被copy到内核缓冲区 2、read函数返回,文件数据从内核缓冲区copy到用户缓冲区 3、write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。 4、数据从socket缓冲区copy到相关协议引擎。

以上细节是传统read/write方式进行网络文件传输的方式,我们可以看到,在这个过程当中,文件数据实际上是经过了四次copy操作:

硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎

而sendfile系统调用则提供了一种减少以上多次copy,提升文件传输性能的方法。Sendfile系统调用是在2.1版本内核时引进的: Java代码 收藏代码

sendfile(socket, file, len);

运行流程如下: 1、sendfile系统调用,文件数据被copy至内核缓冲区 2、再从内核缓冲区copy至内核中socket相关的缓冲区 3、最后再socket相关的缓冲区copy到协议引擎

相较传统read/write方式,2.1版本内核引进的sendfile已经减少了内核缓冲区到user缓冲区,再由user缓冲区到socket相关缓冲区的文件copy,而在内核版本2.4之后,文件描述符结果被改变,sendfile实现了更简单的方式,系统调用方式仍然一样,细节与2.1版本的不同之处在于,当文件数据被复制到内核缓冲区时,不再将所有数据copy到socket相关的缓冲区,而是仅仅将记录数据位置和长度相关的数据保存到socket相关的缓存,而实际数据将由DMA模块直接发送到协议引擎,再次减少了一次copy操作。

原创文章,作者:YOUNG,如若转载,请注明出处:http://www.178linux.com/54790

(19)
上一篇 2016-10-26 22:28
下一篇 2016-10-27 09:41

相关推荐

  • Linux运维之进程管理

    一、      进程概念 进程是内核的一个功能,在Linux中,运行一个程序或命令可以出发一个事件而驱动一个PID,在linux系统中,系统只识别二进制程序文件,我们可以通过执行系统上的二进制程序来运行程序,进而产生进程。在linux系统中第一个进程是init程序,它是系统开机第一个加载的程序,用来支撑系统的…

    Linux干货 2016-09-13
  • CentOS6 网络管理之网卡配置及简单路由设置

    CentOS6中关于网络配置的命令有很多,本文将介绍几个平时最长用的几个命令,以及网卡IP地址的配置和简单路由配置。 1、经常使用的查看IP地址命令为 ifconfig,不跟参数的情况下默认查看所有已启用的网卡信息,如下图所示: 如果想查看具体某块网卡信息,则可以在ifconfig后面跟上网卡设备,如只查看eth0的信息则执行:ifconfig eht0 即…

    Linux干货 2016-09-05
  • N25期第一周作业

    计算机组成及其功能 计算机由硬件和软件组成,硬件是基础,是软件活动的舞台,软件是灵魂,使硬件发挥最大的作用,两者缺一不可。计算机硬件是由物理元器件构成的有形实体,主要是数字逻辑电路。计算机软件是由计算机程序构成的无形的东西,需要存储在有形的硬件(如主存储器、硬盘等)中,可以实现更高层次的逻辑功能。目前大多数计算机是根据冯.诺依曼体系结构的思想来设计的,即具有…

    Linux干货 2016-11-30
  • 运维第一步

    学友分享各自工作经历

    2018-03-26
  • N22第八周作业

    1、请描述网桥、集线器、二层交换机、三层交换机、路由器的功能、使用场景与区别。 网桥: 网桥是早期的二层网络设备,每个端口分别有一条独立的交换信道,不是共享一条信道,可隔离冲突域。网桥比集线器(Hub)性能更好,集线器上各端口都是共享同一条信道的,工作于数据链路层。后被端口更多的交换机替代。 集线器: 多端口中继器,工作在物理层,本身不具备识别信号的能力,只…

    Linux干货 2016-10-17