服务器和客户端为同一台机器:XEON 3.0G/2G/SUSE 10.0/Kernel 2.6.13-15-smp
软件环境:
Java虚拟机均采用BEA JRockit,版本号为R26.0.0-189-53463-1.5.0_04-20051122-2040-linux-ia32,运行时参数均指定为-Xms512m -Xmx512m。
除Resin外,所有server的backlog都设为10000(未找到Resin中设置该选项的位置)。QuickServer虽然提供了file server,但是由于其发送完成后不关闭连接,用AB无法测试。
-
Echo web server
-
Cindy 2.4.4 http server
-
Cindy 3.0a4 http server (use SocketSessionAcceptor)
-
Cindy 3.0a4 http server (use ServerSocketChannelSession)
-
MINA 0.9.2 http server
-
QuickServer 1.4.7 echo web server (blocking mode, disable log and admin)
-
QuickServer 1.4.7 echo web server (non-blocking mode, disable log and admin)
-
-
File web server
-
cindy 3.0a4 http server (use SocketSessionAcceptor)
-
cindy 3.0a4 http server (use ServerSocketChannelSession)
- tomcat 5.5.15 (disable log)
-
jetty 5.1.10 (disable log)
-
resin 3.0.18 (disable log)
-
apache 2.0.54
-
lighttpd 1.4.11 (disable log)
-
thttpd 2.25b (disable log)
-
测试工具:
Apache Benchmark,2.0.40-dev版本。
先使用concurrent level 10,测试10w(大文件测试2k个)个请求热身,结果不记入统计。随后分别使用concurrent level 1/10/100/500/1000,测试20w(大文件测试1w个)个请求,对结果进行统计。
测试结果
表格中为Requests per second,数值越高越好。
Echo web server:
Concurrent | Cindy 2.4.4 | Cindy 3.0a4 (acceptor) | Cindy 3.0a4 (session) | MINA 0.9.2 | QS 1.4.7 (blocking) | QS 1.4.7(non-blocking) |
---|---|---|---|---|---|---|
1 | 3376 | 2760 | 3062 | failed | 2299 | failed |
10 | 4882 | 4581 | 4561 | failed | 3244 | 1890 |
100 | 4998 | 4903 | 4494 | failed | 1425 | 1890 |
500 | 4891 | 4528 | 4847 | failed | 1338 | 1353 |
1000 | 4546 | 4018 | 4552 | failed | 1192 | 1313 |
File web server (small file 100 bytes):
Concurrent | Cindy 3.0a4 (acceptor) | Cindy 3.0a4 (session) | Tomcat 5.5.15 | Jetty 5.1.10 | Resin 3.0.18 | Apache 2.0.54 | lighttpd 1.4.11 | thttpd 2.25b |
---|---|---|---|---|---|---|---|---|
1 | 2444 | 2641 | 3294 | 2308 | 3809 | 2982 | 4540 | 3145 |
10 | 3812 | 3823 | 4275 | 3177 | 5231 | 3563 | 6044 | 4156 |
100 | 4193 | 3673 | 4578 | 3221 | 4257 | 3579 | 5849 | 4215 |
500 | 3759 | 3737 | 3896 | 3145 | 4309 | 3385 | 4888 | 4104 |
1000 | 3776 | 3773 | 3858 | 2987 | 4040 | 2685 | 4041 | 3986 |
File web server (small file 100 bytes, keep alive):
Concurrent | Cindy 3.0a4 (acceptor) | Cindy 3.0a4 (session) | Tomcat 5.5.15 | Jetty 5.1.10 | Resin 3.0.18 | Apache 2.0.54 | lighttpd 1.4.11 | thttpd 2.25b |
---|---|---|---|---|---|---|---|---|
1 | 5119 | timeout | 7023 | 4980 | 3720 | 5771 | 8824 | - |
10 | 5275 | timeout | 6878 | 5289 | 3753 | 6602 | 13441 | - |
100 | 6322 | timeout | 9609 | 3947 | 4041 | 6391 | 12951 | - |
500 | 5237 | timeout | 5952 | 5234 | 4331 | 6292 | 12495 | - |
1000 | 5612 | timeout | 5478 | 4318 | 4046 | 3367 | 11696 | - |
<P
File web server (large file 947111 bytes):
Concurrent | Cindy 3.0a4 (acceptor) | Cindy 3.0a4 (session) | Tomcat 5.5.15 | Jetty 5.1.10 | Resin 3.0.18 | Apache 2.0.54 | lighttpd 1.4.11 | thttpd 2.25b |
---|---|---|---|---|---|---|---|---|
1 | 299 | 280 | 163 | 128 | 251 | 385 | 280 | 340 |
10 | 257 | 255 | 203 (62 failed) | 213 | 253 | 366 | 318 | 365 |
100 | 237 | 240 | 190 (9991 failed) | 189 | 226 | 339 | 296 | 288 |
500 | 218 | 214 | 183 (46 failed) | 186 (1 failed) | 211 | 305 | 281 | 286 |
1000 | 196 | 182 | 167 (23 failed) | 182 (43 failed) | 177 | 258 | 238 | 240 |
总结
先解释一下为什么Cindy 3.0a4的测试会有两种:一种是基于SocketSessionAcceptor的,一种是基于ServerSocketChannelSession 的。在开发机器上测试时,这两种类型的测试结果有较大的差距,基于Acceptor的测试实际上同时有两个线程在运行,一个线程不停的accept,然后 另一个核心线程做相应的处理;而基于Session的测试实际上只有一个线程在运行,就是核心线程既负责accept,也负责处理。在赛扬2.4的机器 上,第一种的测试成绩大约为650#/sec,而第二种的测试成绩大约能到900#/sec。鉴于这两者在开发机器上的性能差距,所以在服务器上也做了这 两种测试。
另外,由于这种测试绝大部分时间都是消耗在网络I/O上面,业务逻辑的处理用时非常少,所以只有在使用DirectDisptcher时才拥有最好 的响应时间,多开线程会使响应时间大幅下降。也正是这个原因,前两种类型在开发机上的测试结果有如此大的差距。不过由于这次测试机器的CPU是XEON, 双核,所以这两种类型的测试结果差距不明显。
在Echo web server的测试中,MINA 0.9.2在完成一个请求后就不再相应后续的请求了,可能是代码中存在的一些Bug所导致,所以这次测试对MINA来说其实稍微有些不公平,我会等它在后 续的版本修正了这个问题后再进行一次测试;本来在开发机上QuickServer的测试结果和Cindy的测试结果非常接近,在blocking模式下, 性能甚至稍微超出Cindy 3.0a4,没想到放到服务器上测试时会有这么大的差距;Cindy 2.4.4依旧傻快傻快,呵呵,不过它的模型没有Cindy 3.0这么容易扩充,而且Cindy 3.0在这种场景下和它的差距也是非常小的,所以还是推荐尽早升级到Cindy 3.0。
基于小文件的测试,Resin和Tomat遥遥领先,阻塞I/O+线程池的效率充分发挥了出来。并且这种压力测试速度又快,一个连接非常短的时间就 能被处理完,正好是阻塞I/O+线程池的优势所在。在concurrent较小的情况下,这种优势更加明显,在concurrent逐渐增大后,阻塞I /O和非阻塞I/O处理效率上就越来越接近了。在这个测试中Jetty的结果比较令人失望。
Keep alive的连接测试中,基于Session的测试耗时太长被中途放弃,怀疑是由于单线程运行+Keep alive造成了始终在处理第一个连接所造成,这个还有待证实;Tomcat的表现更是突出,而在这个场景中本来应该是非阻塞I/O的强项所在。不过最大 的concurrent也只到1000,在真实的环境中,如果concurrent持续增大,cindy的优势应该会更加突出才对。
大文件的测试类似于Keep alive的测试,这种场景应该也是非阻塞I/O的优势场景。在该场景中,cindy总算体现了非阻塞I/O的优势,而tomcat的表现就有点失望了, 失败数也太多了一点……我研究过Tomcat的源代码,没采用JNI的话它是基于阻塞I/O的实现,只能通过SO_TIMEOUt来中断对数据的读取和写 入,所以它在运行时会通过计算服务器的负载来设置相应的SO_TIMEOUT,负载小于33%情况下采用默认的SO_TIMEOUT,33%到66%之间 SO_TIMEOUT减半,66%到90%之间,SO_TIMEOUT变为默认的1/3,超过90%则急速降为默认的5%。我怀疑在大文件的测试当中,由 于服务器线程负载太大,所以导致超时时间变为默认的5%,从而造成了这么多的失败数。
总体来讲,在基于NIO的异步I/O框架中,我认为Cindy的效率应该算是很不错的了;阻塞I/O+线程池的做法在并发量少、连接时间短的应用中 比NIO有着更高的效率,但是随着并发量的上升,两者的差距会逐渐缩小(再上升会不会反超?未经证实……)。但Java的网络层效率还是和C/C++的实 现还是有着明显差距,高性能网络应用的首选还是C/C++。