日期:2020年1月3日 天气 :阴转小雨
1.在技术对接群中有人喊话:导入供应商合同功能一直没有反应?
心想,又是个瞎操作的,我先去测试账号上试一把 ???打脸,赶紧找问题:导入操作是有开始/结束日志的,先看看日志打印到哪儿了 ----------grep XXXX common-info.log ,只有开始的日志没有结束的???
现在我手上掌握的信息:
- 这个方法一共就5步操作 ,开启事务--->查询数据--->新增一条记录--->更新几条旧记录--->发DingDing消息---> 提交事务
- 这个功能上线一段时间了,不是堆栈溢出,代码逻辑就没问题
2.第一次大胆猜测
猜测: 因为方法外面加了事务,事务互相等待,死锁了,赶紧去数据库检查一番
SELECT * FROM INFORMATION_SCHEMA.INNODB_TRX;
+-----------------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+------------------+----------------------------+
| trx_id | trx_state | trx_started | trx_requested_lock_id | trx_wait_started | trx_weight | trx_mysql_thread_id | trx_query | trx_operation_state | trx_tables_in_use | trx_tables_locked | trx_lock_structs | trx_lock_memory_bytes | trx_rows_locked | trx_rows_modified | trx_concurrency_tickets | trx_isolation_level | trx_unique_checks | trx_foreign_key_checks | trx_last_foreign_key_error | trx_adaptive_hash_latched | trx_adaptive_hash_timeout | trx_is_read_only | trx_autocommit_non_locking |
+-----------------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+------------------+----------------------------+
| 421347106262192 | RUNNING | 2020-01-07 10:44:32 | NULL | NULL | 0 | 158 | NULL | NULL | 0 | 0 | 0 | 1136 | 0 | 0 | 0 | REPEATABLE READ | 1 | 1 | NULL | 0 | 0 | 0 | 0 |
+-----------------+-----------+---------------------+-----------------------+------------------+------------+---------------------+-----------+---------------------+-------------------+-------------------+------------------+-----------------------+-----------------+-------------------+-------------------------+---------------------+-------------------+------------------------+----------------------------+---------------------------+---------------------------+------------------+----------------------------+
得到数据:然后发现并没有死锁的线程,只有一个正在running的线程,而且这个线程没有执行语句??====> 那说明不关死锁的事情,事务一切正常。
分析数据-获取结果: 通过数据库直接 kill sql_thread_id,发现方法依旧没有返回结束日志
新的问题:可还有什么问题会导致方法一直没返回??
3.第二次大胆猜测
猜测:批量更新几条旧记录的sql语句,运行出问题
得到数据:分析这个语句在这之前依旧运行了好长时间,数据都能正常更新。做了空值判断了。语句就是我写的,做执行计划语句分析,效率没问题。
分析数据-获取结果:批量更新的sql没问题
新的问题:可还有什么问题会导致方法一直没返回??
4.第三次--误打误撞
迷茫:现在已经有点迷茫了,这么简单的一个方法,就这么简单的几步操作,查询/新增/更新/发DINGDING ,嗯?? 发丁丁,这方法会不会有问题,以前都用这个的,用了好长时间了,不应该出问题在这里的,不管了,先看一下jvm信息
得到数据: 先查有多少java进程,找出出问题的服务进程
查看对应进程的hotspot VM运行日志信息 jstack -l 42042
发现有线程被park挂起了,一直处于wait状态(好激动,好兴奋,有头绪)继续看下去,发现是钉钉客户端发消息的时候出现了互相竞争导致(其中的具体细节就不展开了)
分析-得到结果: 原来是钉钉发消息出问题
提出解决方案: 为了避免再出现这个问题,发钉钉消息,外部通过ThreadPoolExecutor 异步发送,加timeOut时间,(发消息量不大)钉钉客户端通过多实例避免资源竞争出现wait