测试提 Bug
的基本要素,主要包括:
- 期望得到的结果
- 实际得到的结果
- 如何重现问题
生产环境出了故障,当然也脱离不开这 3 个要点。只不过相对重现问题会略微复杂。毕竟,故障总是我们意外之外的情况。
根据 Bug
发生的现象,我们会提出很多假设,然后进行逐步排除。
当问题发生时,最应想到的是:系统最近是否有过改动。很大概率上,一个正常工作的服务会一直维持工作,直到某种外力出现。如果确实是新功能上线导致的,可以结合具体情况,考虑是否回滚到老版本。但有些时候,回滚可能还会引发二次问题,需要特别注意。
接下来:
继续保存冷静,简要评估问题的严重程度,及时给外部作出反馈。这里的反馈特别重要,不仅可以让大家了解故障的进展情况,而且,大家还可能提供非常有价值的建议。
接下来:
仔细分析故障发生的现象,不要忽略错误日志的任何细节。这个过程中,日志显得尤为重要。一个好的日志记录,必须能还原或推断出当时故障的现场。日志信息主要包括:上下文信息、报错信息。
当然,有时候故障会涉及多个微服务,最好能有一个trace_id
,用来跟踪故障的发生过程,以及具体是微服务中的哪台服务器发生的故障。
接下来:
如果无法绝对确定故障的原因,我们需要复现Bug
,也就是前文提到的逐个排除。这开发过程中,追加重要服务的测试用例非常重要,可能会节约好多宝贵的时间。
但也存在难点,比如一些伪相关的原因误导我们的判断。故障一般都有连锁反应,有时候会很难分辨问题的主次。
Go
开发排查问题
Q1
服务发生 panic
时,结合日志中打印的堆栈信息,可以很容易定位到出错的代码,并作出很多可能的推测。然后,结合具体的上下文信息,能很快复现问题。整个过程中,日志是问题排查的关键。
日志必须包含 panic
的堆栈信息,最好有链路的 trace_id
信息。如果在开发过程中,有对应的 Test
就更好了。
Q2
对于接口响应慢的情况,可以依靠 pprof
工具进行诊断。其中,最可能的是调用外部服务慢,比如经典的 MySQL
慢查询。
如果排除了外部依赖的问题,那很可能是程序代码自身问题。通过 pprof
的各种信息展示,也能很快定位。
珍惜Bug
不要放过任何 Bug
,对Bug
的处理过程要做好梳理、总结。下面是总结的模版:
-- 细节
-- 灾难响应
-- 事后总结
-- 做的好的地方
-- 做的不好的地方