测试同学使用tsung测试openfire时发现注册并发数过低,同事经过测试认为数据库是最大瓶颈,建议将mysql数据库改造成mongo数据库。
首先尝试改造了ofUser表相关操作,使注册逻辑整体走mongo:
改造涉及文件如下:
在org.jivesoftware.database 包下仿照DefaultConnectionProvider、DbConnectionManager创建mongo的相关Provider和Manager
为了减轻字段映射压力,使用了morphia,因此,需要创建相应的pojo,如ofUser.java
改造所有涉及ofUser表的增删改查
由于原来为了适应多种数据库,所以在其中增加了很多判断,搞明白逻辑后可以去除这些判断。
mongo连接方面参考了以下文章:
http://www.linuxidc.com/Linux/2012-01/52150.htm
http://www.cnblogs.com/huangfox/archive/2012/04/01/2428947.html
http://blog.csdn.net/magicfoxhu/article/details/7568728
openfire数据库相关参考了下面的文章:
http://www.myexception.cn/database/1249683.html
mongo的api及文档:
http://api.mongodb.org/java/2.8.0/
http://docs.mongodb.org/manual/genindex/
java操作mongo:
http://www.cnblogs.com/hoojo/archive/2011/06/02/2068665.html
http://tech.it168.com/a2011/0617/1206/000001206231_all.shtml
http://blog.sina.com.cn/s/blog_5d3241cc0100q7yp.html
http://www.2cto.com/database/201202/118157.html
http://www.cnblogs.com/yuechaotian/archive/2013/02/04/2891416.html
http://blog.csdn.net/mengxiangyue/article/details/8957085
使用morphia:
http://my.oschina.net/u/142072/blog/35714
http://wenku.baidu.com/view/83b56947a8956bec0975e357.html
http://www.blogjava.net/watchzerg/archive/2012/09/20/388109.html
http://www.cnblogs.com/hoojo/archive/2012/02/17/2355384.html
在寻找的时候还发现了个特好玩的morphia使用者:
https://github.com/turbidsoul/turbidsoul.github.io/commit/fe4bcdc7238b24ed06aaf327e3470ced676d1b27
在做pojo的时候特意研究了下objectid呀~发现了很多好东东哦~
http://www.cnblogs.com/xjk15082/archive/2011/09/18/2180792.html
http://www.kuqin.com/database/20120317/319007.html
http://blog.nosqlfan.com/html/3511.html
——————————————分割线————————————————————————————————————————————————————————
改造完成开始性能测试:
使用tsung测试:500请求/s 运行5分钟
数据库插入数/理论插入数,
mysql注册基本稳定在75%
mongo注册基本稳定在30%!!!!
震惊了我,mongo的性能怎么可能这么差!!
赶紧查查mongo性能提升相关的文档:
http://database.51cto.com/art/201109/293088.htm
第一条:是否建立索引,果然,我并没有建立索引,而在注册时需要先查一下此用户是否存在再进行插入,查询对索引需求大,建立索引,参考如下文档:
http://blog.sina.com.cn/s/blog_af52238c0101bhno.html
建立username索引,再次测试:
mongo注册率稳定在76%
松了一口气,但是只币mysql高1%,这可不行,开始监控mongo性能,参考:
http://www.361way.com/mongo-mem/1489.html
http://www.cnblogs.com/shanyou/archive/2010/10/02/1841348.html
http://blog.csdn.net/liubo2012/article/details/8203751
发现mongo一直处于非繁忙状态,高并发行为并没有对其产生压力。只有少数insert方法执行速度超过10ms,但是数量极少
怀疑代码或者测试工具有问题,修改代码:
(1)去除逻辑中的query妹纸保留insert,性能没有提升--》性能与query无关
(2)关闭性能监控,性能没有提升--》性能与性能监控无关
(3)删除索引,性能没有提升--》性能与索引无关
(4)不使用morphia方法使用driver自带方法--》性能没有提升,与morphia方法无关
(5)去除db重连逻辑--》性能没有提升,与此逻辑无关
(6)使用morphia save方法,每1000个注册请求,调用一次--》性能下降,原因:morphia.save并非调用批量方法,积攒1000个请求在使用此方法依旧是一个个插入,反而增大了压力。解决:改造成driver自带insert 批量插入方法,上升至76%,--》与批量无关,但是批量插入的确比单个效果更好,(貌似批量操作会有全局锁问题,需要查看http://blog.chinaunix.net/uid-26660567-id-4106642.html)
(7)增大客户端单机连接数,20改为400,性能无明显变化,查询资料:http://blog.csdn.net/jollyjumper/article/details/8553307,增加连接数反而可能使性能下降。
--依旧原因未知,实验mongo shell循环插入10w条。参考:
http://www.myexception.cn/other-database/383981.html
10w条用时40s,监控mongo性能,返现在使用mongo shell循环插入10w条时压力比tsung 500 并发高。再次确定mongo应对压力无问题。
无法,开始使用笨办法:查看数据库数据,希望能行数据中找到缺失规律,还真被我找到了!!--
插入6000条数据,前5335条插入无丢失,只丢失5336-6000的数据。推测一定不是并发造成的丢失。
在代码逻辑的insert语句前打印日志,与数据库数据进行对比,发现日志打印数与插入数据库数完全相同,再次确认与数据库无关,推测可能是自行修改的mongo逻辑和mysql逻辑不通导致,测试mysql逻辑,发现打印日志数与插入数据库数依旧相同---》确定数据库绝对无压力。
————————————————————————————我是无奈的分割线————————————————————————————————
忽然被告知,测试同学配置的tsung有问题。啊啊啊啊啊啊啊==。。。明天使用同事自己做的压测工具。。
其他参考文档:
关于Mysql和Mongo的性能测试
http://blog.sina.com.cn/s/blog_591888d50101jx67.htmlOpenfire 性能优化 http://blog.csdn.net/blade2001/article/details/9094331
java链接mongo http://blog.csdn.net/freebird_lb/article/details/7470384
________第二天的分割线——————————————————————————————
使用了asmack组件提供的接口,瞬间创建多线程施压测试,测试环境(Intel(R) Xeon(R) CPU 2.13GHz ,内存:4139668 kB,64位)
mongo最长消耗时间是mysql最长消耗时间的2/5左右。
mongo在高并发注册情况下,成功率远高于mysql,具体数据如下:
数据库类型 | 方式 | 总发送请求数 | 失败数 | 请求完成时长 | 成功数 | 总实时长 | 每秒完成数 | 备注 |
Mongo | 10000线程,每个线程发送2次请求 | 20000 | 0 | 48001 | 20000 | 8650492 | 416.6579863 | |
Mongo | 20000线程,每个线程发送1次请求 | 20000 | 0 | 49708 | 20000 | 6905026 | 402.3497224 | |
Mongo | 30000线程,每个线程发送1次请求 | 30000 | 0 | 72908 | 30000 | 12203271 | 411.4774785 | |
Mongo | 38000线程,每个线程发送1次请求 | 38000 | 1391 | 99858 | 36609 | 20398798 | 366.610587 | |
Mongo | 38000线程,每个线程发送1次请求 | 38000 | 0 | 88637 | 38000 | 12488874 | 428.7148708 | |
Mongo | 385线程,每个线程发送100次请求 | 38500 | 0 | 88597 | 38500 | 32518607 | 434.55196 | |
Mongo | 385线程,每个线程发送100次请求 | 38500 | 0 | 89802 | 38500 | 32518607 | 428.7209639 | |
Mongo | 3850线程,每个线程发送10次请求 | 38500 | 1878 | 99142 | 36622 | 36155249 | 369.3893607 | |
Mongo | 3850线程,每个线程发送10次请求 | 38500 | 0 | 85427 | 38500 | 29957272 | 450.6771864 | |
Mongo | 38500线程,每个线程发送1次请求 | 38500 | 0 | 90267 | 38500 | 15107830 | 426.5124575 | |
Mongo | 38500线程,每个线程发送1次请求 | 38500 | 0 | 89531 | 38500 | 12403008 | 430.0186528 | |
415.0619297 | 平均值 |
所有mongo请求不成功问题都是由于以下问题造成的 错误: Nested Exception: java.net.NoRouteToHostException: Cannot assign requested address at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200) at java.net.Socket.connect(Socket.java:529) at java.net.Socket.connect(Socket.java:478) at org.jivesoftware.smack.proxy.DirectSocketFactory.createSocket(DirectSocketFactory.java:28) at org.jivesoftware.smack.XMPPConnection.connectUsingConfiguration(XMPPConnection.java:555) at org.jivesoftware.smack.XMPPConnection.connect(XMPPConnection.java:999) at Main.runRegisterTest(Main.java:54) at Main$3.run(Main.java:402) 原因:由于快速创建连接,端口被占用满,产生TIME_WAIT 端口 解决方案:http://bbs.chinaunix.net/thread-3842444-1-1.html 不能确定影响范围,暂时不进行解决 第二解决方案: 研究发现,Linux对外的随机分配端口是由一定限制的,理论上单机对外的端口最大值为65535,除去一些保留端口和被占用端口外,也应该在6W左右,但实际上单机建立对外连接时,默认不超过28232个连接。 执行以下命令就很清楚原因了: $ cat /proc/sys/net/ipv4/ip_local_port_range 输出结果为: 32768 61000 这就是Linux随机分配端口的范围,如果在该范围内有被占用的端口,那么连接数肯定小于28232.如果想更改这个范围,可以执行以下命令: # echo "10000 65535" > /proc/sys/net/ipv4/ip_local_port_range 检测发现Mongo性能情况一直良好,基本无等待队列产生 |