# 某个操作很慢,问题排查方法
# 适用场景
在如下场景下,都是某个操作很慢的情况,可以按照本文方式做排查:
- 某一个功能很慢:比如提交处理协同要10秒,又或者打开会议已开列表页面要8秒,又或者翻页要等待10秒
- 某一个功能操作后无反应,比如申请会议室页面,点击确定按钮后一直停在那不成功,可能要几十秒才反应过来
基于以上场景,可以说明当前系统某一个请求出现了问题,可能是数据库,可能是BLOCK锁,此时最好的解决方法是进行线程dump,分析当前时间区间对应请求到底在干什么。
# 技能要求
下面操作涉及一定的技术基础,需要有一定技术的运维或Java开发人员操作和分析。Java Thread dump分析是Java开发人员必备技能。
# 工作要求
如项目上遇到了缓慢问题,必须按照此文档,由对应技能要求的人员重现问题,抓取多份Thread Dump,先自行分析原因,如未分析出结果再提取这几份Thread Dump由专业的技术分析。
# 分析方法
V5系统内置了线程dump的工具,并且使用体验上做了极大优化,开发人员能够最快速度分析问题源头。如果出现某个功能响应慢,优先用V5系统内部的线程dump进行分析!
# 案例一:分析请求缓慢问题
问题示例:V5功能-国际化资源导出时很慢,需要1分多钟
1)通过系统管理员帐号登录,访问系统监控,点击thread dump就能拉出当前时间Jvm中运行的所有线程堆栈。
2)找到出性能问题的功能点,重新重现下性能问题。比如上面国际化资源模块,点击导出,通过浏览器F12工具会发现导出操作一直在Pending等待结果。
3)上面性能问题出现了,说明后台线程一直在运行再回到步骤1),系统监控页面点击页面下方的“Thread Dump”,弹出新页面,可以显示当前时刻的线程堆栈。
4)点击一次Thread Dump不够,最好是每隔几秒去点击一次,点击多次去找共同点,比如下图就是导出了7次,可以看到从第4次开始,一直都卡在doSheetContent这个方法,代码位置在Line 354行。
5)从线程堆栈可以看出,在执行20多秒之后,当前线程都在doSheetContent Line 354行这个代码位置:
6)随后查看源代码,可以看到Line354指向一个dataRecord.getRow()方法,再往下探getRow方法有toArray操作,而且是放在for循环内,类似于SQL循环了,肯定有性能问题。修复方法就是把dataRecord.getRow()放在for循环外层,执行一次即可。
案例总结:先登录system下的系统监控页面,随后复现性能慢的点,通过系统监控的thread dump每隔几秒跟踪下当前执行线程,定位执行慢的代码。这就是性能问题的固定分析套路。
# 案例二:某个操作卡住无反应问题
问题示例:用户新建会议时,如果选择了“会议地点”,点击发送后一直卡在“正在发送”界面,并且关闭浏览器会议新建不成功。
问题分析:只有发送会议这一个操作会出现此问题,则说明是保存会议这个动作出现了事故,解决方案依然是通过系统管理员的thread dump分析当前保存会议的线程在干什么。
操作方式见“案例一:分析请求缓慢问题”中的模式:
- 首先复现问题并且保持现场,在出问题的环境重新操作一遍复现问题,保障发送会议一直处于“正在发送”阶段
- 然后换个浏览器用系统管理员帐号登录系统后台,找到“系统监控”,访问系统监控下面的thread dump,可以每隔几秒钟打开一个thread dump
- 分析thread dump内容,找到问题原因
总结以上分析结果:
1.有大量BLOCKED请求,都是MeetingRoomManagerImpl.applyRooms上面,说明会议保存请求存在死锁
2.通过thread dump全局搜索发现锁的源头都是owned by H-108,此时就要分析H-108为何没执行完
3.通过分析发现H-108Running了2天都没结束,再分析线程堆栈可以看到问题出在数据库查询,大概率是查询该条数据时出现死锁导致
解决动作:
如果要临时紧急处理,则重启OA服务即可解决。
如果要深挖问题根本原因,则要分析H-108那个数据库查询为何会死锁,这个要DBA连上数据库,结合锁检查SQL寻找问题源头---说不定H-108也不是问题根本,它只是受害者。
如果要保障代码健壮性,还应该检查MeetingRoomManagerImpl.applyRooms源代码,分析是不是代码中的锁粒度太大?是否可以缩小锁的范围,不要挂起那么多线程。