弹性
OpenTelemetry Collector 的设计考虑了各种组件和配置,以最大程度地减少遥测数据在处理和导出过程中的丢失。然而,理解可能发生数据丢失的场景以及如何减轻这些风险,对于建立一个弹性的可观察性管道至关重要。
理解 Collector 的弹性
弹性的 Collector 在面临不利条件时,能够维持遥测数据的流和处理能力,确保整体可观察性管道的正常运行。
Collector 的弹性主要体现在其如何处理数据,当配置的端点(追踪、指标或日志的目的地)变得不可用,或者 Collector 实例本身出现崩溃等问题时。
发送队列(内存缓冲)
Collector 的导出器内置的最基本弹性形式就是发送队列。
工作原理:当配置一个导出器时,它通常包含一个发送队列,该队列在内存中缓冲数据,然后将其发送到下游端点。如果端点可用,数据会快速通过。
处理端点不可用:如果端点变得不可用,例如由于网络问题或后端重启,导出器无法立即发送数据。此时,它不会丢弃数据,而是将其添加到内存中的发送队列。
重试机制:Collector 采用带有指数退避和抖动的重试机制。在等待间隔后,它会反复尝试发送缓冲的数据。默认情况下,它会重试长达 5 分钟。
数据丢失场景
- 队列已满:内存队列的大小是可配置的(默认通常是 1000 个批次/请求)。如果端点一直不可用,并且新数据持续到达,队列可能会填满。一旦队列填满,传入的新数据将被丢弃,以防止 Collector 耗尽内存。
- 重试超时:如果端点在配置的最长重试持续时间(默认为 5 分钟)内仍然不可用,Collector 将停止重试队列中最旧的数据并将其丢弃。
配置:您可以在导出器设置中配置队列大小和重试行为。
exporters: otlp: endpoint: otlp.example.com:4317 sending_queue: storage: file_storage queue_size: 5_000 # Increase queue size (default 1000) retry_on_failure: initial_interval: 5s max_interval: 30s max_elapsed_time: 10m # Increase max retry time (default 300s)
为任何通过网络发送数据的导出器启用发送队列。根据预期的流量、Collector 可用的内存以及端点可接受的停机时间,调整 queue_size 和 max_elapsed_time。监控队列指标(otelcol_exporter_queue_size、otelcol_exporter_queue_capacity)。
持久化存储(预写日志 - WAL)
为了防止 Collector 实例本身崩溃或重启时发生数据丢失,您可以使用 file_storage 扩展来为发送队列启用持久化存储。
工作原理:发送队列不仅在内存中缓冲数据,还会在尝试导出之前将其写入磁盘上的预写日志(WAL)。
处理 Collector 崩溃:如果 Collector 在数据位于其队列中时崩溃,数据会被持久化到磁盘。当 Collector 重启时,它会从 WAL 中读取数据,并恢复尝试将其发送到端点。
数据丢失场景:如果磁盘发生故障或空间不足,或者即使 Collector 重启后端点仍然不可用且超出重试限制,数据仍然可能丢失。其保证可能不如专用消息队列那么强。
配置
- 定义
file_storage扩展。 - 在导出器的
sending_queue配置中引用存储 ID。
extensions: file_storage: # Define the extension instance directory: /var/lib/otelcol/storage # Choose a persistent directory exporters: otlp: endpoint: otlp.example.com:4317 sending_queue: storage: file_storage # Reference the storage extension instance service: extensions: [file_storage] # Enable the extension in the service pipeline pipelines: traces: receivers: [otlp] exporters: [otlp]- 定义
为关键 Collector(如网关实例或收集关键数据的代理)使用持久化存储,因为这些 Collector 由于崩溃而导致的数据丢失是不可接受的。确保所选目录具有足够的磁盘空间和适当的权限。
消息队列
为了获得最高级别的弹性,特别是在不同的 Collector 层级之间(如代理到网关)或在您的基础设施和供应商后端之间,您可以引入一个专用的消息队列,如 Kafka。
- 工作原理:一个 Collector 实例(代理)使用 Kafka 导出器将数据导出到 Kafka 主题。另一个 Collector 实例(网关)使用 Kafka 接收器从该 Kafka 主题消费数据。
- 处理端点/Collector 不可用
- 如果消费 Collector(网关)宕机,消息会简单地累积在 Kafka 主题中(直到达到 Kafka 的保留限制)。只要 Kafka 正常运行,生产 Collector(代理)就不会受到影响。
- 如果生产 Collector(代理)宕机,没有新数据进入队列,但消费者可以继续处理现有消息。
- 如果 Kafka 本身宕机,生产 Collector 需要自己的弹性机制(如发送队列,可能带有 WAL)来缓冲发往 Kafka 的数据。
- 数据丢失场景:数据丢失主要与 Kafka 本身(集群故障、主题配置错误、数据过期)或生产端在没有足够本地缓冲的情况下发送到 Kafka 的失败有关。
- 配置
代理 Collector 配置(生产者)
exporters: kafka: brokers: ['kafka-broker1:9092', 'kafka-broker2:9092'] topic: otlp_traces receivers: otlp: protocols: grpc: service: pipelines: traces: receivers: [otlp] exporters: [kafka]网关 Collector 配置(消费者)
receivers: kafka: brokers: ['kafka-broker1:9092', 'kafka-broker2:9092'] topic: otlp_traces initial_offset: earliest # Process backlog exporters: otlp: endpoint: otlp.example.com:4317 # Consider queue/retry for exporting *from* Gateway to Backend service: pipelines: traces: receivers: [kafka] exporters: [otlp]
对于需要高持久性的关键数据路径,特别是跨网络边界(例如,数据中心、可用区之间或到云供应商),使用消息队列。这种方法利用了 Kafka 等系统内置的强大弹性,但增加了运营复杂性,并需要管理消息队列系统的专业知识。
数据丢失的场景
在以下情况下可能发生数据丢失
- 网络不可用 + 超时:下游端点不可用的时间超过了
retry_on_failure设置中配置的max_elapsed_time。 - 网络不可用 + 队列溢出:下游端点不可用,并且发送队列(内存或持久化)在端点恢复之前已满。新数据将被丢弃。
- Collector 崩溃(无持久化):Collector 实例崩溃或被终止,并且它仅使用了内存发送队列。内存中的数据将丢失。
- 持久化存储故障:
file_storage扩展使用的磁盘发生故障或空间不足。 - 消息队列故障:外部消息队列(如 Kafka)发生中断或数据丢失事件,并且生产 Collector 没有足够的本地缓冲。
- 配置错误:导出器或接收器配置不正确,导致数据流中断。
- 禁用了弹性:在配置中明确禁用了发送队列或重试机制。
防止数据丢失的建议
遵循以下建议,以最大程度地减少数据丢失并确保可靠的遥测数据收集
- 始终使用发送队列:为通过网络发送数据的导出器启用
sending_queue。 - 监控 Collector 指标:积极监控
otelcol_exporter_queue_size、otelcol_exporter_queue_capacity、otelcol_exporter_send_failed_spans(以及指标/日志的等效指标),以便及早检测潜在问题。 - 调整队列大小和重试参数:根据预期的负载、内存/磁盘资源和可接受的端点停机时间,调整
queue_size和retry_on_failure参数。 - 使用持久化存储(WAL):对于在 Collector 重启期间不允许数据丢失的代理或网关,为发送队列配置
file_storage扩展。 - 考虑使用消息队列:为了在网络段之间实现最大的持久性,或解耦 Collector 层级,如果运营开销可接受,请使用托管消息队列,如 Kafka。
- 使用适当的部署模式
- 采用代理 + 网关的架构。代理处理本地收集,网关处理处理、批处理和弹性导出。
- 将弹性工作(队列、WAL、Kafka)集中在网络跳跃处:代理 -> 网关 和 网关 -> 后端。
- 应用程序(SDK)与本地代理(Sidecar/DaemonSet)之间的弹性通常不太关键,因为本地网络通常是可靠的;在此处添加队列有时会因代理不可用而对应用程序产生负面影响。
通过理解这些机制并应用适当的配置,您可以显著提高 OpenTelemetry Collector 部署的弹性并最大程度地减少数据丢失。