OpenTelemetry 采样技术全解析
1. 引言
遥测数据管理面临着数据量过大的挑战,数据生成时可能消耗过多资源,传输和存储成本也较高,分析时还需要大量资源筛选。采样技术可以在保留数据价值和保真度的同时,减少仪器产生的数据量。本文将探讨 OpenTelemetry 中采样的相关概念、策略、配置方法以及常见问题。
2. 技术要求
在开始之前,需要满足以下技术要求:
- 代码获取 :可以使用以下命令从 GitHub 克隆代码仓库:
$ git clone https://github.com/PacktPublishing/Cloud-Native-Observability
$ cd Cloud-Native-Observability/chapter12
- Python 环境 :运行代码需要安装 Python 3.6 或更高版本。可以使用以下命令检查 Python 版本:
$ python --version
Python 3.8.9
$ python3 --version
Python 3.8.9
如果未安装 Python 或版本不符合要求,可以从 Python 官网 下载并安装兼容版本。
- OpenTelemetry 包安装 :使用 pip 安装以下 OpenTelemetry 包:
$ pip install opentelemetry-distro \
opentelemetry-exporter-otlp
$ pip freeze | grep opentelemetry
opentelemetry-api==1.8.0
opentelemetry-distro==0.27b0
opentelemetry-exporter-otlp==1.8.0
opentelemetry-exporter-otlp-proto-grpc==1.8.0
opentelemetry-exporter-otlp-proto-http==1.8.0
opentelemetry-instrumentation==0.27b0
opentelemetry-proto==1.8.0
opentelemetry-sdk==1.8.0
- OpenTelemetry 收集器 :可以从 GitHub 直接下载 OpenTelemetry 收集器。本文使用的版本为 v0.43.0 。以下是下载 macOS AMD64 兼容二进制文件的示例命令:
$ wget -O otelcol.tar.gz https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v0.43.0/otelcol-contrib_0.43.0_darwin_amd64.tar.gz
$ tar -xzf otelcol.tar.gz otelcol-contrib
$ chmod +x ./otelcol-contrib
$ ./otelcol-contrib --version
otelcol-contrib version 0.43.0
如果没有匹配环境的包,可以从 GitHub 手动编译收集器。
3. 跨信号的采样概念
采样是从较大的数据集中选择一个子集进行分析的过程,常用于研究领域。选择采样的原因可能是分析整个数据集不可行、不必要或不实际。例如,要记录商店停车场中每辆车的平均车门数,如果停车场有 20,000 辆车,选择 2,000 辆车进行分析可能更合适。
采样方法可以分为以下两类:
- 概率采样 :采样概率是已知的,应用于数据集中的所有数据点。例如,对停车场中 10% 的车辆进行采样,可以记录每第十辆车的数据。在小数据集中,概率采样的效果较差,因为数据点之间的变异性较高。
- 非概率采样 :数据的选择基于数据的特定特征。例如,为了方便选择离商店最近的 2,000 辆车。这种方法会引入偏差,因为离商店最近的停车区域可能有指定车位或为小型车辆预留的车位,从而影响结果。
3.1 追踪采样
在 OpenTelemetry 中,采样主要是决定如何处理构成特定追踪的跨度(span)。根据采样器的配置,追踪中的跨度要么被处理,要么被丢弃。OpenTelemetry 的各个组件参与将采样决策传递到整个系统:
- 采样器(Sampler) :是起点,允许用户选择采样级别。OpenTelemetry 规范中定义了几种采样器。
- 追踪器提供者(TracerProvider) :将采样器作为配置参数接收,确保由特定追踪器提供者提供的追踪器生成的所有追踪都一致地进行采样。
- 采样决策 :创建追踪时,会做出是否采样该追踪的决策,并将该决策存储在与该追踪中所有跨度关联的 SpanContext 中。通过配置的传播器将采样决策传播到参与分布式追踪的所有服务。
- 跨度处理器(SpanProcessor) :跨度结束后,跨度处理器应用采样决策,将所有采样追踪的跨度传递给跨度导出器(SpanExporter),未采样的追踪不会被导出。
3.2 指标采样
对于某些类型的数据,采样可能会严重改变数据,使其失去价值。例如,记录服务的每个传入请求并递增计数器,采样此数据会导致未采样的增量对应的请求未被记录,从而使记录的值失去原始数据的意义。
单个指标数据点比单个追踪小,通常管理指标数据的处理和存储开销较小,但这取决于数据的维度和数据点的收集频率等因素。减少指标信号产生的数据量主要通过聚合数据来实现,而不是选择特定点并丢弃其他点。不过,在指标的一个方面涉及采样:示例(exemplars)。示例是允许指标与追踪关联的数据点,不需要为未采样的追踪生成示例。截至 2021 年 12 月,OpenTelemetry 规范仍在讨论如何配置示例及其采样。
3.3 日志采样
截至撰写本文时,OpenTelemetry 中没有关于日志信号是否或如何采样的规范。目前正在考虑的方法有:
- 提供配置选项,仅发出与采样追踪关联的日志记录。
- 像配置追踪采样一样配置日志记录采样,仅发出总日志的一部分。
日志采样的另一种替代方法是聚合。包含相同消息的日志记录可以聚合为一条记录,并包含重复事件的计数器。
4. 采样策略
在为分布式系统配置采样时,选择的策略通常取决于环境。不同的采样策略在系统的不同点做出采样决策。
4.1 头部采样
头部采样是在追踪开始时决定是否丢弃追踪的最快方法。创建追踪中第一个跨度(根跨度)的应用程序决定是否采样该追踪,并通过上下文将该决策传播到后续调用的每个服务。这向追踪中的其他参与者发出信号,指示是否应将此跨度发送到后端。
头部采样的优点是减少了整个系统的开销,每个应用程序可以在不计算采样决策的情况下丢弃不必要的跨度,还减少了数据传输量,对网络成本有显著影响。
然而,头部采样也存在问题。应用程序可能配置不同的采样策略,导致不尊重根跨度的决策,使后端收到不完整的追踪。此外,在追踪开始时做出采样决策可能会错过有价值的信息,因为在做出决策时并非所有信息都可用。
4.2 尾部采样
尾部采样是在追踪完成后再做出采样决策的策略。这允许采样器对追踪进行一些分析,以检测潜在的异常或有趣的事件。
尾部采样的缺点是,分布式系统中的所有应用程序都必须生成并传输遥测数据到一个决定是否采样的目的地,这对于大型分布式系统来说成本较高。此外,采样器必须在内存中缓冲或存储整个追踪的数据,直到做出决策,这会增加内存和存储消耗。为了缓解内存问题,可以配置最大追踪持续时间,但这会导致在设定时间内未完成的追踪出现数据缺口。
4.3 概率采样
概率采样确保数据是随机选择的,消除了采样数据中的偏差。它既可以作为一种配置应用于其他采样策略,也可以作为一种独立的策略。在 OpenTelemetry 中, TraceIdRatioBased 采样器结合标准的随机追踪 ID 生成器提供了概率采样的机制。采样决策是通过将可配置的比率应用于追踪 ID 的哈希值来计算的。由于追踪 ID 在系统中传播,所有配置了相同比率和 TraceIdRatioBased 采样器的组件可以在决策时独立应用相同的逻辑。
5. 可用的采样器
OpenTelemetry 规范中定义了以下几种采样器:
- Always on :始终对所有追踪进行采样。
- Always off :从不采样任何追踪。
- Trace ID ratio :如前文所述,是 OpenTelemetry 中可用的一种概率采样器。
- Parent-based :支持头部采样策略的采样器。可以配置为始终开启、始终关闭,或者在没有为追踪做出采样决策时使用追踪 ID 比率决策作为后备。
6. 通过 SDK 在应用程序级别进行采样
允许应用程序决定采样内容为应用程序开发人员和运维人员提供了很大的灵活性,因为这些应用程序是追踪数据的来源。在 OpenTelemetry 中,可以将采样器配置为追踪器提供者的属性。
以下是一个示例代码,展示了如何配置不同的采样器并生成追踪:
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor, ConsoleSpanExporter
from opentelemetry.sdk.trace.sampling import ALWAYS_OFF, ALWAYS_ON, TraceIdRatioBased
def configure_tracer(sampler):
provider = TracerProvider(sampler=sampler)
provider.add_span_processor(BatchSpanProcessor(ConsoleSpanExporter()))
return provider.get_tracer(__name__)
always_on_tracer = configure_tracer(ALWAYS_ON)
always_off_tracer = configure_tracer(ALWAYS_OFF)
ratio_tracer = configure_tracer(TraceIdRatioBased(0.5))
with always_on_tracer.start_as_current_span("always-on") as span:
span.set_attribute("sample", "always sampled")
with always_off_tracer.start_as_current_span("always-off") as span:
span.set_attribute("sample", "never sampled")
with ratio_tracer.start_as_current_span("ratio") as span:
span.set_attribute("sample", "sometimes sampled")
运行代码:
$ python sample.py
输出可能有以下情况:
- 包含一个名为 always-on 的追踪。
- 不包含名为 always-off 的追踪。
- 可能包含名为 ratio 的追踪,可能需要多次运行代码才能看到该追踪的输出。
示例输出:
{
"name": "ratio",
"attributes": {
"sample": "sometimes sampled"
}
}
{
"name": "always-on",
"attributes": {
"sample": "always sampled"
}
}
需要注意的是,实际应用中通常只使用一个采样器,除非单个应用程序包含具有不同采样要求的多个服务。此外,除了通过代码配置采样器,还可以通过 OTEL_TRACES_SAMPLER 和 OTEL_TRACES_SAMPLER_ARG 环境变量进行配置。
通过应用程序配置可以使用头部采样,但单个应用程序没有足够的信息来做出尾部采样决策,这需要使用 OpenTelemetry 收集器。
7. 使用 OpenTelemetry 收集器进行采样
OpenTelemetry 收集器是进行采样的自然点,目前支持通过处理器进行尾部采样和概率采样。本文主要关注尾部采样处理器。
7.1 尾部采样处理器
尾部采样处理器除了支持通过指定概率采样百分比来配置采样外,还可以根据追踪的各种特征做出采样决策,例如:
- 整个追踪的持续时间
- 跨度属性的值
- 跨度的状态码
以下是一个配置收集器的代码示例,展示了如何使用尾部采样处理器:
receivers:
otlp:
protocols:
grpc:
exporters:
logging:
loglevel: debug
processors:
tail_sampling:
decision_wait: 5s
policies: [{ name: always, type: always_sample }]
service:
pipelines:
traces:
receivers: [otlp]
processors: [tail_sampling]
exporters: [logging]
启动收集器:
$ ./otelcol-contrib --config ./config/collector/config.yml
以下是一个发送多个追踪到收集器的应用程序代码:
import time
from opentelemetry import trace
tracer = trace.get_tracer_provider().get_tracer(__name__)
with tracer.start_as_current_span("slow-span"):
time.sleep(1)
for i in range(0, 20):
with tracer.start_as_current_span("fast-span"):
pass
在新终端中使用 OpenTelemetry 自动检测启动程序:
$ opentelemetry-instrument python multiple_traces.py
查看收集器终端的输出,应该会看到总共 21 个追踪被发出。
现在更新收集器配置,只采样 10% 的追踪:
processors:
tail_sampling:
decision_wait: 5s
policies:
[
{
name: probability,
type: probabilistic,
probabilistic: { sampling_percentage: 10 },
},
]
重启收集器并再次运行 multiple_traces.py ,结果应该显示大约 10% 的追踪,即大约两个追踪。由于配置依赖于使用追踪标识符的概率采样,且追踪 ID 是随机生成的,小样本集的结果会有一些差异,可能需要多次运行命令才能看到采样策略的效果。
还可以配置尾部采样处理器组合策略,例如继续捕获 10% 的追踪,但始终捕获持续时间超过 1 秒的操作的追踪:
processors:
tail_sampling:
decision_wait: 5s
policies:
[
{
name: probability,
type: probabilistic,
probabilistic: { sampling_percentage: 10 },
},
{ name: slow, type: latency, latency: { threshold_ms: 1000 } },
]
重启收集器并运行示例代码,会发现收集器的输出中既包含一定比例的追踪,也包含包含 slow-span 的追踪。
需要注意的是,根据已知特征选择采样追踪会在跨度选择中引入偏差,可能会无意中隐藏有用的遥测数据。在配置采样使用非概率数据时要谨慎,结合概率和非概率采样可以解决这个限制。
总结
采样是管理遥测数据量的有效方法,但不同的采样策略和方法各有优缺点。在实际应用中,需要根据具体情况选择合适的采样策略和采样器,并注意避免采样配置不一致和引入偏差的问题。通过 OpenTelemetry 的 SDK 和收集器,可以灵活地配置和实现采样,以满足不同的需求。
OpenTelemetry 采样技术全解析
8. 采样策略对比
为了更清晰地了解不同采样策略的特点,下面通过表格进行对比:
| 采样策略 | 优点 | 缺点 | 适用场景 |
| — | — | — | — |
| 头部采样 | 减少系统开销,降低数据传输量 | 可能导致追踪不完整,错过有价值信息 | 对性能要求高,数据量较大,对信息完整性要求相对较低的场景 |
| 尾部采样 | 可分析追踪特征,检测异常事件 | 成本高,增加内存和存储消耗 | 需要深入分析追踪数据,对信息完整性要求较高的场景 |
| 概率采样 | 消除采样偏差,可独立应用或与其他策略结合 | 小数据集效果较差 | 数据分布较为均匀,需要随机选择数据的场景 |
通过这个表格,可以根据实际需求更准确地选择合适的采样策略。
9. 采样配置流程图
下面是一个 mermaid 格式的流程图,展示了在 OpenTelemetry 中进行采样配置的主要流程:
graph LR
A[选择采样策略] --> B{选择采样器}
B --> C1[Always on]
B --> C2[Always off]
B --> C3[Trace ID ratio]
B --> C4[Parent-based]
C1 --> D[配置 TracerProvider]
C2 --> D
C3 --> D
C4 --> D
D --> E[创建追踪]
E --> F{做出采样决策}
F --> G[采样追踪]
F --> H[丢弃追踪]
G --> I[SpanProcessor 处理]
I --> J[SpanExporter 导出]
这个流程图展示了从选择采样策略到最终数据导出的整个过程,帮助我们更直观地理解采样配置的步骤。
10. 常见问题及解决方法
在使用 OpenTelemetry 采样技术时,可能会遇到一些常见问题,下面是一些问题及解决方法:
- 问题 1:采样配置不一致
- 现象 :后端收到不完整的追踪,部分跨度丢失。
- 原因 :分布式系统中多个应用程序的采样配置不一致。
- 解决方法 :确保所有应用程序使用一致的采样配置,可通过统一的配置文件或环境变量进行配置。
- 问题 2:采样引入偏差
- 现象 :某些类型的数据被过度采样或未被采样,导致数据失真。
- 原因 :使用非概率采样方法,根据特定特征选择数据。
- 解决方法 :谨慎使用非概率采样,结合概率和非概率采样方法,减少偏差。
- 问题 3:尾部采样成本高
- 现象 :系统资源消耗大,网络传输成本高。
- 原因 :尾部采样需要收集和存储整个追踪的数据。
- 解决方法 :配置最大追踪持续时间,减少不必要的数据存储;优化采样策略,只对关键追踪进行尾部采样。
11. 最佳实践建议
根据前面的讨论,以下是一些使用 OpenTelemetry 采样技术的最佳实践建议:
- 选择合适的采样策略 :根据系统的特点和需求,选择头部采样、尾部采样或概率采样,也可以结合使用多种策略。
- 保持采样配置一致 :在分布式系统中,确保所有应用程序使用相同的采样配置,避免出现追踪不完整的问题。
- 谨慎使用非概率采样 :非概率采样可能会引入偏差,尽量结合概率采样使用,以保证数据的代表性。
- 优化尾部采样 :如果使用尾部采样,配置最大追踪持续时间,减少资源消耗。
- 监控和调整 :定期监控采样效果,根据实际情况调整采样策略和配置,以满足不断变化的需求。
12. 总结与展望
采样是管理遥测数据量的重要手段,OpenTelemetry 提供了丰富的采样策略和工具,帮助我们在保留数据价值的同时,有效减少数据量。通过合理选择采样策略和采样器,结合 SDK 和收集器进行灵活配置,可以满足不同场景下的需求。
未来,随着分布式系统的不断发展,对遥测数据管理的要求也会越来越高。OpenTelemetry 可能会进一步完善采样技术,提供更多的采样策略和优化方法。同时,也需要我们不断探索和实践,以更好地应用采样技术,提高系统的可观测性和性能。
希望本文能够帮助你深入理解 OpenTelemetry 采样技术,在实际应用中做出更合理的决策。如果你有任何问题或建议,欢迎留言讨论。
超级会员免费看
81

被折叠的 条评论
为什么被折叠?



