在工作中遇到一个问题,在解决问题时,经历了一些挫折,但最终还是将问题解决。其中有些心路历程,做下记录。
突发
一个之前可以正常启动的应用忽然无法正常启动,但是也不报错。
实际上,应用并没有什么大的更新,唯一有变动也是在于最近数据库有些变化。但是,部署环境中依然有一套应用是正常运行的。这就是个诡异的地方。
面对问题,回想之前是否曾经有过类似经历,直觉告诉我,可能是因为应用中存在的license校验逻辑的问题,如果证书过期,那么应用就会启动不了。但是,与当前应用(暂称为应用A)相似的应用(暂称为应用B),依然是可以正常启动的。我是认为,应用A与应用B中的证书是相同的。起码,曾经的运行历史是可以证明,证书是有效的。何况还有部署环境的应用可以背书。况且,如果证书有问题,是会报错的。(所以,逻辑证据在错误面前,也同样是有说服力的)
在放弃上面的想法之后,我着力通过清理操作,来解决问题。实际上,我并未探知到问题的原因,但是历史经验告诉我,与重启系统同样,mvn clean清理下已经生成的target目录,未尝不会带来意外的效果。实际上,并不能。
在经过一番努力之后,发现问题并没有解决,我开始走上歧途。
歧途
首先是,在bing中搜索springboot应用无法正常启动,但也不报错的情状。只能说有些遇到类似的问题的,但是情况并不相同。有主张是由于日志冲突的,有主张是没有引入spring-boot-starter-web的,有个总结性的帖子列举了一些关乎内存资源、服务是否可用的,还有提供在入口类上添加捕获逻辑,打印异常的。很遗憾,帮助性不大。
实际上,随着浏览这些帖子,我开始有些担心是否是因为我对dubbo并不熟悉造成的(应用A是dubbo应用)。但有些明确的是,问题出现在有些错误被捕捉之后,应用就退出了。之所以为什么没有日志,还是没有清楚?
而此时,我对部署环境上的应用A开始怀疑,因为它在正常运行,它们是同样的代码。由于本地环境与部署环境的配置基本一致,这种怀疑就愈发严重。当我开始重启部署环境上的应用A时,糟糕的事情发生了。
糟糕
部署环境上的应用A竟然重启失败,启动日志也是没有打印错误信息。现在,一个假象被戳穿了,但是,问题到底出现在哪?
我有些怀疑是否是由于某些dubbo服务没有发布,所以,我多此一举的查看了dubbo-admin的信息,实际上,这只是无头苍蝇般的探索。
此时,我已经不相信从bing上搜索的结果,这就像看着搜索结果去给自己诊断治病一般。我开始寻求专业的问题网站--segmentfault,它现在是我解决问题的一道微光。
微光
在segmentfault中搜索,结果也不如人意。但是,一个篇帖子无意中让我注意到可以直接调试内嵌的Tomcat的启动过程。于是,这道微光,真的成了希望之光。
重新开始debug,希望似乎就在眼前。虽然帖子上,让我留意到TomcatEmbeddedServletContainer
类,但是当我在它的startDaemonAwaitThread()
方法中打断点时,很遗憾并没有什么发生。
但没关系,在基本确定方法路径之后,下面才是真正的解决之道。
解决
虽然TomcatEmbeddedServletContainer
类没有带来惊喜,但我注意到TomcatStarter
可能才是真正的关键。实际上,这个判断是对的。随着Debug的深入,终于在初始化上下文的时候,发现了应用A相关的代码。
哭笑不得的是,问题还是出现在license校验上。在校验证书时,返回值中的某个取值为0,此时系统会退出。虽然,此时证书还并没有过期。这扩展了我的认知,证书没有过期依然会有应用退出风险。而日志之所以未打印出来,是因为该校验逻辑在的jar所使用的日志是Log4j,而应用A采用的日志是logback。这也能解释,为什么同样是license校验问题,应用B能够打印日志,应用A并不同。所以,开始认为应用A与应用B类似,这种感觉很表面。特别是,当我发现应用A与应用B在引用license校验的逻辑的依赖jar,也并不相同时。
在基本探查完问题之后,我试着用应用B中的license替换掉应用A的license,应用A启动成功。此时此刻,满是感慨,甚至愤慨!
小结
清晰合理的debug逻辑,也许会被无知、彷徨、迷惘揪扯而变得错综复杂,但是有些基本点依然是存在。我记得,我曾经也沿着Tomcat启动debug过,并帮助自己梳理过license校验逻辑。但是,以为可以通过清理、网上搜索快速解决问题的侥幸心理,让这件事情变得欲速不达了。
因此,找到问题的切入点,debug的入口点,解决问题的基本主线,才是正确的解决之道。也许,我们有很多的无知、迷惑,但是了解这个问题的也许还是自己。而网上的搜索,只能是帮助,不可能是拿来可行的急救药。