一次怪异的生产事故
起因
前几天,我对代码略作修改后,从测试环境最终到生产环境发布了某个组件。(我们这里实行快速迭代,因此每周都有发布。)
灰度发布时,该组件业务逻辑运行正常,却突然发现我司APM产品的埋点都没有了。
埋点看不到,相当于该应用各种指标监控都没了,应用不受控制了,是个大事件。
短暂排查(如检查配置等)了之后仍未解决,立刻回滚到上一次版本(简称为release_old
)。
果然,release_old
版本的APM产品埋点正常。
结论很明显:肯定是我提交的代码出了问题。
排查
反复review代码后,实在思考不出问题之所在。因为相关代码与和APM Agent的配置没有任何变动。
这个时候心里是挺慌的:回滚能够解决一时的问题,不找到根本原因,以后发布都可能出这种问题。
仔细一想,我这边变化不大,有不有可能是APM那边的有变更呢?
因此,仍旧使用release_old
版本的代码,但是重新编译,发布。
(我们的发布系统回滚是直接使用旧的发布包)
最终,同样没有APM埋点。
这是终于知道:确实是外部依赖APM Agent变更导致的问题。
Root Cause
问题还没结束,继续排查代码依赖的Jar,比较灰度发布不正常的机器和正常的机器,有如下发现:
发现主要的异同就是这个xxx-common-1.0.7-20161212.094128-2.jar
与xxx-common-1.0.7-20161128.040513-1.jar
。
前者是最新的编译打包结果,后者是埋点正常的打包结果。
是不是它呢?采样替换法,将20161212
替换成20161128
的版本,重新启动应用。Agent埋点正常。
最终结论,问题就出在这个xxx-common-1.0.7-20161212.094128-2.jar
中——xxx-common
组件的SNAPSHOT的版本。
真正的原因是:我的项目的maven依赖中使用的是xxx-common
的1.0.7-SNAPSHOT
,而我发布时正好将它一个有问题的SNAPSHOT版本带上去了(刚deploy上去,还未测试)。最终联系该组件Owner,待bug修复,使用最新的稳定版,发布。一切正常!
思考
最终找到问题大约花了两个小时,自我感觉算快的。
解决这个问题的难点在于不仅要对自己项目的深刻了解,还要了解项目的外部依赖(或依赖的外部服务)。
而这个小事故的本质原因就是项目使用了SNAPSHOT版本的组件。
所谓SNAPSHOT,即是应用开发过程中的不稳定版本。有时我们图方便,懒得频繁去更新版本,就把依赖写成SNAPSHOT。而就是这个懒惰,某些bug会随着它偷偷的进入你的项目,会让以后花更多时间去还债。
在开发时,我们使用SNAPSHOT版本无可厚非,加快开发速度和减少沟通成本。但是发布到生产的应用时,应杜绝使用不稳定的SNAPSHOT版本,才尽可能避免外部因素影响到你的项目。