0
129
0
0
首页/专栏/ 技术分享/ 查看内容

ClickHouse 官方文档:如何与 OpenTelemetry 集成【4/5】

 admin   发表于  2024-12-13 14:49
专栏 技术分享


与 ClickHouse 相关的组件  

OpenTelemetry 包括多种功能组件。除了定义数据与 API 规范、标准协议及字段命名规则外,它提供了两个在基于 ClickHouse 的可观测性解决方案中尤为重要的功能:

1. OpenTelemetry Collector

Collector 是一个代理组件,用于接收、处理和导出遥测数据。在基于 ClickHouse 的解决方案中,Collector 主要用于日志收集和事件处理,随后将数据批量化插入 ClickHouse。

2. 语言 SDK

OpenTelemetry 提供了一系列语言 SDK,用于实现遥测数据的规范、API 和导出。这些 SDK 确保应用程序中的跟踪能够正确记录,并生成相关的 span,同时通过元数据在服务间传递上下文,构建分布式跟踪。这些 SDK 配套的生态系统还能自动为常用库和框架实现埋点功能,无需用户手动修改代码,便可开箱即用。

基于 ClickHouse 的可观测性解决方案充分利用了 OpenTelemetry Collector 和语言 SDK,使遥测数据的生成、收集和分析更加高效。


发行版

OpenTelemetry Collector 提供多个版本,其中与 ClickHouse 解决方案相关的 filelog 接收器和 ClickHouse 导出器仅包含在 OpenTelemetry Collector Contrib 版本中。

这个版本包含了大量的组件,适合用户在开发阶段尝试不同的配置。然而,在生产环境中,我们建议用户只部署所需的组件。这样做的理由包括:

  • 减少 Collector 的体积,从而缩短部署时间

  • 降低潜在的安全风险,减少攻击面

用户可以使用 OpenTelemetry Collector Builder 来创建自定义 Collector。


使用 OTel 导入数据

Collector 部署角色

为了收集日志并将其存入 ClickHouse,我们推荐使用 OpenTelemetry Collector。该 Collector 可以以两种主要角色部署:

  • 代理(Agent)  代理实例通常部署在边缘节点上,例如服务器或 Kubernetes 节点,或直接从应用程序接收已埋点的事件。在这种部署模式下,代理实例与应用程序一起运行,通常作为 sidecar 或 DaemonSet 配置。代理可以直接将收集到的数据发送到 ClickHouse,或者先发送到网关实例,再进行集中处理。如果代理直接将数据发送到 ClickHouse,则称为“代理部署模式”。

  • 网关(Gateway)  网关实例提供独立的服务,通常按集群、数据中心或区域进行部署。例如,在 Kubernetes 中部署一个网关,所有应用程序和代理都通过一个统一的 OTLP 端点发送数据。网关部署模式通常包含多个网关实例,并配有负载均衡器来分配请求。所有代理和应用程序通过这一单一端点进行通信。

以下示例展示了一个简单的代理 Collector,直接将数据发送到 ClickHouse。有关网关部署和适用场景的详细信息,请参见《使用网关进行扩展》。


收集日志

使用 OpenTelemetry Collector 的主要优势在于,它能够帮助您的服务快速卸载数据,同时将重试、批处理、加密、敏感数据过滤等复杂任务交给 Collector 处理。

在 Collector 中,数据处理分为接收、处理和导出三个阶段。接收器负责收集数据,可以是拉取(pull)或推送(push)方式。处理器用于对数据进行转换和增强。导出器则负责将数据发送到目标服务。虽然理论上,这个目标服务也可以是另一个 Collector,但在这里我们假设所有数据都直接发送到 ClickHouse 进行处理。

我们建议用户深入了解 Collector 的所有接收器、处理器和导出器。

Collector 提供了两种主要的日志收集方式:

通过 OTLP 协议-在这种模式下,日志数据通过 OTLP 协议从 OpenTelemetry SDK 推送到 Collector。OpenTelemetry 的演示实例采用了这一方法,各种语言的 OTLP 导出器假设一个本地 Collector 端点。此时,Collector 必须配置为使用 OTLP 接收器 — 请参考上面的演示配置。采用这种方式的一个好处是,日志数据将自动带有 Trace Id,便于用户在后续查询时将日志与特定的 trace 对应起来,反之亦然。

这种方式要求用户为应用程序代码加上相应的 OpenTelemetry SDK 进行埋点。

通过 Filelog 接收器抓取日志-Filelog 接收器通过监控磁盘上的日志文件来收集日志,并将其发送到 ClickHouse。这个接收器能处理复杂的任务,比如识别多行日志、处理日志轮换、通过检查点确保重启后的可靠性,并提取日志结构。它还能支持跟踪 Docker 和 Kubernetes 容器的日志,并通过 Helm chart 部署,自动从这些日志中提取结构信息并增强 pod 相关数据。

大多数情况下,部署环境会同时使用这两种接收器。我们建议用户阅读 Collector 的官方文档,熟悉相关概念,配置结构以及安装步骤。

提示:otelbin.io

otelbin.io 是一个非常实用的工具,可以帮助用户验证和可视化配置,确保 Collector 配置正确无误。


结构化与非结构化日志

日志可以是结构化的,也可以是非结构化的。

结构化日志 使用如 JSON 这样的数据格式,定义了元数据字段,例如 http 状态码和源 IP 地址。

{    "remote_addr":"54.36.149.41",    "remote_user":"-","run_time":"0","time_local":"2019-01-22 00:26:14.000","request_type":"GET",    "request_path":"\/filter\/27|13 ,27|  5 ,p53","request_protocol":"HTTP\/1.1",    "status":"200",    "size":"30577",    "referer":"-",    "user_agent":"Mozilla\/5.0 (compatible; AhrefsBot\/6.1; +http:\/\/ahrefs.com\/robot\/)"}

非结构化日志 通常也包含一些可以通过正则表达式提取的固有结构,但它们主要以纯文本字符串的形式记录日志。

54.36.149.41 - - [22/Jan/2019:03:56:14 +0330] "GET/filter/27|13%20%D9%85%DA%AF%D8%A7%D9%BE%DB%8C%DA%A9%D8%B3%D9%84,27|%DA%A9%D9%85%D8%AA%D8%B1%20%D8%A7%D8%B2%205%20%D9%85%DA%AF%D8%A7%D9%BE%DB%8C%DA%A9%D8%B3%D9%84,p53 HTTP/1.1" 200 30577 "-" "Mozilla/5.0 (compatible; AhrefsBot/6.1; +http://ahrefs.com/robot/)" "-"

我们建议用户尽量使用结构化日志,特别是以 JSON 格式(即 ndjson)记录日志。这样做可以简化后续日志的处理过程,无论是在通过 Collector 处理器发送到 ClickHouse 之前,还是在插入时通过物化视图进行处理。结构化日志能够有效减少后续处理所需的资源,从而降低 ClickHouse 解决方案对 CPU 的需求。


示例

为了便于理解,我们提供了一个结构化(JSON)日志和一个非结构化日志的数据集,每个数据集大约包含 1000 万行数据,下载链接如下:

  • 非结构化日志

  • 结构化日志

下载方式:公众号后台回复“数据集”获取

在以下示例中,我们使用结构化日志数据集。请确保下载并解压该文件,以便复现接下来的示例。

下面是一个简单的 OTel Collector 配置示例,配置中读取磁盘上的日志文件,使用 filelog 接收器,并将处理后的日志输出到标准输出(stdout)。由于我们的日志是结构化的,因此我们使用 json_parser 操作符。请根据实际情况修改访问结构化日志文件的路径。

考虑使用 ClickHouse 进行解析

下面的示例展示了如何从日志中提取时间戳。此过程需要使用 json_parser 操作符,将整个日志行转换为 JSON 格式,并将结果存储在 LogAttributes 字段中。尽管这种方法会占用一定的计算资源,但可以通过在 ClickHouse 中使用 SQL 提取结构的方式更加高效地完成这一任务。对于非结构化日志,您可以使用 regex_parser 来达到相同的效果,具体示例如下所示。

config-structured-logs.yaml

receivers:  filelog:    include:      - /opt/data/logs/access-structured.log    start_at: beginning    operators:      - type: json_parser        timestamp:          parse_from: attributes.time_local          layout: '%Y-%m-%d %H:%M:%S'processors:  batch:    timeout: 5s    send_batch_size: 1exporters:  logging:    loglevel: debugservice:  pipelines:    logs:      receivers: [filelog]      processors: [batch]      exporters: [logging]

用户可以按照官方说明在本地安装 OpenTelemetry Collector。需要注意的是,安装时要确保选择包含 filelog 接收器的 contrib 发行版。例如,用户应该下载 otelcol-contrib_0.102.1_darwin_arm64.tar.gz,而不是 otelcol_0.102.1_darwin_arm64.tar.gz。发布版本可以在此处找到【https://github.com/open-telemetry/opentelemetry-collector-releases/releases】

安装完成后,OTel Collector 可以通过以下命令启动:

./otelcol-contrib --config config-logs.yaml

假设使用结构化日志,输出的日志消息将如下所示:

LogRecord #98ObservedTimestamp: 2024-06-19 13:21:16.414259 +0000 UTCTimestamp: 2019-01-22 01:12:53 +0000 UTCSeverityText:SeverityNumber: Unspecified(0)Body: Str({"remote_addr":"66.249.66.195","remote_user":"-","run_time":"0","time_local":"2019-01-22 01:12:53.000","request_type":"GET","request_path":"\/product\/7564","request_protocol":"HTTP\/1.1","status":"301","size":"178","referer":"-","user_agent":"Mozilla\/5.0 (Linux; Android 6.0.1; Nexus 5X Build\/MMB29P) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/41.0.2272.96 Mobile Safari\/537.36 (compatible; Googlebot\/2.1; +http:\/\/www.google.com\/bot.html)"})Attributes:    -> remote_user: Str(-)    -> request_protocol: Str(HTTP/1.1)    -> time_local: Str(2019-01-22 01:12:53.000)    -> user_agent: Str(Mozilla/5.0 (Linux; Android 6.0.1; Nexus 5X Build/MMB29P) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.96 Mobile Safari/537.36 (compatible; Googlebot/2.1; +http://www.google.com/bot.html))    -> log.file.name: Str(access.log)    -> status: Str(301)    -> size: Str(178)    -> referer: Str(-)    -> remote_addr: Str(66.249.66.195)    -> request_type: Str(GET)    -> request_path: Str(/product/7564)    -> run_time: Str(0)Trace ID:Span ID:Flags: 0

上面显示的是 OTel collector 生成的单条日志消息。我们将在后续部分展示如何将这些日志消息导入到 ClickHouse。

完整的日志消息 schema 和可能出现的附加字段(如果使用其他接收器)可以在此查看【https://opentelemetry.io/docs/specs/otel/logs/data-model/】我们强烈建议用户阅读并熟悉这个 schema

关键点是,日志行本身作为字符串存储在 Body 字段中,而通过 json_parser 操作符,JSON 数据被自动提取到 Attributes 字段中。该操作符还用于将时间戳提取到 Timestamp 列中。有关如何处理 OTel 日志的更多建议,请参见处理部分(Processing)。

操作符

操作符是日志处理的基本单元。每个操作符执行一个特定的任务,例如从文件中读取行或从字段中解析 JSON。多个操作符可以串联成一个处理管道,以实现所需的功能。

在上述日志消息中,未包含 TraceIDSpanID 字段。如果启用了分布式追踪,用户可以采用类似的方法,从 JSON 中提取这些字段。

对于需要收集本地或 Kubernetes 日志文件的用户,我们建议先了解 filelog 接收器的配置选项,特别是如何处理偏移量和多行日志解析的配置。


收集 Kubernetes 日志

对于 Kubernetes 日志的收集,我们建议参考 OpenTelemetry 的官方文档指南。我们推荐使用 Kubernetes Attributes Processor 来丰富日志和指标,特别是添加 pod 的元数据。这些元数据可能是动态生成的,例如标签,并将存储在 ResourceAttributes 列中。ClickHouse 当前将该列的数据类型设置为 Map(String, String)。有关如何处理和优化这种类型的更多信息,请参考《使用映射和从映射中提取数据》。


收集追踪

对于希望在代码中实施追踪并收集追踪数据的用户,我们建议按照 OpenTelemetry 的官方文档进行操作。

为了将追踪事件传送到 ClickHouse,用户需要部署 OTel collector,接收通过 OTLP 协议传输的追踪事件。OpenTelemetry 的示例演示了如何为每种支持的编程语言实施追踪,并将事件发送到 collector。以下是一个配置示例,展示了如何将事件输出到 stdout:


示例

由于追踪数据必须通过 OTLP 协议接收,我们使用 `telemetrygen` 工具来生成追踪数据。请按照此处的说明完成安装【https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/cmd/telemetrygen】

以下配置通过 OTLP 接收器接收追踪事件,并将它们发送到 stdout。

配置文件: config-traces.xml

receivers:  otlp:    protocols:      grpc:        endpoint: 0.0.0.0:4317processors:  batch:    timeout: 1sexporters:  logging:    loglevel: debugservice:  pipelines:    traces:      receivers: [otlp]      processors: [batch]      exporters: [logging]

通过以下命令运行配置:

./otelcol-contrib --config config-traces.yaml

使用 telemetrygen 向 collector 发送追踪事件:

$GOBIN/telemetrygen traces --otlp-insecure --traces 300

这将导致如下的追踪消息输出到 stdout:

Span #86    Trace ID    : 1bb5cdd2c9df5f0da320ca22045c60d9    Parent ID   : ce129e5c2dd51378    ID          : fbb14077b5e149a0    Name        : okey-dokey-0    Kind        : Server    Start time  : 2024-06-19 18:03:41.603868 +0000 UTC    End time    : 2024-06-19 18:03:41.603991 +0000 UTC    Status code : Unset    Status message :Attributes:    -> net.peer.ip: Str(1.2.3.4)    -> peer.service: Str(telemetrygen-client)

上面显示的是 OTel collector 生成的一条追踪消息。我们将在后续部分演示如何将这些消息导入到 ClickHouse。

追踪消息的完整 schema 会在此文档中进行维护【https://opentelemetry.io/docs/concepts/signals/traces/】。我们强烈建议用户熟悉这个 schema,以便更好地理解消息的结构。


处理 - 过滤、转换和丰富

正如我们在之前设置日志事件时间戳的示例中所展示的那样,用户往往需要对事件消息进行过滤、转换和丰富。这可以通过 OpenTelemetry 提供的多个功能来实现:

  • 处理器-处理器接收接收器收集的数据,并在将数据发送到导出器之前进行修改或转换。处理器会按照在 collector 配置文件中定义的顺序依次应用。处理器是可选的,但通常推荐使用一个最小的处理器集。当将 OTel collector 与 ClickHouse 一起使用时,建议使用以下几种处理器:

    • 内存限制器(memory_limiter):防止 collector 出现内存溢出的情况。有关如何配置内存限制,请参考《估算资源》。

    • 基于上下文的富集处理器:例如,Kubernetes Attributes Processor,它能自动使用 k8s 元数据(如源 pod ID)来丰富 span、metric 和 log 的资源属性。

    • 头部或尾部采样:如果需要追踪数据,可以使用头部或尾部采样。

    • 基本过滤:在无法通过运算符实现时,可以丢弃不需要的事件(见下文)。

    • 批处理:在与 ClickHouse 配合使用时,批处理是必须的,以确保数据能以批量方式发送到 ClickHouse。请参见《导出到 ClickHouse》【https://clickhouse.com/docs/en/observability/integrating-opentelemetry#exporting-to-clickhouse】

  • 运算符-运算符是日志处理的基本单元。它支持基本的字段解析,例如设置事件的严重性(Severity)和时间戳(Timestamp)。运算符支持 JSON 解析、正则表达式解析、事件过滤和简单的字段转换。我们建议将事件过滤放在此阶段进行。

我们建议避免在运算符或转换处理器中进行过度的事件处理。因为这些操作会消耗大量内存和 CPU,尤其是 JSON 解析。大部分数据处理可以通过物化视图和列在 ClickHouse 插入时进行,只有少部分需要上下文感知的富集操作(如添加 k8s 元数据)无法通过这种方式处理,仍需在 OTel collector 中处理。

如果处理发生在 OTel collector 中,建议将转换处理放在网关实例中,而尽量减少代理实例的处理工作。这样可以确保边缘代理(通常运行在服务器上)所需的资源尽可能少。一般来说,用户只会在代理实例中执行基本的过滤、时间戳设置和上下文相关的富集操作。例如,如果网关实例位于不同的 Kubernetes 集群中,k8s 元数据的富集将需要在代理实例中进行。


Example


以下示例配置展示了如何收集非结构化日志文件。在配置中,通过使用运算符(operators)对日志行进行解析(例如使用 `regex_parser` 提取结构化信息)并过滤事件。同时,还引入了处理器(processor)来批量处理事件并优化内存使用,以确保系统的稳定性和高效运行。

config-unstructured-logs-with-processor.yaml

receivers:  filelog:    
              
              

路过

雷人

握手

鲜花

鸡蛋

版权声明:本文为 clickhouse 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论