扩展OpenTelemetry Collector

使用OpenTelemetry Collector规划可观测性流水线时,应考虑随着遥测采集量增加,如何扩展整条流水线。

下面各节将帮助你完成规划:讨论哪些组件需要扩展、如何判断扩展时机,以及如何执行扩展计划。

扩展什么

虽然OpenTelemetry Collector在一个二进制程序中处理所有遥测信号类型,但各种信号的扩展需求可能不同,需要不同的扩展策略。首先分析工作负载,确定哪类信号预计占据最大负载,以及Collector将接收哪些格式。例如,扩展抓取集群与扩展日志接收器有很大不同。

还要考虑工作负载的弹性:一天中的特定时段是否有高峰,还是24小时负载相似?收集这些信息后,就能知道需要扩展什么。

例如,假设你需要抓取数百个Prometheus端点,每分钟接收来自fluentd实例的1 TB日志,并从最新微服务接收OTLP格式的应用指标与链路。在这种情况下,需要一种能分别扩展各类信号的架构:扩展Prometheus接收器时,抓取器之间必须协调,确定每个抓取器负责哪个端点。

相比之下,无状态日志接收器可以按需水平扩展。将接收指标与链路的OTLP接收器放在第三个Collector集群中,可以隔离故障,并更快迭代,不必担心重启繁忙的流水线。由于OTLP接收器支持所有遥测类型,可以将应用指标和链路保留在同一实例中,在需要时水平扩展。

何时扩展

同样,应先理解工作负载,再决定何时扩容或缩容。不过,Collector发出的某些指标能为采取行动的时机提供线索。

当流水线使用memory_limiter处理器时,otelcol_processor_refused_spans是一个有用指标。这个处理器限制Collector可使用的内存。实际内存占用可能略高于配置的上限,但最终memory_limiter会阻止新数据继续通过流水线,并通过该指标记录拒收情况。

其他遥测类型也有对应指标。如果数据过于频繁地被拒绝进入流水线,通常应考虑扩容Collector集群。当各节点内存占用显著低于处理器配置的上限时,可以缩容。

另一组需关注的指标是导出器队列相关的otelcol_exporter_queue_capacity与otelcol_exporter_queue_size。等待可用工作线程发送数据期间,Collector会在内存中排队。如果工作线程不足,或后端太慢,数据就会在队列中堆积。

队列达到容量后(原文写为otelcol_exporter_queue_size > otelcol_exporter_queue_capacity),会拒绝数据,并记录otelcol_exporter_enqueue_failed_spans。增加工作线程通常能让Collector导出更多数据,但这未必是你希望的结果,参见下文“何时不应扩展”。

一般建议监控队列大小,达到容量的60%–70%时考虑扩容;若持续很低则考虑缩容,同时保持最低副本数,例如3个,以确保韧性。

还应熟悉准备使用的组件,因为不同组件可能发出其他指标。例如,负载均衡导出器会记录导出操作的耗时,并通过直方图otelcol_loadbalancer_backend_latency暴露。

可以据此判断各后端处理请求的耗时是否接近:单个后端变慢,可能意味着Collector之外的问题。

对于Prometheus接收器这类执行抓取的接收器,如果抓取所有目标所需时间经常逼近抓取间隔,就应扩展或分片抓取任务。此时需要增加抓取器,通常就是新增Collector实例。

何时不应扩展

理解哪些迹象意味着扩展不会带来好处,可能与知道何时扩展同样重要。例如,遥测数据库无法承受负载时,如果不扩展数据库,向集群加入更多Collector也无济于事。同样,Collector与后端之间的网络连接饱和时,增加Collector可能带来有害的副作用。

一种识别方式仍是观察otelcol_exporter_queue_size与otelcol_exporter_queue_capacity。队列大小持续接近容量,说明导出数据比接收数据慢。可以尝试增大队列容量,这会增加Collector内存消耗,但也能为后端争取缓冲空间,避免永久丢弃遥测数据。

不过,如果不断增大容量,队列大小也以相同比例持续上升,就应排查Collector以外的环节。此时增加工作线程也不会有帮助,只会让已经承受高负载的系统压力更大。

另一个后端可能有问题的迹象是otelcol_exporter_send_failed_spans增大,表示向后端发送数据永久失败。如果这种情况持续发生,扩容Collector很可能只会恶化局面。

如何扩展

至此,我们已知道流水线中哪些部分需要扩展。从扩展角度看,组件可分为三类:无状态组件、抓取器和有状态组件。

大多数Collector组件都是无状态的。即使它们在内存中保存某些状态,这些状态也不影响扩展。

Prometheus接收器等抓取器通过配置从外部位置获取遥测数据,然后逐个抓取目标,将数据放入流水线。

尾部采样处理器等组件会保存与业务处理有关的重要内存状态,因此不能简单扩展。扩容这些组件之前必须仔细考虑。

扩展无状态Collector并使用负载均衡器

好消息是,大多数情况下扩展Collector很简单:增加副本,再通过负载均衡器将流量分配到各副本即可。

需要实现以下目标时,负载均衡器必不可少:

  • 将传入遥测流量分发到多个无状态Collector实例,避免单个实例过载。
  • 提高采集流水线的可用性和容错能力;实例故障时,将流量转向健康实例。
  • 按需求水平扩展Collector层。

在Kubernetes环境中,可以使用Istio、Linkerd等服务网格,或云厂商负载均衡器提供的成熟负载均衡与限流方案。它们往往提供超越基本负载分发的流量管理、韧性和可观测性功能。

使用gRPC接收数据时——OTLP常见的场景——应使用理解gRPC的L7负载均衡器。普通L4负载均衡器可能与某一个后端Collector维持持久连接,使客户端总是访问同一个实例,抵消扩容的收益。划分采集流水线时仍应考虑可靠性。

例如,工作负载运行在Kubernetes中时,可通过DaemonSet在同一物理节点上部署Collector,并让远程中央Collector在数据送入存储前负责预处理。节点较少而Pod较多时,Sidecar可能更合适:无需专用gRPC负载均衡器,也能改善Collector各层之间gRPC连接的负载分配。

使用Sidecar还有助于避免某个DaemonSet Pod故障时,影响节点上所有Pod依赖的关键组件。

Sidecar模式是在工作负载Pod中加入一个容器。OpenTelemetry Operator可以自动执行这一操作。需要创建OpenTelemetry Collector自定义资源(CR),并在PodSpec或Pod中加入注解,让Operator注入Sidecar:

---
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: sidecar-for-my-workload
spec:
  mode: sidecar
  config: |
    receivers:
      otlp:
        protocols:
          grpc:
            endpoint: 0.0.0.0:4317
    processors:

    exporters:
      # Note: Prior to v0.86.0 use the `logging` instead of `debug`.
      debug:

    service:
      pipelines:
        traces:
          receivers: [otlp]
          processors: []
          exporters: [debug]
---
apiVersion: v1
kind: Pod
metadata:
  name: my-microservice
  annotations:
    sidecar.opentelemetry.io/inject: 'true'
spec:
  containers:
    - name: my-microservice
      image: my-org/my-microservice:v0.0.0
      ports:
        - containerPort: 8080
          protocol: TCP

如果希望绕过Operator,手动添加Sidecar,可参考以下示例:

apiVersion: v1
kind: Pod
metadata:
  name: my-microservice
spec:
  containers:
    - name: my-microservice
      image: my-org/my-microservice:v0.0.0
      ports:
        - containerPort: 8080
          protocol: TCP
    - name: sidecar
      image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector:0.69.0
      ports:
        - containerPort: 8888
          name: metrics
          protocol: TCP
        - containerPort: 4317
          name: otlp-grpc
          protocol: TCP
      args:
        - --config=/conf/collector.yaml
      volumeMounts:
        - mountPath: /conf
          name: sidecar-conf
  volumes:
    - name: sidecar-conf
      configMap:
        name: sidecar-for-my-workload
        items:
          - key: collector.yaml
            path: collector.yaml

扩展抓取器

部分接收器主动获取遥测数据并送入流水线,例如host_metrics与prometheus接收器。主机指标采集通常无需扩容,但Prometheus接收器抓取数千个端点时,可能需要拆分任务。不能简单地以相同配置增加实例,否则集群中每个Collector都会尝试抓取相同端点,带来乱序样本等更多问题。

解决方法是按Collector实例对端点分片,使新增副本后,各实例负责不同端点集合。

一种方法是每个Collector使用各自的配置文件,只发现属于自己的端点。例如,每个Collector负责一个Kubernetes命名空间,或具有特定标签的工作负载。

另一种方法是使用Target Allocator。它是一个额外的二进制程序,可随OpenTelemetry Operator部署,将给定配置中的Prometheus抓取目标分配到Collector集群。可以使用如下自定义资源启用它:

apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: collector-with-ta
spec:
  mode: statefulset
  targetAllocator:
    enabled: true
  config: |
    receivers:
      prometheus:
        config:
          scrape_configs:
          - job_name: 'otel-collector'
            scrape_interval: 10s
            static_configs:
            - targets: [ '0.0.0.0:8888' ]

    exporters:
      # Note: Prior to v0.86.0 use the `logging` instead of `debug`.
      debug:

    service:
      pipelines:
        metrics:
          receivers: [prometheus]
          processors: []
          exporters: [debug]

完成协调后,OpenTelemetry Operator会将Collector配置转换为:

exporters:
   # Note: Prior to v0.86.0 use the `logging` instead of `debug`.
   debug: null
 receivers:
   prometheus:
     config:
       global:
         scrape_interval: 1m
         scrape_timeout: 10s
         evaluation_interval: 1m
       scrape_configs:
       - job_name: otel-collector
         honor_timestamps: true
         scrape_interval: 10s
         scrape_timeout: 10s
         metrics_path: /metrics
         scheme: http
         follow_redirects: true
         http_sd_configs:
         - follow_redirects: false
           url: http://collector-with-ta-targetallocator:80/jobs/otel-collector/targets?collector_id=$POD_NAME
service:
   pipelines:
     metrics:
       exporters:
       - debug
       processors: []
       receivers:
       - prometheus

注意,Operator为otel-collector抓取配置加入了global部分和新的http_sd_configs,指向它创建的Target Allocator实例。现在,只需修改CR的replicas属性来扩展Collector,Target Allocator就会为每个Collector实例(Pod)提供定制的http_sd_config,相应分配负载。

扩展有状态Collector

某些组件在内存中保存数据,扩容后会产生不同结果。例如,尾部采样处理器会在一段时间内保存span,直到认为链路完整时才做采样决策。向Collector集群增加副本,意味着同一链路的span可能被不同Collector接收。各实例分别判断是否采样,可能得到不同答案。

这种行为会导致链路缺失span,无法准确反映该次事务发生的情况。

使用span-to-metrics处理器生成服务指标时也可能出现类似情况。不同Collector接收同一服务的数据后,按服务名进行的聚合会不准确。

为解决这一问题,可以在执行尾部采样或span-to-metrics处理的Collector前,部署包含负载均衡导出器的Collector层。该导出器对链路ID或服务名进行一致性哈希,确定哪个后端Collector接收同一链路的span。可以配置它使用某个DNS A记录背后的主机列表,例如Kubernetes无头服务。

该服务后面的部署扩容或缩容时,负载均衡导出器最终会看到更新后的主机列表。也可以指定静态主机列表。增加副本数即可扩展配置了负载均衡导出器的Collector层。请注意,各Collector可能在不同时间执行DNS查询,导致短暂的集群视图差异。

在弹性变化频繁的环境中,建议减小interval值,缩短集群视图不一致的时间。

以下配置以DNS A记录作为后端信息来源,即observability命名空间中的Kubernetes服务otelcol:

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:

exporters:
  load_balancing:
    protocol:
      otlp:
    resolver:
      dns:
        hostname: otelcol.observability.svc.cluster.local

service:
  pipelines:
    traces:
      receivers:
        - otlp
      processors: []
      exporters:
        - load_balancing

原文:Scaling the Collector,OpenTelemetry官方文档,最后修改于2026年9月10日。源文档采用CC BY 4.0;本稿为中文翻译。原配置中的版本与历史API(包括v1alpha1、0.69.0和v0.86.0前的logging说明)保留,未部署验证。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容