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? 性能应该有比较明显的提升?
网上有一些资料,吹嘘的nginx aio性能提升,神奇云云。我有点将信将疑,因为都没有任何的测试数据比较,均是人云亦云。另外,多数配置都是或多或少有问题的。
我使用的centos, nginx aio要使用,必须是centos 5.5以上。因为只有5.5的kernel才有aio的backport,nginx并没有使用libaio。
此外,nginx的aio本来是为freebsd开发,linux固然可以使用,不过受到了linux aio的很多限制。
1. 必须使用direct io. 这样一来,导致无法使用vm的disk cache.
2. 文件只有大小和directio_alignment定义block size整数倍的数据才可以使用aio,当文件整数据块之前和之后,那些不能取整的部分则是blocking方式读取的,这也是为什么需要output-buffer。directio_alignment大小取决于你使用的文件系统,默认是512,而对于xfs,注意,如果你没有修改xfs bsize, 需要调整为xfs默认的4k.
我使用的配置如下:
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的传说, 各个说好,其实多数都没实际印证过。
推荐阅读
-
mysql 数据同步 出现Slave_IO_Running:No问题的解决方法小结
-
Win10下C# DateTime出现星期几问题的解决方法
-
WPF中窗体最大化问题的解决方法
-
MySQL server has gone away 问题的解决方法
-
Android编程中调用Camera时预览画面有旋转问题的解决方法
-
Android 表情面板和软键盘切换时跳闪问题的解决方法
-
阿里云主机上安装jdk 某库出现问题的解决方法
-
Java常见问题之javac Hello.java找不到文件的解决方法
-
SpringBoot 监控管理模块actuator没有权限的问题解决方法
-
Xcode 9下适配iPhoneX导致iOS 10不兼容问题的解决方法