zoukankan      html  css  js  c++  java
  • 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 
     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操作。

  • 相关阅读:
    判断一个图是否有环 无向图 有向图
    经典算法解析
    图的深度优先遍历DFS(邻接矩阵表示法)
    Prim算法求最小生成树MST以及和kruskal算法的对比
    oracle连接中出现错误ORA12541,ORA12514,ORA01017的解决方法
    visual studio 自动整理代码
    解决Google code和Google group无法登录的问题
    Dijkstra算法求单源最短路径(二)(BFS的改版)
    快速排序算法QuickSort
    推荐资料
  • 原文地址:https://www.cnblogs.com/wajika/p/6565913.html
Copyright © 2011-2022 走看看