最近有版本特性要上线,但是在上线的过程中遇到了“阻碍”,使得上线过程不是很顺利,想必你也曾经遇到过吧!
1
问题背景
说说大概的场景吧。 由于系统里面增加了权限的限制,不同用户拥有不同的数据权限。 当前的方案是查询用户uid和对应的数据列表存放在本地内存里,并且需要定时捞取对应的关系数据存储在本地缓存LocalCacheMap中,key为uid,value为List。
接着其它接口则根据LocalCacheMap获取对应的数据权限进行相关的判断。
我们准备上线时,发现功能不正常,本来应该是能正常过滤权限数据的时候却没有生效?
但是其它同学在测试环境验证基本没问题的! 所以就有很大的疑问了。
我都不相信这功能真的在测试环境上OK? 对测试结果表示怀疑,所以我跟组内同学在测试环境验证一波,确实是没问题的。 那么继续查看检验代码逻辑,查看是否有哪里不严谨,可能存在隐藏的bug。
在看代码的过程中也发现了日志打的太少了,重点的地方都不打下,起码还能知道从哪里跟踪,(对于代码注释等规范,可见原创《 互联网Code Review最佳实践分享 》),所以对于这点暂且不说,我也不想说重新补打日志,然后重新打包,发版排查。
为了一探究竟,此时必然还是需要使用强大的工具Arthas,之前就已经解决过我的生产问题。
可见于原创: 《 实战使用Arthas排查生产问题: 实例方法接口调用 》,所以继续使用阿尔萨斯Arthas来排查定位。
2
排查解决问题
1)排查一 :
此时借助Arthas,尝试调用获取缓存数据:
调用实例方法,获取到的结果为null,说明缓存中没有我要的数据,这就很奇怪了。 然后我去验证拉去权限数据的接口,手动去调http接口,此时在服务器上使用curl手动调用接口,但是接口返回的443,所以我怀疑是不是调用的接口问题造成缓存数据为空? 此时找了运维同学帮忙确认下是不是网络的问题,最后排查结果确实是网络没有放行,于是等待网络问题解决之后继续上线流程。
但是,网络问题虽然解决了,再次验证功能还是跟刚才一样,why? 继续排查...
2)排查二 :
此时,再次借助Arthas,调用了refresh方法,来手动触发缓存刷新操作。
执行刷新操作,返回null,这是正常的,因为refresh返回void,此次刷新耗时在1132ms。
接着,再调前面获取缓存数据的接口:
数据出来了! ! ! 说明权限数据接口是正常的,拉取数据是正常,接着我们就在功能上进行验证,确实都正常了。
那么问题就出在刷新方法的调用上,是否没触发或者调用者已经没调用等等情况。 查看了代码之后才发现发现是使用TimerTask来定时执行任务,定时更新缓存数据。
Timer timer = new Timer(false);
timer.schedule(new RefreshTask(), 10*1000L, 30*1000L);
private class RefreshTask extends TimerTask {
@Override
public void run() {
reflesh();
}
}
reflesh() {
// 拉去权限数据
// 更新缓存数据
}
就是这样来维护缓存数据。 那么为什么它没执行? 按道理启动之后都会每30秒执行一次才对,但是为什么没有呢?
3)罪魁祸首 :
想必很多人知道TimerTask会存在一个问题,就是定时调度执行的方法如果没有捕获处理异常的话,那么它就会终止,基本上不会再运行了。 所以应该是这个问题造成的。
那么,应该要找到它抛异常的地方才能验证我们这个问题。 所以从日志里面找,最终发现:
确实是在启动不久(10秒左右)的地方,抛了NPE异常,所以这也验证了我们的问题,罪魁祸首就是它了。
4)解决:
ScheduledExecutorService executorService =
new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern(
"schedule-task-%d").build());;
executorService.scheduleWithFixedDelay(
new RefreshTask() , 10*1000L, 30*1000L, TimeUnit.MILLISECONDS);
使用ScheduledThreadPoolExecutor来定时调度刷新缓存。 比TimerTask的好处就是出现异常也会继续重新定时调度。
3
总结
这种问题,虽说不是特别难的问题,但经验不是很丰富的开发人员却在日常中常会犯的,也会影响正常特性上线,造成发版阻碍,影响功能上线。
针对此次“事件”, 总结 一下,以免下次再犯:
1)日志,日志,要打印,要打印好。
2)尽量别用TimerTask,别踩坑,如要用一定要捕获处理好异常,一般建议使用ScheduledExecutorService代替。 (阿里规约)
3)要学会使用Arthas,在紧急“救火”中非常有用!
此“事故”真实发生,若有雷同,实属巧合。 :)
以上所述就是小编给大家介绍的《实战生产问题:真的别再使用 TimerTask 了》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Python 实战 Kafka 生产者 API
- 实战使用 Arthas 排查生产问题:实例方法接口调用
- 实战生产问题:真的别再使用 TimerTask 了
- 生产实战:如何正确地读取jar包中的File
- istio服务网格生产环境ingress网关部署SSL实战
- Elasticsearch生产环境索引管理深入剖析-搜索系统线上实战
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Compilers
Alfred V. Aho、Monica S. Lam、Ravi Sethi、Jeffrey D. Ullman / Addison Wesley / 2006-9-10 / USD 186.80
This book provides the foundation for understanding the theory and pracitce of compilers. Revised and updated, it reflects the current state of compilation. Every chapter has been completely revised ......一起来看看 《Compilers》 这本书的介绍吧!