谷歌、度娘搜索Nginx优化,能搜索出很多的文章,动不动就几万并发,十万并发,看着好像真是那么回事似的。
从使用Tengine的过程中,对Tengine/Nginx的优化,我个人认为Tengine的优化是脱离不开使用它的环境及部署结构的,单说优化
Tengine的意义并不大,况且每家公司的业务各不相同,所以优化不是简单的事情。即便如此,我总结了下,从以下几个方便入手浅谈下
Tengine/Nginx的性能优化。本文以Tengine为主,Nginx大部分都适用。
1、网络
带宽
一个需要支持1万并发且平均页面内容在100KB的情况下,就需要大概1G的带宽,如果带宽只有100M,需要支持这样的场景无论如何也是不可能的。更好的带宽可以支持更高的并发
路由
现在的IDC运营商有很多,越小的运营商在路由优化上就不怎么样,例如在对IDC进行测试的时候,大部分运维使用ping来测试机房的网络质量,这种测试
其实是点到点的测试,中间大网的情况就测试不到。在使用mtr进行测试的时候,可以看到每一跳的延迟及路由,很多时候会发现浮动路由。这种情况下网络质量
一定不好。最好通过mtr对机房提供的IP连续进行一周的测试,路径都比较稳定的时候这样的机房值得选择。
2、硬件
CPU
一般情况下作为Tengine/Nginx的应用,CPU的频率我认为对性能影响还是较小的,但是核心数对于Tengine/Nginx而言确实很有用,
更多的核心数外加HT技术,可以让Tengine/Nginx运行更多的worker,从而提升Tengine/Nginx的负载能力
内存
内存的容量直接对Tengine/Nginx可承载的连接数有影响(主要指ESTAB连接)。另外大容量的内存在结合tmpfs进行合理使用的话,可以作为Tengine/Nginx的各种temp目录及各种缓存目录,降低对磁盘IO的消耗
网卡
目前在互联网公司DELL的服务器应该是用的最多的了,而且在用户没有特殊需求的时候,配置的网卡通常是Broadcom
BCM57XX的,这种网卡比较便宜所有在处理小包的时候,带宽利用率不高,且流量大的时候会出现大量丢包。在Tengine/Nginx的机器上还是推
荐使用Intel X350I QP的网卡,在使用最新的网卡驱动后,可以对网卡做出更多性能控制(X350默认的RSS队列最大为8个)
磁盘
磁盘的IO能力个人认为在硬件里的比重不高,在拿Tengine/Nginx作为专用缓存服务器的时候,使用SATA
SSD或者PCIe-SSD卡时可以作为缓存存放的目录路径。一般Intel S3710 800G的大概7000左右,同容量宝存的800G
PCIe-SSD大约1.5W。
3、系统
TCP/IP协议栈
CLOSE_WAIT与TIME_WAIT
这两种连接状态是Web服务器中大家最关心的也是最让大家头疼的,虽然很多的博客里说现在服务器内存大,这种连接达到几万、几十万时对内存的消耗不是问题
不用去理会,但是在一些场景中可能会对应用造成很大的影响。例如在我们的业务中出现CLOSE-WAIT状态时,是数据库有长事务执行时导致Resin出
现了CLOSE-WAIT连接,当这种连接数高于10个时,应用就会打开慢直到应用打不开。所以需要对其进行优化。尽量避免系统中出现过多的这两种连接。
当Tengine/Nginx反向代理后端服务器的时候,Tengine所在的服务器上会出现TIME-WAIT(跟后端服务器断开后产生的状态)以及
CLOSE-WAIT(客户端断开后产生的状态)的连接,一般为了减少Tengine/Nginx与后端服务器通信时造成的TIME-WAIT连接,主要
需要如下的配置,例如:
配置一
upstream example {
server 192.168.0.1:8080;
keepalive 4;
}
server{
listen 80 backlog=2048;
server_name www.example.com;
location = /favicon.ico {
error_page 404 = 200;
log_not_found off;
access_log off;
}
location = /robots.txt {
error_page 404 = 200;
log_not_found off;
access_log off;
}
location / {
include proxy_opt.conf;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_pass http://example;
}
}
配置二
server{
listen 80 backlog=2048;
server_name www.example.com;
location = /favicon.ico {
error_page 404 = 200;
log_not_found off;
access_log off;
}
location = /robots.txt {
error_page 404 = 200;
log_not_found off;
access_log off;
}
location / {
include proxy_opt.conf;
proxy_pass http://192.168.0.1:8080;
}
}
两种配置,都可以实现www.example.com的访问,区别在于配置一因为使用upstream且在upstream里配置了keepalive连
接,在压力较大的时候Nginx与后端server之间的CLOSE-WAIT以及TIME-WAIT将非常少,因为有长连接。而配置二是直接
proxy_pass,在压力大的时候CLOSE-WAIT和TIME-WAIT的数量将比较多,在这种情况下,容易产生孤儿连接,孤儿连接一般占用内存
约64K且为不可交换内存(可参考内核文档)。在Tengine中不光可以在upstream中配置与upstream的长连接,还支持长连接超时参数。
(此处估计有人说优化TCP/IP协议栈就可以降低CLOSE-WAIT和TIME-WAIT的连接数了,真的吗?你去试试就知道了。)
除了在Nginx上启用upstream来减少CLOSE-WAIT和TIME-WAIT的连接数外,还有2种方式:
a)在/etc/sysctl.conf中将net.ipv4.tcp_max_tw_buckets的值改为0,可以快速释放TIME-WAIT连接(此法比较暴力,但在系统负载比较高时比较好使,有点像Haproxy中的option forceclose)
b)编辑kernel中include/net/tcp.h
将
#define TCP_TIMEWAIT_LEN (60*HZ)
修改为
#define TCP_TIMEWAIT_LEN (5*HZ)
重新编译内核
4、Tengine本身
安装方式的选择
对于Tengine的安装,目前貌似官方只提供源码包,只能编译安装。
对于Nginx的安装,可以通过在线的软件源进行在线安装,也可以源码编译安装
在线安装一般使用通用的CPU指令集对Nginx进行编译,这种方式不能很好的利用当前CPU的指令集,且配置文件、可执行文件均不能自定义安装目录。对于大规模进行批量化部署时不方便。
源码编译可以通过指定gcc的参数结合CPU的指令集对Nginx进行编译,可以充分使用CPU的指令集提升性能,且安装目录可以自定义,通过修改可执行文件的rpath还可以被fpm打包成公司专用的rpm包,适合批量部署。
对于GCC可使用的参数,可以参考GCC的官方手册
基本配置的优化
#自动设置Nginx启动的worker数量,默认是CPU的processor数(不是core数)
worker_processes auto;
#自动将Nginx的worker进程绑定到CPU的processor上,1.9.10才支持auto,Tegine默认支持
worker_cpu_affinity auto;
#设置所有worker的open files数,如不设置默认为系统ulimit -n的大小
worker_rlimit_nofile 100000;
#开启pcre jit功能,编译pcre的时候需要开启jit功能
pcre_jit on;
events{
use epoll;
worker_connections 8192;
每个worker的最大连接数,这个数字不光光只Nginx与Client间的连接,还包括Nginx与后端Server的连接数,配置的时候须注意
worker_rlimit_nofile>worker_connections*workers
accept_mutex off;在访问量较大的网站上建议关闭accept_mutex机制
}
client_header_buffer_size 8k;
client_header_timeout 10;
client_body_buffer_size 256k;
client_body_timeout 10;
large_client_header_buffers 4 8k;
client_max_body_size 20m;
send_timeout 10;
keepalive_timeout 30;
keepalive_requests 5000;
reset_timedout_connection on;
log_format access
配置文件中的各种buffer
proxy_pass
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffer_size 64k;
proxy_buffers 4 64k;
proxy_busy_buffers_size 128k;
proxy_temp_file_write_size 512k;
proxy_next_upstream error timeout invalid_header http_503 http_404 http_502 http_504;
proxy_max_temp_file_size 32m;
proxy_intercept_errors on;
fastcgi_pass
fastcgi_connect_timeout 30;
fastcgi_send_timeout 15;
fastcgi_read_timeout 15;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 512k;
单台Tengine最大连接数估算
合理利用proxy_cache和fastcgi_cache
SO_REUSEPORT && TCP Fast Open
关于SO_REUSEPORT和TCP Fast Open的原理以及它们是做什么的,可以自行谷歌上查找
就这reuseport功能Tengine 2.1.0就支持,Nginx直到1.9.1才支持reuseport
SO_REUSEPORT特性本来是kernel 3.9以上才支持的功能,不过Red Hat在其6.5版本开始就支持该特性了,所以使用CentOS 6系列的童鞋只需要升级内核大于6.5版本的就可以使用了。
TCP Fast Open这个特性RHEL
6中并没有支持,真的需要3.7以上的内核才支持,有需要使用这个特性的童鞋可以升级内核,升级可以安装UEK内核,或者通过ELRepo安装高版本的内
核,通知需要重新编译Tengine或者Nginx用以支持TFO,另Haproxy 1.5已经支持TFO功能
合理使用tmpfs
在使用Nginx的过程中,总是会考虑使用proxy_cache,fastcgi_cache,同时也会产生各种临时文件,大多数情况下,运维工程师都
会使用物理磁盘去承担这部分工作,但这样会产生额外的IO,重要的是响应速度方面磁盘要低于内存,所以在针对各种cache,以及各种temp的情况,有
以下建议可参考:
a)用Nginx做缓存服务器
在使用1U DELL R630且内存为128G的前提条件下,如果被缓存的数据小于64G,可考虑直接使用tmpfs来作为proxy_cache或者fastcgi_cache的存储介质,当缓存数量非常大时也可以使用PCIe-SSD来做缓存的存储介质
b)将Nginx产生的临时文件放入tmpfs
本人使用的做法,将mount tmpfs的命令写入Nginx的启动脚本中。读者可自行研究,以下为自用启动脚本
注意tmpfs如果使用echo {1,2,3} > /proc/sys/vm/drop_caches是无法释放tmpfs占用的内存的,除非清空tmpfs
#! /bin/sh # Description: Startup script for Tengine # chkconfig: 2345 55 25 PATH=/sbin:/bin:/usr/sbin:/usr/bin DESC="Tengine daemon" NAME=tengine DAEMON=/opt/websuite/tengine/sbin/nginx CONFIGFILE=/opt/config/tengine/nginx.conf PIDFILE=/opt/run/tengine/$NAME.pid SCRIPTNAME=/etc/init.d/rc.tengine TESTPATH=/opt/websuite CACHEDIR=/opt/websuite/tengine/cache TEMPDIR=/opt/websuite/tengine/temp set -e [ -x "$DAEMON" ] || exit 0 do_start() { $DAEMON -c $CONFIGFILE || echo -n "tengine already running" } do_stop() { $DAEMON -c $CONFIGFILE -s stop || echo -n "tengine not running" } do_reload() { $DAEMON -c $CONFIGFILE -s reload || echo -n "tengine can‘t reload" } do_mount_ramdisk() { mount -t tmpfs tmpfs $TEMPDIR/client -o defaults,size=32M,uid=websuite,mode=755 mount -t tmpfs tmpfs $TEMPDIR/proxy -o defaults,size=32M,uid=websuite,mode=755 mount -t tmpfs tmpfs $TEMPDIR/fastcgi -o defaults,size=32M,uid=websuite,mode=755 mount -t tmpfs tmpfs $TEMPDIR/hmux -o defaults,size=32M,uid=websuite,mode=755 mount -t tmpfs tmpfs $CACHEDIR/proxy -o defaults,size=512M,uid=websuite,mode=755 mount -t tmpfs tmpfs $CACHEDIR/fastcgi -o defaults,size=512M,uid=websuite,mode=755 } do_umount_ramdisk() { umount $TEMPDIR/client umount $TEMPDIR/proxy umount $TEMPDIR/fastcgi umount $TEMPDIR/hmux umount $CACHEDIR/proxy umount $CACHEDIR/fastcgi } case "$1" in start) echo -n "Starting $DESC: $NAME" if [ $(mount|grep $TESTPATH|wc -l) -eq 0 ];then do_mount_ramdisk fi do_start echo "." ;; stop) echo -n "Stopping $DESC: $NAME" do_stop if [ $(mount|grep $TESTPATH|wc -l) -gt 0 ];then do_umount_ramdisk fi echo "." ;; reload) echo -n "Reloading $DESC configuration..." do_reload echo "." ;; restart) echo -n "Restarting $DESC: $NAME" do_stop sleep 1 do_start echo "." ;; *) echo "Usage: $SCRIPTNAME {start|stop|reload|restart}" >&2 exit 3 ;; esac exit 0
5、Nginx常见部署场景
静态资源网站
Tengine+PHP-FPM
Tengine+Tomcat
Tengine使用hmux构建Resin集群
Tengine结合KVM构建Web集群
Haproxy/LVS+Tengine的配合使用
6、监控
Tengine基本状态输出
利用nginx-module-vts输出更多数据
7、其他
分布式缓存
缓解机器人压力
动态更新upstream
有Varnish的架构中Tengine扮演的角色