mysql数据库的一个测试结果,有些出乎意料

库是空库,比较直接得到1000次数据库连接和从池中得到连接的性能差别
下边是代码;
PoolManager pm = PoolManager.newInstance();
long total = 0;
int i = 0;
for (; i < 1000; i++) {
long curTime = System.currentTimeMillis();
Connection conn = pm.getConnection("mysqlPool");
long afTime =System.currentTimeMillis();

long margin = afTime-curTime;
total+=margin;
System.out.println(
"得到第"
+ i
+ "个数据库连接:"
+ conn
+ " 耗时:"
+ margin);
pm.freeConnection("mysqlPool", conn);
}
System.out.println("平均耗时为:"+(total/i));
pm.release();
结果:
* 数据库测试,测试连接池在并发访问1000客户端连接时的工作效率
* 1,不加入释放语句
* 1000次连接,耗时最短40毫秒,最长150 毫秒,平均在46左右
* 2,加入释放语句
* 10000 次 得到连接,最短30毫秒,最常40毫秒,平均在35左右

对连接池化后,除了性能比较稳定(摆动幅度较小)外,在得到连接的时间上差别也不算很大。

再,N多的地方都说mysql在并发100以上的访问,性能会大幅下降,从这个测试也看不出来。

探讨一下。

还是一句老话,你这样的测试是无意义的。性能测试是一门学问,需要投入很多的人力物力财力资源去测试,测试用例,测试环境,测试工具都要精心设计。单看你的测试用例就不对,结论也更加无意义。而且这样无意义的测试会误导初学者。

你这只是重复连接/释放N次,并没有并发的代码阿。如果把你的代码做成一个thread,然后run N个这种thread,似乎与你的测试并发的目的更接近些。

噢,对了,再告诉你一个经典的产生误导的测试:就拿你上面的例子,或者再加点料,可以这样来做:

写一个最简单的Servlet/JSP(用Servlet/JSP的目的是便于测试多线程并发访问,其实不用Servlet/JSP也可以测出同样的结果)。这个Servlet/JSP是这样的,从数据库连接池获得一个连接,然后做一个最简单的select查询,比如select count什么的,然后关闭连接,把连接返回到连接池中。另外建议把你的System.out语句去掉,消除对测试结果的影响。

然后使用Apache Web Server带的ab测试工具来并发访问该Servlet/JSP:

ab -n 1000 -c 20 http://.../TestServlet

上述命令行的意思是模拟20个用户并发访问该Servlet,共发送1000个请求,ab测试会返回很多统计信息,包括多长时间完成测试,平均每请求需要多少秒完成,以及成功完成的请求数,失败的请求数等等,这是一个非常专业非常有用的的web性能测试工具。

按照正常的逻辑,大家一定会认为,由于并发20个请求,数据库连接池当然会分配20个数据库连接给Servlet来使用的,并且测试的Servlet逻辑如此简单,运行速度非常快,自然会花很少的时间就可以完成测试过程。

但是测试结果一定大出意料之外!实际上测试需要花很长很长很长的时间才能完成,甚至无法正常完成测试过程!测试完成以后参考ab的测试报告,就可以看到,平均每个Servlet要花很长时间才能完成请求,并且至少有超过60%以上的请求都失败了。大部分Servlet都甚至没能正常运行,这是为什么?如果你的app server有数据库连接池监视工具,你还可以看到更奇怪的现象,就是自始至终,数据库连接池中只使用了一个数据库连接,其它所有的连接,即使你预创建了,也一直被闲置,并没用被连接池分配给Servlet,这又为什么?为什么连接池放着闲置的连接不用? 就算并发Servlet再多,也硬是只用一个连接,这样的话,连接池的作用等于完全没用了?

做完上面的测试以后,你在你的Servlet里面简单加上一句话,Thread.sleep(1000);然后再重复上面的测试。就会发现测试完成时间大大缩短,平均每Servlet完成请求的时间非常短,而平均每秒处理的请求数有巨大的提升,同时几乎所有的Servlet都成功的完成请求,几乎没有失败的请求。并且这个时候,你可以观察到数据库连接池的的确确是分配了20个连接给Servlet来使用的。这又是为什么?

这就是一个经典的测试陷阱:让程序跑的更慢一些,反而得到了性能的巨大提升和程序稳定性的巨大提升!这是否意味着数据库驱动的程序我们应该多加点Thread.sleep语句呢,让程序跑得慢点,反而可以极大的提升性能呢?

这个例子说明了性能测试,绝对不是一般人可以干得来的活。测试是一门高深的学问,测试需要巨大的投资,测试需要精心的设计。像IBM,HP这样的大公司有自己专门的测试实验室,每年投入巨资进行软件硬件的测试,测试结果最终就是一个简单的proposal罢了,可是这个简单的proposal凝结了无数的智慧和资源。

而我们自己随随便便写一个测试用例,然后在自己的机器上随便跑跑,就冒冒失失的宣布某某软件的性能如何如何,简直是井底之蛙!浅薄之至!我每次看到这样的所谓某某软件评测报告,我就无言语了,愤怒的无言语了。自己夜郎自大,关起门来意淫一下也没有人管得着,但是到处把这种荒谬的测试结论到处宣传,简直就是FUD,会严重误导初学者!像TSS的j2ee vs .net petstore 测试就是如此。我还时不时在网络上看到什么asp,jsp,php性能测试,TMD胡说八道,跟白痴一样。

所以性能测试千万要慎重,不要随随便便下什么结论,这样只能带来极大的危害。

出现这样测试陷阱的原因显然是因为测试用例设计不合理导致的,但原因在哪里呢?

原因是因为连接池是线程安全类导致的。连接池本质上是一个集合,集合里面的元素就是空闲的数据库连接对象。从池中申请一个空闲连接,就是从集合中remove一个元素;将一个连接返回池就是集合add一个元素。而这些add和remove操作方法因为都要修改集合对象,所以都必须进行同步,也就是说在对池的操作过程中,池是处于锁定状态。因此过于频繁的池操作将造成瓶颈。

在前一个测试中,当第1个Servlet请求向连接池申请连接的时候,池锁定,池进行remove元素操作,然后池将一个连接对象返回给Servlet,然后池解除锁定,准备响应第2个Servlet请求的申请连接。但是此时由于第1个Servlet执行的太快了,已经完成select操作,向池归还连接对象,于是池又进入锁定状态,add元素操作,第2个Servlet只有挂起,干等的份,更不用说后面第3个,第4个,第n个Servlet请求了,全部挂起。等第1个Servlet执行完毕了,第2个Servlet马上又申请连接,于是池又进入锁定状态,后面的所有Servlet继续全部挂起等待。所有的1000个请求最后变成了串行执行,效率极度低下!后面的Servlet请求由于挂起等待,最后超时失败。

后一个测试中,加入Thread.sleep语句之后,减慢了对池操作的频率。当第2个Servlet请求池分配连接对象的时候,第1个Servlet还在sleep中,因此反到可以从池中分配到一个新的连接对象,加快了运行速度。

因此可以看出,测试用例设计不合理之处就在数据查询逻辑太简单了。真实的运行环境中,由于数据查询逻辑不会那么简单,因此也不会那么快执行完毕,就像后一个测试一样,反而不会出现频繁的池锁定现象。而前一个测试用例的设计显然不符合真实的环境的运行情况,因而测试的结果也是荒谬而可笑的。

这告诉我们,没有精心的设计测试方案,没有能够最大限度模拟真实环境的测试用例,那么测试根本就是在瞎忙,让人家内行看笑话。


有专门的Benchmarks用来做相关的模拟测试,如TPC-C, TPC-W等,它们是用来模拟多用户并发的情况,Mysql也有专门的工具crash-me等,是用PHP实现的。的确,这样的测试的确是不容易的,特别是环境复杂的情况,要得到一个公平的platform的确不易。

rabbin 同志每次总是把别人的帖子大段大段的贴过来,什么时候有自己的观点。

ab有那样的结果,只能说是他设计的问题。什么叫做内行?rabbin同志越来越有最初hecc同志的遗风了。

做这个不是想做mysql的性能测试。初试的目的只是想知道池的容量加大到100以上时性能的下降问题。

池的初始容量是5,在5以上每次都是新从数据库得到连接,所以可以比对新得到连接和从池中直接返回连接的差别。

至于池锁死的问题,没看我的池实现不要那么快下结论。

没使用线程是因为最初的目的不是测试并发的问题,但从结果中已经知道了要知道的东西。

你的话真是莫名其妙!诬赖我是否让你感到很爽?我什么时候抄袭别人的帖子了?我所有的帖子全部都是我自己一个字一个字用拼音加加敲出来了,我的帖子也全部都是我自己的想法,什么叫做“每次把别人的帖子大段大段贴过来?”,你到找一个证据我来看看。

你现在又不敢说想做mysql性能测试了,改成了原来是要测试你自己的池实现,不过看看你自己上面的帖子是怎么说的吧!

库是空库,比较直接得到1000次数据库连接和从池中得到连接的性能差别

嘿嘿,错误谁都会犯,这世界上也没有绝对的对错。

意思是说rabbin不要每次做出一副高高再上指点江山的样子,除了自己觉得谁都是菜鸟。动辄说人是白痴胡说八到。

这里大家只是做技术上的一个交流而已,不要变成骂人的灌水的地儿。

其实你不用那么敏感,我并没有说你,如果你看一下我的帖子就应该看到我在说那些随便写个测试程序就妄谈asp,php,jsp孰优孰劣的人是白痴。只不过我一惯对性能测试看得极重,很反感由于错误测试造成的误导,刚好在这里有感而发罢了。不过看来我以后还是不要随便在论坛放厥词了,省得引起论战 :)

IMHO,almost posts by sinio_feng are useless,full of attack and boast.

看了看,忍不住回帖一下,sinio_feng 既然你贴程序出来了就虚心点。
robbin的话我从来没在任何其他论坛看到过类似的,不知道sinio_feng为何故意诽谤,如果受不了别人的批评就到别的坛子玩去...

技术讨论难免不顾情面,声音大了点,语气尖锐点,如果技术上说不过就人身攻击也太没品了,人家用什么语气发言是人家的自由。

ps:不得不多声明一下,我不是任何人的马甲,只是个潜水员而已。

忍不住想说:我们做技术的都是直性子,大家为了技术的准确性随时都可以争个脸红脖子粗,但是请针对事情,不要对人。就算争论打起来,争完了还是好哥们。

ps:“ps”是什么意思?