并行运行策略
- 风险最低:通过让两个系统同时运行,你可以在验证 ClickStack 并帮助用户熟悉新系统的同时,继续访问现有数据和仪表盘。
- 数据自然过期:大多数可观测性数据的保留期都比较短 (通常为 30 天或更短) ,因此可以随着 Elastic 中的数据自然过期,平稳完成过渡。
- 迁移更简单:无需借助复杂的数据传输工具或流程,在两个系统之间迁移历史数据。
迁移数据我们在”迁移数据”一节中演示了一种将关键数据从 Elasticsearch 迁移到 ClickHouse 的方法。对于较大的数据集,不建议使用这种方法,因为它通常难以提供理想的性能——其瓶颈在于 Elasticsearch 的高效导出能力有限,并且仅支持 JSON 格式。
实施步骤
调整保留期
配置 Elastic 的生存时间 (TTL) 设置,使其与您期望的保留期一致。设置 ClickStack 的 生存时间 (TTL),使数据保留相同的时长。验证并比较
- 在两个系统上运行查询,以确保数据一致性
- 比较查询性能和结果
- 将仪表盘和告警迁移到 ClickStack。目前这仍需手动完成。
- 验证所有关键仪表盘和告警在 ClickStack 中都能按预期工作
逐步过渡
- 随着 Elastic 中的数据自然过期,您会越来越依赖 ClickStack
- 一旦确认 ClickStack 运行稳定可靠,您就可以开始将查询和仪表盘逐步切换过去
长期保留
- 继续并行运行这两个系统,直到 Elastic 中的所有数据都已过期
- ClickStack 的分层存储能力可帮助高效管理长期数据。
- 考虑使用 materialized views 来维护聚合后或经过过滤的历史数据,同时允许原始数据过期。
迁移时间安排
- 保留 30 天:可在一个月内完成迁移。
- 保留更长时间:继续并行运行,直到 Elastic 中的数据过期。
- 历史数据:如果确有必要,可考虑使用迁移数据导入特定的历史数据。
迁移设置
推荐设置
- ClickHouse Cloud:默认采用单分片、多副本架构。存储与计算可独立扩缩容,因此非常适合摄取模式难以预测且读取密集型的可观测性场景。
- ClickHouse OSS:在自管理部署中,我们建议:
- 从单分片开始
- 通过增加 CPU 和 RAM 进行纵向扩容
- 使用分层存储,借助兼容 S3 的对象存储扩展本地磁盘容量
- 如果需要高可用性,请使用
ReplicatedMergeTree - 对于容错能力,在可观测性工作负载中,每个分片 1 个副本 通常就足够了。
何时需要分片
- 你的摄取速率超过单个节点的容量 (通常 >500K 行/秒)
- 你需要进行租户隔离或按区域隔离数据
- 你的总数据量过大,即使使用对象存储,单台服务器也无法承载
数据保留与 生存时间 (TTL)
- 自动删除过期数据
- 将较旧的数据迁移到冷对象存储
- 仅将近期且经常查询的日志保留在高速磁盘上
迁移数据
- 用于数据富集的小型查找表 (例如用户映射、服务目录)
- 存储在 Elasticsearch 中、需要与可观测性数据关联的业务数据;相比 Elasticsearch 更受限的查询能力,ClickHouse 的 SQL 能力和商业智能集成使这类数据更易于维护和查询。
- 需要在迁移过程中保留的配置数据
迁移 schema
在 ClickHouse 中为从 Elasticsearch 迁移的索引创建一张表。您可以将 Elasticsearch 类型映射到对应的 ClickHouse 等效类型。或者,也可以直接使用 ClickHouse 中的 JSON 数据类型,该类型会在数据写入时动态创建相应类型的列。请参考以下针对包含syslog 数据的索引的 Elasticsearch 映射:Elasticsearch 映射
Elasticsearch 映射
ClickHouse schema
ClickHouse schema
- Tuple 用于表示嵌套结构,而非使用点号表示法
- 根据映射使用相应的 ClickHouse 类型:
keyword→Stringdate→DateTimeboolean→UInt8long→Int64ip→Array(Variant(IPv4, IPv6))。这里使用Variant(IPv4, IPv6),因为该字段中同时包含IPv4和IPv6。object→JSON,用于结构无法预先确定的 syslog 对象。
- 列
host.ip和host.mac是显式声明的Array类型;而在 Elasticsearch 中,所有类型都是数组。 - 添加了一个使用时间戳和主机名的
ORDER BY子句,以提高基于时间的查询效率 - 使用
MergeTree作为引擎类型,最适合日志数据
- 数据验证 – 除特定结构外,强制采用严格的 schema 可避免列数爆炸的风险。
- 避免列爆炸风险:虽然 JSON 类型可扩展到潜在的数千列,其中 subcolumns 会作为专用列存储,但这可能导致 column file 爆炸,即创建过多的 column file,从而影响性能。为缓解这一问题,JSON 使用的底层 Dynamic 类型 提供了
max_dynamic_paths参数,用于限制以独立 column file 形式存储的唯一路径数量。一旦达到阈值,额外路径就会使用紧凑编码 format 存储到共享 column file 中,从而在支持灵活数据摄取的同时兼顾性能和存储效率。不过,访问这个共享 column file 的性能会稍逊一些。另请注意,JSON 列也可以结合 type hints 使用。带有“提示”的列将具有与专用列相同的性能。 - 更轻松地查看路径和类型的内部信息:尽管 JSON 类型支持使用内部信息函数来确定已推断出的类型和路径,但对于静态结构,借助
DESCRIBE等方式查看通常更简单。
或者,您也可以创建一个仅包含一个
JSON 列的表。我们在 JSON 定义中为
host.name 和 timestamp 列提供了类型提示,因为我们会在排序键/主键中使用它们。这有助于 ClickHouse 确认这些列不会为 NULL,并明确应使用哪些子列 (每种类型可能对应多个子列,否则这里会有歧义) 。JSON。有关在 schema 中使用 JSON 类型及如何高效应用它的更多详情,建议参阅指南 “Designing your schema”。安装 elasticdump
我们建议使用 elasticdump 从 Elasticsearch 导出数据。该工具依赖 node,应安装在一台在网络上可同时便捷访问 Elasticsearch 和 ClickHouse 的机器上。对于大多数导出任务,我们建议使用至少配备 4 个 CPU 核心和 16GB RAM 的专用服务器。elasticdump 在数据迁移方面有以下几个优势:- 它直接与 Elasticsearch REST API 交互,确保数据能够被正确导出。
- 在导出过程中借助 Point-in-Time (PIT) API 保持数据一致性——它会在特定时刻创建数据的一致性快照。
- 可直接将数据导出为 JSON 格式,并流式传输到 ClickHouse 客户端进行插入。
elastic dump 运行在同一可用区或数据中心,以尽量减少网络出站流量并最大化吞吐量。安装 ClickHouse 客户端
请确保在elasticdump 所在的服务器上已安装 ClickHouse。不要启动 ClickHouse 服务器——这些步骤只需要客户端。流式传输数据
要在 Elasticsearch 和 ClickHouse 之间流式传输数据,请使用elasticdump 命令,并将输出直接通过管道传给 ClickHouse 客户端。以下命令会将数据插入我们结构清晰的表 logs_system_syslog。elasticdump 使用了以下标志:type=data- 将响应限制为仅包含 Elasticsearch 中的文档内容。input-index- 我们的 Elasticsearch 输入索引。output=$- 将所有结果重定向到 stdout。sourceOnly标志可确保在响应中省略元数据字段。searchAfter标志用于通过searchAfterAPI 高效地对结果进行分页。pit=true- 使用 point in time API 确保不同查询之间的结果一致。
这里的 ClickHouse 客户端参数 (凭据除外) :
max_insert_block_size=1000- 达到这个行数后,ClickHouse 客户端就会发送数据。增大该值可以提高吞吐量,但代价是生成一个块所需的时间更长,因此数据出现在 ClickHouse 中的时间也会更晚。min_insert_block_size_bytes=0- 关闭服务端按字节进行的块 squashing。min_insert_block_size_rows=1000- 在服务端对来自客户端的块进行 squashing。在这种情况下,我们将其设置为max_insert_block_size,这样行会立即显示出来。增大该值可提高吞吐量。query="INSERT INTO logs_system_syslog FORMAT JSONAsRow"- 以 JSONEachRow format 插入数据。如果发送到定义明确的 schema (例如logs_system_syslog) ,这种方式是合适的。
你可以预期吞吐量达到每秒数千行的量级。
插入到单个 JSON 行中如果要插入到单个 JSON 列中 (参见上文的 更多详情请参见“将 JSON 作为对象读取”。
syslog_json schema) ,也可以使用相同的插入命令。不过,你必须将 format 指定为 JSONAsObject,而不是 JSONEachRow,例如:转换数据 (可选)
上述命令假设 Elasticsearch 字段与 ClickHouse 列之间是一对一映射。用户通常需要在将数据插入 ClickHouse 之前,先对 Elasticsearch 数据进行过滤和转换。这可以通过input table function 实现,它允许我们对 stdout 执行任意 SELECT 查询。假设我们只想存储前述数据中的 timestamp 和 hostname 字段。ClickHouse schema:elasticdump 的数据插入此表,只需使用 input 表函数即可——借助 JSON 类型动态检测并选择所需的列。请注意,这个 SELECT 查询也可以很方便地加入过滤条件。@timestamp 字段名进行转义,并使用 JSONAsObject 输入格式。