架构
OpenTelemetry Collector 是一个可执行文件,它可以接收遥测数据,对其进行处理,并将其导出到多个目标,如可观察性后端。
Collector 支持多种流行的开源协议来接收和发送遥测数据,并且它提供了一个可扩展的架构来添加更多协议。
数据接收、处理和导出是通过 管道 来完成的。您可以配置 Collector 来拥有一个或多个管道。
每个管道包含以下内容:
同一个接收器可以包含在多个管道中,多个管道也可以包含同一个导出器。
管道
管道定义了数据在 Collector 中的路径:从接收,到处理(或修改),最后到导出。
管道可以处理三种遥测数据类型:跟踪 (traces)、指标 (metrics) 和日志 (logs)。数据类型是管道配置定义的属性。管道中使用的接收器、处理器和导出器必须支持特定的数据类型,否则在加载配置时会报告 pipeline.ErrSignalNotSupported 异常。
下图代表了一个典型的管道:
--- title: Pipeline --- flowchart LR R1(Receiver 1) --> P1[Processor 1] R2(Receiver 2) --> P1 RM(...) ~~~ P1 RN(Receiver N) --> P1 P1 --> P2[Processor 2] P2 --> PM[...] PM --> PN[Processor N] PN --> FO((fan-out)) FO --> E1[[Exporter 1]] FO --> E2[[Exporter 2]] FO ~~~ EM[[...]] FO --> EN[[Exporter N]]
管道可以有一个或多个接收器。所有接收器的数据都会被推送到第一个处理器,该处理器处理数据,然后将其推送到下一个处理器。如果进行采样或过滤,处理器可能会丢弃数据。这个过程一直持续到管道中的最后一个处理器将数据推送到导出器。每个导出器都会收到每个数据元素的副本。最后一个处理器使用 fanoutconsumer 将数据发送到多个导出器。
管道是在 Collector 启动时根据配置中的管道定义构建的。
管道配置通常如下所示:
service:
pipelines: # section that can contain multiple subsections, one per pipeline
traces: # type of the pipeline
receivers: [otlp, zipkin]
processors: [memory_limiter]
exporters: [otlp, zipkin]
上一个示例定义了一个用于跟踪遥测数据的管道,它有两个接收器、两个处理器和两个导出器。
接收器
接收器通常监听网络端口并接收遥测数据。它们也可以主动获取数据,例如通过抓取器 (scrapers)。通常一个接收器被配置为将接收到的数据发送到一个管道。然而,也可以配置同一个接收器将相同的接收数据发送到多个管道。这可以通过在多个管道的 receivers 键中列出同一个接收器来实现。
receivers:
otlp:
protocols:
grpc:
endpoint: localhost:4317
service:
pipelines:
traces: # a pipeline of “traces” type
receivers: [otlp]
processors: [memory_limiter]
exporters: [otlp]
traces/2: # another pipeline of “traces” type
receivers: [otlp]
processors: [transform]
exporters: [otlp]
在上面的示例中,otlp 接收器会将相同的数据发送到管道 traces 和管道 traces/2。
配置使用复合键名,形式为
type[/name]。
当 Collector 加载此配置时,结果如下所示(部分处理器和导出器已省略以简化):
flowchart LR
R1("`#quot;opentelemetry-collector#quot; Receiver`") --> FO((fan-out))
FO -->|Pipeline 'traces'| P1["`#quot;memory_limiter#quot; Processor`"]
FO -->|Pipeline 'traces/2'| P2["`#quot;transform#quot; Processor`"]
P1 ~~~ M1[...]
P2 ~~~ M2[...]当同一个接收器在多个管道中被引用时,Collector 在运行时只创建一个接收器实例,该实例会将数据发送到一个 fan-out consumer。fan-out consumer 进而将数据发送到每个管道的第一个处理器。从接收器到 fan-out consumer 再到处理器的at 数据传播是通过同步函数调用完成的。这意味着如果一个处理器阻塞了调用,其他连接到此接收器的管道将无法接收相同的数据,并且接收器本身会停止处理和转发新接收到的数据。
导出器
导出器通常将它们接收到的数据转发到网络上的某个目标,但它们也可以将数据发送到其他地方。例如,debug 导出器会将遥测数据写入日志目标。
配置允许有多个相同类型的导出器,即使在同一个管道中。例如,您可以定义两个 otlp 导出器,每个导出器发送到不同的 OTLP 端点。
exporters:
otlp/1:
endpoint: example.com:4317
otlp/2:
endpoint: localhost:14317
一个导出器通常从一个管道获取数据。但是,您可以配置多个管道将数据发送到同一个导出器。
exporters:
otlp:
protocols:
grpc:
endpoint: localhost:14250
service:
pipelines:
traces: # a pipeline of “traces” type
receivers: [zipkin]
processors: [memory_limiter]
exporters: [otlp]
traces/2: # another pipeline of “traces” type
receivers: [otlp]
processors: [transform]
exporters: [otlp]
在上面的示例中,otlp 导出器从管道 traces 和管道 traces/2 获取数据。当 Collector 加载此配置时,结果如下所示(部分处理器和接收器已省略以简化):
flowchart LR M1[...] ~~~ P1["`#quot;memory_limiter#quot; Processor`"] M2[...] ~~~ P2["`#quot;transform#quot; Processor`"] P1 -->|Pipeline 'traces'|E1[["`#quot;otlp#quot; Exporter`"]] P2 -->|Pipeline 'traces/2'|E1
处理器
一个管道可以包含顺序连接的处理器。第一个处理器从为该管道配置的一个或多个接收器获取数据,最后一个处理器将数据发送到为该管道配置的一个或多个导出器。第一个和最后一个处理器之间的所有处理器仅从一个前一个处理器接收数据,并发送到一个后一个处理器。
处理器可以在转发数据之前转换数据,例如添加或删除 span 的属性。它们也可以通过决定不转发数据来丢弃数据(例如,probabilisticsampler 处理器)。或者它们可以生成新数据。
处理器的相同名称可以在多个管道的 processors 键中被引用。在这种情况下,这些处理器使用相同的配置,但每个管道始终获得自己的处理器实例。每个处理器都有自己的状态,并且处理器之间永远不会共享。例如,如果 transform 处理器在多个管道中使用,每个管道都有自己的 transform 处理器,但如果它们在配置中引用相同的键,则每个 transform 处理器都以完全相同的方式配置。请参阅以下配置:
processors:
transform:
error_mode: ignore
trace_statements:
- set(resource.attributes["namespace"],
resource.attributes["k8s.namespace.name"])
- delete_key(resource.attributes, "k8s.namespace.name")
service:
pipelines:
traces: # a pipeline of “traces” type
receivers: [zipkin]
processors: [transform]
exporters: [otlp]
traces/2: # another pipeline of “traces” type
receivers: [otlp]
processors: [transform]
exporters: [otlp]
当 Collector 加载此配置时,结果如下所示:
---
title: Pipeline "traces"
---
flowchart LR
R1("`zipkin Receiver`") --> P1["`#quot;transform#quot; Processor`"]
P1 --> E1[["`#quot;otlp#quot; Exporter`"]]---
title: Pipeline "traces/2"
---
flowchart LR
R1("`otlp Receiver`") --> P1["`#quot;transform#quot; Processor`"]
P1 --> E1[["`#quot;otlp#quot; Exporter`"]]请注意,每个 transform 处理器都是独立的实例,尽管它们都以 send_batch_size 为 10000 的方式进行配置。
同一个处理器的名称不能在一个管道的
processors键中被多次引用。
作为代理运行
在典型的虚拟机/容器上,用户应用程序运行在一些进程/ pod 中,并使用 OpenTelemetry 库。以前,库会执行所有跟踪、指标和日志的记录、收集、采样和聚合,然后通过库导出器将数据导出到其他持久存储后端,或者在本地 zpages 上显示。这种模式有几个缺点,例如:
- 对于每个 OpenTelemetry 库,必须用原生语言重新实现导出器和 zpages。
- 在某些编程语言(例如 Ruby 或 PHP)中,在进程中进行统计聚合非常困难。
- 为了启用 OpenTelemetry span、统计数据或指标的导出,应用程序用户需要手动添加库导出器并重新部署他们的二进制文件。这在发生事件时尤其困难,因为用户希望立即使用 OpenTelemetry 来调查问题。
- 应用程序用户需要负责配置和初始化导出器。这些任务容易出错(例如,设置错误的凭据或被监控的资源),并且用户可能不愿用 OpenTelemetry 来“污染”他们的代码。
为了解决上述问题,您可以将 OpenTelemetry Collector 作为代理运行。该代理作为一个守护进程在虚拟机/容器中运行,并且可以独立于库进行部署。一旦代理部署并运行,它就应该能够从库中检索跟踪、指标和日志,并将它们导出到其他后端。我们还可以让代理能够将配置(例如采样概率)推送到库。对于那些无法在进程中进行统计聚合的语言,它们可以发送原始测量值,由代理进行聚合。
flowchart LR
subgraph S1 ["#nbsp;"]
subgraph S2 ["#nbsp;"]
subgraph VM [VM]
PR["Process [Library]"] -->|Push sample spans, metrics| AB[Agent Binary]
AB -->|Push configs| PR
end
subgraph K8s-pod [K8s Pod]
AC["`App Container [Library]`"] --> AS[Agent Sidecar]
AS --> AC
end
subgraph K8s-node [K8s Node]
subgraph Pod1 [Pod]
APP1[App] ~~~ APP2[App]
end
subgraph Pod2 [Pod]
APP3[App] ~~~ APP4[App]
end
subgraph Pod3 [Pod]
APP5[App] ~~~ APP6[App]
end
subgraph AD [Agent Daemonset]
end
APP1 --> AD
APP2 --> AD
APP4 --> AD
APP6 --> AD
end
end
subgraph Backends ["#nbsp;"]
AB --> BE[Backend]
AS --> PRM[Prometheus Backend]
AS --> JA[Jaeger Backend]
AD --> JA
end
end
class S2 noLines;
class VM,K8s-pod,K8s-node,Pod1,Pod2,Pod3,Backends withLines;
class PR,AB,AC,AS,APP1,APP2,APP3,APP4,APP5,APP6,AD,BE,PRM,JA nodeStyle
classDef noLines stroke:#fff,stroke-width:4px,color:#000000;
classDef withLines fill:#fff,stroke:#4f62ad,color:#000000;
classDef nodeStyle fill:#e3e8fc,stroke:#4f62ad,color:#000000;对于其他库的开发人员和维护者:通过添加特定的接收器,您可以配置一个代理来接受来自其他跟踪/监控库(如 Zipkin、Prometheus 等)的跟踪、指标和日志。有关详细信息,请参阅 接收器。
作为网关运行
OpenTelemetry Collector 可以作为一个网关实例运行,接收一个或多个代理或库,或者以支持协议之一发送数据的任务/代理导出的 span 和指标。Collector 配置为将数据发送到配置的导出器。下图总结了部署架构:
flowchart LR
subgraph S1 ["#nbsp;"]
subgraph S2 ["#nbsp;"]
subgraph S3 ["#nbsp;"]
subgraph VM [VM]
PR["Process [Library]"]
end
subgraph K8s-pod [K8s Pod]
AC["`App Container [Library]`"]
end
subgraph K8s-node [K8s Node]
subgraph Pod1 [Pod]
APP1[App] ~~~ APP2[App]
end
subgraph Pod2 [Pod]
APP3[App] ~~~ APP4[App]
end
subgraph Pod3 [Pod]
APP5[App] ~~~ APP6[App]
end
subgraph AD [Agent Daemonset]
end
APP1 --> AD
APP2 --> AD
APP4 --> AD
APP6 --> AD
end
end
subgraph S4 ["#nbsp;"]
PR --> OTEL["`OpenTelemetry Collector Service`"]
AC --> OTEL
AD --> OTEL
OTEL ---> BE[Backend X]
end
end
subgraph S5 ["#nbsp;"]
subgraph S6 ["#nbsp;"]
JA[Jaeger Backend]
end
subgraph S7 ["#nbsp;"]
PRM[Prometheus Backend]
end
end
JA ~~~ PRM
OTEL --> JA
OTEL --> PRM
end
class S1,S3,S4,S5,S6,S7,S8 noLines;
class VM,K8s-pod,K8s-node,Pod1,Pod2,Pod3 withLines;
class S2 lightLines
class PR,AC,APP1,APP2,APP3,APP4,APP5,APP6,AD,OTEL,BE,JA,PRM nodeStyle
classDef noLines stroke-width:0px,color:#000000;
classDef withLines fill:#fff,stroke:#4f62ad,color:#000000;
classDef lightLines stroke:#acaeb0,color:#000000;
classDef nodeStyle fill:#e3e8fc,stroke:#4f62ad,color:#000000;OpenTelemetry Collector 也可以部署在其他配置中,例如接收来自其他代理或客户端的数据,这些数据以其接收器支持的格式之一发送。