第 5 章:一段 Redis span 变长,究竟证明了什么
假设同一条请求中,Redis span 从几毫秒变成几百毫秒。最容易说出口的结论是“Redis 变慢了”,但这个 span 通常从客户端调用前开始,到客户端获得结果后结束。连接池等待、应用线程调度、序列化、网络和服务端执行,都可能落在这个区间里。
5.1 把观察点说清楚
订单服务创建 redis SET order client span,然后调用 Jedis 的真实 SETEX。实验通过 redis_delay_ms 在该 span 内、实际 Redis 命令之前等待。这个设计故意制造一种很像缓存依赖变慢的 trace,却让我们知道真正的等待发生在应用侧。
{"id":"redis-slow","redis_delay_ms":350}输入范围限制在 0—1500 毫秒,避免实验参数变成无限休眠工具。运行产物中 trace-redis-slow.json 保存原始 trace;results.json 还记录该 client span 的实际持续时间。验收只要求注入 350 毫秒时观察区间至少覆盖其中大部分,不会断言整个请求恰好耗时 350 毫秒。CI 调度、消息发布和导出都可能带来额外时间。
5.2 对比比绝对数字更有用
先执行 normal,再执行 redis-slow。比较时保持路由、业务数据规模和消息处理方式基本一致,只改变等待参数。若 Redis client 区间显著变长,而 RocketMQ 发布区间没有同样增长,故障范围就比“一切都慢”小得多。
但这仍然只是客户端视角。要进一步断言服务端执行变慢,需要结合 Redis 命令统计、慢日志或服务器资源。本书没有把这些证据放进自动验收,所以结论应停在“客户端包围的这段工作变慢,且实验注入位于该范围”。这不是保守措辞的游戏,而是避免下一步错误地给 Redis 扩容。
反方向也值得练习:如果网关慢、订单 server span 慢,但 Redis 与发布区间都短,说明存在未被这些子 span 解释的时间。可能是线程等待,也可能是没有仪表化的业务计算。不要为了使图形看起来完整,直接把空白区间归到最近的依赖头上。
5.3 业务标识与缓存键的边界
示例使用 otelbook:order:<id>,TTL 为一小时,消费者结果另写 otelbook:processed:<id>。这些键便于读者独立核查状态,也保证实验不需要清空整个 Redis。GET 订单入口会产生自己的 HTTP trace 与 Redis GET span,不能假定它继承创建请求的 trace;它们通过订单号关联的是同一业务对象,不是同一次执行。
本实验没有展示缓存命中率优化,也没有模拟 Redis 集群故障。JedisPooled 提供连接管理,我们手工创建的 span 只包围明确代码范围,不等于自动观测了内部每次连接重试。接入自动仪表化时,需要避免同一命令同时被手工和 agent 重复包围,造成重复计数或混淆。
练习。 列出 Redis client span 内可能发生的四类等待。选其中两类,分别说明能补充什么独立证据;再说明为什么把 redis_delay_ms 实验结果写成“Redis 服务端延迟测试”是不准确的。
客户端接口和生命周期可对照 Redis 官方 Jedis 文档。