avatar

Ryan's Blog

The first step is always the hardest.

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于
  • 工具
Home Zipkin 依赖关系图不显示数据排查:zipkin-dependencies、存储配置与定时计算
文章

Zipkin 依赖关系图不显示数据排查:zipkin-dependencies、存储配置与定时计算

Posted 2021-12-22 Updated 8 days ago
By Ryan Chen
22~28 min read

前言

最近在使用 Zipkin 排查链路问题时,遇到一个容易误判的现象:Trace 查询页面可以看到调用链,但 Dependencies 依赖关系图一直没有数据。

image.png

这个问题通常不是 Zipkin UI 坏了,也不一定是 Span 没有上报,而是因为 Zipkin 的 Trace 数据和 Dependencies 依赖关系数据不是同一类数据。Trace 页面展示的是原始 Span;Dependencies 页面展示的是经过聚合计算后的服务依赖边。如果没有运行依赖计算任务,依赖页面就可能为空。

为什么 Trace 有数据,但 Dependencies 为空

Zipkin 的核心流程可以简单理解为:

  1. 应用通过 Zipkin 客户端或 OpenTelemetry Collector 上报 Span。
  2. Zipkin Server 接收 Span,并写入后端存储,例如 Elasticsearch、MySQL、Cassandra 等。
  3. Trace 查询页面直接读取 Span 数据。
  4. Dependencies 页面读取的是另外生成的服务依赖数据。

因此,Trace 页面能查到链路,只能说明 Span 已经写入成功;Dependencies 页面为空,则通常说明依赖关系还没有被计算,或者计算任务读到的存储、索引、时间窗口不对。

Zipkin 依赖关系图是怎么生成的

Zipkin 依赖图依赖 zipkin-dependencies 任务生成。它会读取指定时间窗口内的 Span 数据,分析服务之间的 client/server 调用关系,然后把聚合后的依赖边写回存储中。

以 Elasticsearch 为例,常见过程是:

  1. 从 zipkin-span-* 这类 Span 索引中读取数据。
  2. 根据 Span 中的 service name、kind、traceId、parentId 等信息计算调用关系。
  3. 将结果写入 zipkin-dependency-* 这类依赖索引。
  4. 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

说明任务虽然执行完成,但当前时间窗口内没有计算出有效的服务依赖关系。

image.png

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 更容易定位问题。

参考资料

  • Zipkin 官网
  • Zipkin Architecture
  • openzipkin/zipkin-dependencies
  • Zipkin Docker 配置说明
  • Zipkin Elasticsearch Storage
指南
Zipkin 链路追踪 分布式追踪 zipkin-dependencies Elasticsearch OpenSearch 问题排查 可观测性
License:  CC BY 4.0
Share

Further Reading

Jun 27, 2026

Agent 架构设计原则:Router、Runtime 与 Business Script 的职责划分

本文整理一套适合 Router Agent + Skill + Runtime 架构的设计原则:Agent 只负责业务决策,Runtime 统一负责执行、恢复、Trace、Checkpoint 和 Evidence,Business Script 只做确定性业务执行。

Sep 9, 2024

Redis 核心概念、数据结构与高可用架构详解

系统梳理 Redis 的核心数据类型、底层结构、过期与淘汰、持久化、事务、主从复制、Sentinel、Cluster、缓存一致性和分布式锁等机制,适合作为 Redis 学习、面试复习和高可用架构设计参考。

Sep 5, 2024

B+树原理与 MySQL InnoDB 索引机制解析

本文从 B+ 树的多叉平衡结构、叶子节点链表、范围查询和磁盘 I/O 特性出发,解释数据库索引为什么常采用 B+ 树,并结合 MySQL InnoDB 的聚簇索引、二级索引、回表、覆盖索引和联合索引机制理解其实际应用。

OLDER

GitLab Docker 部署与 Personal Access Token 配置指南

NEWER

KMS 服务搭建指南:Windows 与 Office 激活配置

Recently Updated

  • Agent 架构设计原则:Router、Runtime 与 Business Script 的职责划分
  • RocketMQ 架构设计与应用最佳实践:高可用消息队列核心解析
  • Redis 核心概念、数据结构与高可用架构详解
  • B+树原理与 MySQL InnoDB 索引机制解析
  • MySQL AUTO_INCREMENT 插入 0 变成自增值的原因与解决方案

Trending Tags

RocketMQ Windows Feign Docker Zipkin SonarQube OkHttp HttpClient API 性能优化

Contents

©2026 Ryan's Blog. Some rights reserved. · 粤ICP备2022031588号