请选择 进入手机版 | 继续访问电脑版
0
103
0
0
首页/专栏/ 技术分享/ 查看内容

ClickHouse 官方文档:如何管理可观测性数据【3/5】

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


分区

分区功能允许在磁盘上根据某列或 SQL 表达式对数据进行逻辑划分。每个分区可以独立操作,例如单独删除。这使得用户能够根据时间高效地在存储层之间迁移分区或其子集,或者自动过期和清理数据。

分区是在创建表时通过 PARTITION BY 子句指定的。此子句支持对任意列进行 SQL 表达式计算,计算结果决定数据行将被分配到哪个分区。

在磁盘上,每个分区通过共享的文件夹名称前缀实现逻辑关联,支持独立查询。例如,默认的 otel_logs 模式按天分区,使用表达式 toDate(Timestamp)。当数据写入 ClickHouse 时,系统会对每行数据执行该表达式。如果结果分区已经存在,数据将被路由到对应分区;如果是某天的第一条记录,系统会自动创建一个新分区。

CREATE TABLE default.otel_logs(...)ENGINE = MergeTreePARTITION BY toDate(Timestamp)ORDER BY (ServiceName, SeverityText, toUnixTimestamp(Timestamp), TraceId)

可以对分区执行多种操作,包括备份、列级别的修改、通过变更操作 (mutation) 来调整或删除数据行,以及清除索引(如二级索引)。

例如,假设 otel_logs 表按天分区。如果其中存储了结构化日志数据集,则该表会包含多天的日志数据:

SELECT Timestamp::Date AS day,     count() AS cFROM otel_logsGROUP BY dayORDER BY c DESC
┌────────day─┬───────c─┐2019-01-2223339772019-01-2323266942019-01-2619864562019-01-2418962552019-01-251821770└────────────┴─────────┘
5 rows in set. Elapsed: 0.058 sec. Processed 10.37 million rows, 82.92 MB (177.96 million rows/s., 1.42 GB/s.)Peak memory usage: 4.41 MiB.

可以通过查询系统表简单地查看当前的分区:

SELECT DISTINCT partitionFROM system.partsWHERE `table` = 'otel_logs'
┌─partition──┐2019-01-222019-01-232019-01-242019-01-252019-01-26└────────────┘
5 rows in set. Elapsed: 0.005 sec.

此外,我们可能会设置另一个表,例如 otel_logs_archive,用于归档较早的数据。通过分区移动,数据可以高效迁移到此归档表中(这仅需更改元数据)。

CREATE TABLE otel_logs_archive AS otel_logs--move data to archive tableALTER TABLE otel_logs    (MOVE PARTITION tuple('2019-01-26') TO TABLE otel_logs_archive--confirm data has been movedSELECT    Timestamp::Date AS day,    count() AS cFROM otel_logsGROUP BY dayORDER BY c DESC
┌────────day─┬───────c─┐2019-01-2223339772019-01-2323266942019-01-2418962552019-01-251821770└────────────┴─────────┘
4 rows in set. Elapsed: 0.051 sec. Processed 8.38 million rows, 67.03 MB (163.52 million rows/s., 1.31 GB/s.)Peak memory usage: 4.40 MiB.
SELECT Timestamp::Date AS day, count() AS cFROM otel_logs_archiveGROUP BY dayORDER BY c DESC
┌────────day─┬───────c─┐2019-01-261986456└────────────┴─────────┘
1 row in set. Elapsed: 0.024 sec. Processed 1.99 million rows, 15.89 MB (83.86 million rows/s., 670.87 MB/s.)Peak memory usage: 4.99 MiB.

这种方法优于其他方式,例如使用 INSERT INTO SELECT,将数据重写到目标表。

分区移动

在表之间移动分区需要满足多个条件。例如,表的结构、分区键、主键以及索引或投影必须一致。有关在 ALTER DDL 中指定分区的更多详细信息,请参考相关文档。

此外,通过分区删除数据是一种高效的方法。这种方式比使用变更操作或轻量级删除更节省资源,因此建议优先采用。

ALTER TABLE otel_logs    (DROP PARTITION tuple('2019-01-25'))
SELECT Timestamp::Date AS day, count() AS cFROM otel_logsGROUP BY dayORDER BY c DESC┌────────day─┬───────c─┐2019-01-2246679542019-01-2346533882019-01-243792510└────────────┴─────────┘

注意  

当设置 ttl_only_drop_parts=1 时,TTL 功能会利用这一特性以更高效地管理数据。详细内容请参阅使用 TTL 进行数据管理的相关文档。


应用场景  

以上说明了分区如何帮助高效地移动和操作数据。在实际应用中,分区操作在可观测性 (Observability) 场景中最常用于以下两种情况:

1. 分层存储架构:数据在冷热存储层之间迁移(参见存储层),以支持冷热分层的架构设计。

2. 高效删除:当数据达到指定的 TTL 时,可以快速清理(参见使用 TTL 进行数据管理)。

我们将在后续部分深入分析这两种场景。


查询性能  

分区可以提升查询性能,但效果依赖于具体的访问模式。如果查询仅针对少量分区(如单个分区),性能通常会有所改善,尤其是在分区键不包含在主键中,并且查询通过分区键筛选时。然而,涉及多个分区的查询可能会因数据部分增加而变慢。如果分区键已经是主键的前几个字段,针对单个分区的性能优势会大幅降低甚至不存在。此外,当每个分区中的值是唯一时,分区还可以优化 GROUP BY 查询。总体而言,用户应优先优化主键,并仅在访问模式对某些可预测的子集(如按天分区,且查询主要集中于最近一天的数据)有明确需求时,考虑使用分区作为查询优化手段。有关这一优化行为的具体示例,请参考相关文档【https://medium.com/datadenys/using-partitions-in-clickhouse-3ea0decb89c4】


使用 TTL(生存时间)管理数据  

在基于 ClickHouse 的可观测性 (Observability) 解决方案中,TTL 是一项关键功能,用于高效管理和保留数据。面对海量数据的持续增长,TTL 可以自动处理旧数据的过期和删除,优化存储资源的使用,同时保持系统性能,无需手动干预。通过聚焦于最新和最相关的数据,TTL 不仅能让数据库保持精简,还能降低存储成本并提升查询效率。此外,它还能帮助用户遵守数据保留政策,系统性地管理数据生命周期,从而增强可观测性方案的可持续性和可扩展性。

在 ClickHouse 中,TTL 可以在表级或列级进行配置。


表级 TTL  

在日志和跟踪的默认架构中,通常包含一个 TTL 设置,用于在指定时间段后删除数据。这个 TTL 配置通过 ttl 键在 ClickHouse 导出器中指定,例如:

exporters: clickhouse:   endpoint: tcp://localhost:9000?dial_timeout=10s&compress=lz4&async_insert=1   ttl: 72h

目前,TTL 的时间配置支持 Golang Duration 语法。建议用户以小时(h)为单位设置 TTL,并确保该设置与分区周期保持一致。例如,如果表是按天分区,则 TTL 应为天数的倍数(如 24h、48h、72h)。这样可以自动为表添加 TTL 子句,例如 ttl: 96h

PARTITION BY toDate(Timestamp)ORDER BY (ServiceName, SpanName, toUnixTimestamp(Timestamp), TraceId)TTL toDateTime(Timestamp) + toIntervalDay(4)SETTINGS index_granularity = 8192, ttl_only_drop_parts = 1

默认情况下,当 ClickHouse 合并数据部分时,过期数据会被清理。如果检测到数据已过期,ClickHouse 会触发一次非计划合并以完成删除操作。

计划的 TTL  

TTL 不会立即生效,而是根据系统的计划触发。MergeTree 表的 merge_with_ttl_timeout 设置定义了执行带 TTL 的合并操作之间的最小时间间隔(以秒为单位)。默认值为 14400 秒(4 小时)。需要注意,这只是最低间隔,实际触发时间可能更长。如果该值设置过低,可能会导致频繁的非计划合并,从而消耗大量系统资源。用户可以通过命令 ALTER TABLE my_table MATERIALIZE TTL 强制执行 TTL。

重要提示:建议启用 ttl_only_drop_parts=1(默认架构已包含此设置)。启用后,当某个数据部分内的所有行都已过期时,ClickHouse 会直接删除整个部分。与部分清理过期数据行(在 ttl_only_drop_parts=0 下通过资源密集型变更操作实现)相比,删除完整部分的方式更高效,允许设置更短的 merge_with_ttl_timeout 时间,并显著降低系统性能的影响。如果数据按与 TTL 过期相同的单位(例如天)分区,则数据部分会自然限定在该时间区间内,从而使 ttl_only_drop_parts=1 得以高效应用。


列级 TTL  

在上述表级数据过期的基础上,ClickHouse 还支持为列单独设置 TTL。当数据逐渐变得不再需要时,可以删除那些对调查价值较低且占用资源的列。例如,我们建议在日志数据中保留 Body 列,以防需要引用在插入时未提取的动态元数据(如新的 Kubernetes 标签)。但在经过一定时间(如 1 个月)后,如果这些元数据被确认无用,就可以删除 Body 列以优化存储开销。

以下示例展示了如何在 30 天后删除 Body 列。

CREATE TABLE otel_logs_v2(    `Body` String TTL Timestamp + INTERVAL 30 DAY,    `Timestamp` DateTime,    ...)ENGINE = MergeTreeORDER BY (ServiceName, Timestamp)


注意 

要设置列级 TTL,用户需要自定义表的架构。这一功能无法通过 OTel 收集器配置。


数据重新压缩  

尽管我们推荐使用 ZSTD(1) 作为默认压缩算法来处理可观测性 (Observability) 数据集,但用户也可以尝试其他压缩算法或更高的压缩级别,例如 ZSTD(3)。除了在架构初始化时定义压缩配置外,还可以设置在特定时间段后更改压缩算法。例如,一些算法可以显著提高压缩率,但可能会降低查询性能。对于查询频率较低的旧数据,这种折衷是可以接受的;而对于频繁使用的近期数据,则更适合使用性能更优的压缩方式。

以下示例展示了如何在 4 天后切换为使用 ZSTD(3) 压缩数据,而不是删除数据。

CREATE TABLE default.otel_logs_v2(    `Body` String,    `Timestamp` DateTime,    `ServiceName` LowCardinality(String),    `Status` UInt16,    `RequestProtocol` LowCardinality(String),    `RunTime` UInt32,    `Size` UInt32,    `UserAgent` String,    `Referer` String,    `RemoteUser` String,    `RequestType` LowCardinality(String),    `RequestPath` String,    `RemoteAddress` IPv4,    `RefererDomain` String,    `RequestPage` String,    `SeverityText` LowCardinality(String),    `SeverityNumber` UInt8,)ENGINE = MergeTreeORDER BY (ServiceName, Timestamp)TTL Timestamp + INTERVAL 4 DAY RECOMPRESS CODEC(ZSTD(3))

性能评估  

我们建议用户在选择压缩级别和算法时,同时评估其对数据插入和查询性能的影响。例如,增量编解码器 (Delta Codec) 对压缩时间戳特别有效,但如果时间戳属于主键的一部分,则可能会导致过滤性能下降。

关于 TTL 配置的更多细节和示例,请参考相关文档【https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes】。这些示例包括如何为表和列添加或修改 TTL,以及 TTL 如何支持构建存储层次结构(如热-温架构)。有关更多信息,请参阅存储层的说明。


存储层  

在 ClickHouse 中,用户可以通过不同的磁盘类型创建存储层,例如将热点数据存储在 SSD 上,而将历史数据存储在 S3 上。这样的架构能够有效降低存储成本,同时由于历史数据查询频率较低,其性能要求(查询 SLA)可以适当放宽。

不适用于 ClickHouse Cloud  

ClickHouse Cloud 不支持多层存储。它将所有数据存储在 S3 中,并通过 SSD 缓存节点提供快速访问。因此,存储层功能在 ClickHouse Cloud 中并无必要。

为了创建存储层,用户需要先定义磁盘,并基于这些磁盘制定存储策略。在创建表时,可以为其指定存储卷。数据会根据磁盘的填充率、数据部分大小和卷的优先级在磁盘之间自动迁移。更多细节请参考相关文档【https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes】

虽然用户可以手动使用 ALTER TABLE MOVE PARTITION 命令在磁盘之间移动数据,但也可以通过 TTL 自动控制卷之间的数据迁移。有关完整示例,请参考相应的文档。


管理架构更改  

随着系统不断演进,日志和跟踪的架构难免会发生变化,例如在监控新系统时需要支持额外的元数据或新的 pod 标签。通过采用 OTel 架构生成数据,并以结构化的方式捕获事件,ClickHouse 的架构能够很好地适应这些变化。然而,当新元数据被引入或查询模式发生变化时,用户可能需要调整架构以满足新的需求。

为了避免架构更改带来的系统停机,可以采用以下方法:


使用默认值  

用户可以为新列设置默认值。在插入数据时,如果未显式提供该列的值,系统将使用预定义的默认值。

架构更改可以先于物化视图的转换逻辑或 OTel 收集器配置的调整进行,这样新的列在更改完成后会被自动发送到目标表。

在完成架构更改后,可以重新配置 OTel 收集器。假设用户遵循“使用 SQL 提取结构”中推荐的流程,其中 OTel 收集器将数据发送到 Null 表引擎,并由物化视图提取目标架构并存储到目标表,则可以通过 ALTER TABLE ... MODIFY QUERY 语法修改视图逻辑。以下是一个示例,展示了目标表及其物化视图的用法(类似于“使用 SQL 提取结构”中的流程),以便从 OTel 结构化日志中提取目标架构:

CREATE TABLE default.otel_logs_v2(    `Body` String,    `Timestamp` DateTime,    `ServiceName` LowCardinality(String),    `Status` UInt16,    `RequestProtocol` LowCardinality(String),    `RunTime` UInt32,    `UserAgent` String,    `Referer` String,    `RemoteUser` String,    `RequestType` LowCardinality(String),    `RequestPath` String,    `RemoteAddress` IPv4,    `RefererDomain` String,    `RequestPage` String,    `SeverityText` LowCardinality(String),    `SeverityNumber` UInt8)ENGINE = MergeTreeORDER BY (ServiceName, Timestamp)
CREATE MATERIALIZED VIEW otel_logs_mv TO otel_logs_v2 ASSELECT Body, Timestamp::DateTime AS Timestamp, ServiceName, LogAttributes['status']::UInt16 AS Status, LogAttributes['request_protocol'] AS

路过

雷人

握手

鲜花

鸡蛋

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

评论
返回顶部