一、更新sql死锁问题
项目中的一个接口,进行压测。该接口采用异步方式来跑,本来觉得压测没有多大意义。但实际情况,测试给的数据,虽然tps很高,但抖动特别厉害。换句话说,接口性能很不稳定。查看日志,发现update数据的时候报了deadlock死锁错误。另,异步线程中有很多跟数据库交互的操作。
搜了一下,其实并发更新时,很容易出现死锁情况,解决方式尽量分先后,该篇文章说的很详细了。
解决方式: https://blog.csdn.net/qq_16681169/article/details/74784193
顺便了解了一下myisam和innodb区别:https://blog.csdn.net/chajinglong/article/details/56666771
二、数据库可用连接数达到上限问题
错误描述:Cause: java.sql.SQLException: Cannot get a connection, pool error Timeout
waiting for idle object;
前端在调用该接口时,需要返回参数,该参数需要insert消息入库后获取。
1)在该接口主线程中,有两次与数据库的交互,均为入库操作。其余与数据库的交互全部放在异步线程。最开始的优化方式,所有异步线程中的操作均采取归类批量来执行(sql的增删改查)。改完后压测一次,数据如下:
并发数 | TPS指标 | x响应时间(ms) | 说明 | cpu占用率 | 内存占用率 | w网卡流量(进/出) |
20/50/100 | 20/21/28 | 18/102 | / | 20.37% | 42.25% | 12.44Mbps/12Mbp |
主要看一下表中的并发数和TPS指标,其他参数未及时记录,不正确。随着并发量的增加,TPS增长几乎为0,说明此时已达性能瓶颈,在接口中加日志,查看每一步调用时间,发现单独调用一次接口执行时,同步入库耗时非常短,只有50ms左右,但并发量大的时候,耗时达2200ms。很奇怪。于是继续优化。
2)在(1)的基础上,从主线程抽出一次入库操作放入异步线程,这样主线程入库操作只有一个。继续测试,数据如下:
并发数 | TPS指标 | x响应时间(ms) | 说明 | cpu占用率 | 内存占用率 | w网卡流量(进/出) |
20/50/100 | 20/21/19 | 18/102 | / | 20.37% | 42.25% | 12.44Mbps/12Mbp |
尼玛的,TPS居然一点变化都没有,这下郁闷了。
抱着死马当活马医的心态,把并发数猛的调到200。结果在查看日志时,发现了如下错误:
Cause: java.sql.SQLException: Cannot get a connection, pool error Timeout waiting for idle object;
很明显,数据库的连接不够了。
同步线程入库很快,但并发量大的时候,异步线程中有非常多和数据库交互的操作,长时间占用连接对象,导致新的请求只能等待,入库操作也无法执行,整个过程耗时边长。
解决方式:
查看了一下MySQL配置文件,发现maxActive=100,果断调整为1000,maxActive=1000,再次压测,结果如下:
并发数 | TPS指标 | x响应时间(ms) | 说明 | cpu占用率 | 内存占用率 | w网卡流量(进/出) |
20/50/100/200 | 60/80/118/118 | 18/102 | / | 20.37% | 42.25% | 12.44Mbps/12Mbp |
TPS指标,翻倍了。
问题解决!
三、服务器内存溢出
错误描述:java.lang.OutOfMemoryError: unable to create new native thread;
TPS指标上去了,但数值仍然较小。继续增大并发量的时候,发现日志中报如下错误:
java.lang.OutOfMemoryError: unable to create new native thread
内存溢出,无法创建native线程。
用Java自带工具jvisualvm.exe远程连接项目的tomcat,发现实际项目在压测过程中,内存只用了1G不到,而Java虚拟机被分配的内存高达8G之多,显然虚拟机不存在内存溢出的情况。请教了一下前辈,在创建线程时,不仅仅消耗Java虚拟机资源,服务器内存不足时同样会有溢出现象。
解决方式:
调整虚拟机内存大小为4G,空余出另外4G供服务器自身使用,设置完毕后重启tomcat。再次增大并发请求时,不再出现该错误了。内存配置在tomcat的Catalina.sh文件中。
问题解决!