前言
由于最近公司业务需求,我们需要重新开发一套系统,其中需求就是需要高TPS,高性能数据库读写能力,由此我测试了Mysql,JDBC、MyBatis并且集成Kafka来做一个性能测试。由于在框架测试上的代码不能公开,这里我自己重新快速写了个Demo,具体代码和完整的测试文档我也会上传至我的Github上。
JDBC效率测试
单条新增及更新
1 | public void insert() { |
最后结果
注意代码中的conn.setAutoCommit(false),下面分别时开启自动提交和关闭自动提交的结果:
- 开启自动提交最后结果:总计插入50000条,共计耗时61秒
- 关闭自动提交最后结果:总计插入50000条,共计耗时19秒
同样测试单条更新的结果,由于更新和新增只是单纯的sql语句不一样,这里代码就不贴了,如有需求可以去Git上下载完整代码
- 开启自动提交最后结果:总计单条循环更新50000条,共计耗时96秒
- 关闭自动提交最后结果:总计单条循环更新50000条,共计耗时26秒
批量新增及更新
1 | public void batchUpdate() { |
想要让批量更新的效率提高,网上也有很多答案,我这里整理了一下,大多是在jdbcUrl上做操作:
1 | &allowMultiQueries=true&rewriteBatchedStatements=true |
经过我一番测试&rewriteBatchedStatements=true这行参数加了是真的起了效果,如下是对这个参数的介绍:
1 | MySQL的JDBC连接的url中要加rewriteBatchedStatements参数,并保证5.1.13以上版本的驱动,才能实现高性能的批量插入。 |
&allowMultiQueries=true这个参数加与不加对JDBC批量更新基本无影响,他只是支持可以一次发送多条sql语句,如果不加这个参数当我们发送多条并以;
隔开会报错,如下是官方的解释:
1 | allowMultiQueries |
最后结果
- JdbcUrl不加任何配置,总计批量循环更新50000条,共计耗时27秒
- Jdbcurl加&rewriteBatchedStatements=true,总计批量循环更新50000条,共计耗时3秒
- jdbcurl加&allowMultiQueries=true,总计批量循环更新50000条,共计耗时24秒
- jdbcurl加&allowMultiQueries=true&rewriteBatchedStatements=true,总计批量循环更新50000条,共计耗时3秒
Mybatis效率测试
Mybatis单条更新
1 | public void single() { |
此处测试的是整合Mybatis测试单条更新效率,和JDBC一样我们针对不同jdbcUrl参数来进行测试
最后结果
- 不配置JdbcUrl,最后结果:总计MyBatis单条更新50000条,共计耗时234秒。
- 配置&rewriteBatchedStatements=true,最后结果:总计MyBatis单条更新50000条,共计耗时224秒
- 配置&allowMultiQueries=true,最后结果:总计MyBatis单条更新50000条,共计耗时222秒
- 配置&allowMultiQueries=true&rewriteBatchedStatements=true,最后结果:总计MyBatis单条更新50000条,共计耗时228秒
Mybatis批量更新
CASEWHEN实现批量更新
1 | public void updateBatch() { |
1 | <update id="updateBatch" parameterType="java.util.List"> |
CASEWHEN方法实际上是把,众多更新拼接成一条sql语句,一次性提交,如果语句很长的话,效率并不理想
最后结果
- 不配置JdbcUrl,最后结果:总计MyBatis批量更新50000条,共计耗时146秒
- 配置&rewriteBatchedStatements=true,最后结果:总计MyBatis批量更新50000条,共计耗时144秒
- 配置&allowMultiQueries=true,最后结果:总计MyBatis批量更新50000条,共计耗时142秒
- 配置&allowMultiQueries=true&rewriteBatchedStatements=true,最后结果:总计MyBatis批量更新50000条,共计耗时143秒
拼接多条SQL实现批量更新
1 | public void updateBatchList() { |
1 | <update id="updateBatchList" parameterType="java.util.List"> |
使用该方法,必须在JdbcUrl后面拼接参数&allowMultiQueries=true,否则将会无法运行。
该方法主要是将众多更新语句,用“;”隔开,拼接成多条SQL语句进行批量提交,该方法在要更新大量数据的情况下,效率客观,但是数量越多,服务卡住可能性比较高。
最后结果
- 配置&rewriteBatchedStatements=true,最后结果:总计MyBatis批量更新50000条,共计耗时25秒
- 配置&allowMultiQueries=true&rewriteBatchedStatements=true,总计MyBatis批量更新50000条,共计耗时26秒
开启Mybatis批处理多条SQL
1 | public void executorTypeBatchList() { |
1 | <update id="updateBatchList" parameterType="java.util.List"> |
最后结果
- 配置&rewriteBatchedStatements=true,最后结果:总计MyBatis批量更新50000条,共计耗时23秒
- 配置&allowMultiQueries=true&rewriteBatchedStatements=true,总计MyBatis批量更新50000条,共计耗时25秒
多线程批量更新效率测试
测试发现多线程并不是越多效率越高,多线程之所以快是因为能提高CPU的使用率,但是多线程数量多了,会导致频繁切换CPU上下文,最后就得不偿失了。
最后结果
- 开启3个线程更新5W条,最后结果:共计耗时22秒
- 开启4个线程更新5W条,最后结果:共计耗时65秒
- 开启5个线程更新5W条,最后结果:共计耗时65秒
- 开启10个线程更新5W条,最后结果:共计耗时98秒
kafka批量消费更新入库效率测试
1 |
|
kafka配置文件
1 | spring: |
注意:要使用kafk批量消费,必须开启batch-listener
属性,kafka的线程数,和他的分区数对应,有多少分区数,就能开启多少线程去消费。
最后结果
一个Topic 4个分区 副本1
5W条 5000条为一批 单线程 4145ms
5W条 5000条为一批 三线程 1934ms
5W条 5000条为一批 四线程 2187ms
5W条 1W条为一批 单线程 5746ms
5W条 1W条为一批 三线程 3372ms
5W条 1W条为一批 四线程 2149ms
10W条 1W条为一批 单线程 14039ms
10W条 1W条为一批 三线程 6249ms
10W条 1W条为一批 四线程 4335ms
一个Topic 8个分区 副本1
- 10W条 1W条为一批 单线程 11180ms
- 10W条 1W条为一批 四线程 4303ms
- 10W条 1W条为一批 六线程 3976ms
- 10W条 1W条为一批 八线程 3590ms