分布式调用链存储架构对比:Jaeger、Tempo、SkyWalking 与商业方案
调用链(Distributed Tracing)存储是可观测性体系中技术分歧最大的领域之一。不同于时序和日志有相对收敛的存储模式(TSDB 与 ClickHouse-like),调用链系统的存储方案因索引策略的根本分歧而分化为三条路径。
本章逐一分析 Jaeger、Grafana Tempo、Apache SkyWalking、Zipkin 以及 Datadog/Splunk 商业方案的存储架构,最后进行横向对比。
新手类比:调用链就像快递物流追踪——每个包裹(请求)经过每个分拣中心(服务)都会产生一条签收记录(span),快递单号(trace_id)把所有记录串在一起。查一下单号,就能看到包裹从发货到签收的完整路径。
区别在于:调用链的 “快递单号” 是 128 位的 trace_id,每个服务还会加上自己的 “内部工单号”(span_id)。下方动画展示 trace 上下文如何在服务间传播:
动画说明:上方动画循环展示一个请求从 Gateway 穿透到 Database 的全过程。每个节点收到请求后,保持相同的 trace_id(快递单号不变),但生成新的 span_id(自己的签收记录)。traceparent 请求头携带这些信息在服务间传递。所有 span 收集后,通过 parent_span_id 串联成完整的调用链树——实现端到端请求可视化。
Jaeger
Jaeger 是 CNCF 毕业项目,Uber 开源,作为 OpenTelemetry 的参考实现之一,在调用链领域有着广泛影响力。
Span/Trace 数据模型
Jaeger 的 TraceID 在数据模型层是 16 字节序列,有多种表示形式[J2]:UI 层 hex 字符串(128 位时 32 字符)、Go domain model 一对无符号 64 位整数(big-endian)、Protobuf model byte 序列。
Span 模型包含:traceId、spanId、parentSpanId、operationName、startTime、duration、tags、logs、process(service/tags)、references(follows-from / child-of)[J4]。
底层存储结构与索引设计
Jaeger 后端的核心权衡体现在两条路径[J2]:
Cassandra 路径(KV 存储 + 客户端索引):单条 span 写入本身快,但 Jaeger 必须在 KV 之上自行实现搜索能力 → 写放大严重:除写 span 本身一条记录外,还要为 service name、operation name 各写一条索引,并且 每个 tag 都要额外写一条索引。
Elasticsearch/OpenSearch 路径(倒排索引):写一条 span 即一次写,所有索引在 ES 节点内部完成。搜索能力强、结果一致、可被 Kibana 直接查询做聚合分析。
官方明确推荐 ES/OpenSearch 优于 Cassandra,理由即上述搜索能力与写放大[J2]。
支持的存储后端[J1][J3]:Cassandra 4.x/5.x、Elasticsearch 7.x/8.x、OpenSearch 1.0+、ClickHouse(经 Remote Storage API 认证)、Badger(嵌入式)、memory(测试)、Kafka(仅作缓冲)。
采样机制(核心特色)
Jaeger 客户端实现一致性的头采样(upfront/head-based):根服务做决策并随请求传播,保证整条 trace 的 spans 要么全采要么全不采[J6]。
客户端采样器类型[J6]:const(全采/全不采)、probabilistic(概率,默认 0.001 = 0.1%)、ratelimiting(漏桶)、remote(默认,向 agent/collector 拉取策略)。
自适应采样(v1.27+)[J6]:Collector 观察收到的 spans,按 service/endpoint 组合重算采样概率,使采集量匹配 --sampling.target-samples-per-second。
注意:Jaeger 没有原生的尾采样(tail-based)能力,这是其相对 OTel Collector / Splunk 的明显局限。
拓扑分析
Dependencies 页面在内存存储时按需计算;分布式存储下太贵,需跑离线作业——旧的 spark-dependencies(周期性 Spark)或新的实验性 jaeger-analytics(Flink 流式持续构建)[J2]。
Grafana Tempo
Tempo 是 Grafana Labs 推出的调用链存储系统,设计哲学与 Loki 一脉相承。
设计哲学:只索引 TraceID(类 Loki 理念)
Tempo 的核心理念与 Loki 一脉相承:不对 trace 内容建倒排索引,只索引 TraceID,trace 内容以压缩 block 存对象存储[T7][T24]。这把"索引成本"从海量属性压缩到单一 TraceID 上,据 designround 二级估算可降低约 100× 成本(官方未公布精确数字),实现"无限保留"[T24]。
微服务架构与组件
Tempo 所有组件编译进同一二进制,用 -target 控制启动哪个,支持单体/微服务两种模式[T7]。
写路径架构:
flowchart TD
A[Distributor] --> B[Kafka]
B --> C[Block-builder]
C --> D[ObjectStorage]
B --> E[Metrics-generator]
E --> F[Mimir/Prometheus]
style A fill:#2196F3,color:#fff
style B fill:#FF9800,color:#fff
style C fill:#9C27B0,color:#fff
style D fill:#4CAF50,color:#fff
style E fill:#9C27B0,color:#fff
style F fill:#4CAF50,color:#fffTempo 写入路径包含 6 个关键组件:Distributor 接收多格式 spans 并做 TraceID 哈希分片,写入 Kafka 作为持久 WAL;Block-builder 消费 Kafka 按时间窗组织 blocks 送对象存储;Metrics-generator(可选)从 trace 派生 RED 指标写回 Prometheus/Mimir。
读路径架构:
flowchart TD
A[Querier] --> B[ObjectStorage]
A --> C[Live-store]
D[Kafka] --> C
style A fill:#2196F3,color:#fff
style B fill:#4CAF50,color:#fff
style C fill:#FF9800,color:#fff
style D fill:#FF9800,color:#fff读路径中,Live-store 消费 Kafka 提供约近 30 分钟~1 小时的实时数据查询;Querier 同时在对象存储 block 与 live-store 中查找 trace,利用 bloom filters 和 index 高效定位。
关键组件详解[T7]:
- Distributor:接收 spans(支持 Jaeger/OTLP/Zipkin 格式),按
traceID哈希分片,写 Kafka。仅当 Kafka 确认后才向客户端 ACK[T7] - Kafka 兼容系统:作为 distributor 与下游间的持久 WAL,解耦读写路径[T7]
- Block-builder:消费 Kafka partition,按可配置时间窗组织 spans 成 block,送对象存储[T7]
- Live-store(读路径):消费 Kafka 提供近期数据查询(约最近 30min~1h)[T7]
- Querier:在对象存储 block 与 live-store 中查找,用 bloom filters 和 index 高效定位 block 内 trace[T7][T29]
- Metrics-generator(可选):从 trace 派生 RED 指标和服务图,写 Mimir/Prometheus[T7][T12]
Block 结构与 Parquet 存储格式
Tempo 2.0 起 Apache Parquet 列式格式成为默认[T8]。一个 block 是对象存储里的一个目录[T9]:
| 文件 | 用途 |
|---|---|
meta.json | block 元数据(时间范围、tenant、block ID) |
data.parquet | 列式 trace 数据 |
| Bloom filters | 概率数据结构,高效 TraceID 查找(默认 false_positive 0.01) |
| Index | TraceID → data.parquet 中 row group 的映射 |
Schema 设计:面向 span 的高度嵌套 Parquet schema[T9]:
- Intrinsic 字段(顶层列):trace ID、span ID、parent span ID、span name、span kind、duration 等,查询始终高效
- 通用属性:其余 resource/span 属性存于通用
Attrs列(key-value),查询需扫描属性 map,较慢 - 专用列(Dedicated columns):可把高频查询属性提升为独立 Parquet 列以加速[T9][T30]
TraceQL 查询语言(2.0+)
TraceQL 是类 PromQL/LogQL 的 trace 查询语言[T13][T8]:{} 始终从当前 trace 选择一组 spans,如 { span.http.status_code = 500 }[T15]。Parquet 列式存储使 TraceQL 只需读取相关列,大幅减少 IO[T9]。
Apache SkyWalking
SkyWalking 是 ASF 顶级项目,以其丰富的分析能力和实时拓扑计算在 Java 生态中广泛应用。
OAP(Observability Analysis Platform)架构
flowchart TD
A[Probes] --> B[OAP<br/>Receiver + Aggregator]
B --> C[流式处理]
B --> D[批处理]
C --> E[Storage]
D --> E
E --> F[UI]
style A fill:#2196F3,color:#fff
style B fill:#9C27B0,color:#fff
style C fill:#2196F3,color:#fff
style D fill:#2196F3,color:#fff
style E fill:#4CAF50,color:#fff
style F fill:#FF9800,color:#fffSkyWalking 逻辑分四部分:Probes(探针)、Platform backend(OAP)、Storage、UI[SW16]。OAP 是核心大脑,兼具 Receiver 与 Aggregator 角色,完成接收、清洗、分析、聚合、存储、查询[SW17]。探针(蓝色)上报数据给 OAP(紫色),OAP 内部通过流式处理和批处理两道流程加工数据后写入存储(绿色),最终由 UI(橙色)查询展示。
OAP 两大核心流程[SW17]:
- 流式处理:实时接收 Agent 上报原始数据,解析链路模型,生成服务拓扑、实时指标、调用关系
- 批处理:按时间维度对历史数据聚合,生成小时级/天级指标
分析规则用三种 DSL 定义:OAL(trace/metrics 聚合规则)、MAL(metrics)、LAL(log)[SW18]。OAP 默认架构 不引入 MQ[SW16]。
Segment 数据模型(关键概念)
Segment 是 SkyWalking 独有概念[SW19]:一个 segment 包含 单个 OS 进程内一次请求的所有 spans。跨进程时,每个进程产生一个独立 segment,通过 reference 串联成完整 trace。
三种 Span 类型[SW19]:
- EntrySpan:服务提供方/服务端端点
- LocalSpan:不涉及远程服务的普通方法
- ExitSpan:服务客户端/MQ producer(如 JDBC 访问 DB、读 Redis)
拓扑图计算与端点级度量
- 拓扑:OAP 用 STAM 流式拓扑分析法,从 ExitSpan 的 peer 地址与 reference 实时构建 service/instance/endpoint 间的依赖关系[SW18][SW19]。这是相对 Jaeger/Zipkin 离线作业的显著优势(实时拓扑)
- 端点级度量:OAL 分析 trace span,按 endpoint 聚合 QPS、P99、成功率等 RED 指标[SW17][SW18]
存储后端与 BanyanDB
可插拔存储接口,支持 Elasticsearch、BanyanDB、MySQL、H2、TiDB[SW16]。BanyanDB 是 SkyWalking 团队自研的专用存储[SW20]。
BanyanDB 数据模型层级[SW14]:数据组织为 group 内的 streams、measures、traces、properties。
- Measure:时序数据点序列,支持 GORILLA 编码 + ZSTD 压缩。
entity定义唯一时间序列 - Trace:专为分布式追踪设计——按 trace ID 分组 spans,每个 span 一个数据点,需指定
trace_id_tag_name、span_id_tag_name、timestamp_tag_name - TopNAggregation:在写入阶段预计算 Top/Bottom N 实体[SW14]
索引机制[SW14]:三种索引结构:
- INVERTED(倒排):适合 measure tag,查询性能好
- SKIPPING(跳表/跳过索引):多数 stream tag,优先空间利用
- TREE(树索引):专为 trace 设计,用用户可控的 int64 排序键(如 duration、timestamp)存树索引
Zipkin
Zipkin 是 Twitter 开源的最早的调用链系统之一,其数据模型影响深远(B3 传播协议广泛被 Jaeger/SkyWalking 参考)。
架构与 Span 数据模型
Zipkin 四大组件[Z23]:collector、storage、search(query service)、web UI。Tracer 在应用内记录 timing/metadata,只 in-band 传播 ID,out-of-band 异步上报 span。
Span 模型比 Jaeger/SkyWalking 更精简[Z23][Z24]:核心字段 traceId、id(spanId)、parentId、name、timestamp、duration、annotations(带 endpoint 的时序事件)、tags。用 B3 头(X-B3-TraceId / X-B3-SpanId)传播。
存储后端
最初为 Cassandra 构建(Twitter 内部),后插件化[Z23]:Cassandra(可扩展、schema 灵活、高写吞吐、原生 TTL)、Elasticsearch(查询强、支持复杂分析)、MySQL/Postgres(结构化、易维护,仅中小型/测试用)。
依赖图存储与计算
与 Jaeger 类似,Zipkin 不在存储中实时维护依赖图,而是用 zipkin-dependencies Spark 作业离线聚合:从 spans 提取 parent→child 服务调用关系,聚合成 DependencyLink[Z23]。这是与 SkyWalking 实时拓扑的关键差异。
商业方案(Datadog/Splunk)
Datadog:头采样 + 15 分钟全量 + 15 天智能保留
数据量级洞察[D21]:Datadog 对客户群的调研显示,未采样 trace 量约为日志量的 5 倍,采样后仍为日志量的 2 倍。
采样哲学[D21]:坚持头采样,决策在 trace 开始做出,通过 trace context 传播。据 Datadog 公开架构博客,默认目标 10 trace/s(DD_APM_MAX_TPS,公开技术 docs 未明确此默认值)。
- Live Search(15 分钟滚动窗口):可查询最近 15 分钟内所有已 ingest 的 spans(100% 全量,无需索引)
- 15 天索引保留:超出 15 分钟需通过 retention filters 索引 spans
- Intelligent Retention Filter:diversity sampling(多样性采样)+ 1% flat sampling(1% 扁平采样)
Trace Metrics(RED)[D21]:基于 100% 应用流量计算 rate/error/duration 指标(非采样)——即"指标全量、trace 采样"的混合策略。
Splunk APM:100% 全量无采样
Splunk 宣称 100% 全量存储 traces(产品页措辞,未在技术 docs 给出独立验证)[D25][D26]:不采样,存储全量 trace,使工程师可回溯查询任意 trace(对间歇性故障,万分之一出现的请求也能查)。
- Trace Analyzer:基于 100% trace,按任意 tag 值/错误/延迟组合搜索任意 trace[D26]
- Tag Spotlight:识别问题 trace 的共性
- AlwaysOn Profiling:持续监控 Java/.NET/Node.js 的 CPU/内存,把代码级热点与具体 trace 关联[D25]
VictoriaTraces
定位:基于 VictoriaLogs 的调用链存储
VictoriaTraces 是 VictoriaMetrics 团队开发的调用链数据库,基于 VictoriaLogs 构建[VT1][VT2]。核心设计思路:将 OTLP 协议收到的 span 数据转化为结构化日志,复用 VictoriaLogs 的高效列式 LSM-Tree 引擎。对外兼容 Jaeger Query Service JSON API,可直接接入 Grafana 的 Jaeger 数据源[VT3]。
架构模式
单机模式:单一二进制 victoria-traces-prod,同时负责 ingestion、存储和查询,Kubernetes 中以 StatefulSet 部署。
集群模式由三个独立组件构成[VT4]:
| 组件 | 职责 |
|---|---|
vtinsert | 接收 OTLP trace span,按 trace ID 哈希均匀分发到各 vtstorage 节点 |
vtstorage | 存储 trace span 于本地磁盘,处理来自 vtselect 的查询请求 |
vtselect | 接收用户查询,分发到各 vtstorage 并聚合结果后返回 |
组件间通过 HTTP 通信:vtinsert → vtstorage 使用 POST /internal/insert,vtselect → vtstorage 使用 GET /internal/select/*。
数据模型:Span 即日志
VictoriaTraces 不定义专有 trace 存储格式,而是将 OTLP span 拍平为结构化日志[VT3]:
| 字段类别 | 示例 | 说明 |
|---|---|---|
| 时间戳 | _time | 默认使用 EndTimeUnixNano |
| 流标签 | _stream | {resource_attr:service.name="payment", name="tcp.connect"} |
| Trace 标识 | trace_id, span_id, parent_span_id | 调用链关联 |
| Resource 属性 | resource_attr:service.name | OTLP Resource 拍平展开 |
| Span 属性 | span_attr:http.status_code | OTLP Span Attributes 拍平展开 |
| 计算字段 | duration | ingestion 时自动计算 |
这种设计的核心优势:所有字段自动建立全文索引,无需预定义索引 schema——相比 Tempo 需要手动配置专用列才能加速属性查询,VictoriaTraces 使用体验更接近日志搜索引擎。
写入路径
flowchart TD
A["OTLP Spans<br/>gRPC / HTTP"] --> B["vtinsert<br/>按 Trace ID 分片"]
B --> C["vtstorage<br/>转结构化日志"]
C --> D["VictoriaLogs<br/>列式 LSM-Tree"]
D --> E["本地磁盘<br/>per-day 分区"]写入流程详解:
- 数据接收:通过 OTLP/gRPC 或 OTLP/HTTP 端点接收 span 流
- Trace ID 分片:vtinsert 按 trace_id 哈希将 span 分发到对应 vtstorage 节点,保证同一 trace 的所有 span 落在同一节点
- 数据转换:vtstorage 将 OTLP span 拍平为结构化日志——resource attributes 展开为
resource_attr:*,span attributes 展开为span_attr:*,并自动计算duration - 列式写入:经由 VictoriaLogs 的 LSM-Tree 引擎写入本地磁盘,按天分区存储。与 VictoriaMetrics 不同,VictoriaTraces 目前暂不支持对象存储[VT6]
查询路径
flowchart TD
A["Grafana<br/>Jaeger 数据源"] --> B["vtselect<br/>分发查询"]
B --> C["vtstorage<br/>LogsQL 检索"]
C --> D["VictoriaLogs<br/>全文索引扫描"]
D --> E["跨节点<br/>结果合并"]
E --> F["返回 Trace<br/>Waterfall 视图"]两层查询接口[VT5]:
- Jaeger 兼容 API:
/select/jaeger/api/traces/{trace_id}— 按 trace ID 精确查询,同时提供服务列表、操作列表、服务依赖图等 Jaeger 原生 API - LogsQL 查询接口:
/select/logsql/query— 使用 LogsQL 对所有 span 字段进行全文搜索,支持包括 span 属性在内的任意字段过滤
LogsQL 示例:
| |
性能对比
官方在 10,000 spans/s(4 CPU, 8 GiB RAM)下的对比测试[VT6]:
| 指标 | VictoriaTraces | Grafana Tempo | ClickHouse |
|---|---|---|---|
| CPU 使用 | 0.50 vCPU | 1.35 vCPU | 0.69 vCPU |
| 内存使用 | 1.15 GiB | 4.26 GiB | 1.12 GiB |
| 磁盘使用 | 3.27 GiB | ~4.4 GiB | 5.86 GiB |
在 30,000 spans/s 高负载下,VictoriaTraces 相比 Tempo 节省 3.7x 内存和 2.6x CPU[VT6]。Docker 镜像仅 15.1 MB,无任何外部依赖。
与主流方案对比
| 维度 | VictoriaTraces | Grafana Tempo | Jaeger(Elasticsearch) |
|---|---|---|---|
| 存储引擎 | VictoriaLogs(列式 LSM-Tree) | 对象存储 + Parquet | Elasticsearch 倒排 |
| 查询语言 | LogsQL + Jaeger API | TraceQL | 无(API-only) |
| 外部依赖 | 无(裸二进制) | 对象存储(S3/GCS) | Elasticsearch / Cassandra |
| 资源效率 | 极高(3.7x < Tempo) | 中 | 低(写放大) |
| 部署复杂度 | 低(单二进制 / 三组件) | 中(多组件 + 对象存储) | 中(多组件 + ES 运维) |
| 成熟度 | 预览版(v0.9.3) | 稳定版 | 稳定版 |
调用链横向对比
索引策略对比(核心分歧)
flowchart TD
A[调用链索引策略] --> B[全倒排索引派<br/>搜索灵活成本高]
A --> C[只索引 TraceID 派<br/>成本极低]
A --> D[混合派<br/>平衡搜索与成本]
A --> E[全文索引派<br/>VictoriaTraces]
style A fill:#FF9800,color:#fff
style B fill:#f44336,color:#fff
style C fill:#4CAF50,color:#fff
style D fill:#9C27B0,color:#fff
style E fill:#795548,color:#fff调用链存储的索引策略可分为四大流派:全倒排索引派(红色)以 Jaeger/ES、Zipkin/ES、Datadog、Splunk 为代表,搜索灵活但索引成本高;只索引 TraceID 派(绿色)以 Tempo 为代表,成本极低但 TraceID 以外的搜索需依赖列式扫描;混合派(紫色)以 SkyWalking BanyanDB 的多索引结构和 Datadog 的分层保留为代表;全文索引派(棕色)以 VictoriaTraces 为代表,基于 VictoriaLogs 全文索引,所有字段自动索引无需预定义 schema。
- 全倒排索引派:Jaeger(ES)、Zipkin(ES)、Datadog/Splunk — 搜索灵活但成本高、写放大
- 只索引 TraceID 派:Tempo — 成本极低、TraceID 查询快、内容搜索靠列式扫描 + TraceQL
- 混合派:SkyWalking(BanyanDB INVERTED+SKIPPING+TREE 多索引,trace 专用 TREE)、Datadog(近期全量 + 远期选择性索引)
- 全文索引派:VictoriaTraces — 基于 VictoriaLogs 全文索引,所有字段自动建立索引,无需预定义 schema,按需全文搜索任意属性
采样策略对比
| 项目 | 头采样 | 尾采样 | 自适应 |
|---|---|---|---|
| Jaeger | ✅(默认 remote) | ❌ | ✅(v1.27+,按 endpoint) |
| Tempo | ❌(后端全收) | — | — |
| SkyWalking | ✅(agent 端) | — | — |
| Zipkin | ✅(客户端) | ❌ | ❌ |
| Datadog | ✅(默认 10 trace/s) | 部分支持 | ✅ |
| Splunk | ❌(全量不采样) | — | — |
| VictoriaTraces | ❌(依赖 OTel Collector 采样) | — | — |
Jaeger 采样流程示意
sequenceDiagram
participant RS as RootService
participant C as Collector
participant A as Agent
participant DS as DownstreamService
RS->>RS: 决策采样
RS->>DS: 传播 trace context
DS->>DS: 继承采样决策
DS->>C: 上报 spans
C->>C: 自适应调整
C->>A: 回推策略
A->>RS: 更新采样策略
Note over RS,DS: 头采样保证整条 trace 一致性Jaeger 的采样流程展示了头采样的完整生命周期:根服务(RootService)在请求入口做出采样决策,通过 trace context 传播给下游服务(DownstreamService),下游继承同一决策保证整条 trace 的一致性。Collector 接收上报后按 service/endpoint 组合进行自适应调整,并通过 Agent 回推更新采样策略。
容量估算参考[T24]
5M spans/s 采样前 → 500K spans/s 采样后(10%)→ 250 MB/s 摄入 → 21.6 TB/天(原始 JSON)→ ClickHouse 列式压缩 5-10x 后约 3 TB/天 → 14 天约 300 TB(原始)/ ~40 TB(压缩)。
来源
[J1] Jaeger Features. https://www.jaegertracing.io/docs/1.57/features/
[J2] Jaeger Architecture. https://www.jaegertracing.io/docs/1.57/architecture/
[J3] Jaeger CLI / Storage Backends. https://www.jaegertracing.io/docs/1.57/cli/#storage-backends
[J4] Jaeger Data Model. https://www.jaegertracing.io/docs/1.57/data-model/
[J6] Jaeger Sampling. https://www.jaegertracing.io/docs/1.57/sampling/
[T7] Tempo Architecture. https://grafana.com/docs/tempo/latest/operations/architecture/
[T8] Tempo 2.0 Release. https://grafana.com/blog/2023/03/07/grafana-tempo-2.0-is-here/
[T9] Tempo Parquet Design. https://grafana.com/docs/tempo/latest/operations/parquet/
[T12] Tempo Metrics-generator. https://grafana.com/docs/tempo/latest/metrics-generator/
[T13] TraceQL Documentation. https://grafana.com/docs/tempo/latest/traceql/
[T15] TraceQL Examples. https://grafana.com/docs/tempo/latest/traceql/examples/
[T24] Grafana Labs Keynote / Tempo Capacity Estimate. https://grafana.com/blog/2021/09/22/grafana-tempo-1.0/
[T29] Tempo Bloom Filters. https://grafana.com/docs/tempo/latest/operations/bloom-filters/
[T30] Tempo Dedicated Columns. https://grafana.com/docs/tempo/latest/operations/dedicated-columns/
[SW14] BanyanDB Data Model. https://skywalking.apache.org/docs/main/latest/en/setup/backend/banyandb/
[SW16] SkyWalking Architecture. https://skywalking.apache.org/docs/main/latest/en/concepts-and-designs/overview/
[SW17] SkyWalking OAP. https://skywalking.apache.org/docs/main/latest/en/setup/backend/oap/
[SW18] SkyWalking OAL. https://skywalking.apache.org/docs/main/latest/en/concepts-and-designs/oal/
[SW19] SkyWalking Segment Model. https://skywalking.apache.org/docs/main/latest/en/concepts-and-designs/segment/
[SW20] BanyanDB Overview. https://skywalking.apache.org/docs/main/latest/en/setup/backend/banyandb/
[Z23] Zipkin Architecture. https://zipkin.io/pages/architecture.html
[Z24] Zipkin Span Model. https://zipkin.io/zipkin-api/#/default/get_trace__traceId_
[D21] Datadog APM Trace Sampling. https://docs.datadoghq.com/tracing/guide/trace_sampling_and_storage/
[D22] Datadog Intelligent Retention. https://docs.datadoghq.com/tracing/trace_retention/
[D25] Splunk APM AlwaysOn Profiling. https://www.splunk.com/en_us/observability/apm.html
[D26] Splunk APM Trace Analyzer. https://docs.splunk.com/observability/en/apm/traces/trace-analyzer.html
[VT1] [官方] VictoriaTraces overview: https://docs.victoriametrics.com/victoriatraces/
[VT2] [官方] VictoriaTraces GitHub: https://github.com/VictoriaMetrics/VictoriaTraces
[VT3] [官方] VictoriaTraces key concepts: https://docs.victoriametrics.com/victoriatraces/keyconcepts/
[VT4] [官方] VictoriaTraces cluster: https://docs.victoriametrics.com/victoriatraces/cluster/
[VT5] [官方] VictoriaTraces querying: https://docs.victoriametrics.com/victoriatraces/querying/
[VT6] [官方] VictoriaTraces benchmark (distributed tracing with VictoriaLogs): https://victoriametrics.com/blog/dev-note-distributed-tracing-with-victorialogs/
[VT7] [官方] VictoriaTraces data ingestion: https://docs.victoriametrics.com/victoriatraces/data-ingestion/