我对HTTP服务器很感兴趣,我花了大量时间来试用它们,还喜欢从不同角度来比较它们。 今天我将用同一个用例对以下不同的HTTP服务器库进行测试:
|
|
之所以选择这些库是因为我现在对它们几个最感兴趣。Mochiweb, 是一个稳定的库,在生产环境上使用广泛(估计曾经,或者现在还是,和其它组件一起,被 Facebook 来作聊天服务的后端);Cowboy,一个刚刚诞生不久的库,其开发者在 Erlang 社区里十分活跃;NodeJS,将 javascript 引入服务端,开创了一个充满各种可能的新世界(可与前端共用代码,入门成本低等);还有 Tornadoweb,因为 Python 仍然是我最喜欢的语言之一,另外 Tornadoweb 在各种性能测试和生产环境中都有出色的表现,是 FriendFeed 的后端实现。 关于这个测试,还有两个重要的原则。首先,我并不想做 "Hello World" 类型的测试:对于这类测试,使用静态内容服务器(如 Nginx)就完全可以了。这个测试主要针对动态内容服务器。其次,我计划隔一段时间就关闭 socket,因为现实中是不可能仅靠几个 socket 来承担所有负载压力的。 |
|
为了实现上面所说的第二点,我决定使用一个经过修改 的 HttPerf。这是一个来自HP公司的知名的测试工具,使用广泛。它的作用是往服务器发送指定数目的请求,然后根据响应的数目、整个过程中产生错误以及其他信息来生成报告。HttpPerf 最好的一点是,你可以指定一个参数(叫"-num-calls"),来告诉它你在关闭 socket 前一次性要发送多少个请求(就是 socket 连接)。这次测试用到的命令为: httperf --timeout=5 --client=0/1 --server= --port=8080 --uri=/?value=benchmarks --rate= --send-buffer=4096 --recv-buffer=16384 --num-conns=5000 --num-calls=10 我将速度(--rate)从100开始一直增加到 1200。由于每秒请求数目等于 rate*num-calls,这个测试实际上每秒发送的请求数目由 1000 增加到 12000。总的请求数目等于 num-conns*rate,每次迭代中实际等于 50000。 |
|
这个测试实际上是请求服务器:
因此,实际上测试的是服务器的:
服务器是一个双核的1.5G内存的虚拟机系统,安装了 Ubuntu 10.04 LTS,并打上了最新的补丁。/etc/sysctl.conf 已经过优化,主要参数如下: # Maximum TCP Receive Window net.core.rmem_max = 33554432 # Maximum TCP Send Window net.core.wmem_max = 33554432 # others net.ipv4.tcp_rmem = 4096 16384 33554432 net.ipv4.tcp_wmem = 4096 16384 33554432 net.ipv4.tcp_syncookies = 1 # this gives the kernel more memory for tcp which you need with many (100k+) open socket connections net.ipv4.tcp_mem = 786432 1048576 26777216 net.ipv4.tcp_max_tw_buckets = 360000 net.core.netdev_max_backlog = 2500 vm.min_free_kbytes = 65536 vm.swappiness = 0 net.ipv4.ip_local_port_range = 1024 65535 net.core.somaxconn = 65535 |
|
本文测试的各个库的版本:
各个库都采用默认设置来运行。其中 Erlang 开启了 Kernel Polling。另外,为了让所有库只使用一个CPU,我禁用了SMP。 测试结果 HttPerf 的原始输出文件可从 这里 下载 预期和实际响应图 超时错误图 响应时间图 注:上面的图的Y-轴使用了对数 总响应时间图 由图可知,Tornadoweb 最高约为 1500 请求/秒,NodeJS 为 3000,Mochiweb 为4850, Cowboy 为8600, Misultin 为9700。除了 Misultin 和 Cowboy 没有或者只有少数错误外,其他库在高负载情况下性能下降明显。请注意,这里的“错误”是指超时错误(大于5秒没有响应)。Total responses 指总的响应数目,response times 指的是响应时间。 |
不得不说,这些结果还是让我比较吃惊的。写到这里,希望各位读者能在代码和测试方法上给我提些意见,以进行更好的测试。欢迎各种意见,我将和其他贡献者一起,在后续的讨论中继续更新这篇文章以及更正相关错误。 注意:文章内容不代表本人观点,请不要由此进行言论攻击。正是由于这些结果太让我惊奇,我才把这篇文章发布出来。 对于这些结果,你的观点是怎样的呢? |
|
—————————————————–
更新 (2011-5-16) 现在各种各样的测试正源源不断地冒出来。在你们阅读这些测试报告(也包括我的)的时候,我想着重强调一点: 对于各种测试报告,人们常常误认为:如果一个测试对象在图表中表现越好,那么这个测试对象在所有的应用场景下都是最好的。这种观点绝对,绝对是错误的! |
|
"快速"只是优秀WEB服务器库的众多特点之一:在选择组件进行开发之前,你还必须考虑健状性、功能、易于维护、尽可能接近标准、代码可用性、支持社区、开发速度及其他因素。没有哪个测试是适用于所有情况的。这类测试问题侧重于某一方面:程序运行速度够快、负载能力够强或者尽量少的数据传输量。 因此,请仅将本文测试作为参考的一个因素,而不要武断地下结论。本文引用的库都很优秀,也很有意思,但是你在使用之前,请经过充分的考虑。本文在语言或者在测试方法若有不当,欢迎指正,严厉一些也没关系。 谢谢。 |