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操作。

nginx AIO机制与sendfile机制的更多相关文章

  1. 深入理解PHP之:Nginx 与 FPM 的工作机制

    网络上有很多关于如何配置 Nginx + FPM 的文章,但它们更多从操作的角度出发,告诉我们怎么做,但却没有告诉我们为什么要这么做,本文从 Nginx 与 FPM 的工作机制出发,探讨配置背后的原理 ...

  2. Httpd服务进阶知识-调用操作系统的Sendfile机制

    Httpd服务进阶知识-调用操作系统的Sendfile机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.不用 sendfile 的传统网络传输过程 read(file, tm ...

  3. Atitit.事件机制 与 消息机制的联系与区别

    Atitit.事件机制 与 消息机制的联系与区别 1. 消息/事件机制是几乎所有开发语言都有的机制,在某些语言称之为消息(Event),有些地方称之为(Message).1 2. 发布/订阅模式1 3 ...

  4. cookie机制和session机制的原理和区别[转]

    一.cookie机制和session机制的区别 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. 同时我们也看到,由于在服务器端保持状态的 ...

  5. Linux内核学习笔记3——分段机制和分页机制

    一 分段机制 1.什么是分段机制 分段机制就是把虚拟地址空间中的虚拟内存组织成一些长度可变的称为段的内存块单元. 2.什么是段 每个段由三个参数定义:段基地址.段限长和段属性. 段的基地址.段限长以及 ...

  6. cookie机制和session机制的区别(面试题)

    一.cookie机制和session机制的区别 具体来说cookie机制采用的是在客户端保持状态的方案,而session机制采用的是在服务器端保持状态的方案. 同时我们也看到,由于才服务器端保持状态的 ...

  7. ActiveMQ讯息传送机制以及ACK机制

    http://blog.csdn.net/lulongzhou_llz/article/details/42270113 ActiveMQ消息传送机制以及ACK机制详解 AcitveMQ是作为一种消息 ...

  8. 浅谈java编译机制和运行机制

    源文件和字节码的组成方式 源文件: 拓展名后跟java的文件即java的源文件. Java 源码编译由以下三个过程组成: 1.分析和输入到符号表 2.注解处理 3.语义分析和生成class文件 流程图 ...

  9. [转帖]Linux分页机制之分页机制的演变--Linux内存管理(七)

    Linux分页机制之分页机制的演变--Linux内存管理(七) 2016年09月01日 20:01:31 JeanCheng 阅读数:4543 https://blog.csdn.net/gatiem ...

随机推荐

  1. Java 读取某个目录下所有文件、文件夹

    /** * @Author: * @Description:获取某个目录下所有直接下级文件,不包括目录下的子目录的下的文件,所以不用递归获取 * @Date: */ public static Lis ...

  2. 解决eclipse导出javadoc时的“错误: 编码GBK的不可映射字符”问题(转)

    http://blog.csdn.net/psy1100/article/details/51179342 今天要将自己的API接口和MODEL导出来一份java doc参考文档, 但是在导出的时候却 ...

  3. [转]nodejs深入学(7)理解Buffer

    原文: https://www.jianshu.com/p/e3f14cdf78f1 --------------------------------------------------------- ...

  4. Arrow functions and the ‘this’ keyword

    原文:https://medium.freecodecamp.org/learn-es6-the-dope-way-part-ii-arrow-functions-and-the-this-keywo ...

  5. 设置Linux中的Mysql不区分表名大小写

    1. MySQL数据库的表名在Linux系统下是严格区分大小写的,在Windows系统下开发的程序移植到Linux系统下,如果程序中SQL语句没有严格按照大小写访问数据库表,就可能会出现找不到表的错误 ...

  6. background-size中contain和cover中的数学公式

    background-size的contain和cover是怎么用的,大家应该都明白.但是里面也有一些有趣的数学关系. 基本概念 上面就是我们对于 rimage (图片宽高比).rviewport ( ...

  7. Android学习之Android studio TraceView和lint工具的使用具体解释

    上次讲述了一下Android studio Terminal的使用配置,今天又学习了一下关于Traceview和lint工具的使用. 首先来讲lint吧: Android lint工具是Android ...

  8. C#中将DLL文件打包到EXE文件

    1:在工程目录增加dll目录,然后将dll文件复制到此目录,例如: 2:增加引用,定位到工程的dll目录,选中要增加的dll文件 3:修改dll文件夹下面的dll文件属性 选中嵌入式资源,不复制. 4 ...

  9. 火狐浏览器flash经常奔溃的

    火狐浏览器flash经常奔溃的 1.首先,在火狐浏览器地址栏在输入:about:config?filter=dom.ipc.plugins.flash.disable-protected-mode,按 ...

  10. css 进度条

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...