Nginx的c30k问题解决方法

服务器 发布日期:2024/11/6 浏览次数:1

正在浏览:Nginx的c30k问题解决方法

最近我们的下载服务遭遇了c30k,导致nginx的下载服务近乎停滞。原因嘛,很简单,服务器部署在国外,众所周知的原因,SL机房的线路不稳,加上不同地区出口速率抖动很厉害,为了加速下载,我们放开了限制,允许用户使用多线程的下载工具。这样一来,自然产生了c10k问题。下载文件都不小,每个用户至少使用4线程,同时下载若干个素材。。。很自然并发链接数30k以上。

更受限于手头money,无法扩容(实际上要有钱也不会跑国外)。因此,必须提高单机并发能力和吞吐量。

我们的下载服务是使用Perl写的一个Plack应用,典型的PSGI,实现下载验证,实时防火墙,用户下载跟踪等等,无法直接使用静态文件分发(实际上Perl的性能还是很高效的,部署于Starman,对比PHP的实现,是后者(PHP-FPM)的10倍左右)。

Starman是一个很不错的PSGI Server,它使用传统的Prefork模式。即便高效,但Prefork确实无法有效应对c10k,我无法把Starman的worker增大到几百上千个。在以前的文章曾经提到Evented IO是能够应付c10k的一个方案。因此,我使用Twiggy换下了Starman。Twiggy是基于AE(AnyEvent)的一个PSGI Server,单进程。在低并发下,单进程的Twiggy的qps是弱于Starman,不过到了高并发,Twiggy的优势就显现出来了。在实际部署中,我启动了多个Twiggy进程,分别监听独立的端口,nginx则使用upstream进行负载均衡。 10个Twiggy的吞吐量已经远远超过了50个Starman worker。 Twiggy的开销也不大,因此可以很放心的增加Twiggy的进程。

感谢PSGI的接口规范,从Starman切换到Twiggy,应用程序无需做任何改动。(前提是程序内不能有阻塞io的操作)。

另一个问题是服务器的IO-Wait比较高,毕竟下载这个是IO-Bound的任务。

Nginx支持Linux Native AIO,因此我考虑是否使用AIO能够大大降低IO-Wait"codetitle">复制代码 代码如下:
location /archive {
internal;
aio on;
directio 4k;
directio_alignment 4k;
output_buffers 1 128k;
}

当启用AIO后,可以看到vmstat中,cache的内存消耗迅速降低,这是因为使用AIO必须使用directio,这就绕过了vm的diskcache。

实际性能如何,AIO一定很快么? 这点即便是Igor也不确定。

从我们自己的实际效果看,AIO并没有明显的性能提升,相反,偶尔会轻微增加了IO-Wait,这是因为无法利用diskcache,而如果文件多数又和directio_alignment有偏差(尤其是断点续传的时候,多数文件读取位置在directio_alignment数据边界外),这部分的数据必须使用blocking io读取,又没有disk cache,增加IO-Wait也可以理解。

最终,结论是,与其使用不那么靠谱的Nginx AIO, 不如多开一些Nginx的worker,重复利用vm disk cache, 当内存100%利用率的时候,nginx的静态文件分发效率是高于AIO模式的。

BTW,这个实际用例也重新印证了我的一个观点,不要轻信网上那些毫无测试数据的忽悠,多数都是copy & paste的传说, 各个说好,其实多数都没实际印证过。