不喜欢看文字可以跳转[B站视频](https://www.bilibili.com/video/BV1vy4y1q7GQ/)
定时任务备份表task数据到task_history中,备份后将原数据删除。
如下示例:
```
@Scheduled(fixedDelay = 5)
public String taskBackUp() {
while (true) {
try {
boolean flag = selfProxy.process();
if (flag) break;
} catch (Exception e) {
}
}
return "success";
}
@Transactional(rollbackFor = Exception.class)
public boolean process() {
List<Task> list = taskMapper.getList();
if (CollectionUtils.isEmpty(list)) {
return true;
}
List<TaskHistory> historyList = list.stream().map(t -> {
TaskHistory ts = new TaskHistory();
BeanUtils.copyProperties(t, ts);
return ts;
}).collect(Collectors.toList());
//将数据插入历史表
taskHistoryMapper.insert(historyList);
//删除原表数据 这里会报错
taskMapper.delete(list);
return false;
}
```
上线触发定时任务后收到gc报警,应用吞吐量下降。因为实现时出现bug导致delete时抛出异常,数据产生回滚,但是外层做了catch,不会打断循环。也就是原本是想一点点备份数据直到备份完成,但是因为产生异常导致每次都是处理第一批数据,造成了死循环。这个是产生问题的原因,通过异常日志是能够定位到的。
但是这个case我想在日志不明确时可以通过什么手段能定位到该问题呢?所以将异常日志移除。看是否通过其他手段定位到在异常信息不明确时定位到问题。
答案:
在不确定的情况下还是整体看下进程情况吧。
执行`java -jar /chaosblade-0.6.0/arthas-boot.jar`选择进程,输入`dashboard`可以看到整体的情况。如图:
可以看到有个线程**长期**占用CPU99%,这个线程肯定有问题。另外观察到`gc.parnew.count`与`gc.concurrentmarksweep.count`增长的速度也比较快。
下面异常的线程在做什么:
执行多次`thread 41(41是线程id)`可以看到都是在执行sql查询操作。
再去查看线程栈中对应代码以及sql查询日志便能够定位到是产生了死循环导致的。
另外还有一种方式就是针对内存做profile,查看到分配内存最多的线程,然后看其线程栈也能找到原因,这种方法交给大家自己探索下,有问题可以在下方留言。