← 返回场景决策

🔍 Debug排查场景决策

什么时候用 / 什么时候不用 / 边界在哪里 — 8 大核心场景全解析

看日志 抓包 火焰图 线程dump 堆dump Arthas 链路追踪 排查思路

1. 看日志 — 第一排查手段

日志 = 飞机黑匣子 出事后回放记录,找出问题在哪
什么时候先看日志
  • 接口报错:5xx 错误 — 先看服务端 ERROR 日志
  • 业务逻辑异常:订单状态不对 — 搜索订单号关键字
  • 定时任务失败:凌晨跑的任务没成功 — grep 任务名
  • 数据不一致:金额对不上 — 搜索交易号看流程

📊 日志排查决策表

问题类型看什么日志关键字工具
接口500应用ERROR日志Exception / Caused bygrep/ELK
慢接口访问日志耗时 > 阈值Nginx access.log
OOMGC日志 + 堆dumpOutOfMemoryErrorjmap
死锁线程dumpBLOCKED / waitingjstack
MQ消费失败消费者日志消息ID + 异常MQ控制台 + 应用日志

💻 日志排查命令

📁 server-diagnostics
📂 /var/log/app/
📄 app.log
📂 scripts/
📄 log_search.sh
# 实时看日志 tail -f /var/log/app/app.log # 搜索异常关键字 grep -n "NullPointerException" app.log # 搜索某个订单的所有日志 grep "ORDER-2024-001234" app.log # 看最近10分钟ERROR日志 find /var/log/app -name "*.log" -mmin -10 | xargs grep "ERROR" # ELK 查询(Kibana) // level: ERROR AND message: "orderId: 1234" // @timestamp: [now-30m TO now]
面试金句 grep + find 组合是 Linux 下日志排查的基本功:grep -n 带行号方便定位上下文,find -mmin -10 找最近 10 分钟修改的文件。ELK(Elasticsearch+Logstash+Kibana)将分散的日志聚合到统一搜索平台,Kibana 用 Lucene 查询语法(level:ERROR AND message:"orderId:1234")实现全文检索+时间范围过滤+字段匹配,比 grep 更高效地处理 TB 级日志。

2. 抓包 — 网络问题排查

抓包 = 路口装监控 每辆车从哪来到哪去,车上带了什么,全拍下来
什么时候抓包
  • 接口不通:请求没到服务器还是服务器没返回 — 抓包看请求到底发出没
  • 数据不对:接口返回值和预期不同 — 抓包看实际返回内容
  • CORS 问题:浏览器报跨域错误 — 抓包看 OPTIONS 请求和响应头
  • Cookie 问题:请求没带 Cookie — 抓包看请求头
  • 第三方对接:微信/支付宝回调没收到 — 抓包验证

📊 抓包工具决策表

工具层级适合难度
Chrome DevToolsHTTP前端接口调试
Charles/FiddlerHTTP/HTTPS前后端联调、Mock
tcpdumpTCP/IP服务器网络排查
Wireshark全协议深入网络分析
📁 server-diagnostics
📂 capture/
📄 capture.pcap
📂 scripts/
📄 network_capture.sh
# tcpdump 服务器抓包 # 抓 8080 端口的 HTTP 请求 tcpdump -i any port 8080 -A -s 0 # 抓某个IP的请求 tcpdump -i any host 10.0.0.5 -w capture.pcap # 抓 HTTP POST 请求 tcpdump -i any -A -s 0 'tcp port 8080 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'
面试金句 tcpdump 是服务器侧抓包的黄金标准:-i any 监听所有网卡,-A 以 ASCII 输出(方便看 HTTP 内容),-s 0 不截断包(完整捕获),-w file.pcap 保存到文件后用 Wireshark 图形化分析。生产环境用 tcpdump 抓包需注意性能影响(高流量时可能丢包),建议用 BPF 过滤器缩小范围(如 port 8080)。

3. 火焰图 — CPU性能排查

火焰图 = 城市天际线 越宽的建筑越占空间(越耗CPU),一眼看出哪里最"胖"
什么时候看火焰图
  • CPU 飙高:top 看到某个 Java 进程 CPU 100% — 火焰图定位热点方法
  • 接口延迟:某个接口响应慢 — 火焰图找到耗时方法
  • GC 频繁:GC 占用大量 CPU — 火焰图看到 GC 热点
  • 性能优化:找到优化点 — 哪个方法调用最多/最耗时

💻 生成火焰图

📁 server-diagnostics
📂 profiling/
📄 flamegraph.html
📄 async-profiler.sh
# 方式1:async-profiler(推荐,Java专用) # 下载 async-profiler java -jar async-profiler.jar -d 30 -f flamegraph.html <pid> # 30秒后生成 flamegraph.html,浏览器打开即可 # 方式2:jstack 采样 + 生成 # 多次 jstack 统计方法出现频率 for i in {1..10}; do jstack <pid> > stack_$i.txt sleep 1 done # 方式3:Arthas 生成火焰图 # java -jar arthas-boot.jar # profiler start # 等待30秒 # profiler stop --format html
面试金句 火焰图(Flame Graph)将大量调用栈采样可视化:横轴=方法在采样中出现的比例(越宽=越占 CPU),纵轴=调用深度(栈顶在最上方)。async-profiler 基于 perf_events / AsyncGetCallTrace,开销极低(<1%),不触发 safepoint 停顿,远优于 JFR/JStack 采样方式。"宽且浅"的方法是优化重点。

4. 线程dump — 线程问题排查

什么时候用线程dump
  • 死锁:两个线程互相等待 — jstack 会自动报告 FOUND A JAVA LEVEL DEADLOCK
  • 线程泄漏:线程数持续增长 — dump 看哪些线程在做什么
  • 请求卡住:接口一直不返回 — dump 看处理线程在等什么
  • CPU 高:先 top 找到高CPU线程,再 jstack 看对应线程栈
📁 server-diagnostics
📂 thread-analysis/
📄 thread_dump.txt
📄 find_high_cpu.sh
# 获取线程dump jstack <pid> > thread_dump.txt # 找 CPU 最高的线程 # Step 1: 找到Java进程 jps -l # Step 2: 找到高CPU线程ID top -Hp <pid> # 假设线程ID是 12345 # Step 3: 转为16进制 printf "%x\n" 12345 # 输出: 3039 # Step 4: 在dump中搜索 jstack <pid> | grep "0x3039" -A 30 # 死锁示例输出: # Found one Java-level deadlock: # ============================= # "Thread-1": # waiting to lock monitor...,- locked <0x000000076b...>(a java.lang.Object), # which is held by "Thread-0" # "Thread-0": # waiting to lock monitor...,- locked <0x000000076b...>(a java.lang.Object), # which is held by "Thread-1"
面试金句 top -Hp → printf %x → jstack grep 是排查 Java CPU 飙高的标准三步法:top -Hp(-H 显示线程级)找到 CPU 最高的 nid,转 16 进制后在 jstack 输出中搜索 nid=0x3039 对应的线程栈。⚠️ jstack 输出的 nid 是十六进制,top 显示的是十进制,必须转换。jstack 自动检测死锁并输出 Found one Java-level deadlock 提示。

5. 堆dump — 内存问题排查

什么时候用堆dump
  • OOM:java.lang.OutOfMemoryError — 分析什么对象占满内存
  • 内存泄漏:内存持续增长不释放 — 找到泄漏对象
  • GC 频繁:Full GC 停顿长 — 看老年代被什么占满
📁 server-diagnostics
📂 heap-analysis/
📄 heap.hprof
📄 jvm_options.txt
# 手动获取堆dump jmap -dump:format=b,file=heap.hprof <pid> # OOM 时自动dump(推荐配置) // JVM启动参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/heapdump.hprof # 用 MAT (Memory Analyzer Tool) 分析 # 1. 下载 Eclipse MAT # 2. 打开 heapdump.hprof # 3. 查看 Leak Suspects(泄漏嫌疑对象) # 4. 查看 Dominator Tree(占内存最大的对象) # 5. 查看 GC Roots 引用链(谁引用了这个对象导致无法回收) # 快速查看堆概况(不用dump) jmap -histo <pid> | head -20 # 输出类似: # num #instances #bytes class name # 1: 1234567 123456789 [B (byte数组) # 2: 567890 45678901 java.lang.String
面试金句 -XX:+HeapDumpOnOutOfMemoryError 是生产必备 JVM 参数:OOM 发生时自动 dump 堆快照,事后用 MAT(Eclipse Memory Analyzer Tool) 分析。Dominator Tree 按对象持有内存大小排序("支配者树"),GC Roots 引用链展示泄漏对象通过什么路径被持有导致无法回收(如 ThreadLocal、静态集合、未关闭的 Connection)。jmap -histo 是无 dump 快速诊断:直接看对象计数 Top N。

6. Arthas — 线上诊断神器

Arthas = 远程B超 不用重启,不用改代码,直接看 JVM 内部

📊 Arthas 常用命令决策表

命令功能什么时候用
dashboard全局面板(线程/内存/GC)快速了解 JVM 状态
thread查看线程状态CPU高/死锁/线程卡住
jad反编译类确认线上代码版本
watch观察方法调用看入参/返回值/异常
trace追踪方法调用链接口慢,定位哪个方法耗时
sc/search搜索类确认类是否被加载
heapdump导出堆dump内存问题
profiler生成火焰图CPU性能分析

💻 Arthas 实战

📁 server-diagnostics
📂 arthas/
📄 arthas_commands.sh
📂 target-app
📄 OrderService.class
# 启动 Arthas java -jar arthas-boot.jar # 选择你的 Java 进程 # 1. trace 追踪慢接口 trace com.example.service.OrderService createOrder # 输出: # +---[200ms] createOrder() # +---[150ms] checkStock() ← 这里最慢! # +---[30ms] saveOrder() # +---[20ms] publishEvent() # 2. watch 观察方法入参和返回值 watch com.example.service.OrderService createOrder "{params, returnObj, throwExp}" -x 2 # 每次调用都会打印入参、返回值、异常 # 3. 反编译确认代码版本 jad com.example.service.OrderService # 看到源码 → 确认是不是最新版本 # 4. 条件追踪(只看特定订单) trace com.example.service.OrderService createOrder 'params[0].orderId == "ORD123"'
面试金句 Arthas 通过 Java Agent + 字节码增强 实现运行时诊断,不重启、不改代码trace 统计方法内部每个子调用的耗时(类似火焰图的时间维度版),watch 通过 OGNL 表达式 {params, returnObj, throwExp} 在方法返回时打印入参/返回值/异常,jad 反编译确认线上运行的 class 是否是最新的——经典排查场景是"明明改了代码为什么没生效"(往往是部署没更新或 classpath 冲突)。

7. 链路追踪 — 微服务调用链排查

链路追踪 = 快递物流追踪 你的包裹经过了哪些中转站,哪里卡住了

📊 链路追踪方案决策表

方案语言存储适合
SkyWalkingJava AgentElasticsearchJava微服务首选
Zipkin多语言内存/ES/MySQLSpring Cloud Sleuth
Jaeger多语言Elasticsearch/Cassandra云原生/K8s

💻 SkyWalking 基本使用

📁 order-service
📂 deploy/
📄 start_with_skywalking.sh
📂 src/main/java
📄 OrderService.java
# JVM 启动参数挂载 Agent java -javaagent:/path/to/skywalking-agent.jar \ -Dskywalking.agent.service_name=order-service \ -Dskywalking.collector.backend_service=oap:11800 \ -jar app.jar # 自动采集: # 1. 每个 HTTP 请求的调用链 # 2. MySQL/Redis/MQ 调用 # 3. 接口耗时、错误率 # 4. 服务拓扑图 // 代码中添加自定义 Span import org.apache.skywalking.apm.toolkit.trace.TraceContext; public void processOrder(Order order) { // 获取 traceId,方便日志关联 String traceId = TraceContext.getTraceId(); log.info("traceId={}, orderId={}", traceId, order.getId()); }
面试金句 SkyWalking 通过 Java Agent 字节码增强实现零代码侵入的链路追踪:启动时 -javaagent 挂载,自动拦截 HTTP/MySQL/Redis/MQ 调用并注入 TraceId(传递通过 HTTP Header 的 sw8 协议)。TraceContext.getTraceId() 获取当前链路 ID,与日志关联后,一个 traceId 即可在 ELK 中串联整条微服务调用链——这是分布式系统从现象到根因的桥梁。

8. 排查思路 — 从现象到根因

现象 定位 根因 修复

📊 常见问题排查路线图

现象第一步第二步第三步
接口500看日志 ERROR搜索异常堆栈找到出代码行修复
接口慢看接口耗时日志trace定位慢方法优化SQL/加缓存
CPU飙高top -Hp找线程jstack看线程栈死循环/正则回溯/加密
内存泄漏jmap -histo看对象MAT分析heap dump修复未关闭资源
死锁jstack报告死锁看锁获取顺序统一加锁顺序
网络不通ping/telnet测试tcpdump抓包防火墙/路由配置
MQ消费慢看消费延迟看消费者日志消费逻辑优化/扩容
数据不一致对比数据源搜索日志找时间点修复同步逻辑
💭 排查心法
  1. 先复现:能复现=解决了一半
  2. 先看日志:日志是成本最低的排查手段
  3. 缩小范围:从前端→网关→服务→数据库→网络,逐层排除
  4. 二分法:注释掉一半代码,看问题是否消失
  5. 对比法:正常环境 vs 异常环境,找差异
  6. 时间线:按时间线梳理,问题出现在哪个变更之后

🔍 Debug排查场景决策 · 全栈资料库

← 返回场景决策