后端系统开发之解决历史bug

背景:系统里上游模块A会下发一个参数exp给下游服务B,由于这个参数exp长期未使用,一直无人关注,最近有同事设计的方案需要用到参数exp,却发现exp未生效。(历史BUG能一直存在的前提:无人关注和使用)

第一次排查:观察A的请求日志,发现A在请求下游服务B之前有参数exp,因此怀疑是服务B出了问题。查看B的代码,果然有一处非常明显的BUG,原来exp被其他参数覆盖了!(怀疑+验证是排查问题的常用手段)

解决方案:修改代码,如果exp有值则不要覆盖。感慨:找到真相以后修改真容易啊!(显而易见的答案会让人放松警惕,其实这只是真相的一部分)

验证:由于测试环境出现问题,搭建测试拓扑失败,因此采用模拟的方式进行验证,即模拟A服务向B服务发送exp,验证OK。(这里埋下一个隐患,测试环境与线上真实环境不符,测试方法不科学)

上线:上线后分析日志,发现问题并没有解决,与预期不符,仔细检查线上配置,确认不是配置问题。(接受现实的勇气难能可贵,赶紧回滚吧)

回滚:与预期不符,暂时回滚到上一次版本。(原则:先止损,再分析排查问题,在线服务不宜恋战)

测试:重新搭建测试拓扑,这一次找到了之前测试拓扑搭建失败的原因,搭建测试拓扑成功。测试发现与线上环境一样,果然之前的修复并没有完全解决问题,BUG应该不只一处!(如果当时在搭建测试环境上多花点功夫,就能提前暴露问题,不会导致上线后回滚的情况发生)

排查问题:gdb设置断点,发现字符串太长无法显示全,通过命令取消gdb字符串显示长度限制。然后故事高潮来了,发现一个诡异的现象:A服务发出的请求中有exp参数,但是B服务收到的参数没有exp参数,为什么其他参数都没有丢,偏偏这个参数不见了?(相信科学,真相往往只有一个)

求助:当局者迷,只好求助辉哥,给辉哥演示分析过程;旁观者清,辉哥怀疑A服务没有把exp参数发送给B,或者B在什么地方把参数给丢弃了。由于我在A服务中打了日志(A服务是lua语言开发的,打日志很方便),于是怀疑是B服务的问题,但是gdb结果表明我的猜测是错的,验证的方法是:我把A服务的代码中exp参数手动去掉,gdb发现B服务收到的请求长度没有变化,如果B之前收到了exp参数,那么长度应该变化才对,找出一个反例便证明了之前的假设是错误的。那么答案只剩一个:A服务没有发出exp参数!(排查问题要大胆假设小心求证,先入为主会导致看不到真相)

隐藏BUG:为什么日志显示A发送了exp参数,但是排查结果却表明它没有发送该参数呢?这里有一个隐藏BUG,A在组装http请求的时候,确实是有exp参数的,但是在发送函数send_request的时候,这个函数把exp参数给悄悄删除了!这个发送函数是个公共函数,之前没有关注它的实现。(函数单一职责的重要性,不要在一个函数里做多余的事情,否则就会前人埋坑后人踩;还有一个深层次原因:对于调用的公共函数没有去关心它如何实现,踩坑只是时间问题)

至此,一桩历史悬案告破:A服务有一个隐藏BUG,难以察觉,B服务有一个明显的BUG,一目了然,巧合的是,由于测试环境没有搭建成功,通过模拟测试的方法只验证了修复B是否有效,而忽视了A中BUG的影响,导致一次上线失败,耗费大量时间排查问题。

扫描二维码关注公众号,回复: 5644547 查看本文章

经验总结:

1,重视测试流程,一定不要跳过正规测试流程,让问题在第一时间暴露,避免上线回滚。

2,重视开发规范,函数的单一职责原则,应严格遵守,不给后人挖坑。

3,阅读公共库函数,不能当黑盒子看待,主动去看其实现,弄清楚原理和故事。

4,不要想当然,先入为主,思维定势会导致无法进步,要保持谦虚,勤于学习和总结,不断进步。

(全文完)

猜你喜欢

转载自blog.csdn.net/wanfang323/article/details/87909648
今日推荐