常见问题排查方案
线上问题排查思路
系统日志:CPU,内存,磁盘IO,网络(延迟,丢包)
应用日志:JVM,GC 分析,堆内存,线程状态
中间件:数据库(死锁,慢 SQL),数据库连接池满
Java 死锁:挂起,不响应请求,cpu 下降
//jstack -l
主要表现是 CPU 升高高后下降
查看 deadlock相关信息
优化方案:一次性获取所有锁,顺序获取,设置超时时间,不存在互斥情况可以使用 threadlocal 等
慢SQL 排查
事前 开启慢SQL日志,然后根据超时时间排查
推荐专业的 APM/监控平台
现代应用通常依赖专业的监控工具来实时发现和诊断问题。
- Prometheus + Grafana: 配合
mysqld_exporter收集 MySQL 指标(如 QPS、TPS、缓存命中率),通过图表实时显示数据库性能趋势。 - 云服务商的性能分析工具 (如 AWS RDS Performance Insights): 提供图形化界面,显示最慢的 SQL 语句、等待时间、等待事件等。
- SkyWalking / New Relic / Pinpoint 等 APM (Application Performance Monitoring) 工具: 追踪请求在应用服务和数据库之间的调用链,可以直接定位导致某个业务请求变慢的具体 SQL 语句。
慢 sql explain分析
id table type key key_len rows extra
| EXPLAIN 关键指标 | 含义及优化目标 |
|---|---|
**<font style="color:rgb(68, 71, 70);">type</font>** |
连接类型。 决定了查询的访问级别。目标是达到 **<font style="color:rgb(68, 71, 70);">const</font>**> **<font style="color:rgb(68, 71, 70);">eq_ref</font>**> **<font style="color:rgb(68, 71, 70);">ref</font>**> **<font style="color:rgb(68, 71, 70);">range</font>**。 最差的情况是 <font style="color:rgb(68, 71, 70);">ALL</font>(全表扫描)。 |
**<font style="color:rgb(68, 71, 70);">possible_keys</font>** |
MySQL 认为可能用到的索引。 |
**<font style="color:rgb(68, 71, 70);">key</font>** |
MySQL 实际使用的索引。 如果此处为 <font style="color:rgb(68, 71, 70);">NULL</font>,则表示没有使用索引。 |
**<font style="color:rgb(68, 71, 70);">key_len</font>** |
索引中使用的字节数。<font style="color:rgb(68, 71, 70);">key_len</font>越短越好(在保证唯一性的前提下)。 |
**<font style="color:rgb(68, 71, 70);">rows</font>** |
估计扫描的行数。 数值越小越好。行数过大是性能差的主要指标。 |
**<font style="color:rgb(68, 71, 70);">Extra</font>** |
额外信息。****目标是避免以下警告: * **<font style="color:rgb(68, 71, 70);">Using filesort</font>**: 需要额外的排序,通常是因为没有使用到索引进行排序。 * **<font style="color:rgb(68, 71, 70);">Using temporary</font>**: 需要使用临时表,通常是因为执行了分组 ( <font style="color:rgb(68, 71, 70);">GROUP BY</font>) 或排序 ( <font style="color:rgb(68, 71, 70);">ORDER BY</font>) 但没有合适的索引。 |
主要是看sql执行的过滤行数,索引情况,排序额外信息
优化 sql 方案有哪些,拆分表,使用索引,避免索引失效,减少返回列*,
语句优化方向有
| 优化方向 | 具体方法 |
|---|---|
| 精确取数 | * 避免 **<font style="color:rgb(68, 71, 70);">SELECT *</font>**: 明确指定所需列,减少数据传输和 IO 开销。 * 小而精: 使用 <font style="color:rgb(68, 71, 70);">LIMIT</font>限制返回行数;避免子查询,尽量用 <font style="color:rgb(68, 71, 70);">JOIN</font>代替;避免 <font style="color:rgb(68, 71, 70);">OR</font>连接大范围查询。 |
| 分页优化 | * 深度分页优化: 针对 <font style="color:rgb(68, 71, 70);">LIMIT offset, count</font>中 <font style="color:rgb(68, 71, 70);">offset</font>很大的情况,使用延迟关联或主键限定来优化。例如,先通过索引找到起始行的主键,再通过主键快速关联获取数据。 |
| 连接优化 | * 避免全连接: 确保 <font style="color:rgb(68, 71, 70);">JOIN</font>关联的字段有索引且数据类型一致。 * 大表驱动小表: 优化 <font style="color:rgb(68, 71, 70);">IN</font>和 <font style="color:rgb(68, 71, 70);">EXISTS</font>通常让小表驱动大表。 |
外部配置
使用sql 缓存池(热点数据和索引)innodb_buffer_pool_size,
使用 sql 连接池等,ssd 硬盘等
导入导出内存溢出
日志定位存在 Java heap space OOM
提前 dump 命令 HeapDumpOOMError HeapDumpPath = xxx 地址
使用 MAT 分析或者 Jvisualvm
线上导入导出导致的 OOM (Out Of Memory) 异常,通常是因为在处理大文件或海量数据时,程序一次性将所有数据加载到内存中,或者未能及时释放对象。
排查这类 OOM 问题的核心思路是:确认 OOM 类型 -> 捕获现场数据 -> 分析内存快照 -> 改进代码的数据处理模式。
以下是详细的排查方向和步骤:
🛑 线上导入导出 OOM 排查步骤
阶段一:确认 OOM 类型与现场
首先要确定抛出的是哪种类型的 OOM,以及程序当时正在做什么。
| OOM 类型 | 原因分析 | 应对措施 |
|---|---|---|
**Java heap space** |
最常见。 堆内存不足。大量数据对象(如 List、Map、Excel Cell 对象)占用过多内存。 | 增大堆内存 (治标);内存泄漏或大对象 (治本)。 |
**GC overhead limit exceeded** |
GC 频繁且效果甚微。程序花费了大量时间在 GC 上,但回收的内存很少,导致应用执行效率极低。 | 内存泄漏或堆太小。 |
**Metaspace** |
元空间不足。通常与导入导出无关,但如果涉及大量类的动态加载(如反射、动态代理),可能出现。 | 增大 Metaspace 大小。 |
操作: 检查应用日志,获取完整的 OOM 堆栈信息。
阶段二:捕获内存快照(Heap Dump)
内存快照(Heap Dump)是分析 OOM 的唯一数据源,它记录了 OOM 发生时的所有对象信息。
- 自动生成 Heap Dump:
在 JVM 启动参数中添加以下参数,让 JVM 在 OOM 发生时自动生成 .hprof 文件:
- Bash
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/path/to/dump/app.hprof
- 手动生成 Heap Dump(卡顿但未 OOM):
如果应用已经卡顿但尚未 OOM,可以使用 jmap 手动捕获:
- Bash
jmap -dump:format=b,file=/path/to/dump/manual.hprof <PID>
阶段三:分析内存快照(Heap Analysis)
使用专业的分析工具(如 MAT (Memory Analyzer Tool) 或 JVisualVM)打开 .hprof 文件进行分析。
- 查找最大的对象(Dominator Tree):
- 在分析工具中查看 Dominator Tree(支配树) 视图。
- 关注点: 查找占用内存比例最高的对象。在导入导出场景中,这些对象通常是:
ArrayList或HashMap实例,里面存储了海量行数据对象。byte[]或char[],可能存储了整个大文件的原始内容。String对象,如果字符串数量巨大或出现重复字符串(但未被优化)。
- 分析对象引用链(Path to GC Root):
- 一旦找到最大的对象,右键点击并查看其“Path to GC Root”(引用链)。
- 目标: 确定该大对象被哪个线程或静态变量等 GC Root 所持有,从而定位到是哪一段代码未能及时释放引用。
改用流式读取,sql 流式查询,逐行处理,批量提交等
频繁 FullGC
打印 gc 详细日志
PrintGCDetails gc.log
//jstat 或者 arthas dashboard
Eden survior Old
堆内存 jmap 生成
是否存在大对象到 old Gen 解决方案 临时调整大小缓解 修改代码
OOM问题
以上同步,但是要注意可能情况,Error 日志 Heap Dump 日志堆转存文件 GC 日志
分析 Heap Dump,大对象/内存泄露问题
大对象集合/长生命周期/无限增长/缓存未清理等
CPU 飙高
可以通过 top 命令查询进程
然后使用top hd
jstack 转16进制 查询对应线程程信息
可能原因有
1.死循环
2.频繁垃圾回收
3.死锁问题
MySQL 死锁问题
show engine innodb status 查看状态找到 LATEST DETECTED DEADLOCK部分,
解决方案顺序一致性获取锁,减少事务范围,乐观锁版本号实现呢
可以加适当的索引/最好使用行级锁
预防.设置死锁监控记录错误日志
MySQL 数据库连接满
show processlist,show full processlist,查询占用连接
慢日志情况,是否正确关闭,有没有连接泄露问题,是不是有长连接
合理配置,使用 mysql 性能配置
优化方案,慢查询优化,增大最大连接数?连接泄露问题?分库分表解决.开启监控
Java 进程突然挂了
系统日志,应用日志分析,内存不足?栈溢出?堆内存分析,
cpu top命令,
内存使用 free -m 磁盘 df -h
栈溢出死循环,使用oom 不存在内存不足
线上系统接口响应慢/突然响应慢
使用工具查看响应时间,吞吐量,错误率
Skywalking Promethus 等
数据库性能分析
外部依赖 api 分析
等
突然响应慢
系统资源问题?
应用监控
数据库性能?
线程进程分析
网络分析
压力测试
高并发的线程安全问题
查看并发控制 synchronized volatile lock等
共享资源访问
线程安全集合
日志分析
cpu 分析内存分析
压测工具
线上大量错误日志
1.elk收集存储日志
2.日志优先级排序
3.快速定位和分析,关键字,时间和频率,上下文信息
4.深入调查是代码还是其他问题等
5.解决问题
6.验证并总结优化

浙公网安备 33010602011771号