Nginx之大并发服务器架构实战技法一和Nginx之大并发服务器架构实战技法二这两篇文章中,我分别做了大并发优化思路的详解和对nginx 2000并发的压力测试。我们发现 Nginx 不尽人意,2000个并发的时候, 就错误率非常之高。这时候我们按照之前的两个优化思路,首先我们看看nginx 的错误日志。我们看到, open"xxxx"failed,Too many open files;出问题了。这就是说操作系统不允许一个进程一次打开那么多的html文件。
Too many open files 报错。
另外一方面,我们看下socket 能否建立起来,命令: dmesg tail。我们发现“SYN flooding on port 80.sending sookies.”。服务器说,80端口被请求的特别快。是不是遭受到 洪水攻击了,所以每一次请求都带了一个 cookies ,防止别人洪水攻击。挡住了一部分。
洪水攻击报错
这就是之前说的两个方面,建立的socket 能否很多。打开的文件是否很多。我们接下来对它进行调试。
看看 ulimit -n ,发现在机器上,能打开1024个文件。然后我们把它变大。注意这个ulimit -n 20000 是操作系统层面改的。
我们通过统计模块看,并发依然不尽人意。那么我们来分析,这到底是为什么?
我们首先从两个地方来努力, 一个就是socket ,一个是文件。
socket层面 ,我们又分两个部分来讨论。一个是系统层面,一个是nginx 层面。
1、系统层面:
1)、允许打开的最大连接数:它的内核有一个叫做somaxconn。
2)、加快tcp连接的回收: 连接之后就断开了。一般它不能马上断开的,有一个延迟。tcp 是否立即回收。
它在内核有一个 recycle。
3)、空的tcp是否允许回收利用,内核有一个 reuse.
4)、 洪水攻击。那么如果系统认为是洪水攻击,抵御我们咋办呢?我们要让它不做洪水抵御。
2、nginx 层面:
1)、每一个子进程允许打开的连接,也就是 worker_connnections。
2)、http连接快速关闭 keepalive_timeout。
如上几点,在socket 层面上,我们希望能够尽可能多的socket文件,而且有人用完了还能快速回收。这就像商场,首先把座位弄多些。客人吃完饭就立即收拾,能快速回收。如果有人点了餐但是不吃了。那么这个位置需要能立即利用。同时来的客人越多越好,我们不做洪水抵御。通过这四个方向,参数需要调优。同时对于nginx worker_connnections,我允许你单个子进程允许建立多少连接,比如我们允许建立10000的连接。这是在socket 层面做的努力。
文件层面:我们也可以分为系统和nginx两个方面来考虑。
1、系统层面:ulimit -n ,需要设置一个大的值。
2、nginx 层面:子进程允许打开的文件:worker_rlimit_nofile,一个子进程最大能打开多少个文件。
那么我们把这个思路一整理,就可以动手了,如下:
首先socket, nginx 一个子进程允许打开多少个连接,我们把它调大一些,1万以上。
nginx 最大连接数
系统层面,我们看看当前系统层面的somaxconn,我们看到系统默认最大打开的连接数为128,这个肯定不行。
所以这个要放大。注意somaxsonn 这个文件不是一个真正的文件。proc是系统运行状态的数值,其实这些都是从内存读出来的。所以你如果修改这个数值,它就立即生效了。因为它是系统状态的数值。
所以我们把它修改大到50000。同时我们加快tcp 的回收。我们通过命令查看,发现值为0,那就意味着它不会快速回收,那么我们就把它修改为1,让它能够快速回收。空的tcp回收,也是直接 给响应的参数置1。
不做洪水抵御,我们先来看看当前它是否帮我们做洪水抵御了。通过tcp_syncookies,我们看到值为1,
系统在做洪水抵御。所以也不用抵御了。我们直接把它置为0就可以了。
刚才的东西,为了方便操作,我们来一个脚本,把刚才的写进脚本批量执行,把上面的四个选项调过来。它是立即生效的。那到现在为止,socket我们从nginx 和系统方面都做了加大和优化。
socket 系统方面调优参数
再来看文件层面。首先把系统层面打开的文件数量变大。ulimit -n 50000 。另外 nginx 本身是否允许你打开那么多的文件。所以在配置文件中还应该加一个:worker_rlimit_nofile 10000,一个工作进程允许打开多少个文件。
文件 nginx 层面允许打开文件数设置
nginx reload 一下,这时候,我们再一次压力测一下,5000并发,请求200000,我们看到,5000个并发,错误率为0,而且80%的请求都保持在200毫秒之内。nginx 很容易就能做到5000的并发。而且我们的机器不是什么很高档的服务器。就是普通的PC服务器,所以nginx 的性能还是值得肯定的。
我们在做一次压力测试,加一个 -k 的选项,看浏览器统计,我们看到这次waiting有了一个显著的变化。那么,-K是干什么的?我们随便打开一个浏览器的调试模式。
增加了 -k 参数的压力测试
显示keep-alive
单台5000并发错误率为0
keep-alive 这个东西是干什么的? 有好处也有坏处。在http 1.0时代,在client 和 server 端,请求、 应答、 断开。到了http 1.1 的时候,请求你的主页,在主页上还包括了很多的css、 js、 图片,所以,请求你的主页后,你能不能不要把tcp 断开。我请求css 的时候,我的http连接建立在你刚才的http之上,就类似我排一次队,取好几次东西,那么keep-alive 在http1.1之后加上,也有好处,它就是防止了频繁的TCP握手。但是对于高并发网站来说。这里就是一个弊大于利的东西了。因为高并发网站,他们的TCP都是那么的珍贵。结果你抢到一个,还保存了那么长时间。默认为65秒。这显然是一个浪费,所以在高并发网站中 keepalive_timeout 0,是一个要严重注意的选项。如果非想用,把它控制在2秒之内。在大了就不太合适了。我们这里置为0,就是不支持这个功能了。这是,你看已经没有keepalive,取而代之的是:connection:close,这样能加快tcp的回收。
我们通过两台客户端,每台5000并发100000请求,同时压服务器,通过观察nginx 统计模块观察。发现10000的并发比较容易就实现了。而且错误率夜很低或者基本没有。最后通过我们的优化。在原来2000并发撑不住到10000并发轻松实现了。