在线服务开发和维护人员,往往都会遇到服务出现故障的状况。在处理了几次在线的问题之后,想简单的做一点总结。个人认为在线故障的处理分为这样几个阶段:
- 故障定位
- 故障恢复
- 总结改进
- 故障定位
怎样快速的定位问题对于在线故障处理起到了至关重要的作用,因为这决定了后续恢复故障的方式和方法。针对不同问题定位的方法也不尽相同,下面我就针对我个人遇到的比较多的问题进行一些总结。
1. 响应时间变慢
响应时间变慢是在线服务经常遇到的一个问题,个人认为响应时间变慢主要分为外部和内部两个方面的情况:
- 外部依赖导致的响应变慢
- 外部依赖导致的响应变慢
- 缓存响应变慢
- 第三方依赖导致的响应变慢
- 内部资源紧张
- CPU 使用率过高
- 内存资源不够用
- 线程池不够用
- 连接未释放导致的资源耗尽
我们要能够快速的定位外部依赖的问题就需要我们针对外部依赖的请求加上详细的 metric 信息,这样当故障来临的时候我们才能够及时的发现问题。
在内部资源方面,我们需要深入的了解服务所依赖的资源,并对这些资源进行详细的状态监控。例如监控 CPU 的使用,监控 GC 的状态,监控线程池和连接池的状态信息等。
2. 服务 down 掉
某个服务 down 掉了也是我们可能会遇到的问题,服务 down 掉主要分为以下几种情况:
- 服务所在机器 down 了
- 服务进程被 kill 了
- 服务进程 crash 了
机器 down 机出现的时候往往具有一定的偶然性,一般不会大面积出现,故障也不会进一步扩大。这种情况下我们重启机器或者直接迁移服务应该就能恢复。
服务进程被 kill 掉,例如进程由于使用过多的 memory 导致 os 内存进展而杀死该进程。这种情况下系统日志往往会有一定的记录,分析日志即可得到相关的信息,进行相应的处理即可。
服务进程 crash 掉,通过 core dump 文件即可看到进程在 crash 的时候的大致状况,并通过 core dump 文件进行相应的分析处理即可。
3. 服务返回不正确的结果
服务返回不正确的结果往往发生在系统刚发布之后,由代码的问题引入,这个时候我们需要及时回滚到之前的稳定版本,之后再对相应的修改进行分析。 对于 HTTP 服务,service 可能开始返回诸如 50X, 40X 问题,这里我们需要确定这些错误的返回是不是来源于我们自己的服务,还是源于调用链中的某个环节,例如 Loadbalance,Proxy 等。
- 故障恢复
怎么进行故障恢复可能很大程度上取决于我们的故障定位,针对不同的问题采用不同的方式恢复故障或者防止故障的进一步扩大。下面列举一些针对不同情况的处理方案:
- 数据库,缓存或者第三方依赖响应变慢,这个时候我们需要找出响应变慢的来源,并决定是否要进行适当的收缩,例如断开对这些服务的依赖。需要我们开发的服务具备收缩的能力, 自动收缩更佳。 之后便是便是数据库,缓存变慢的原因并进行恢复,或者等待第三方服务的恢复。
- 由于内存泄露导致的内存问题, 尝试重启服务看服务能否暂时恢复。 不行可回滚到之前的某个稳定版本进行重新发布。
- 服务进程被 kill 掉,需要我们查看相关的系统日志,找出问题的原因,并更改相关的配置。
- 服务进程 crash, 尝试重启或者回滚到之前的稳定版本。
- 返回不正确的结果,在确定是新的修改引入的 bug 之后回滚到之前的稳定版本。
- 总结改进
每一次在线故障发生之后都是一次很好的学习机会,核心问题是如何避免类似问题的再发生,而不是指责相关的人员。我们采用的方式一般会在故障解决和分析完毕之后开一个总结会议,将故障发生和解决的全过程进行总结。分析故障发生的具体原因,总结我们在开发和流程中需要完善的地方,并给相关的人员创建相应的任务。
- 解决故障的原则
解决问题是我们的第一任务。很多时候可能我们并没有完全弄清楚问题的原因,但是可能通过重启等手段就可以到达恢复故障的目的,这个时候我们不要犹豫,如果找到什么使得服务能够尽快恢复的方法,就迅速展开行动。
保护现场。 在故障发生以后我们定位问题的时候,由于时间非常紧急,我们可能还并不能完全分析清楚故障发生的原因,就需要进行相关恢复操作了。这种情况下为了后续能够更好的分析和解决问题, 我们需要尽可能的保护故障发生的现场。 比如将某台问题机器从 LoadBalance 拿下来,Dump 当时的线程和内存信息等。
全面分析问题。只有全面细致的分析问题发生的原因和背景,我们才能更好的采取相关的行动来避免类似问题的发生。
最后想说的是在解决线上故障的时候,切记解决问题才是我们的第一任务,不要因为过多的纠结于问题发生的原因而耽误了时间。另外保护现场为后续我们进行更为全面深入地分析提供了基础。