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种。一般来说,运行在freebsd,linux,MacOS,Solaris上性能不会有很巨大的差别,所有选择你自己熟悉的OS比要选择所谓"绝对优化"的,但是不熟悉的OS更加重要。不过,windows是一个例外,在生产环境中,千万不要把nginx运行在windows上。因为windows有自己的event polling方法,而nginx的作者明确说明不支持该方法。
    在nginx中,可以在配置文件中指定所使用的event polling模型,指令如下:
  
    use epoll;   Linux系统
    use   kqueue;  FreeBSD系统
 
    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。通常,如果超过4个worker 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,那么意味着其实我们每秒只能处理8个connection。显然这个数字超过了大多数人的需求,尤其是当我们使用2-4个worker process的时候。但是对于大流量的站点,并且打开了keep-alvie,那么应该时刻考虑到这一点。
    当考虑worker connections的值的时候,其实很简单,流量增加就增加这个值。2048对于绝大多数人应该够用了,不过如果你的站点真的增长这么快的话,那么最大该设置多大,只有你自己尝试了。
 
    4.CPU Affinity
    设置CPU affinity的意思是告诉nginx,每个worker process应该使用哪一个CPU core,指定以后该worker process只会使用你指定的那个CPU core。请小心的做这个配置,因为OS的CPU调度器在处理负载均衡方面远比人类做的更好。如果你确实认为你需要在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如何处理网络缓冲,何时将他们刷新给最终用户。因为这两个参数不会明显提高或改变任何事情,如果你不明白这两个参数的含义,那我建议你不用碰它,保持默认值就好了。
 
 
    三、硬件的限制
    上边已经讨论了OS,nginx本身的一些限制,现在让我们看看怎么把服务器的性能压榨到底。
    服务器上能成为瓶颈的就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_buffers proxy_buffers  指令指定了处理upstream回应的buffer大小,也就是PHP,Apache或其他。上边也说到了,如果这个buffer太小,在响应用户之前,nginx将不得不把upstream服务器返回来的响应存储在临时文件中。注意,nginx的buffer是有上限的,这个上限由 fastcgi_max_temp_file_size proxy_max_temp_file_size 控制。当然也可以通过将 proxy_buffering 设置成off来关闭proxy connections的buffer(通常不是个好主意!)。
 
    示例如下:
    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
---------------


 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值