您的位置:首页 > 编程语言 > PHP开发

一次php和java的性能比拼

2020-02-29 17:58 375 查看
被测方案 虚拟用户数 GET平均响应时间(秒) UPDATE平均响应时间(秒) 每秒点击数
php 500 0.056 0.072 7759
1000 0.195 0.166 7471
1500 0.318 0.270 7471
单个jvm 500 0.122 0.052 5330
集群jvm 500 0.058 0.058 8500
1000 0.124 0.127 8062
1500 0.193 0.193 7763
2000 0.265 0.267 7656
2399 0.318 0.320 7593
3000 0.396 0.398 7488
4000 0.551 0.553 7338
5000 0.660 0.664 7542

1、单个jvm

理论上来说java的性能应当是高于php的,但是结果很让人失望,无论我如何加大压力,在单个jvm的时候,java都达不到每秒7700请求的指标。我首先想到的是对tomcat做性能调优,我先后使用了以下措施:
  • 增大jvm内存 -Xmx1578m
  • 使用tomcat nio http connector
  • 增大tomcat处理请求的线程数量,maxThreads=2000,processorCache=2000,acceptCount=10000
  • 增大jedis连接池和c3p0数据库连接池到2000
  • 不使用数据库连接池
  • 不使用jedis连接池
  • 不使用spring mvc直接使用servlet
以上措施中只有不使用jedis连接池少量的提高了每秒请求数和响应时间,其他的措施没有多少改进,而且不用数据库连接池时,性能急剧下降,每秒请求数下降到不足之前的五分之一。为了找出性能瓶颈,找出原因,我用jprofiler分析,发现了一些问题。

1.1 commons-pool在并发时性能不佳

jedis的对象池是用commons-pool实现的,这个实现在多线程,并发情况下反倒成了性能瓶颈之一。当2000线程处理请求时,每个线程都要先锁定一个对象才能获取或归还jedis对象,导致这些线程在这个地方排队,性能降低。后来改成每个请求都重新打开一次jedis链接后,性能反倒有一点提升。

1.2 数据库连接池让人又爱又恨

不用数据库连接池是万万不行的,每次打开数据库连接,性能太差。相比之下php没有使用连接池,性能依旧很好,估计是jdbc实现的问题。使用了数据库链接池后,c3p0和commons-pool一样,在并发时,也能成了性能瓶颈,好多线程都在等待获得c3p0的锁。

1.3 诡异的线程集体空闲,集体繁忙

从jprofiler的线程运行图里能看到,tomcat的线程大部分时间不是在处理请求,而是在莫名其妙的空闲,代码停在了tomcat使用的jre自带的ThreaderExecutor一个方法上。而且,这些线程往往同时空闲持续近10秒的时间,然后突然繁忙起来,去争抢数据库的锁,运行,然后再次先后都陷入空闲。load runner的每秒请求数曲线和响应时间曲线呈现出巨大的波动,一会每秒点击高达10000,一会跌入2000以下。而从jprofiler看出,jvm的内存空间使用不超过500m,而且波动很平稳,gc表现稳定,没有大量的全垃圾收集(full gc)。

1.4 apr也打破不了僵局

因此,我怀疑是不是jvm在处理大量并发tcp连接的时候,性能不好,导致这样的局面。为此,我想到了使用tomcat native。它可以让tomcat使用c语言实现的本地代码库来处理tcp连接,而这个库也是apache httpd使用的,性能应当相当好,至少在处理网络方面应当很好吧。编译安装成功后,测试数据显示,并没有多少改变,很让人沮丧。那些线程还是那样的间歇性地集体空闲,集体繁忙。

1.5 jetty和glassfish的表现

看来问题可能处在tomcat自身,于是我用jetty和glassfish做了测试。jetty的 4000 表现和tomcat一样,一样的性能指标,一样诡异的线程。glassfish的性能指标比tomcat稍微差一点,但是它的每秒请求数和响应时间比较稳定,波动不大,很稳定,这一点比tomcat和jetty好多了。用jprofiler看了一下glassfish只有5个线程在处理http请求,而且这些线程都一直处于繁忙状态,不会像tomcat和jetty,众多线程间歇性集体空闲集体繁忙,不均匀。由此我想到,是不是线程配置得太多了,导致tomcat和jetty调度不过来,才会出现那样的诡异的现象。

1.6 tomcat的最佳线程数

我测试了不同线程数的时候tomcat的表现。和glassfish同样5个线程时,tomcat表现很糟糕,逐渐增大tomcat线程数量到50后,性能指标达到了2000线程时的性能指标,再加上去,性能变化不大。看来tomcat默认的200线程数量是很有道理的,200可能是目前大部分机器的最优配置了。

1.7 单个jvm的极限

无论怎么调线程数量,换什么样的服务器,单个jvm最多也只能达到每秒处理5300请求。看来一个jvm是有性能极限的,很可能不能完全的发挥硬件的能力。

2 集群

集群方案是这样的,前端一个apache,使用mod_jk把请求转发到后端的多个tomcat或glassfish。apache, tomcat和glassfish自然是在同一台物理机上的。由于tomcat和jetty的实现机制太像了,就没有单独测试jetty。而tomcat和glassfish在集群时性能表现一样,没有明显的差别。而且,从2个jvm逐步增大到6个,性能表现也没有明显差别。使用apache在前端转发后,tomcat也像glassfish一样变得平稳了,估计这得归功与ajp协议,和mod_jk的连接复用。

2.1 性能分析

集群后java的性能表现终于超越了php。随着压力的增大,java的响应时间增长比php缓慢。在相同的响应时间下,java每秒处理了更多的请求,峰值时多处理近10%。相同响应时间时,java能承受更大的压力,如果以虚拟用户数量来衡量,能多承受50%的压力。 无论php和java,随着压力的增大,请求响应时间和每秒请求数快速上升,但是到达一个点后,压力再增大,每秒请求数会缓慢的下降,而请求响应时间会缓慢的上升。

3 结论

3.1 单个大jvm不如多个小jvm

一个线程很多,内存很大的jvm并不能完全发挥硬件的性能,还不如多个内存小,线程少的多个jvm集群。尽管多个小jvm总体上用了更多的内存,但是每个jvm内的线程少,意味着jvm调度的复杂性减小,竞争同一个锁的线程数更少。

3.2 一定要用数据库连接池

如果不用数据库连接池,java的表现太差了。看来mysql的jdbc driver比它的php用的c语言实现重得多。

3.3 tomcat jetty glassfish

测试中使用的是tomcat7 jetty8和glassfish3.2三者的性能表现差不多,而glassfish更加有好的使用界面,更加稳定的性能数据,使它表现得更出色。

3.4 java的性能还是比php好的

在相同的硬件下,如果单个jvm不能完全发挥硬件的性能,通过多个jvm的集群可以,而且会超过php。 我想,在这个测试例子中,因为每次打开连接执行一次数据库操作,java的数据库连接池的优势没有完全体现出来,否则java应该会表现得更好。如果是cpu计算密集型的任务,java的性能应该会更好。

转载于:https://my.oschina.net/komodo/blog/919187

  • 点赞
  • 收藏
  • 分享
  • 文章举报
choulu2000 发布了0 篇原创文章 · 获赞 0 · 访问量 451 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: