ClickHouse 官方文档:如何管理可观测性数据【3/5】
分区功能允许在磁盘上根据某列或 SQL 表达式对数据进行逻辑划分。每个分区可以独立操作,例如单独删除。这使得用户能够根据时间高效地在存储层之间迁移分区或其子集,或者自动过期和清理数据。 分区是在创建表时通过 PARTITION BY 子句指定的。此子句支持对任意列进行 SQL 表达式计算,计算结果决定数据行将被分配到哪个分区。 在磁盘上,每个分区通过共享的文件夹名称前缀实现逻辑关联,支持独立查询。例如,默认的 otel_logs 模式按天分区,使用表达式 toDate(Timestamp)。当数据写入 ClickHouse 时,系统会对每行数据执行该表达式。如果结果分区已经存在,数据将被路由到对应分区;如果是某天的第一条记录,系统会自动创建一个新分区。
可以对分区执行多种操作,包括备份、列级别的修改、通过变更操作 (mutation) 来调整或删除数据行,以及清除索引(如二级索引)。 例如,假设 otel_logs 表按天分区。如果其中存储了结构化日志数据集,则该表会包含多天的日志数据:
可以通过查询系统表简单地查看当前的分区:
此外,我们可能会设置另一个表,例如 otel_logs_archive,用于归档较早的数据。通过分区移动,数据可以高效迁移到此归档表中(这仅需更改元数据)。
这种方法优于其他方式,例如使用 INSERT INTO SELECT,将数据重写到目标表。
此外,通过分区删除数据是一种高效的方法。这种方式比使用变更操作或轻量级删除更节省资源,因此建议优先采用。
应用场景 以上说明了分区如何帮助高效地移动和操作数据。在实际应用中,分区操作在可观测性 (Observability) 场景中最常用于以下两种情况: 1. 分层存储架构:数据在冷热存储层之间迁移(参见存储层),以支持冷热分层的架构设计。 2. 高效删除:当数据达到指定的 TTL 时,可以快速清理(参见使用 TTL 进行数据管理)。 我们将在后续部分深入分析这两种场景。 查询性能 分区可以提升查询性能,但效果依赖于具体的访问模式。如果查询仅针对少量分区(如单个分区),性能通常会有所改善,尤其是在分区键不包含在主键中,并且查询通过分区键筛选时。然而,涉及多个分区的查询可能会因数据部分增加而变慢。如果分区键已经是主键的前几个字段,针对单个分区的性能优势会大幅降低甚至不存在。此外,当每个分区中的值是唯一时,分区还可以优化 GROUP BY 查询。总体而言,用户应优先优化主键,并仅在访问模式对某些可预测的子集(如按天分区,且查询主要集中于最近一天的数据)有明确需求时,考虑使用分区作为查询优化手段。有关这一优化行为的具体示例,请参考相关文档【https://medium.com/datadenys/using-partitions-in-clickhouse-3ea0decb89c4】。 在基于 ClickHouse 的可观测性 (Observability) 解决方案中,TTL 是一项关键功能,用于高效管理和保留数据。面对海量数据的持续增长,TTL 可以自动处理旧数据的过期和删除,优化存储资源的使用,同时保持系统性能,无需手动干预。通过聚焦于最新和最相关的数据,TTL 不仅能让数据库保持精简,还能降低存储成本并提升查询效率。此外,它还能帮助用户遵守数据保留政策,系统性地管理数据生命周期,从而增强可观测性方案的可持续性和可扩展性。 在 ClickHouse 中,TTL 可以在表级或列级进行配置。 表级 TTL 在日志和跟踪的默认架构中,通常包含一个 TTL 设置,用于在指定时间段后删除数据。这个 TTL 配置通过 ttl 键在 ClickHouse 导出器中指定,例如:
目前,TTL 的时间配置支持 Golang Duration 语法。建议用户以小时(h)为单位设置 TTL,并确保该设置与分区周期保持一致。例如,如果表是按天分区,则 TTL 应为天数的倍数(如 24h、48h、72h)。这样可以自动为表添加 TTL 子句,例如 ttl: 96h。
默认情况下,当 ClickHouse 合并数据部分时,过期数据会被清理。如果检测到数据已过期,ClickHouse 会触发一次非计划合并以完成删除操作。
重要提示:建议启用 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 列。
尽管我们推荐使用 ZSTD(1) 作为默认压缩算法来处理可观测性 (Observability) 数据集,但用户也可以尝试其他压缩算法或更高的压缩级别,例如 ZSTD(3)。除了在架构初始化时定义压缩配置外,还可以设置在特定时间段后更改压缩算法。例如,一些算法可以显著提高压缩率,但可能会降低查询性能。对于查询频率较低的旧数据,这种折衷是可以接受的;而对于频繁使用的近期数据,则更适合使用性能更优的压缩方式。 以下示例展示了如何在 4 天后切换为使用 ZSTD(3) 压缩数据,而不是删除数据。
关于 TTL 配置的更多细节和示例,请参考相关文档【https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/mergetree#table_engine-mergetree-multiple-volumes】。这些示例包括如何为表和列添加或修改 TTL,以及 TTL 如何支持构建存储层次结构(如热-温架构)。有关更多信息,请参阅存储层的说明。 在 ClickHouse 中,用户可以通过不同的磁盘类型创建存储层,例如将热点数据存储在 SSD 上,而将历史数据存储在 S3 上。这样的架构能够有效降低存储成本,同时由于历史数据查询频率较低,其性能要求(查询 SLA)可以适当放宽。
为了创建存储层,用户需要先定义磁盘,并基于这些磁盘制定存储策略。在创建表时,可以为其指定存储卷。数据会根据磁盘的填充率、数据部分大小和卷的优先级在磁盘之间自动迁移。更多细节请参考相关文档【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 结构化日志中提取目标架构:
|
版权声明:本文为 clickhouse 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。