测试环境
应用结构:
JWS(基于Play定制)+2次库表写入+分库分表
目标:TPS=5000
测试工具:Jmeter、Sysbench
并发线程:16
性能目标
TPS>=5000
现状
采用Jmeter在16并发场景下测试2分钟,最终并发在1200-1300之间,距离性能目标比较遥远。
优化过程
- 首先考虑可能是代码某个地方有问题,暂时没有考虑数据库,因为根据经验不应该这么低。所以,开始反复注释怀疑代码(不包括访问数据库的代码),但实际测试发现数据并无任何改变。
- 开始怀疑可能是数据库插入操作比较耗时。注释数据库插入代码后,发现TPS明显提升至14000左右,因此可以断定瓶颈是在数据库插入造作。
- 采用Jmeter对MySQL进行基准测试,测试得出当前MySQL的插入TPS<2800,并且观察数据库服务器IO uitil保持在80%以上,因此断定当前MySQL配置已经达到顶峰。
- 检查MySQL配置。根据《MySQL配置原理和技巧(ver 0.2).ppt》检查关键配置项,最终发现general-log配置为1,修改为0后,性能提升300左右,达到3100多。
- 担心Jmeter测试数据不准,采用Sysbench对MySQL做性能测试,发现TPS依然是3100,最终说明现有MySQL最高性能也就是3100了。
- 应用每次调用会做两次数据库插入操作,因此按照3100换算后,可以推算出应用的TPS不会高于1500,和测试情况相符。向DBA询问线上MySQL的写入性能数据为5000,则推算线上应用TPS应低于2500,依然无法达标。
- 采用异步队列+批量插入的方式,最终将TPS提升到8000以上。
优化方案
- 应用内部构建异步队列,用于存储请求消息。所有的请求,提交到异步队列即立刻返回。
- 构建调度线程,调度频率为100毫秒;调度线程负责计算每个工作线程需要处理的请求消息数,并提交工作任务到工作线程池,并同步等待其完成。
- 工作线程池负责消费异步队列中的消息,其线程数是3。
- 每条工作线程根据其要处理的请求消息数,决定批量进行Insert操作的数量,而不是一个请求Insert一次。
注:MySQL插入性能优化可参见:http://tech.uc.cn/?p=634