采样
Grafana Tempo 是一款经济高效的解决方案,可以摄取和存储追踪,为您的应用资产提供最大程度的可观测性。然而,有时出于某些限制,存储所有追踪可能并非最佳选择,例如与运行时或出站流量相关的成本。有多种方法可以降低追踪量,包括采用不同的采样策略。
采样是指确定要存储(在 Tempo 或 Grafana Cloud Traces 中)哪些追踪以及要丢弃哪些追踪的过程。采样有两种不同的策略类型:头部采样和尾部采样。
采样功能同时存在于Grafana Alloy和 OpenTelemetry Collector 中。Alloy 可以收集、处理和导出遥测信号,其配置文件使用Alloy 配置语法。
请参阅启用尾部采样获取说明。
头部采样和尾部采样
进行采样时,您可以使用头部或尾部采样策略。
头部采样策略通常会尽早决定是否对追踪进行采样,无需考虑整个追踪。这是一种简单但有效的采样策略。请参阅头部采样文档获取有关应用程序可观测性的更多信息。
尾部采样策略是在考虑了所有或大部分 Span 后才决定是否对追踪进行采样。例如,尾部采样是仅对包含错误或请求持续时间较长的追踪进行采样的良好选择。尾部采样的配置、实现和维护更为复杂,但对于遥测量较高的大型系统来说,它是推荐的采样策略。
有关采样的更多信息,请参阅OpenTelemetry 采样文档。
采样和遥测关联
采样是关于是否保留(然后存储)追踪或丢弃它的决定。这些决定在将追踪数据与其他信号关联时会产生影响。
例如,许多进行插桩的服务也会生成日志、指标或性能画像。这些信号可以相互引用。对于追踪来说,这种引用可以通过嵌入到日志行、嵌入到指标值中的Exemplar,或嵌入到追踪中的性能画像 ID 来实现。
通过选择不采样某个追踪,在某些情况下,特定信号会引用已丢弃追踪的 ID。这种丢弃可能导致在 Grafana 中出现这种情况:从日志行或指标值的 Exemplar 跟随链接到追踪 ID 时,对该追踪 ID 的查询失败,因为该追踪未被采样。性能画像可能不会显示,除非明确查询它们,因为本应包含性能画像火焰图的追踪尚未存储。
这通常不是大问题,因为采样策略倾向于选择显示非正常行为的追踪,例如抛出错误或请求延迟较长。观察者更有可能选择显示这些问题的追踪,而不是显示正常行为的追踪。了解信号之间如何关联有助于确定如何选择这些策略。
OpenTelemetry 尾部采样处理器的工作原理
在尾部采样中,采样决定是在工作流程的末尾做出的,这使得采样决定更加准确。Alloy 使用OpenTelemetry 尾部采样处理器。
Alloy 按追踪 ID 组织 Span,并评估其数据,判断是否满足定义的策略类型之一(例如,延迟
或状态码
)。例如,策略可以检查追踪是否包含错误或追踪持续时间是否长于指定阈值。
如果追踪满足至少一个策略的条件,则会被采样。
决策周期
为了按追踪 ID 对 Span 进行分组,Alloy 会将 Span 缓冲一段可配置的时间,之后将其视为完成的追踪。这段可配置的时间称为决策周期。运行时间较长的追踪会被分成多个部分。
在特定追踪的持续时间长于决策周期的情况下,对于超出决策周期窗口的任何未来 Span,可能会做出多个决策。这可能导致追踪中的某些 Span 被采样,而另一些则不会。
例如,假设尾部采样器的决策周期是 10 秒,并且存在一个策略来采样至少有一个 Span 设置了错误的追踪。其中一个追踪持续时间为 20 秒,并且在时间偏移量为 15 秒时,有一个 Span 显示错误状态。
当观察到追踪的第一个 Span 时,10 秒的决策周期开始计时。决策周期到期后,尾部采样器将不会观察到任何带有错误状态的 Span,因此会丢弃该追踪的 Span。
当追踪的下一个 Span 到达时,一个新的 10 秒决策周期开始。在此周期内,观察到的其中一个 Span 设置了错误。当决策周期到期时,该周期内追踪的所有 Span 都将被采样。
这会导致 Tempo 中存储一个碎片化的追踪,其中只有追踪最后 10 秒的 Span 可供查询。虽然这仍然是一个可能有用的追踪,但仔细确定如何设置决策周期是确保正确采样追踪 Span 的关键。
然而,使用更长的决策周期会增加为每个追踪做出决策所需的 Span 缓冲内存开销。
因此,启用决策缓存可以确保即使决策周期到期后,先前对特定追踪 ID 做出的采样决定仍然有效。有关更多详细信息,请参阅“缓存”部分。
缓存
OpenTelemetry 尾部采样处理器包含两个独立的缓存:采样缓存(sampled cache)和非采样缓存(non-sampled cache)。采样缓存保留了先前决定保留 Span 的所有追踪 ID 列表。非采样缓存保留了先前决定丢弃 Span 的所有追踪 ID 列表。这两个缓存都由应存储在缓存中的最大追踪数进行配置,并且可以独立或联合启用。
在上面的图中,如果两个缓存都启用,则在 10 秒后做出丢弃该追踪样本的决定,并将追踪 ID 存储在非采样缓存中。这意味着即使该追踪中具有错误状态的 Span,在初始决策周期后也会被丢弃,因为非采样缓存匹配追踪 ID 并提前丢弃 Span。同样地,如果已经做出了采样决定,则未来的任何 Span 即使不匹配任何策略,但由于其追踪 ID 在采样缓存中找到,也会被保留。
理解这些缓存的工作原理可以确保您保留先前做出的决定。例如,您可以使用采样缓存来缩短对追踪的未来决策过程,立即对传入的 Span 进行采样。这使得无需缓冲任何其他 Span 即可做出决策。
以下是使用缓存的一些一般准则。每个安装都不同。使用缓存可能会影响生成的数据量。
缓存类型 | 用例 | 优点/注意事项 |
---|---|---|
采样缓存 | 保留已采样的追踪的任何未来 Span。 |
|
非采样缓存 | 丢弃已明确决定不采样的追踪的任何未来 Span。 |
|
两者都启用 | 使用一个初始决策周期,该周期一次性做出决定并在后续使用该决定。 |
|
注意
同时启用采样缓存和非采样缓存所表现的功能类似于未启用缓存的情况。然而,一旦初始决策周期到期,它会缩短未来的决策过程。同时启用这两个缓存会降低缓冲 Span 的内存需求。
尾部采样负载均衡
对于多实例 Alloy 部署,可能会出现同一追踪的 Span 发送到不同实例的情况。在大多数情况下,采样决策依赖于单个实例接收到特定追踪 ID 的所有 Span。
您可以配置 Alloy 将属于特定追踪 ID 的 Span 导出到同一实例,从而在实例之间对追踪进行负载均衡。例如,如果有 10 个追踪进来,并且有四个 Alloy 实例,那么每个实例将收到三个追踪,一个实例将收到四个追踪。负载均衡维护所有实例的一致性哈希。
尾部采样负载均衡通常通过运行两层 Collector 来实现。第一层接收遥测数据(在此例中为追踪 Span),然后将其分发到执行采样策略的第二层。
Alloy 包含一个负载均衡导出器,可以根据一组键(对于追踪采样,通常是traceID
键)将数据路由到其他 Collector 目标。Alloy 使用OpenTelemetry 负载均衡导出器。
路由键确保第二层中的特定 Collector 始终处理来自同一追踪 ID 的 Span,从而保证采样决策的正确性。您可以使用静态 IP 地址、多 IP DNS A 记录条目和 Kubernetes 无头服务解析器配置导出器目标。使用此配置可以扩展或缩减第二层 Collector 的数量。
关于负载均衡导出器的扩展性和弹性有一些重要注意事项,主要围绕其最终一致性模型。有关更多信息,请参阅弹性和扩展性注意事项。对于尾部采样,最重要的一点是路由是基于考虑负载均衡器可用后端数量的算法进行的。这可能会在达到最终一致性之前影响追踪 ID Span 的目标。
有关基于 Kubernetes 服务的双层 OpenTelemetry Collector 部署示例 Manifest,请参阅Kubernetes 服务解析器 README。