Zipkin 依赖关系图不显示数据排查:zipkin-dependencies、存储配置与定时计算
前言
最近在使用 Zipkin 排查链路问题时,遇到一个容易误判的现象:Trace 查询页面可以看到调用链,但 Dependencies 依赖关系图一直没有数据。

这个问题通常不是 Zipkin UI 坏了,也不一定是 Span 没有上报,而是因为 Zipkin 的 Trace 数据和 Dependencies 依赖关系数据不是同一类数据。Trace 页面展示的是原始 Span;Dependencies 页面展示的是经过聚合计算后的服务依赖边。如果没有运行依赖计算任务,依赖页面就可能为空。
为什么 Trace 有数据,但 Dependencies 为空
Zipkin 的核心流程可以简单理解为:
- 应用通过 Zipkin 客户端或 OpenTelemetry Collector 上报 Span。
- Zipkin Server 接收 Span,并写入后端存储,例如 Elasticsearch、MySQL、Cassandra 等。
- Trace 查询页面直接读取 Span 数据。
- Dependencies 页面读取的是另外生成的服务依赖数据。
因此,Trace 页面能查到链路,只能说明 Span 已经写入成功;Dependencies 页面为空,则通常说明依赖关系还没有被计算,或者计算任务读到的存储、索引、时间窗口不对。
Zipkin 依赖关系图是怎么生成的
Zipkin 依赖图依赖 zipkin-dependencies 任务生成。它会读取指定时间窗口内的 Span 数据,分析服务之间的 client/server 调用关系,然后把聚合后的依赖边写回存储中。
以 Elasticsearch 为例,常见过程是:
- 从
zipkin-span-*这类 Span 索引中读取数据。 - 根据 Span 中的 service name、kind、traceId、parentId 等信息计算调用关系。
- 将结果写入
zipkin-dependency-*这类依赖索引。 - Zipkin UI 的 Dependencies 页面再读取这些依赖结果。
也就是说,Dependencies 页面不是实时从 Span 中临时算出来的,而是依赖一个额外的批处理计算结果。
下载 zipkin-dependencies
测试环境可以使用官方 quickstart 脚本下载最新版本:
curl -sSL https://zipkin.io/quickstart.sh | bash -s io.zipkin.dependencies:zipkin-dependencies:LATEST zipkin-dependencies.jar
生产环境不建议长期使用 LATEST,更推荐固定版本号,避免因为依赖包升级导致行为变化。例如:
curl -sSL https://zipkin.io/quickstart.sh | bash -s io.zipkin.dependencies:zipkin-dependencies:3.5.0 zipkin-dependencies.jar
实际版本请以 zipkin-dependencies 官方仓库发布版本为准。
使用 Elasticsearch / OpenSearch 存储时执行
如果 Zipkin Server 使用 Elasticsearch 作为存储,执行依赖计算时必须让 zipkin-dependencies 指向同一个 Elasticsearch 集群。
STORAGE_TYPE=elasticsearch \
ES_HOSTS=http://127.0.0.1:9200 \
java -jar zipkin-dependencies.jar
如果你的 Zipkin Server 连接的是多个 Elasticsearch 节点,也要保持一致:
STORAGE_TYPE=elasticsearch \
ES_HOSTS=http://es01:9200,http://es02:9200,http://es03:9200 \
java -jar zipkin-dependencies.jar
如果存储端是 OpenSearch,需要确认当前 Zipkin / zipkin-dependencies 版本对 OpenSearch 或 Elasticsearch 兼容接口的支持情况。排查时重点看两点:
- Zipkin Server 写入 Span 的存储地址;
zipkin-dependencies读取 Span 的存储地址。
两者不一致时,Trace 页面和 Dependencies 页面就会表现不一致。
使用 MySQL 存储时执行
如果 Zipkin 使用 MySQL 存储,需要使用 MySQL 相关环境变量:
STORAGE_TYPE=mysql \
MYSQL_HOST=127.0.0.1 \
MYSQL_TCP_PORT=3306 \
MYSQL_DB=zipkin \
MYSQL_USER=zipkin \
MYSQL_PASS='your_password' \
java -jar zipkin-dependencies.jar
MySQL 场景下重点确认:
- Zipkin Server 和计算任务连接的是同一个库;
- 用户具备读取 Span 表和写入依赖结果的权限;
- 数据库时区和任务执行时间窗口符合预期。
使用 Cassandra 存储时执行
如果 Zipkin 使用 Cassandra 作为存储,可以按下面方式执行:
STORAGE_TYPE=cassandra3 \
CASSANDRA_CONTACT_POINTS=127.0.0.1 \
CASSANDRA_KEYSPACE=zipkin \
java -jar zipkin-dependencies.jar
如果 Cassandra 开启了认证,再补充用户名和密码:
STORAGE_TYPE=cassandra3 \
CASSANDRA_CONTACT_POINTS=127.0.0.1 \
CASSANDRA_KEYSPACE=zipkin \
CASSANDRA_USERNAME=user \
CASSANDRA_PASSWORD=pass \
java -jar zipkin-dependencies.jar
如何判断任务是否执行成功
执行后可以关注日志中的几个关键点:
INFO ElasticsearchDependenciesJob: Processing spans from zipkin-span-2021-12-21
INFO ElasticsearchDependenciesJob: Saving dependency links to zipkin-dependency-2021-12-21
INFO ElasticsearchDependenciesJob: Done
当看到 Saving dependency links 和 Done 时,说明任务已经完成并尝试保存依赖关系。
但是要注意,Done 只代表任务结束,不一定代表一定生成了依赖数据。如果日志中出现下面内容:
No dependency links could be processed from spans
说明任务虽然执行完成,但当前时间窗口内没有计算出有效的服务依赖关系。

Done 之后页面仍然为空,重点排查什么
如果任务执行完成,但 Zipkin UI 的 Dependencies 页面仍然没有数据,可以按下面顺序排查。
1. 时间窗口是否正确
zipkin-dependencies 是按日期窗口计算依赖关系的。实际排查时,经常出现“任务算的是昨天的数据,但 UI 查的是今天”或者“本地时区和 UTC 日期不一致”的问题。
建议排查:
- Span 实际写入的日期;
- 任务执行时的日期窗口;
- Zipkin UI Dependencies 页面选择的日期范围;
- 服务器时区与 UTC 日期差异。
如果你在北京时间凌晨执行任务,尤其要注意 UTC 日期可能还处在前一天。
2. Zipkin Server 和计算任务是否连接同一套存储
这是最常见的问题之一。比如:
- Zipkin Server 写入的是
http://es-prod:9200; zipkin-dependencies连接的是http://localhost:9200;- 或者两者使用了不同的 index prefix。
这种情况下,Trace 页面可能有数据,但依赖计算任务读不到 Span,自然不会生成依赖图。
3. Span 是否具备可计算的调用关系
依赖图依赖服务之间的调用关系。如果 Span 中缺少服务名,或者只有单服务内部 Span,可能无法生成跨服务依赖边。
建议确认:
- 是否存在两个或多个服务之间的调用;
- Span 中的
localServiceName是否正确; - client/server Span 是否成对出现;
- 采样率是否过低,导致关键调用链没有被采集。
4. 存储中是否已经生成依赖结果
以 Elasticsearch 为例,可以检查是否有 dependency 索引:
curl http://127.0.0.1:9200/_cat/indices '*dependency*'\?v
如果没有类似 zipkin-dependency-YYYY-MM-DD 的索引,说明计算结果没有写入成功;如果有索引但 UI 仍为空,则继续检查日期范围、Zipkin Server 存储配置和索引前缀。
配置定时任务
依赖关系通常不需要实时计算,可以每天定时跑一次。例如把执行脚本放到:
/opt/zipkin/calc-zipkin-dependencies.sh
脚本示例:
#!/usr/bin/env bash
set -euo pipefail
cd /opt/zipkin
STORAGE_TYPE=elasticsearch \
ES_HOSTS=http://127.0.0.1:9200 \
java -jar zipkin-dependencies.jar
授予执行权限:
chmod +x /opt/zipkin/calc-zipkin-dependencies.sh
mkdir -p /opt/zipkin/logs
如果编辑的是 /etc/crontab,需要包含执行用户字段:
0 0 * * * root /opt/zipkin/calc-zipkin-dependencies.sh >> /opt/zipkin/logs/zipkin-dependencies.log 2>&1
如果使用 crontab -e,则不需要用户字段:
0 0 * * * /opt/zipkin/calc-zipkin-dependencies.sh >> /opt/zipkin/logs/zipkin-dependencies.log 2>&1
原来容易写错的地方是把 /etc/crontab 写成六段时间表达式,或者漏掉 root 这个用户字段。Linux cron 中 /etc/crontab 和用户 crontab 的格式是不一样的。
快速排查清单
如果 Zipkin Dependencies 页面为空,可以按下面清单快速过一遍:
| 检查项 | 说明 |
|---|---|
| Trace 页面是否有数据 | 有数据只能说明 Span 写入正常,不代表依赖图已生成 |
是否执行了 zipkin-dependencies |
Dependencies 页面依赖离线计算结果 |
| 存储配置是否一致 | Zipkin Server 与计算任务必须读取同一套存储 |
| 日期窗口是否正确 | 注意 UI 查询日期、任务计算日期和 UTC 日期差异 |
| 是否生成 dependency 索引或表 | Elasticsearch 可检查 *dependency* 索引 |
| Span 是否有跨服务调用 | 单服务 Span 或缺少 client/server 关系可能无法生成依赖边 |
日志是否只有 Done |
Done 不等于一定有依赖数据,要看是否保存了 dependency links |
| cron 是否正确 | /etc/crontab 需要用户字段,crontab -e 不需要 |
总结
Zipkin Dependencies 页面为空时,排查重点不是 UI,而是依赖关系是否被计算出来。最核心的判断逻辑是:
- Trace 页面读取的是原始 Span;
- Dependencies 页面读取的是依赖计算结果;
zipkin-dependencies必须连接到和 Zipkin Server 一致的存储;- 执行日期窗口、时区、服务名和 Span 结构都会影响最终结果。
因此,处理这类问题时,建议先确认 Span 数据,再运行 zipkin-dependencies,最后检查 dependency 索引或表是否生成。这样比单纯刷新 UI 更容易定位问题。