开篇语录:以架构师的能力标准去分析每个问题,过后由表及里分析问题的本质,复盘总结经验,并把总结内容记录下来。当你解决各种各样的问题,也就积累了丰富的解决问题的经验,解决问题的能力也将自然得到极大的提升。
励志做架构师的撸码人,认知很重要,可以订阅:架构设计专栏
撸码人平时大多数时间都在撸码或者撸码的路上,很少关注框架的一些底层原理,当出现问题时没能力第一时间解决问题,出现问题后不去层层剖析问题产生的原因,后续也就可能无法避免或者绕开同类的问题。因此不要单纯做Ctrl+c和Ctrl+V,而是一边仰望星空(目标规划),一边脚踏实地去分析每个问题。
一、背景
我们最近在使用mybatis执行批量数据插入,数据插入非常慢:每批次5000条数据大概耗时在3~4分钟左右。架构师的职责之一是疑难技术点攻关:要主动积极解决系统出现的问题,过后由表及里分析问题的本质,复盘总结经验,并把总结内容记录下来分享给团队,确保后续如何智慧地绕开同类问题。
以下是排查问题的过程和思路:
二、定位问题
定位问题的基本思路:
1、日志,排查问题的第一手资料。
2、初步定位问题的方向。
3、排查问题的基本思路。
1、全面打印日志:
日志是排查问题的第一手资料。
logback设置mybatis相关日志打印:
<logger name="org.mybatis.spring" level="DEBUG"/> <logger name="org.apache.ibatis" level="DEBUG"/> <!-- <logger name="java.sql.PreparedStatement" level="DEBUG"/>--> <!-- <logger name="java.sql.Statement" level="DEBUG"/>--> <!-- <logger name="java.sql.Connection" level="DEBUG"/>--> <!-- <logger name="java.sql.ResultSet" level="DEBUG"/>-->
2、日志初步定位问题
发现Creating a new SqlSession到查询语句耗时特别长:5000条sql耗时192秒左右。
3、初步排查问题的基本思路:
有几个可能的原因导致创建新的SqlSession到查询语句耗时特别长:
1. 数据库连接池问题:如果连接池中没有空余的连接,则创建新的SqlSession时需要等待连接释放。可以通过增加连接池大小或者优化查询语句等方式来缓解该问题。
排除连接池问题:MySQL最大连接数的默认值是100, 这个数值对于并发连接很多的数据库的应用是远不够用的,当连接请求大于默认连接数后,就会出现无法连接数据库的错误,应用程序就会报:“Can not connect to MySQL server. Too many connections”-mysql 1040错误,这是因为访问MySQL且还未释放的连接数目已经达到MySQL的上限。
show variables like '%max_connections%';
2. 网络延迟问题:如果数据库服务器和应用服务器之间的网络延迟较大,比跨地域连接,则创建新的SqlSession时会受到影响。可以通过优化网络配置或者将数据库服务器和应用服务器放在同一网络上等方式来解决问题。
排除网络问题:ping mysql地址,耗时都在0.5ms左右。
3. 查询语句过于复杂:如果查询语句过于复杂,则会导致查询时间较长。可以通过优化查询语句或者增加索引等方式来缓解该问题。
排除复杂sql问题:简单insert 语句,通过mysql show processlist查看没有慢查询的连接。
<insert id="batchInsertDuplicate">
INSERT INTO b_table_#{day} (
<include refid="selectAllColumn"/>
) VALUES
<foreach collectio