跳到主要内容

故事回放视图 — 看见代码运行的完整路径

这是 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()

你一眼就能看出来的事:

  1. 总耗时 245ms,但事务占了 163ms — 事务是不是太长了?
  2. 事务里有个 HTTP 调用花了 120ms — 卧槽,事务里调 HTTP?这是严重的事务风险!
  3. 有 2 条 SELECT + 1 条 UPDATE 在事务里 — 这个 UPDATE 只是更新浏览量,需要在事务里吗?
  4. 事务提交后才发 MQ — 这个是对的,不会因为 MQ 失败影响事务
  5. 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 调用清清楚楚,来龙去脉一目了然。