一、AI 辅助排障的核心价值传统排障 vs AI 辅助排障在实际工作中一次常规的 OOM 排查往往以“小时”为单位计算。原因不在于问题本身有多复杂而是大量时间都被消耗在机械操作上登录服务器、生成 dump、下载几个 GB 的文件、再拖进 MAT 等待分析。更麻烦的是即使看到了引用树如何从成千上万个对象中推断出真正的泄漏根因仍然高度依赖个人经验。传统 OOM 排障流程平均耗时2-4小时 ① 收到告警 → 连接服务器 ② jmap-dump:formatb,fileheap.hprofPID③ 下载 heap.hprof可能几个 GB到本地 ④ 打开 MAT 或 VisualVM 等待分析 ⑤ 逐层展开对象引用树猜测泄漏原因 ⑥ 找到问题写报告而引入大模型后整个链条可以被压缩到 15-30 分钟。关键转变在于我们不再把原始 dump 扔给 AI而是先用工具从 dump 中提取结构化摘要再把这份只有几 KB 的摘要送给大模型。这样既绕过了大模型的 token 限制也保留了可供分析的关键信息——对象数量、类型、内存占用排名等。AI 辅助流程平均耗时15-30分钟 ① 收到告警 → 脚本自动采集 dump 提取摘要 ② AI 分析摘要直接指出泄漏对象和可能代码位置 ③ 人工确认 → 修复核心前提大模型处理的不是 GB 级的原始 heap dump而是从 dump 中提取的结构化摘要几 KB。这就是整篇文章可行性的基石——只有把数据量压到这个级别才可能实现“告警即分析”。二、OOM 实战Heap Dump 分析定位内存泄漏2.1 自动化 Heap Dump 采集生产环境最怕遇到 OOM 时什么都来不及做服务就挂了所以我们强烈建议用 JVM 参数让 JVM 在内存溢出时自动生成 dump 并退出。配合 K8s 的自动重启既能拿到现场又不会让服务长时间僵死。手动采集则适合预发或测试环境用jmap或 Arthas 灵活抓取。# 方法一JVM 参数OOM 时自动 dump推荐生产环境-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/tmp/heap-${pid}.hprof-XX:ExitOnOutOfMemoryError# dump 后自动退出让 K8s 重启# 方法二手动采集服务还活着时jmap-dump:formatb,live,file/tmp/heap.hprof$(pgrep-fyour-app.jar)# 方法三Arthas推荐不需要 jmapcurl-Ohttps://arthas.aliyun.com/arthas-boot.jarjava-jararthas-boot.jar# 进入 Arthas 后heapdump--live/tmp/heap.hprof选型建议与踩坑提醒方法一的-XX:ExitOnOutOfMemoryError一定要记得加否则 OOM 后服务可能还“跑着”但无法响应K8s 存活性检查也可能迟迟不重启。方法二使用jmap -dump时加上live选项只 dump 可达对象既能减小文件体积又能过滤掉许多“垃圾”对象让分析更聚焦。如果环境受限没有jmap比如使用最小化镜像方法三的 Arthas 是最佳替代品并且它支持--live过滤还能在后续诊断中直接查看堆信息。2.2 从 Heap Dump 提取摘要核心步骤这是整个 AI 排障中最关键的一环。我们不用把几个 GB 的 hprof 文件下载到本地而是在服务器上直接执行jmap -histo:live获取按空间排序的对象统计直方图。这个命令执行快、输出小但包含了最重要的信息哪些类的实例数量异常、谁占了最多堆内存。# heap_analyzer.pyimportsubprocessimportosfromopenaiimportOpenAI clientOpenAI(api_keyos.getenv(DEEPSEEK_API_KEY),base_urlhttps://api.deepseek.com)defextract_heap_summary(hprof_path:str)-str: 使用 jhat 或 jmap 提取 Heap 统计摘要 不需要下载几 GB 的 hprof 到本地 # 方法1jmap 直接在服务器输出统计resultsubprocess.run([jmap,-histo:live,f{get_java_pid()}],capture_outputTrue,textTrue,timeout60)histogramresult.stdout# 取前 50 行最大的对象类型避免 token 超限lineshistogram.strip().split(\n)headerlines[:3]top_objectslines[3:53]# 按占用空间排序的 Top-50 类型summary\n.join(headertop_objects)returnsummarydefget_java_pid()-str:resultsubprocess.run([pgrep,-f,your-app],capture_outputTrue,textTrue)returnresult.stdout.strip().split(\n)[0]为什么只取前 50 行大模型接口普遍有 token 上限即便 DeepSeek 支持的上下文比较大也要避免每次输入过长、响应变慢。Top 50 已经足够覆盖绝大多数内存泄漏场景泄漏对象通常就是排名前几、实例数对数级异常的类。潜在坑位pgrep -f your-app可能匹配到多个 Java 进程比如部署了多个微服务务必让匹配词足够精确或者改用jps命令进一步过滤。jmap -histo:live会触发一次 Full GC对线上服务有一定影响。如果服务已经濒临 OOM这可能会成为“最后一根稻草”。建议在低峰期执行或者直接用自动 dump 文件离线分析。接下来将精炼后的摘要和应用的业务背景一起喂给 AI让它像一位资深架构师那样帮你解读。defanalyze_oom(heap_summary:str,app_description:str)-str:AI 分析 Heap 摘要定位内存泄漏promptf你是一个 Java 内存泄漏专家精通 JVM 内存分析。 请分析以下 Heap Dump 统计数据找出内存泄漏的根因{f应用描述{app_description}ifapp_descriptionelse}【Heap 对象统计jmap -histo:live 输出】{heap_summary}请输出 1. **最可疑的泄漏对象**指出数量异常的类正常应用不应该有几十万个的类 2. **泄漏原因推断**基于类名推断可能的泄漏场景如 Session 未释放、缓存无限增长等 3. **排查建议**具体的代码排查方向和修复思路 4. **紧急处置**当前是否需要立即重启有没有临时缓解方案 用中文回答简洁直接面向一线工程师。responseclient.chat.completions.create(modeldeepseek-v4-pro,# OOM 分析用 Pro需要较强推理messages[{role:user,content:prompt}],temperature0.1,max_tokens2000)returnresponse.choices[0].message.contentPrompt 设计思路你可能会问为什么不让 AI 直接写代码因为在这个场景里它的价值在于“诊断”而非“编程”。我们通过要求输出结构化报告对象、原因、建议、处置把大模型的推理能力约束在一线工程师最急需的决策链条上。温度参数设为 0.1 能保证分析结果稳定不会一次说“可能是 Session 泄漏”下一次又说“可能是缓存配置错误”。2.3 典型 AI 输出示例将上述脚本串联起来后你最终会得到类似下面这样一份可直接指导操作的分析报告。注意AI 确实会给出像Caffeine或Guava Cache这类具体的修复方案而不是泛泛而谈“优化缓存”。## 内存泄漏分析报告 ### 最可疑的泄漏对象 1. com.example.session.UserSessionCache - **487,293 个实例** 正常 Web 应用同时在线 1000 用户Session 对象不应超过 5000 个 2. java.util.HashMap$Node - **2,847,291 个实例** 数量异常高很可能是被某个长生命周期 Map 持有 3. byte[] - **占用 3.2GB**远超正常水平 ### 泄漏原因推断 **高度可疑UserSessionCache 使用了 static HashMap 存储 Session** 根据类名 UserSessionCache 和超大数量推断 - 可能使用了 static MapString, UserSession cache new HashMap() - Session 只有 put没有 remove 或过期机制 - 每次登录创建新 Session旧的永不清除 ### 排查建议 1. 检查 UserSessionCache.java搜索 static Map 的字段定义 2. 确认 Session 是否有 TTL 或 LRU 淘汰机制 3. 用 Arthas 命令验证 ognl com.example.session.UserSessionCachecache.size() ### ⚡ 紧急处置 **需要立即重启**当前堆使用率 92%随时 OOM 临时方案-Xmx8g 扩大堆内存争取修复时间 根本修复使用 Caffeine 或 Guava Cache 替代手写 HashMap设置最大容量和过期时间三、CPU 飙升实战Thread Dump 分析热点方法CPU 飙升通常比 OOM 更难抓现形因为 CPU 高负载可能瞬间出现又瞬间消失。这里的经验是连抓 3 次 thread dump间隔 5 秒找出每次都出现在 RUNNABLE 且堆栈相似的线程——那就是热点的最大嫌疑人。# 方法1kill 信号最安全kill-3PID# 输出到 stdout需要重定向kill-3$(pgrep-fyour-app.jar)/tmp/thread.dump# 方法2jstack推荐jstack-lPID/tmp/thread_$(date%H%M%S).dump# 方法3连续采集CPU 高时采集 3 次找共同的热点foriin{1..3};dojstack$(pgrep-fyour-app)/tmp/thread_all.dumpecho 采集$i/tmp/thread_all.dumpsleep5done采集到 dump 后同样不要全文丢给大模型。我们只需要统计各状态线程数量并截取前 200 行堆栈通常包含了最繁忙的那几个线程就足以让模型给出定性判断。# thread_analyzer.pydefanalyze_thread_dump(dump_content:str)-str:分析 Thread Dump找出 CPU 热点和死锁# 预处理截取关键部分避免超 tokenlinesdump_content.split(\n)# 取前 200 行包含堆栈摘要和主要线程状态truncated\n.join(lines[:200])# 统计各状态线程数runnable_countdump_content.count(java.lang.Thread.State: RUNNABLE)blocked_countdump_content.count(java.lang.Thread.State: BLOCKED)waiting_countdump_content.count(java.lang.Thread.State: WAITING)timed_wait_countdump_content.count(java.lang.Thread.State: TIMED_WAITING)total_threadsrunnable_countblocked_countwaiting_counttimed_wait_count statsf 线程状态统计 - RUNNABLE{runnable_count}正在运行 - BLOCKED{blocked_count}等待锁 - WAITING{waiting_count}无限等待 - TIMED_WAITING{timed_wait_count}限时等待 - 总线程数{total_threads}为何要先统计状态分布一个健康的应用RUNNABLE 线程数通常与 CPU 核心数处于同一数量级。如果看到几百个线程同时 RUNNABLE要么是业务线程池被打满要么是存在死循环若 BLOCKED 数异常说明锁竞争严重。这些宏观指标能帮助 AI 更快定位问题类型而不是在海量堆栈里瞎猜。promptf你是一个 JVM 性能专家分析 Java Thread Dump。{stats}【Thread Dump 摘要前200行】{truncated}请分析 1. **CPU 热点**哪些线程/方法在消耗 CPURUNNABLE 状态且堆栈相似的线程 2. **死锁检测**是否存在死锁死锁线程是哪些 3. **线程池状态**业务线程池是否耗尽看 pool 相关线程数量 4. **根因判断**CPU 飙升的最可能原因 5. **处理建议**如何快速定位到具体代码行responseclient.chat.completions.create(modeldeepseek-v4-flash,messages[{role:user,content:prompt}],temperature0.1,max_tokens1500)returnresponse.choices[0].message.content模型选择技巧CPU 分析场景对推理深度要求适中但对响应速度有要求可能需要在告警后尽快给出结论因此选用deepseek-v4-flash既能保证质量又能缩短返回时间。四、死锁实战Thread Dump 死锁图谱解读jstack 输出的末尾会自动检测死锁并列出死锁线程和它们各自持有/等待的锁。这段信息是“精华中的精华”直接截取出来喂给 AI几乎可以零成本地获得一份可读性极强的死锁分析。importredefextract_deadlock_info(dump_content:str)-str:专门提取 Thread Dump 中的死锁信息# jstack 会在末尾专门输出死锁摘要deadlock_sectionifFound one Java-level deadlock:indump_content:startdump_content.index(Found one Java-level deadlock:)deadlock_sectiondump_content[start:start3000]# 截取死锁段落ifnotdeadlock_section:return未检测到死锁jstack 未报告 deadlock注意如果代码里用的是显式LockJUC 锁而不是synchronizedjstack 可能不会自动报告死锁此时就需要依靠前一步线程状态统计来预警——大量 BLOCKED 线程就是最明显的信号。promptf分析以下 Java 死锁信息{deadlock_section}请输出 1. **死锁线程**哪几个线程陷入死锁 2. **死锁资源**它们分别持有和等待哪个锁画出等待关系图 3. **代码定位**死锁发生在哪个类的哪个方法根据堆栈推断 4. **修复方案**如何打破死锁调整锁的获取顺序 / 使用 tryLock 超时 / 其他 用中文回答格式清晰。responseclient.chat.completions.create(modeldeepseek-v4-pro,messages[{role:user,content:prompt}],temperature0.1,max_tokens1500)returnresponse.choices[0].message.content为什么死锁分析仍用 Pro 模型因为死锁需要理清“线程 A 持有锁 L1 等待锁 L2线程 B 持有 L2 等待 L1”这种环路对模型的逻辑推导能力要求更高Pro 的表现比 Flash 更稳定。五、慢 SQL 实战Explain 输出 AI 索引建议数据库问题常常不在开发环境的“射程”之内直到上了生产数据量上来才爆发。从performance_schema里直接拉取最慢的 SQL再调用EXPLAIN获取执行计划就能构成一套自动化慢 SQL 分析流水线。# sql_advisor.pyimportpymysqlimportosdefget_slow_sqls(limit:int10)-list[dict]:从 MySQL 慢查询日志获取最慢的 SQLconnpymysql.connect(hostos.getenv(DB_HOST,localhost),useros.getenv(DB_USER),passwordos.getenv(DB_PASSWORD),databaseinformation_schema)withconn.cursor(pymysql.cursors.DictCursor)ascursor:cursor.execute( SELECT DIGEST_TEXT as sql_template, COUNT_STAR as exec_count, ROUND(AVG_TIMER_WAIT/1e9, 2) as avg_ms, ROUND(MAX_TIMER_WAIT/1e9, 2) as max_ms, SUM_ROWS_EXAMINED as rows_examined FROM performance_schema.events_statements_summary_by_digest WHERE SCHEMA_NAME DATABASE() AND AVG_TIMER_WAIT 1e9 -- 平均超过 1 秒 ORDER BY AVG_TIMER_WAIT DESC LIMIT %s ,(limit,))returncursor.fetchall()权限与风险提示这段代码使用information_schema和performance_schema需要数据库账号具备相应读权限。在生产环境运行EXPLAIN是安全的不会真正执行 SQL但仍建议先对 SQL 做脱敏避免敏感表结构通过 AI 外传。defget_explain(sql:str,conn)-str:获取 SQL 的 EXPLAIN 输出withconn.cursor()ascursor:cursor.execute(fEXPLAIN{sql})rowscursor.fetchall()returnstr(rows)defai_sql_advice(sql:str,explain_output:str,table_indexes:str)-str:AI 分析慢 SQL 并给出优化建议promptf你是一个 MySQL 性能优化专家。 【慢 SQL】{sql}【EXPLAIN 输出】{explain_output}{f【现有索引】{table_indexes}iftable_indexeselse}请分析并输出 1. **性能问题**指出 EXPLAIN 中的问题typeALL是全表扫描、keyNULL是无索引等 2. **优化建议** - 需要创建的索引给出完整 CREATE INDEX 语句 - SQL 改写建议如果需要 - 是否可以用覆盖索引 3. **预期效果**优化后预计执行时间 直接给出可执行的 SQL 语句不要废话。responseclient.chat.completions.create(modeldeepseek-v4-flash,messages[{role:user,content:prompt}],temperature0.1,max_tokens1200)returnresponse.choices[0].message.content实战建议AI 给出的CREATE INDEX虽然大多是合理的但绝对不要直接在生产执行。一定要让 DBA 确认数据量、索引空间开销尤其是在大表上创建索引可能带来锁表风险。六、Arthas LLM 自动化诊断流水线如果前面几步是“手动挡”那 Arthas LLM 就是“自动巡航”。通过 Arthas 的 HTTP API我们可以远程下发诊断命令、采集 profiler 数据再送给大模型完成从“发现异常”到“给出报告”的闭环。# arthas_agent.py - 结合 Arthas HTTP API 和 LLM 的自动诊断importrequestsimporttimeclassArthasLLMAgent:Arthas AI 联合诊断 Agentdef__init__(self,arthas_url:strhttp://localhost:39394):self.arthas_urlarthas_urldefexecute(self,command:str)-str:执行 Arthas 命令resprequests.post(f{self.arthas_url}/api,json{action:exec,command:command},timeout30)returnresp.json().get(body,{}).get(result,{})defdiagnose_high_cpu(self,pid:str)-str:CPU 飙升自动诊断print( 采集 CPU 热点数据...)# 使用 Arthas profiler 采集 30 秒火焰图数据self.execute(fprofiler start --duration 30)time.sleep(32)resultself.execute(profiler stop --format summary)profiler_datastr(result)[:3000]# 同时采集 thread 信息thread_infostr(self.execute(thread -n 10))# Top 10 CPU 线程promptfJava 应用 CPU 飙升Arthas 采集数据如下 【Top 10 CPU 线程】{thread_info}【Profiler 采样摘要】{profiler_data}请分析 CPU 热点指出具体方法给出优化建议。responseclient.chat.completions.create(modeldeepseek-v4-pro,messages[{role:user,content:prompt}],temperature0.1,max_tokens1500)returnresponse.choices[0].message.content踩坑记录Arthas 的 profiler 在start时必须指定--duration否则会一直跑忘停会持续消耗 CPU。profiler stop --format summary输出可能会很大这里截取前 3000 字符确保不超 token同时保留最重要的热点方法排名。defcheck_class_method(self,class_name:str,method_name:str)-str:监控指定方法的执行情况# watch 命令监控方法入参和返回值resultself.execute(fwatch{class_name}{method_name}f{{params, returnObj, throwExp}} -n 5 -x 3)returnstr(result)七、局限性说明AI 能做和不能做的排障边界AI 不是银弹把大模型引入排障流程时必须清晰地划定它的能力边界否则很容易产生“AI 说啥就是啥”的盲目信任。能力AI 能做AI 不能做Heap 分析解读对象统计推断泄漏类型分析具体对象引用链需 MATThread 分析识别死锁、分析线程状态分布确认具体代码行需对代码库了解SQL 优化解读 EXPLAIN给出索引建议理解复杂业务数据分布日志分析提取异常模式识别错误趋势替代人工判断业务影响范围黄金原则AI 给出方向人工确认细节。不要盲目执行 AI 给出的DROP INDEX、kill等危险操作。让 AI 做好“排障副驾驶”而最终踩下油门的永远是有经验的工程师。总结整个 AI 辅助 Java 排障流水线可以浓缩为下面这张图告警触发 ↓ 自动采集jmap / jstack / Arthas ↓ 数据提取堆统计摘要 / 线程状态统计 / 慢 SQL ↓ AI 分析DeepSeek V4-Pro低温度确保稳定 ↓ 报告推送钉钉 / 飞书 ↓ 人工确认 → 修复回顾三类典型场景只要记住这几个心法就够用OOM不要传原始 hprof提取jmap -histo:live统计摘要CPU 飙升连续采集 3 次 Thread Dump 找共同热点辅以 Arthas profiler 火焰图死锁jstack 末尾的 deadlock 段落就是完整答案直接喂给 AI 即可。