• nginx的优化


    说起nginx的调优,坏消息是事实上没有方法能很大程度优化nginx,不存在一个"神奇的"设置选项可以将负载降低到原来的一半或者可以让PHP运行速度加倍。不过接下来是好消息,nginx本身已经优化的足够好了!其实相比apache,最大的优化在你敲入"apt-get install","yum install"或者"make install"的时候已经产生了,呵呵。

        那么怎么还要说到nginx调优这个话题呢?

        一个原因是因为nginx有很多的配置选项,这些选项会影响nginx的行为。但是,这些选项的默认值并不是完全针对高负载这种状况优化的,所以需要调整。

        另一个原因是nginx所运行的OS的设置也会影响nginx的运行,想要达到理想的运行效果,也需要调整。

        我们下面就来分别分析一下相关的问题。

     

        一、操作系统的限制

     

       1.操作系统本身

        nginx可以运行在Linux, MacOS, FreeBSD, Solaris, Windows等众多平台上,这些平台都有各自的高性能event polling方法,不过nginx只支持其中的4种。一般来说,运行在freebsdlinuxMacOS,Solaris上性能不会有很巨大的差别,所有选择你自己熟悉的OS比要选择所谓"绝对优化"的,但是不熟悉的OS更加重要。不过,windows是一个例外,在生产环境中,千万不要把nginx运行在windows上。因为windows有自己的event polling方法,而nginx的作者明确说明不支持该方法。

        nginx中,可以在配置文件中指定所使用的event polling模型,指令如下:

      

        use epoll;  Linux系统

        use kqueueFreeBSD系统

     

        2.`ulimit -a`命令所列出来的这些参数

        这些参数是nginx无法超越的。例如,在许多系统中,默认允许打开的最大文件数为1024,如果nginx运行在这个环境下,那么当流量大时就会出现(24: Too many open files) 错误。而nginx的处理能力远不止1024,因此这个参数必须调整。

     

        二、nginx自身的限制

     

        1.编译优化

       

        默认的nginx编译选项是用debug模式(-g)的(debug模式会插入很多跟踪和ASSERT之类),编译以后一个nginx可执行文件有好几MB。去掉nginx的debug模式编译,编译以后只有几百KB

        在源码auto/cc/gcc中,在最后几行中找到如下内容:

     

            # debug

            CFLAGS=”$CFLAGS -g”

     

        CFLAGS这一行删除或者注释掉,然后再编译即可。

     

        另外,如果只是把nginx作为web server,那么可以禁用一些用不到的modules,可以减少内存footprint,提高服务器性能。

        ./configure --prefix=/webserver/nginx --without-mail_pop3_module --without-mail_imap_module  --without-mail_smtp_module --with-http_ssl_module  --with-http_stub_status_module  --with-http_gzip_static_module

     

        2.Worker Processes

        worker process是整个nginx的关键,一旦主进程绑定到了指定的IP/Port上以后,主进程会使用指定的用户派生出worker process,这些worker process会处理所有的用户请求。worker process不是多线程的,不需要将每个connection在不同CPU内核间切换,因此运行多个worker process是必然的,通常每个CPU core对应一个worker process。通常,如果超过4worker process,那么CPU肯定不会成为瓶颈了,因为在CPU成为瓶颈之前,nginx的其他部分肯定已经不行了。


    cat /proc/cpuinfo |grep 'core id'

     

        3.Worker Connections

        worker connctions是一个有点"怪异"的概念,我不确定这个指令的确切目的。但是可以确定的是这个指令可以有效的限制每个worker process在同一时间可以维护多少个连接。如果非要我猜的话,我认为这个指令是一个保险机制,为了防止错误配置的keep-alive耗尽可用端口。

        在默认配制文件中,worker connections的值是1024。通常一个浏览器会针对一个站点打开2个连接,那么最大可以并发服务的用户数量为512个。这个数字看起来不小了,但是考虑到keep-alive默认的timeout值是65,那么意味着其实我们每秒只能处理8connection。显然这个数字超过了大多数人的需求,尤其是当我们使用2-4worker process的时候。但是对于大流量的站点,并且打开了keep-alvie,那么应该时刻考虑到这一点。

        当考虑worker connections的值的时候,其实很简单,流量增加就增加这个值。2048对于绝大多数人应该够用了,不过如果你的站点真的增长这么快的话,那么最大该设置多大,只有你自己尝试了。

     

        4.CPU Affinity

        设置CPU affinity的意思是告诉nginx,每个worker process应该使用哪一个CPU core,指定以后该worker process只会使用你指定的那个CPU core。请小心的做这个配置,因为OSCPU调度器在处理负载均衡方面远比人类做的更好。如果你确实认为你需要在CPU调度器层面做优化的话,你可以选择不同的CPU调度器,不过你需要清楚的知道你自己在干什么,如果不知道,不要碰这个配置。

     

        5.Keep Alive

        keep alive是一个HTTP的特性,其允许用户agent(浏览器)和服务器之间保持连接,以便其他请求共用或者直到指定的timeout时间到达。这个特性事实上并不会改善我们的nginx服务器性能,因为nginx自己可以非常好的处理空闲连接。nginx作者指出,处理10000个空闲连接只耗费2.5MB的内存。

        在这里提到keep alive的目的很简单。keep alive对于终端用户感觉到的等待时间影响是巨大的。如果你的站点看起来载入很快,那么用户会很开心。Amazon做过调查,用户感觉的等待时间和最终业务成交量之间有直接的关系。

        keep alive可以避免在创建HTTP连接过程中许多无用操作,因此它的作用才如此明显。一般我们不需要65这么大的timeout值,但推荐你将这个值设置在10-20之间。

     

        keepalive_timeout 15

     

        6.tcp_nodelay and tcp_nopush

        这两个参数的用途很难理解,因为它们在很底层的网络部分影响nginx。一个简单肤浅的解释是这两个指令控制OS如何处理网络缓冲,何时将他们刷新给最终用户。因为这两个参数不会明显提高或改变任何事情,如果你不明白这两个参数的含义,那我建议你不用碰它,保持默认值就好了。

     

     

        三、硬件的限制

        上边已经讨论了OSnginx本身的一些限制,现在让我们看看怎么把服务器的性能压榨到底。

        服务器上能成为瓶颈的就CPU,内存和IO。对于nginx来说,CPU和内存都不会是瓶颈。因此瓶颈只会产生在IO部分。硬盘相对于CPU和内存来说,是非常非常慢的设备。硬盘读取和写入是非常耗时的操作,因此我们需要尽量减少nginx对硬盘的读写操作。

     

        1.Access log

        nginx默认会将每个请求写入到日志文件中,日志可以用来审计和统计。但是记录日志的操作会带来IO开销。如果你不需要记录日志,直接关闭这个选项就好。如果需要记录日志,最好将日志记录到内存中,然后定期将日志转储到磁盘上。这样可以避免频繁磁盘IO操作,极大提高性能。

     

        access_log off;

     

        2.Error log

        对于error log,其实不应该关闭的。但是为了降低磁盘IO操作,可以调整error log的级别,将这个参数设置成"warn"级别应该足够了,并且也不会产生很大的IO

     

        3.Open File Cache

        从文件系统读取数据包含文件打开和关闭操作,这部分也是磁盘块操作。为了减少这部分操作,可以缓存打开的文件描述符。这个操作使用open file cache 实现,具体可以参考链接中的wiki

     

        4.Buffers

        调整buffer的大小对于nginx很重要,如果buffer设置得太小,nginx将不得不把upstream服务器返回来的响应存储在临时文件中。这会导致同时增加磁盘读写操作,流量越大影响越明显。

        client_body_buffer_size 指令指定了处理客户端请求body部分的buffer的大小。这个一般用于处理POST数据,表单提交,文件上传等操作。如果你要处理很多大的POST提交,那么这个值要设置足够大。

        client_header_buffer_size 指令指定了处理客户端请求header部分的buffer的大小。设置成1K能满足绝大部分需求。

        client_max_body_size 指令指定了可以接受的最大的用户请求body大小。通过HTTP头中的Content-Length确认,如果大小超过这个值,则客户端会得到“Request Entity Too Large” (413)错误。

        large_client_header_buffers 指令分配用于处理从用户那里来的大文件头请求的buffer的最大数量和buffer大小。请求的header不能比其中的一个buffer大,否则nginx会返回“Request URI too large” (414)错误。最长的header行也必须小于一个buffer的大小,否则客户端会得到“Bad request” (400)错误。

        fastcgi_buffersproxy_buffers 指令指定了处理upstream回应的buffer大小,也就是PHP,Apache或其他。上边也说到了,如果这个buffer太小,在响应用户之前,nginx将不得不把upstream服务器返回来的响应存储在临时文件中。注意,nginxbuffer是有上限的,这个上限由fastcgi_max_temp_file_sizeproxy_max_temp_file_size控制。当然也可以通过将proxy_buffering设置成off来关闭proxy connectionsbuffer(通常不是个好主意!)

     

        示例如下:

        client_body_buffer_size 8K;
        client_header_buffer_size 1k;
        client_max_body_size 2m;
        large_client_header_buffers 2 1k;

     

        5.彻底避免磁盘IO

        最彻底的避免磁盘IO的方法是不使用磁盘,如果费用不是问题且数据量不大,那么可以使用ramdisk,将所有数据放到内存中。

     

        6.网络IO

        为了降低网络IO,我们使用gzip module来压缩传输的数据量。设置gzip_comp_level的值为4-5应该比较合适,如果设置更大没什么用处,白白浪费CPU

     

        gzip             on;
        gzip_comp_level  5;
        gzip_min_length  1000;
        gzip_proxied     expired no-cache no-store private auth;
        gzip_types       text/plain application/xml;
        gzip_disable     "MSIE [1-6].";

     

        四、什么?上边还不够?!

     

        如果经过上述的优化仍然不能满足的要求,那么建议你考虑增加更多的服务器吧,稍微花费一点钱买服务器,比你在这里浪费时间微调nginx要来得更有效果。


    --------

    # 与系统CPU的core总数对应
    worker_processes 24;
     
    # nginx可以打开的文件描述符的数量
    # 通常在OS中用'ulimit -n 200000'
    # 或者在/etc/security/limits.conf设置
    worker_rlimit_nofile 200000;
     
    # 错误日志仅记录crit以上级别
    error_log /var/log/nginx/error.log crit
     
    # 每个worker process可以最多服务多少客户端
    # (Max clients = worker_connections * worker_processes)
    # "Max clients" 也受限于系统中可用的socket数量(~64k)
    worker_connections 4000;
     
    # 使用epoll模型
    use epoll;
     
    # 当nginx接到新连接的请求时,会尽可能的接受更多的连接
    # 如果worker_connections参数设置较低,则此参数会对nginx产生冲击,谨慎!
    multi_accept on;
     
    # 缓存打开的文件描述符,参数值应该根据具体应用场景调整(不要照搬下边的数值!)
    open_file_cache max=200000 inactive=20s;
    open_file_cache_valid 30s;
    open_file_cache_min_uses 2;
    open_file_cache_errors on;
     
    # 缓冲log写操作,以提高磁盘IO效率,或者直接关闭access_log
    #access_log /var/log/nginx/access.log main buffer=16k;
    access_log off;
     
    # 调用Sendfile实现内核"zero copy"
    # 一般应该打开,如果用来进行下载等应用磁盘IO重负载应用,可设置为off,以平衡磁盘与网络I/O处理速度
    sendfile on;
     
    # Tcp_nopush选项会让nginx尝试在一个packet内发送其HTTP响应,而不是分帧传送
    # 这对优化吞吐率很有用处,对于在调用sendfile函数前prepending headers也有作用
    tcp_nopush on;
     
    # 不缓冲data-sends(禁用Nagle算法). Good for sending frequent small bursts of data in real time.
    tcp_nodelay on;
     
    # keep-alive连接的超时时间,server会在此时间之后关闭连接
    keepalive_timeout 15;
     
    # client的请求可以转换成keep-alive连接的数量,如果为了性能测试,可以设置的高一些,默认100
    #keepalive_requests 100000;
     
    # 允许server在client停止响应以后关闭连接,释放分配给该连接的内存
    reset_timedout_connection on;
     
    # 如果client对于body的请求超过这个时间,则发送"request timed out"响应,默认60秒
    # 防范慢查询攻击
    client_body_timeout 10;
     
    # 如果client停止读取数据, 在此时间以后释放该连接,默认是60秒
    send_timeout 2;
     
    # 打开gzip压缩,减少数据传输量
    gzip on;
    gzip_static on;
    gzip_comp_level 9;
    gzip_min_length 1400;
    gzip_vary  on;
    gzip_http_version 1.1;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css text/xml text/javascript image/gif image/jpeg application/x-javascript application/xml;
    gzip_disable "MSIE [1-6].(?!.*SV1)";

    ---------------

    --------基本的nginx.conf----

    user  nginx;
    worker_processes 24;

    error_log  /var/log/nginx/error.log crit;
    pid        /var/run/nginx.pid;

    events {
        worker_connections  2048;
        use epoll;
        multi_accept on;
    }

    worker_rlimit_nofile 200000;

    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log /var/log/nginx/access.log main buffer=16k;

        sendfile       on;
        tcp_nopush     on;
        tcp_nodelay    on;

        open_file_cache max=200000 inactive=20s;
        open_file_cache_valid 30s;
        open_file_cache_min_uses 2;
        open_file_cache_errors on;

        client_body_buffer_size 8K;
        client_header_buffer_size 1k;
        client_max_body_size 2m;
        large_client_header_buffers 2 1k;

        keepalive_timeout  15;
        reset_timedout_connection on;
        client_body_timeout 10;
        send_timeout 2;

        gzip on;
        gzip_static on;  
        gzip_comp_level 9;
        gzip_min_length 1400;
        gzip_vary  on;
        gzip_http_version 1.1;  
        gzip_proxied expired no-cache no-store private auth;
        gzip_types text/plain text/css text/xml text/javascript image/gif image/jpeg application/x-javascript application/xml;
        gzip_disable "MSIE [1-6].(?!.*SV1)";

        include /etc/nginx/conf.d/*.conf;
    }

     

    防止php文件解析漏洞

    # Pass all .php files onto a php-fpm/php-fcgi server.
    location ~ .php$ {
        # Zero-day exploit defense.
        # http://forum.nginx.org/read.php?2,88845,page=3
        # Won't work properly (404 error) if the file is not stored on this server, which is entirely possible with php-fpm/php-fcgi.
        # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on another machine.  And then cross your fingers that you won't get hacked.

        try_files $uri =404;

        fastcgi_split_path_info ^(.+.php)(/.+)$;
        #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini

        include fastcgi_params;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        # fastcgi_intercept_errors on;
        # With php5-cgi alone:
        # fastcgi_pass 127.0.0.1:9000;
        # With php5-fpm:

        fastcgi_pass unix:/var/run/php5-fpm.sock;
    }

     

    php-fpm中的配置,与nginx 的fastcgi_pass的路径一致即可,目录要有相应读写权限
    ; Note: This value is mandatory.
    listen = /var/run/php5-fpm.sock

  • 相关阅读:
    在桌面创建robotframework Ride的快捷方式启动RIDE
    RIDE 接口自动化请求体参数中文时报错:“UnicodeDecodeError: 'ascii' codec can't decode byte 0xd7 in position 9......”
    下拉框选择
    Python下安装MySQLdb模块
    出现 Request Entity Too Large问题的解决方法
    Centos配置nginx反向代理8090端口到80端口
    超简单Centos+Docker+Halo搭建java向博客
    JAVA使用POI如何导出百万级别数据
    Mybatis的MapperRegistry错误
    Navicat连接mysql8出现1251错误
  • 原文地址:https://www.cnblogs.com/timelesszhuang/p/4693834.html
Copyright © 2020-2023  润新知