故障排查

测试提Bug的基本要素,主要包括:

  1. 期望得到的结果
  2. 实际得到的结果
  3. 如何重现问题

生产环境出了故障,当然也脱离不开这3个要点。只不过相对重现问题会略微复杂。毕竟,故障总是我们意外之外的情况。

根据Bug发生的现象,我们会提出很多假设,然后进行逐步排除。

当问题发生时,最应想到的是:系统最近是否有过改动。很大概率上,一个正常工作的服务会一直维持工作,直到某种外力出现。如果确实是新功能上线导致的,可以结合具体情况,考虑是否回滚到老版本。但有些时候,回滚可能还会引发二次问题,需要特别注意。

接下来:

继续保存冷静,简要评估问题的严重程度,及时给外部作出反馈。这里的反馈特别重要,不仅可以让大家了解故障的进展情况,而且,大家还可能提供非常有价值的建议。

接下来:

仔细分析故障发生的现象,不要忽略错误日志的任何细节。这个过程中,日志显得尤为重要。一个好的日志记录,必须能还原或推断出当时故障的现场。日志信息主要包括:上下文信息、报错信息。

当然,有时候故障会涉及多个微服务,最好能有一个trace_id,用来跟踪故障的发生过程,以及具体是微服务中的哪台服务器发生的故障。

接下来:

如果无法绝对确定故障的原因,我们需要复现Bug,也就是前文提到的逐个排除。这开发过程中,追加重要服务的测试用例非常重要,可能会节约好多宝贵的时间。

但也存在难点,比如一些伪相关的原因误导我们的判断。故障一般都有连锁反应,有时候会很难分辨问题的主次。

Go开发排查问题

Q1

服务发生panic时,结合日志中打印的堆栈信息,可以很容易定位到出错的代码,并作出很多可能的推测。然后,结合具体的上下文信息,能很快复现问题。整个过程中,日志是问题排查的关键。

日志必须包含panic的堆栈信息,最好有链路的trace_id信息。如果在开发过程中,有对应的Test就更好了。

Q2

对于接口响应慢的情况,可以依靠pprof工具进行诊断。其中,最可能的是调用外部服务慢,比如经典的MySQL慢查询。

如果排除了外部依赖的问题,那很可能是程序代码自身问题。通过pprof的各种信息展示,也能很快定位。

珍惜Bug

不要放过任何Bug,对Bug的处理过程要做好梳理、总结。下面是总结的模版:

-- 细节
-- 灾难响应
-- 事后总结
    -- 做的好的地方
    -- 做的不好的地方