生产环境故障处理的一般办法总结

前言

任何一个系统上线运营后都或多或少会遇到生产环境故障问题,大部分情况下"重启大法"的确好用,但是能否有更符合我们这些"有经验的"工程师的做法呢?


故障: 慢了,挂了,出异常。

处理:找线索、推测原因、再进一步找具体线索验证。

总体的思路

定位->保留现场-> 故障快速恢复(重启/限流/降级/会滚)-> 事后分析(日志/软硬件负载等)-> 优化以及针对性加告警。

  • 线上告警/或者测试/客服反馈故障(模块/用户信息/时间等)
  • 先看对应的模块工作是否正常(把接口往浏览器一敲,看看能不能访问,😄)
  • 上机器看服务日志,看是否有异常日志(一般这种运行时异常,都要通过告警系统告警出来)
  • 如果日志出现异常,回顾是否最近有更新服务,考虑是否需要会滚。
  • 如果没有日志异常,纯粹是服务慢、超时,就要进一步分析了。
  • 服务慢、超时,先看看目前的请求量多少,是否超出了当时的设计,一般这些都有做预警,如果没有预警出来,大概率不是这个原因,当然还是排除一下最好。
  • 如果量不大,那一般就只有几种情况了,一是连接池或者线程池满了,二是GC 导致的停顿,三是数据库。
  • 连接池和线程池满了都可能导致的新的请求无法处理,这个时候可以看下一些连接池的配置,线程池的配置,像数据库连接池如果用的是durid 可以有可视化的界面看,如果没有,可以通过jmap 把 heap都dump出来,查看链接池对象的属性,看类似idle等counter值,当然你也可以用一些在线的反射工具去看。像线程池的话如果是有界队列的可以通过 自定义拒绝策略类将异常告警出来。
  • GC 过程中的STW也可能导致请求超时,这个时候就要看是否堆空间不足,新老年代是否合理,可以考虑隔离一台机器出来把堆dump出来,看是否有内存泄漏。
  • 数据库的话需要看下数据库服务的情况,慢查询等。
  • 如果量大,那么是否考虑进行一个扩容,或者限流,或者考虑是否有DDOS攻击和CC攻击。
  • 当然上一步只是一个分析过程,实际上也不可能让服务一直不回复等我们找到原因,一般都想先收集现场,能打快照的打快照,不能打快照的隔离出一台机器保留现场。

方法

1. 先对现场数据进行定量归类:

  • 异常节点数量,少数节点故障还是多数节点故障。
  • 时间点,出现异常的时间点或者范围,这个很重要,方便定位日志区间。
  • 共同特征,比如是否都是依赖了某个下游服务,是同机房/ISP/程序版本/操作系统

这些最开始的归类有助于快速定位问题所在,记录故障路径,方便后面复盘。由于这些要求保留故障现场,但是我们也不能让服务一直不恢复,所以这些工作要在短时间内完成,如果公司的基础设施比较完善这些也应该能够在事后在各种监控系统进行复查。

先解决问题再找原因,一般操作就是先保留现场,如果能保留快照(短时间内能完成),就保留快照后进行服务恢复,如果不能(比如JVM dump heap 一般要很久),留一台线上机器,隔离流量(域名摘掉解析,nginx upstream 去掉,微服务得话将服务节点下线),其他机器重启恢复。

2. 对于无法从服务表象(日志/接口)看出问题的情况,就要深入服务运行环境进行分析排查。

  • 服务的表现:慢、挂、异常; 应用日志、上下游服务状态。

    Nginx 的 access log

    一些trace 服务,如 spring cloud 的 Sleuth / Zipkin (dubbo 也可以)

    Metric类的系统,直接定位到业务。

  • 硬件状态:CPU、内存、磁盘、网络是否有瓶颈。

    top 命令

    free -h 看内存

    df -h

    iftop

    nload

    ping

    lsof

    netstat

  • 系统/容器/VM状态:系统日志,容器日志,VM GC日志等。

    jstat -gcutil [pid] [period] 查看GC信息

    jmap -heap [pid] 查看jvm堆的使用情况

    唯品会开源的一些工具也挺好用的,https://github.com/vipshop/vjtools

上面这些信息 可以通过一些监控系统,一般上规模的公司都有这些,可以快速获取到这些信息,没有的话,也可以自行上机器通过linux 命令查询到。