故事回放视图 — 看见代码运行的完整路径
这是 dlz-lens 最核心的功能,也是和其他所有工具最大的区别。
别人给你看散落的日志,我们给你回放整个故事。
一句话说清楚
一次请求 = 一个故事。
把这次请求中所有的 IO 调用(SQL / Redis / HTTP / MQ)按时间顺序排列,加上事务边界、耗时、调用者、诊断标签——你看到的不是一堆零散的记录,是一条完整的、可以回放的执行时间线。
它长什么样
这是一个订单详情接口的故事:
[GET] /api/orders/123
总耗时 245ms · 8 次调用 · 1 慢 · 0 错 · ⚠️ 事务风险
─────────────────────────────────────────────────────────────────────
0ms ┌── BEGIN 事务开始
│ ↳ OrderService.java:42 · getOrderDetail()
│
3ms │ SELECT * FROM orders WHERE id = ? 3ms
│ ↳ OrderDao.java:18 · getById()
│
7ms │ SELECT * FROM order_items WHERE order_id = ? 4ms
│ ↳ ItemDao.java:25 · listByOrderId()
│
15ms │ ┌── HTTP: GET https://user-service/api/users/456
│ │ ↳ UserClient.java:87 · getUser()
│ │
135ms │ └── ✅ 200 OK 120ms ← 这也太慢了吧?
│
140ms │ SELECT * FROM user_address WHERE user_id = ? 5ms
│ ↳ AddressDao.java:33 · getByUserId()
│
158ms │ REDIS: SET order:123:viewed = 1, TTL=3600 2ms
│ ↳ OrderService.java:78 · incViewCount()
│
160ms │ UPDATE orders SET view_count = view_count + 1 WHERE id = ? 3ms
│ ↳ OrderDao.java:45 · incViewCount()
│
163ms └── COMMIT 事务提交
↳ OrderService.java:42 · getOrderDetail()
165ms MQ: send topic=order-viewed, key=123 2ms
↳ OrderEvent.java:45 · publishViewed()
你一眼就能看出来的事:
- 总耗时 245ms,但事务占了 163ms — 事务是不是太长了?
- 事务里有个 HTTP 调用花了 120ms — 卧槽,事务里调 HTTP?这是严重的事务风险!
- 有 2 条 SELECT + 1 条 UPDATE 在事务里 — 这个 UPDATE 只是更新浏览量,需要在事务里吗?
- 事务提交后才发 MQ — 这个是对的,不会因为 MQ 失败影响事务
- HTTP 调用 120ms 是最大瓶颈 — 要优化先优化这个
想想看,如果没有故事回放,你要花多久才能搞清楚上面这些信息?
查日志、搜代码、打断点、加日志、重跑……至少半小时起步。
现在?10 秒。
你能从故事里看到什么
🕐 时间线:精确到毫秒的执行顺序
所有调用按真实执行顺序排列,每个调用的开始时间和耗时都精确到毫秒。你能清楚地看到:
- 哪步先执行,哪步后执行
- 每步花了多久
- 哪些是串行的,哪些是并行的(未来支持)
- 总时间花在了哪里
🔐 事务边界:事务范围清清楚楚
BEGIN 和 COMMIT/ROLLBACK 用竖线包裹,事务里有哪些调用一目了然。
一眼就能发现的事务问题:
| 问题 | 表现 | 风险 |
|---|---|---|
| 事务过大 | 事务包裹了很多调用,持续时间长 | 锁持有时间长,并发性能差 |
| 事务里有 HTTP | 事务竖线里出现了 HTTP 调用 | 严重风险!网络IO持有数据库连接和锁 |
| 事务里有 N+1 | 事务里循环查同一张表 | 事务被 N+1 拖长 |
| 嵌套事务 | 多层 BEGIN/COMMIT | 可能是 REQUIRES_NEW 使用不当 |
| 事务回滚 | 以 ROLLBACK 结束 | 需要关注为什么回滚 |
📊 多类型同屏:SQL / Redis / HTTP / MQ 在一起
这是 dlz-lens 和其他工具最大的区别之一——所有类型的 IO 调用在同一条时间线上。
你再也不用:
- 在 SQL 日志里找"这个 Redis 是哪里调的"
- 在 HTTP 日志里猜"之前查了哪些数据"
- 脑补"这个 MQ 消息是在事务里发的还是事务外发的"
所有东西都在一条时间线上,前后关系清清楚楚。
🏷️ 诊断标签:问题自动标出来
故事不是冷冰冰的记录,dlz-lens 会自动分析并标记问题:
| 标签 | 颜色 | 含义 |
|---|---|---|
| 🟠 慢 | 橙色 | 有调用超过了慢阈值 |
| 🟣 N+1 | 紫色 | 同类型调用重复出现超过阈值 |
| 🔴 错 | 红色 | 有调用执行失败 |
| ⚠️ 事务风险 | 黄色 | 事务里有 HTTP 调用、事务过大等 |
有问题的故事会在列表里用对应颜色高亮,一眼就能挑出来。
👆 点哪跳哪:从故事直达代码行
时间线上的每一次调用都带着调用者信息(类名 + 方法名 + 行号)。点一下,直接跳转到 IDEA 里对应的那行代码。
看到事务里有 HTTP 调用?点一下直接跳到那行代码,马上就能改。
故事列表怎么用
控制台的"故事回放"Tab 左侧是故事列表,右侧是选中故事的时间线。
列表里有什么
📋 最近请求
─────────────────────────────────────────────
🔴 [POST] /api/orders 500 842ms 12次 2错
🟠 [GET] /api/orders/123 200 245ms 8次 1慢 ⚠️
🟣 [GET] /api/users/list 200 320ms 26次 N+1
🟢 [GET] /api/products/456 200 18ms 3次
🟢 [POST] /api/cart/add 200 45ms 5次
...
每个故事显示:
- 状态码颜色:绿=2xx,黄=3xx/4xx,红=5xx
- 请求方法 + URL
- 响应状态码
- 总耗时
- 调用次数
- 诊断标签:慢 / N+1 / 错误 / 事务风险
筛选和搜索
- 按状态码筛选:只看 500 错误的请求
- 按标签筛选:只看有 N+1 的、只看有慢调用的
- 按 URL 搜索:输入接口路径模糊匹配
- 按时间倒序:最新的在最上面
一个真实的排障场景
问题:订单列表接口突然变慢了
以前(没有 dlz-lens)
1. 接到反馈:订单列表慢
2. 看监控,发现接口平均耗时从 200ms 涨到 800ms
3. 查日志,一堆 SQL 日志,不知道哪条是哪个请求的
4. 加 traceId 日志,重新发布
5. 再查,发现每个请求执行了 30 多条 SQL
6. 猜:是不是哪里 N+1 了?
7. 搜代码,找可能的循环位置
8. 加更多日志,看循环里查了什么
9. 再发布,再验证
10. 终于定位到:OrderService 里循环查询商品信息
11. 修复,改批量查询
—— 半天到一天过去了
现在(有 dlz-lens)
1. 打开 dlz-lens → 故事回放
2. 找到一个慢的订单列表请求,点进去
3. 时间线上一眼看到:循环里执行了 20 次 SELECT product
4. 紫色 N+1 标签清清楚楚标在那里
5. 点一下调用者 → 直接跳到 OrderService.java:87 那行
6. 修复,改批量查询
—— 5 分钟搞定
这就是故事回放的力量。它把"排障"从一个需要经验和猜测的技术活,变成了一个看图说话的简单事。
还能怎么用
新人入职第一天
"你去把订单创建流程搞懂。"
以前:看代码、看文档、问同事,两三天才能搞清楚。
现在:跑一遍订单创建接口,看故事回放——10 分钟就知道整个流程查了哪些表、改了哪些数据、调了哪些服务、发了哪些消息。
Code Review 时
以前:看 PR 只能看代码逻辑,不知道实际执行了多少次 SQL、有没有隐式 N+1。
现在:把 PR 里的接口都跑一遍,看故事回放——
- 有没有意料之外的 SQL?
- 事务范围合不合理?
- 有没有 N+1?
- 是不是在事务里调了 HTTP?
比纯看代码靠谱多了。
性能优化时
以前:"这个接口慢,优化一下。" 然后你不知道慢在哪,只能瞎猜、瞎加索引。
现在:看故事回放——
- 是某条 SQL 特别慢?→ 加索引 / 优化 SQL
- 是 N+1 导致 SQL 太多?→ 改批量查询
- 是 Redis 慢?→ 查 Redis 问题
- 是下游 HTTP 慢?→ 找下游团队 / 加缓存
精准定位,不做无用功。
💡 这就是为什么叫 "lens"(透镜)。
以前你看代码运行,是隔着毛玻璃——模糊、零散、看不清。
有了 dlz-lens,你相当于拿了一个高清透镜——所有 IO 调用清清楚楚,来龙去脉一目了然。