上周产品出现了一个线上 bug,我和一位同事临时通宵给做了善后处理,本来是有很清晰的处理思路,以及很熟练的处理方法,但是过程中还是出现了各种各样的问题,现做个简单总结,希望能给后续处理同类问题带来帮助。
一、问题背景
客户端代码有一个逻辑,判断一个文件是否是 XML 文件时,实现逻辑不严谨,没有进行充分性校验,选取的判断条件不唯一,类似我在《记一次问题分析解决的完整过程》中臆断的使用换行符来分隔字段的逻辑。
因为这个逻辑的存在,如果获取 XML 文件的 URL 地址不存在,那么返回的 404 页面,也匹配上述的判断条件,结果就命中了不应该命中的流程,继续处理。
在后续处理过程中,预期的数据出现了异常,从而导致了更严重的逻辑异常。
总结:
1、正规长期使用的线上代码,一定要避免山寨的实现方式。
我在文章《记一次问题分析解决的完整过程》中,也说过自己解析 html 时用的山寨方法,结果出现各种奇葩问题,但我那是一次性使用,可以接受,现在是一个长期使用的线上逻辑,这么去实现,完全是埋坑。
2、开发代码 Review 需要增加类似取巧实现方案的检查,有通用逻辑或者 API 处理的,绝对不用自己臆断的实现方案。
3、测试同学在沟通逻辑时,一定要多问一句实现方案,哪怕听懂了大概,也可以判断方案的合理性,以及可能带来的风险。
二、处理方案
因为上面的问题,客户端在逻辑处理时把一个文件夹的文件全部清空了,所以处理方案很明确:想办法把清空的文件恢复。
现在有两种解决方案。
第一种是精细处理,把所有文件都整理出来,一个个的通过升级的方式下发恢复,这种方式针对性强,但是操作过程繁琐,耗时较长,且容易出现二次事故。
另一种是粗暴处理,比如下发一个升级包,把客户端文件全部更新一遍,这种方式的方案简单通用,实施快捷,但是版本变更可能引起用户不适。
权衡之后,我们选择了第二个方案,主要考虑是,相对功能异常而言,用户还是可以接受一些小的改变。
总结:
1、应急处理方案的选择,一定要考虑时间因素,同时考虑成本和风险。
2、方案需要尽快的确定,因为落实过程中还会存在各种不确定性,在前序环节要尽可能节省时间。
3、方案确定后,尽快使用最小集合进行快速验证,避免因为一个关键问题导致方案被推翻重来。
三、落地实施
方案确定后,我们开始细化落地细节。
首先是选择升级包,刚好线上有一个可用升级包,节省了我们重复打包的工作量,这也是选择这个方案的原因之一,但是这个升级包还有 1% 左右的用户覆盖不到,经过权衡,可以接受,于是升级包问题搞定。
然后是升级条件,线上已有三个升级包节点,每个节点都需要互斥,为了避免条件太多造成的错乱,我们选取了一个唯一性文件依赖进行互斥,于是第二个问题搞定。
然而升级条件还有另一个问题,就是我们需要针对本地不存在某个指定的文件进行升级,这个逻辑前不久刚做过修改,我对这个逻辑不熟悉,所以构造和验证这个问题的过程花费了不少的时间,事实证明,熟悉业务逻辑细节非常重要。
当然过程中还涉及对于条件设定的抉择,因为我能查看全局的文件设置,所以能快速准确的找到合适的条件和依赖文件(已经涉及其他组的多个文件了),如果是没有这么多信息,我能想到自己肯定会抓狂,事实再次证明,对于业务逻辑的全局了解,以及相关流程的熟练,对处理问题过程中的判断和实施及其重要。
所有条件都配置好了,最后剩下实际环境的验证,众所周知,测试环境的维护一直都是一项让人头大的事,而复杂的升级配置和特殊环境要求更是如此。
过程中仍然出现了各种各样的问题,但是因为每次都可以准确判断造成问题的原因,极大的节省了定位问题的时间,事实证明,能够准确发现问题的关键点,从而快速定位问题的原因在处理问题过程中至关重要。
四、后怕
每一次处理问题的过程,都是积累的经验得到充分体现的过程
,所以全程都是高度紧张,凌晨 4 点,搞定全部问题,顺利上线。
回家洗澡的时候,不经意的回顾整个问题处理的过程,突然想起来过程中换了三次依赖的目标文件,目前使用的这个依赖文件的可用性验证,做的并不充分,简单说,就是没有在实际环境下去确认这个依赖文件选择的合理性,一边洗澡我一边开始冒冷汗。
赶紧打电话先暂停升级,然后打开电脑进行仔细确认,还好还好,虚惊一场,关键时候的判断还是蛮准确的,并没有搞错这个关键问题,想起来当时换的第二个文件就是因为有这个问题,所以才用的第三个文件,确认安全后又赶紧恢复上线了。
看着窗外已经露出的鱼肚白,终于可以安心的躺下睡觉了。
以上,简单复述了自己处理一个紧急问题的经过,因为脱敏的缘故,细节没有说的特别明确,但是大概意思基本都表达出来了,不知道你在工作过程中是否处理过类似的问题,欢迎给我留言分享你的经验。
当然,如果你觉得自己有所收获,欢迎分享文章到朋友圈 + 点个「在看」让更多人看到,谢谢。