常见问题
关于 Jaeger 的一些常见问题的解答。
为什么依赖关系页面为空?
依赖关系页面显示了由 Jaeger 跟踪的服务及其之间的连接图。当您使用内存存储的 all-in-one
二进制文件时,该图是从内存中存储的所有跟踪数据中按需计算的。但是,如果您使用真正的分布式存储(如 Cassandra 或 OpenSearch/Elasticsearch),扫描数据库中的所有数据来构建服务图将非常昂贵。因此,Jaeger 项目提供了“大数据”作业,可用于从跟踪数据中提取服务图数据。
- https://github.com/jaegertracing/spark-dependencies - 可定期运行的旧版 Spark 作业
- https://github.com/jaegertracing/jaeger-analytics - 可持续运行并在较小时间间隔内构建服务图的新(实验性)流式 Flink 作业
为什么我在 Jaeger 中看不到任何 span?
请参阅故障排除指南。
jaeger-agent 怎么了?
由于 Jaeger 客户端库已弃用且 OpenTelemetry SDK 已逐步取消对 Jaeger Thrift 格式的支持,因此不再需要 **jaeger-agent** 且不再支持它。请参阅架构页面了解替代部署选项。
有时仍然希望运行一个 **主机代理**
- 如果我们希望 SDK 直接将跟踪数据发送到 **jaeger-collector**,我们必须向它们提供 HTTP 端点的 URL。这意味着我们的应用程序需要包含此参数的额外配置,特别是当我们运行多个 Jaeger 安装(例如在不同的可用区或区域)并希望将数据发送到附近的安装时。相比之下,当使用主机代理时,库无需额外配置,因为代理始终可以通过
localhost
访问。它充当 sidecar 并将请求代理到相应的 **jaeger-collector**。 - 可以将主机代理配置为通过向 spans 添加额外标签来丰富具有基础架构特定元数据的跟踪数据,例如当前区域、地区等。如果主机代理作为主机守护进程运行,它将由在同一主机上运行的所有应用程序共享。如果主机代理作为真正的 sidecar 运行,即每个应用程序一个,它可以提供额外的功能,例如强身份验证、多租户(请参阅这篇博文 )、pod 名称等。
- 主机代理允许实现对 **jaeger-collector** 的流量控制。如果在数据中心有数千台主机,每台主机运行许多应用程序,并且每个应用程序都直接向 **jaeger-collector** 发送数据,则每个 **jaeger-collector** 可能需要处理过多的打开连接。代理可以通过更少的连接来负载均衡此流量。
如果您的环境需要主机代理,您可以部署 OpenTelemetry Collector 来承担此角色。
推荐的存储后端是什么?
出于以下原因,Jaeger 团队推荐使用 OpenSearch/Elasticsearch 作为存储后端,而不是 Cassandra:
Cassandra 是一个键值数据库,因此按跟踪 ID 检索跟踪效率更高,但它不像 OpenSearch 那样提供强大的搜索功能。实际上,Jaeger 后端在客户端实现了搜索功能,位于键值存储之上,这限制了其功能并可能产生不一致的结果(参见issue-166 了解更多详情)。OpenSearch 不存在这些问题,从而提供了更好的可用性。OpenSearch 还可以直接查询,例如从 Kibana 仪表板,并提供有用的分析和聚合。
根据过去的性能实验,我们观察到 Cassandra 中的单次写入比 OpenSearch 快得多,这可能表明它可以维持更高的写入吞吐量。然而,由于 Jaeger 后端需要在键值存储之上实现搜索功能,因此将 span 写入 Cassandra 实际上会受到大量写入放大的影响:除了写入 span 本身的一条记录外,Jaeger 还会为服务名称和操作名称索引执行额外的写入,并为每个标签执行额外的索引写入。相比之下,将 span 保存到 OpenSearch 是一次写入,所有索引都在 OpenSearch 节点内部进行。因此,对 Cassandra 的整体吞吐量与 OpenSearch 相当。
Cassandra 后端的一个好处是维护更简单,因为它原生支持数据 TTL。在 OpenSearch 中,数据过期通过索引轮换来管理,这需要额外的设置(参见Elasticsearch Rollover)。
为什么 Jaeger 跟踪 ID 在 Kafka 和 UI 中看起来不同?
在底层,数据模型级别,Jaeger 跟踪 ID 是一个 16 字节的序列。然而,这 16 个字节可以用许多不同的方式表示:
- 在 UI 中,我们历来将它们表示为十六进制编码字符串,例如
7e90c0eca22784ec7e90c0eca22784ec
。当使用 128 位 ID(在 OpenTelemetry 中更常见)时,这些字符串可以是 32 个字符长;如果 ID 是在旧版 64 位模式下生成的,则为 16 个字符。 - 在 Jaeger 后端代码的领域模型 中,我们使用大端编码将跟踪 ID 表示为一对无符号 64 位整数。这样做是为了提高效率,因为 Go 中的字节切片需要额外的内存分配。
- 在原始的Thrift 模型 中,我们也将其表示为一对无符号 64 位整数。
- 在Protobuf 模型 中,ID 表示为字节序列。当 Protobuf 序列化为二进制负载时,这些字节会按原样传输。但是,Protobuf 也支持 JSON 编码,其中字节序列使用 base64 编码进行序列化。因此,如果您配置 collector-Kafka-ingester 管道使用 JSON 编码,您将看到类似
fpDA7KInhOx+kMDsoieE7A==
的跟踪 ID。可以使用在线工具(如 https://base64.guru/converter/encode/hex )将其转换为 UI 能够识别的十六进制编码 ID。
我需要运行多个 collector 吗?
运行高可用性的 **jaeger-collector** 是否能提高整体系统性能,例如减少丢弃的 span 数量并减少跟踪收集的中断时间?是否推荐这样做?如果推荐,原因是什么?
以下是运行多个实例的原因:
- 您的客户端发送的数据量太大,单个 **jaeger-collector** 无法足够快地接收。
- 您需要更高的可用性,例如在升级时对 **jaeger-collector** 进行滚动重启,以便有一些实例仍在运行并能够处理入站数据。
以下不是运行多个实例的原因:
- 为了避免数据丢失。当后端存储无法足够快地保存数据时,**jaeger-collector** 会丢弃数据。增加 **jaeger-collector** 的数量并为其内部队列分配更多内存,可能会提供短暂的缓解,但无法消除存储后端的瓶颈。
如何为 Jaeger UI 配置身份验证
Jaeger UI 不支持任何账户或角色概念,因此无需对用户进行身份验证。如果您只需要身份验证来限制谁可以访问 Jaeger UI,我们建议在其前面运行一个反向代理,例如 HAProxy、NGINX、Keycloak 等。使用标准反向代理的优势在于它们支持与各种身份验证和单点登录服务进行广泛集成,这是我们在 Jaeger UI 中永远无法实现的。
例如,请参阅这篇博文,了解如何使用 Keycloak 保护 Jaeger UI:protecting Jaeger UI with Keycloak 。