您的位置:首页 > 运维架构 > Nginx

nginx的优化

2015-08-01 11:09 756 查看

转:http://blog.sina.com.cn/s/blog_704836f40100zlht.html

说起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_buffersproxy_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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: