主题
界面
主题
做过 ≠ 会做 —— 只有把「一次排查/优化」沉淀成可检索、可复用的卡片,经验才真正属于你。
★ 本节用工具把三个真实案例(全部来自本知识库的实测)固化成解决方案卡 ✓✓:
卡片 1:内存持续增长直到 OOM —— 先用存活量趋势定性,再定位泄漏点
卡片 2:接口偶发卡顿 —— 先看线程栈与死锁,再谈优化
卡片 3:秒杀超卖 —— 先挡流量,再谈一致性
每张卡:现象 / 影响面 / 排查过程 / 根因 / 方案 / 验证 / 适用边界 / 复盘(八字段)✓✓✓★ 工具:python -X utf8 scripts/growth/solution_card.py ✓
★ 两种知识流失 ✗✗:
| 流失 | 后果 |
|---|---|
| 个人:排查完就忘 ✗✗ | 三个月后遇到同类问题,又从头查一遍 |
| 团队:经验在人脑里 ✗✗✗ | 换个人就"没人知道怎么搞" |
★★ 沉淀的价值 ✓✓✓:把「一次性经验」变成「团队可检索的条目」 —— 下次遇到类似现象:先搜卡片,再动手(平均定位时间可以减半)✓✓。
| 字段 | 回答的问题 | 为什么必须有 |
|---|---|---|
| 现象 | 观察到什么(含曲线/报错) | 检索入口 ✓✓ |
| 影响面 | 稳定性 / 正确性?谁受影响 | 定级与上报 ✓ |
| 排查过程 | 一条条命令与结论 | 可复现的路径 ✓✓✓ |
| 根因 | 一句话说透 | 决定方案是否治本 ✓✓✓ |
| 方案 | 改了什么(代码/配置) | 可执行 ✓ |
| 验证 | 怎么证明修好了 | 防"感觉修好了" ✓✓ |
| 适用边界 | 什么情况不适用 | 防误用 ✓✓✓ |
| 复盘 | 一句话教训 | 组织记忆 ✓ |
★ 实测卡 1(节选) ✓✓✓:
现象:服务运行数小时后 OOM(Java heap space);堆使用曲线只涨不跌;重启后复现
排查过程:
· 开启 -Xlog:gc*:file=,观察每次 GC 后的存活量(不是使用量)
· 发现:存活量 61M → 63M 反复顶住 64M 上限,Full GC(G1 Compaction Pause)5 次
· 结论:对象「回收不掉」,不是「分配太快」
根因:缓存没有上限与淘汰策略:**存活对象永远不会被任何收集器释放**
适用边界:适用「存活量单调上涨」;若存活量平稳但停顿长,是另一类问题(调收集器/堆)· 定性先行:先用指标把问题分类(泄漏 / 锁 / 过载),再选工具 ✓✓
· 双重验证:一手日志(GC 日志、线程栈)+ 最小复现,缺一不可 ✓✓✓
· 改完必验:用同一流量回归,给出前后对比数字 ✓✓
· 沉淀边界:写清「什么情况不适用」,避免下次误用 ✓✓✓★★ 模式的用法 ✓✓:新问题先匹配模式("这像不像卡片 3 的过载型?")—— 匹配错了再换方向,比盲目试工具快得多 ✓✓✓。
| 解决方案卡 | ADR(架构决策记录) | |
|---|---|---|
| 回答 | "这类问题怎么解" | "当初为什么这么决策" ✓ |
| 触发 | 一次排查/优化完成后 | 一个决策做出时 ✓ |
| 结构 | 八字段(现象 → 复盘) | 背景 / 决策 / 备选方案 / 后果 / 状态 ✓ |
| 例子 | "存活量上涨 = 代码问题" | "为什么锁定 JDK 21 而不是 17"✓ |
| 复用场景 | 排障(搜索现象) | 评审(解释历史)✓✓ |
★ ADR 的最小格式 ✓✓:一段背景 + 一个决策 + 至少两个备选与淘汰理由 + 后果(含代价) —— 「为什么不选另一个」是 ADR 的灵魂 ✓(与 《系统设计题》 的面试答题同源)。
| 时机 | 动作 |
|---|---|
| 排查结束 24 小时内 ✓✓ | 趁记忆鲜活写卡片(复用 《模拟面试与面试复盘》 的复盘习惯) |
| 决策做出时 ✓ | 当场写 ADR(一段即可,别追求仪式感) |
| 每季度 ✓ | 翻一遍卡片库,把重复出现的模式提炼成"清单" |
★ 渠道 ✓:团队 wiki(共享)+ 个人笔记(私有补充)—— 两处都要有 ✓✓。
① 现象一句话(含关键数字:64M / Full GC 5 次 / OOM)
② 排查过程按时间线列命令与结论(3-5 条)
③ 根因一句话 + 方案一句话
④ 验证方式(同流量回归 + 观察指标)
⑤ **边界与复盘**(最容易被省略、但最有价值)✓✓✓背景:GC 默认 G1、堆 128M 的场景下 Serial 停顿更短(实测 0.591ms vs 1.590ms)
决策:小堆服务显式指定 -XX:+UseSerialGC
备选:G1(默认,但小堆不占优)✗;Parallel(吞吐优先,延迟不敏感场景可选)
后果:单次停顿更短;代价是**大堆场景必须换回 G1**(边界写明)✓✓"2026-09-23 处理了一个 OOM,重启后好了" ✗✗(没有根因、没有验证、没有边界)
—— 这种记录三个月后等于没有 ✓✓工具:scripts/growth/solution_card.py
运行:
python -X utf8 scripts/growth/solution_card.py实测输出(节选):
--- 卡片 2:接口偶发卡顿:先看线程栈与死锁,再谈优化 ---
现象:部分请求卡住不返回;CPU 不高但吞吐下降;重启后缓解、过一阵复发
排查过程:
· jcmd <pid> Thread.print(或 Arthas thread -b)找阻塞关系
· 发现两个线程互相等待对方持有的锁(Found one Java-level deadlock)
根因:**锁顺序不一致**:不同代码路径以不同顺序获取同一组锁
适用边界:只解决「锁顺序」型死锁;线程池耗尽、下游超时不属于此类| # | 错误 | 说明 |
|---|---|---|
| 1 | 只记结论不记过程 ✗✗ | 无法复现,也教不会别人 ✓✓ |
| 2 | 不写适用边界 ✗✗✗ | 下次可能误用到不适用的场景 ✓✓ |
| 3 | 写完不验证 ✗✗ | "感觉修好了"是最贵的错觉 ✓✓ |
| 4 | 拖到月底补记 ✗ | 细节全忘 ✓ |
| 5 | ADR 写成流程文档 ✗ | ADR 只讲「选什么 + 为什么不选另一个」✓✓ |
| 6 | 只存个人笔记 ✗ | 团队检索不到 = 没沉淀 ✓ |
solution_card.py,读懂八字段 ✓✓;验收方式:产出一张八字段齐全(尤其边界与验证)的解决方案卡,且同事能照它复现排查路径。
扩展任务:把本知识库 S6 的实测整理成一本《线上问题排查手册》(按现象索引)✓✓
《团队分享与知识输出》 团队分享与知识输出 —— 把沉淀的卡片讲出去,形成团队资产。
无,可直接开始
暂无