排错套路

排错环境

  1. 开发环境:IDE单步调试

  2. 测试环境:使用编程语言自带的调试工具(Java的jvisualvm/Arthas,Golang的net/http/pprofruntime/pprof

  3. 生产环境:存在权限管控,不允许调试工具从远程附加进程,且生产环境以恢复为主,没有足够的时间和现场来排查。

生产环境排错

生产问题的排查很大程度依赖监控,因为,生产环境出现问题时,要尽快恢复应用,就不可能保留完整现场用于排查和测试。因此,是否有充足的信息(日志、监控和快照)可以了解过去、还原现场就成了关键。

日志

  • 确保错误、异常信息可以被完整地记录到文件日志中。

  • 确保生产上程序的日志级别是 INFO 以上。

记录日志要使用合理的日志优先级:

  • DEBUG 用于开发调试、

  • INFO 用于重要流程信息、

  • WARN 用于需要关注的问题、

  • ERROR 用于阻断流程的错误。

监控

做好充足的,多层次的监控(监控层数取决于应用的部署方案,有一层 OS 就要做一层监控):

  • 主机层次:对 CPU、内存、磁盘、网络等资源做监控。

  • 网络层次:监控专线带宽、交换机基本情况、网络延迟。

  • 中间件和存储层次:不仅仅是监控进程对 CPU、内存、磁盘 IO、网络使用的基本指标,更重要的是监控组件内部的一些重要指标。(比如Prometheus的exporter来对接各种中间件和存储系统)

  • 应用层次:需要监控 JVM 进程的类加载、内存、GC、线程等常见指标(比如Micrometer来做应用监控),此外还要确保能够收集、保存应用日志、GC 日志。

快照

应用进程在某一时刻的快照。

比如生产环境的 Java 应用设置 -XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=… 这 2 个 JVM 参数,用于在出现 OOM 时保留堆快照。

分析定位套路

定位问题,首先要定位问题出在哪个层次上。比如是应用程序自身的问题还是外部因素导致的问题,如果是资源消耗型问题,可能没有异常,需要监控指标配合显性问题来定位。

程序自身问题

比如新版本的BUG,首先应该回滚,尽快恢复生产环境,然后再分析对比版本之间的差异。

外部因素

比如主机、中间件、数据库的问题,按照不同层次分为主机问题以及中间件和存储问题。

  • 主机层次的问题使用工具排查:

    • CPU 相关问题,可以使用 top、vmstat、pidstat、ps 等工具排查;

    • 内存相关问题,可以使用 free、top、ps、vmstat、cachestat、sar 等工具排查;

    • IO 相关问题,可以使用 lsof、iostat、pidstat、sar、iotop、df、du 等工具排查;

    • 网络相关问题,可以使用 ifconfig、ip、nslookup、dig、ping、tcpdump、iptables 等工具排查。

  • 中间件和存储层次的问题:

    • 排查组件所在主机是否有问题;

    • 排查组件进程基本情况,观察各种监控指标;

    • 查看组件的日志输出,特别是错误日志;

    • 进入组件控制台,使用一些命令查看其运作情况。

  • 资源消耗型问题(先通过重启和扩容解决,保留一个节点作为现场):

    • CPU使用过高:top -Hp pid,输入大写的 P 将线程按照 CPU 使用率排序,再使用编程语言自带的工具查看对应的线程,定位出问题的线程当时的调用栈。

    • 内存泄漏或OOM:查看具体堆内存使用情况,可使用编程语言自带的工具。

    • 网络问题:一般是外部因素,可以抓包分析。

    • IO问题:一般是代码引起资源未释放。

分析定位时的注意点

  1. 考虑先有鸡还是先有蛋的问题

  2. 分类寻找规律

  3. 根据调用拓扑分析

  4. 考虑资源限制

  5. 考虑资源相互影响

  6. 网络问题要区分:客户端、服务端、传输

  7. 快照类工具和趋势类工具结合使用

  8. 不要轻易怀疑监控

  9. 如果因为监控缺失等原因无法定位到根因的话,相同问题就有再出现的风险

最后更新于

这有帮助吗?