调试后端系统时,我常遇到这种困惑:请求慢是因为数据库卡了,下游服务拖了后腿,还是内部循环发了60条查询去取60条记录?日志只写 duration_ms=340 和 status=200。然后你开始猜。
这次实验不是为了测 OpenTelemetry 开销,也不是对比 Jaeger 和 Tempo。只想回答一个具体问题:只有日志时你漏掉了什么信号,加上链路追踪后又能看见什么?
![]()
代码仓库在 github.com/JuanTorchia/opentelemetry-spring-boot-lab,commit c12ea4e,tag editorial-final-diagnosis-comparison-v2。
技术栈是 Spring Boot 3.5.7、Java 21、PostgreSQL 16、OpenTelemetry API 1.43.0、OpenTelemetry Java Agent 2.9.0,Jaeger all-in-one。全部用 Docker Compose 启动。跑实验只需一条命令:
.\scripts\run-lab.ps1 -Mode editorial -Size editorial -Runs 3 -Requests 200 -Warmup 20 -Concurrency 8
脚本会启动容器、下载探针、打包 jar、往 Postgres 灌入合成数据(organizations、users、projects、tasks、comments 表)、执行场景、按 traceId 查 Jaeger、最后在 results/ 生成报告。
选 Jaeger 是因为本地简单:一个镜像、自带 Web UI、有 REST API 可按 traceId 查链路。Tempo 也行,但本地演示需要更多组件。这不是生产环境推荐方案。
数据集分两种:editorial 是 5 万条任务,small 是 1 千条。这个差距很重要——要让 N+1 问题产生可见的扇出,而不是微秒级差距被噪声淹没。
关键的埋点决策:pom.xml 里 opentelemetry-api 是编译依赖,但探针是运行时注入。HTTP 服务端、HTTP 客户端、JDBC 全部自动埋点,业务代码零侵入。
只有探针推不出来的业务阶段才用手动 span:
// LabService.java — 手动标记业务意图
Span span = tracer.spanBuilder("business.n_plus_one.load_tasks_then_comments").startSpan();
try (var ignored = span.makeCurrent()) {
// 先拉任务列表,再每条任务查一次评论数
List> tasks = jdbcTemplate.queryForList(...);
for (Map task : tasks) {
// 这条查询循环执行 → 扇出
Integer comments = jdbcTemplate.queryForObject(...);
日志告诉你"成功了",链路告诉你"怎么成功的"。这就是实验要验证的。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.