本文字数17316估计阅读时间44分钟作者Tom Schreiber and Lionel PalacinTL;DR (摘要)ClickHouse 现已推出专为分析和可观测性构建的全新全文搜索功能在一个引擎中结合了快速多词条搜索和大规模聚合。这使得它成为 Elasticsearch 在日志分析领域一个极具吸引力的替代方案。本基准测试将揭示其原因。最后一块“护城河”被填平多年来人们的选择很简单Elasticsearch 用于文本搜索ClickHouse 用于分析。现在 ClickHouse 二者兼具。ClickHouse 现已 集成了一个 重新设计的、由倒排索引 (inverted indexes) 驱动的全文搜索功能。但与传统搜索引擎不同的是匹配的文档会直接送入其原有的向量化分析引擎 (vectorized analytical engine)该引擎在过滤、聚合和大规模扫描方面已 表现出色。这种结合在搜索仅仅是第一步时显得尤为重要。在 可观测性领域尤其是在日志分析中搜索很少仅仅是为了查找文本。用户通常会先搜索某个错误模式然后统计其出现次数、按服务分组、深入更小的时间范围或者隔离受影响的主机。换句话说日志是恰好包含文本的分析数据。在本次基准测试中我们将在真实的 OpenTelemetry 日志工作负载下对比 ClickHouse 和 Elasticsearch 的开源版本 (OSS versions) 在高达 500 亿行的数据集上的表现。抢先看在所有测试的数据集规模上ClickHouse 执行全文分析工作负载的速度比 Elasticsearch 快 2-6 倍。此外ClickHouse 存储 OpenTelemetry 日志数据集的效率也远高于 Elasticsearch。完整的基准测试是端到端可复现的源数据、Schema、查询、数据摄入脚本和测量结果均已发布在我们的 公共 GitHub 仓库中(https://github.com/ClickHouse/TextBench/tree/main) 。接下来我们将阐述基准测试的设置和方法然后探讨这两个系统如何在磁盘上存储 OpenTelemetry 日志最后比较它们的存储占用和查询执行时间。基准测试设置在揭晓结果之前以下是完整的基准测试设置数据集、查询、硬件和系统配置。如果您更关注结果可以直接跳转至存储占用和查询执行时间部分。Dataset该基准测试采用由我们的 OpenTelemetry 演示应用程序生成的真实 OpenTelemetry日志数据集该数据集产生的结构化服务日志与现代可观测性管道中常见的日志类似。为确保基准测试完全可重现所有源数据均以Parquet 文件的形式发布在一个公共 Amazon S3 存储桶中。区域eu-west-3 (欧洲 — 巴黎)公共存储桶s3://public-pme/text\_bench直接 URLhttps://public-pme.s3.eu-west-3.amazonaws.com/text\_bench/part\_{000..009}.parquet文件结构每个 Parquet 文件包含 10 亿条日志记录并按时间戳排序。提示建议在 eu-west-3 区域运行 EC2 基准测试实例以避免跨区域数据摄取延迟和出口费用。基于这些源数据我们以三种不同的规模将相同的基准数据集加载到 ClickHouse 和 Elasticsearch 中数据集行数小型10 亿中型100 亿大型500 亿通过这种方式我们能够评估这两个系统从十亿行级别的部署到应对大规模生产可观测性工作负载时的表现。查询为了评估实际的全文分析搜索性能我们使用了一套包含九个 OpenTelemetry 日志查询的集合。每个查询均基于单词或多词的全文搜索构建并常常伴随过滤、计数、分组、排序或基于时间的聚合操作。这些查询均使用各系统原生的查询语言实现ClickHouse 使用 SQLElasticsearch 使用 Query DSL 和 ES|QL。这套查询旨在反映 Kibana 等工具中典型的日志分析工作流程即用户搜索错误消息后立即对其进行过滤、计数、分组、排序或随时间进行分析。查询组合涵盖了四种常见的调查模式Q1–Q3事件深入分析与日志检索定位匹配给定术语的日志行应用过滤器并查看相关事件。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ1(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L1)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L3)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L3)Q2(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L12)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L25)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L8)Q3(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L25)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L50)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L13)Q4–Q5总体错误和匹配计数计算匹配记录或比较各子集之间的匹配量。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ4(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L33)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L64)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L18)Q5(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L39)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L75)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L23)Q6–Q7服务级别细分根据服务名称、主机或严重性等维度对匹配日志进行分组以识别问题集中之处。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ6(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L45)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L88)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L28)Q7(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L53)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L105)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L33)Q8–Q9: 基于时间的趋势分析将匹配项按时间段聚合以揭示峰值、回落或重复模式。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ8(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L61)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L122)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L38)Q9(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L70)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L146)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L43)综合来看这些查询全面模拟了日志分析中的典型任务涵盖从选择性日志检索到大规模分析搜索。硬件和系统版本两个系统都在相同且独立的单节点环境中进行了基准测试以确保进行公平的同类比较。每个引擎都在其各自的专用 EC2 实例上运行并采用相同的 CPU、内存和存储配置。系统配置ClickHouseClickHouse 使用了一个标准的 MergeTree 表其 OpenTelemetry 日志 模式 包含了时间戳、数值、字符串和映射的原生数据类型。该表按以下方式 排序(ServiceName, Timestamp)此排序键提高了针对按服务和时间范围过滤的常见日志分析查询的数据局部性同时还改进了压缩。在 Body 列上 创建了一个 全文索引。ElasticsearchElasticsearch 使用了一个等效的 索引映射具有相同的逻辑模式和匹配的 物理排序顺序index.sort (ServiceName ASC, Timestamp ASC)主要映射选择Body映射为 text 类型并使用标准分析器支持全文搜索结构化字符串维度映射为 keyword 类型类 Map 的属性字段映射为 flattened 类型TraceFlags 和 SeverityNumber 映射为 byte 类型启用 codec: best_compression 以最小化磁盘占用在 Elasticsearch 允许的最大范围内此配置尽可能地复刻了 ClickHouse 的语义同时遵循了存储最佳实践。为了确保稳定的单节点性能我们使用了这些 JVM和 OS 设置堆内存固定为 30 GiB (-Xms30g -Xmx30g) 以保留 CompressedOopsbootstrap.memory_lock: truevm.max_map_count262144分片布局该基准测试使用了单节点存储优化布局两个系统中均无副本。针对每个数据集ClickHouse 使用了单个分片即单表而 Elasticsearch 则采用了多个分片这遵循了实现最佳分片大小的行业最佳实践每个分片 50GB。在测量之前所有 Elasticsearch 分片都依照最佳实践被强制合并使每个分片只包含一个段。这不仅提升了存储效率也不会阻碍并行搜索的执行因为 Lucene 在查询时仍能逻辑上对单个段进行分区。数据加载ClickHouse 通过其原生的 Parquet 摄入能力直接加载了 Parquet 文件。Elasticsearch 不原生支持读取 Parquet 文件因此数据需要从 Parquet 文件中进行流式传输转换为 NDJSON 格式然后通过 Bulk API 摄入。关于数据摄入的简要说明 本文侧重于分析性日志搜索性能因此我们没有进行全面、系统的摄入基准测试。然而在数据集准备阶段将 50B OTel 日志记录加载到单节点 ClickHouse 实例中开箱即用不到 4 小时。对于类似的单节点 Elasticsearch 配置我们需要调整摄入管道和相关设置才能达到可接受的吞吐量即便如此完成同样的数据加载也耗费了数天大约 5 天。数据摄入吞吐量是可观测性系统在生产环境中需要重点关注的关键问题因此我们可能会在专门的后续基准测试中针对 OTel 日志摄入方面进行深入探讨。在数据成功加载到两个系统后接下来我们将介绍用于公平比较查询性能的方法。方法论为真实反映可观测性工作流的场景我们对两个系统分别在冷启动和热启动两种条件下进行了基准测试。冷启动运行 (Cold runs) 模拟对以前从未查询过的时间范围进行的首次查询此时所需的日志数据必须从磁盘加载。热启动运行 (Hot runs) 模拟当相同数据已被缓存后进行的重复执行。本基准测试中考虑的缓存层级有三个缓存层可能影响查询延迟以下是您的翻译内容1. Linux 页缓存。这是操作系统的文件缓存旨在避免从磁盘重复读取数据。2. 过滤器评估缓存。这些是引擎级别的缓存用于记住先前的条件或过滤器结果以加速重复的筛选工作。ClickHouse: 查询条件缓存(https://clickhouse.com/docs/operations/query-condition-cache)Elasticsearch: 节点查询缓存(https://www.elastic.co/docs/reference/elasticsearch/configuration-reference/node-query-cache-settings)3. 全查询结果缓存。这些缓存用于存储针对相同重复查询的完整响应。ClickHouse: 查询缓存(https://clickhouse.com/docs/operations/query-cache)Elasticsearch: 分片请求缓存(https://www.elastic.co/docs/reference/elasticsearch/rest-apis/shard-request-cache)为了专注于核心执行性能我们在基准测试期间禁用了全查询结果缓存。否则我们测量的将主要是重复的内存结果查找速度这在此并非我们关注的重点。然而我们保持过滤器评估缓存处于启用状态因为它们是引擎正常执行路径的一部分。测量冷运行对于冷运行我们首先完全关闭两个系统清空 Linux 页缓存然后重启服务器在此之后才执行查询。这意味着没有数据页被缓存在内存中引擎必须从磁盘加载所需数据运行时反映了存储效率、剪枝能力以及原始执行速度OTel 日志查询套件中的每个查询都在这些冷启动条件下执行而报告的冷运行总计则是所有单个查询运行时间的总和。测量热运行在热运行测试中系统在各次执行之间保持运行状态并且没有清空 Linux 页缓存。对于每个查询相同的查询会连续执行三次全查询结果缓存保持禁用状态过滤器评估缓存保持启用状态三次运行中最快的一次被记录为热运行结果这种方式可以隔离重复查询的性能同时又不允许完整的查询结果重用。OTel 日志查询套件中的每个查询都在这些条件下进行测量而报告的热运行总计则是所有单个查询运行时间的总和。Elasticsearch Query DSL 与 ES|QL主要图表中的 Elasticsearch 结果均采用 Query DSL。我们还在 ES|QL 中实现了所有功能但在测试中发现在其运行时间持续较慢因此在整个主要基准测试中Query DSL 被用作更可靠的 Elasticsearch 基线。公共基准测试仓库中包含了 Query DSL 与 ES|QL 对应的冷启动和热启动的查询性能对比图。在确定了基准测试方法后我们将深入探讨这两个系统如何在磁盘上存储 OTel 日志。这种磁盘布局是理解后续结果的关键背景信息。OTel 日志在磁盘上的存储方式为了更好地理解下一节中的存储占用空间结果我们首先审视 Elasticsearch 和 ClickHouse 如何在磁盘上存储和压缩已摄入的 OTel 日志。以下图表提供了一个简化示意图。在这两个系统中已摄入的 OTel 日志数据最终都会被写入不可变的磁盘存储单元Elasticsearch 中的 Lucene segmentsClickHouse 中的 data parts这些单元在逻辑上属于分片图中未显示并在后台持续合并成更大的存储单元。通常Segments 会增长到大约 5 GBparts 则增长到大约 150 GB尽管这两个系统都支持更大规模的强制合并。在 Elasticsearch 中分片进而组成了索引详细信息可参见此处https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-vs-elasticsearch/on-disk-format-and-insert-processing#elasticsearchClickHouse 分片的描述可参见此处https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-vs-elasticsearch/on-disk-format-and-insert-processing#clickhouse。在这些磁盘存储单元内部两个系统都将数据组织成专门的数据结构主要用于实现四项功能快速聚合、全文搜索、返回原始文档以及在查询执行期间剪除不相关数据。用于快速聚合的列式存储两个系统都使用列式存储 (columnar storage)聚合查询仅读取所引用的列由于每列均经过压缩因此扫描的字节数更少并能在连续数据上执行向量化 (SIMD) 操作。在 Elasticsearch 的 doc\_values(https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/doc-values) 中每列都会根据其数据类型和基数自动使用 delta 和 gcd 等专用编解码器进行单独编码。然而它并未应用 lz4 或 zstd 等通用压缩算法。在 ClickHouse 中压缩编解码器也会应用于每个 列文件。ClickHouse 支持通用 (general-purpose) (例如 lz4 和 zstd)、专用 (specialized)(例如 delta 和 gcd) 和加密 (encryption) 编解码器 (例如 AES\_128)并且这些编解码器可以按列进行链式组合 (chained) 使用。全文搜索的倒排索引两个系统都使用倒排索引 (inverted index) 作为全文搜索的基本数据结构。存储字段和 \_source在 Elasticsearch 中存储字段 (stored fields)用作文档存储用于在查询响应中返回原始字段值。默认情况下它们还会存储 \_source其中包含原始摄入的 JSON 文档。存储字段的压缩算法由 index.codec 设置定义默认情况下为 lz4若追求更高的压缩率也可选用 zstd但其性能会相对较慢。为什么日志数据需要 _source对于日志分析而言返回原始摄入文档通常至关重要。在 Elasticsearch OSS 中这使得在实践中很难避免使用 _source而企业版则可以使用 合成 _source (synthetic _source)(https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html#synthetic-source)。在 ClickHouse 中没有独立的等效结构原始行直接从存储在列文件中的值重建。稀疏索引用于剪枝 (Pruning)ClickHouse 使用稀疏索引由于 OTel 日志记录在磁盘上以排序顺序存储引擎可以将它们分组到块中并在 ③ 稀疏主索引 (sparse primary index)中记录每个块的值范围从而跳过完全超出请求范围的块。Lucene 具有针对排序数据的相关稀疏索引能力但 Elasticsearch 在用于本次比较的 \_disk\_usage 输出中并未将其作为单独的存储类别暴露出来。还需要注意的是在 Elasticsearch 中倒排索引 (inverted index) 不仅用于全文搜索 (full-text search)。对于除 Body 之外的所有字符串字段我们使用了 keyword 类型而 Timestamp 使用 date 类型数字字段则使用 numeric 类型。所有这些类型默认情况下也会为精确匹配过滤 (exact-match filtering) 填充倒排索引其值按原样索引且不进行分析 (analysis)。这意味着对这些字段的过滤可以通过倒排索引高效地解决使其成为本次比较中与 ClickHouse 稀疏主索引最接近的对应物。用于过滤和评分的点 (Points) 和范数 (norms)在 Elasticsearch 中④ 点 (points) 支持对数字和日期字段进行高效过滤和范围查询而 范数 (norms) 则存储每个文档的评分因子以衡量文本相关性。ClickHouse 不使用独立的评分结构数值和日期过滤通过列式扫描结合稀疏主索引和跳跃索引进行处理。ClickHouse 目前也不对全文搜索结果进行评分这与我们当前的日志分析用例无关。既然存储的基础组件已经明确接下来我们将探讨它们对磁盘使用量的综合影响。OTel 日志存储占用上述存储结构解释了数据字节的存储方式。为了公平地比较整体占用空间我们首先统一了最主要影响磁盘使用量的几个变量1. 相同的磁盘排序顺序数据在磁盘上按相同的键进行排序——在 ClickHouse 中通过排序键按 (ServiceName, Timestamp) 排序在 Elasticsearch 中则通过在相同字段上的索引排序实现。2. 相同的压缩算法存储原始日志内容的核心结构使用相同的压缩算法。具体来说ClickHouse 列文件和 Elasticsearch 存储字段均采用 ZSTD。3. 相同的全文倒排索引范围两个系统都仅在 Body 字段上构建全文倒排索引。在 Elasticsearch 中所有其他字符串字段都被映射为 keyword 类型这意味着它们支持精确匹配过滤但不进行全文搜索分析。最后正如之前(https://clickhouse.com/blog/elasticsearch-log-analytics-clickhouse#shard-layout)所述本次比较采用了存储优化的单节点配置两个系统中均无副本ClickHouse 使用一个分片而 Elasticsearch 则采用多个分片同时遵循最佳实践以实现最优分片大小每个分片 50GB并且强制合并为每个分片一个段。考虑到以上因素下方的图表展示了两个系统在存储 10 亿、100 亿和 500 亿条 OTel 日志记录时的存储占用情况。为了便于解读总体数据图表将这些数据细分为上一节介绍的各个磁盘上的数据结构。图例将每个彩色区域映射到其在 Elasticsearch 和 ClickHouse 中对应的结构而这些底层数据的大小则分别取自 Elasticsearch 的 \_disk\_usage API 和 ClickHouse 的 parts system table。注ClickHouse 的稀疏主索引 (sparse primary index) 已计入总数但在此规模下并不明显 (6.47 MiB / 64.26 MiB/ 320.56 MiB。总体存储空间占用总体而言ClickHouse 存储相同 OTel 日志数据所需的空间约为 Elasticsearch 的五分之一。这一结论在所有这三个规模下均保持一致。1B: ClickHouse 49.49 GiB对比 Elasticsearch 245.06 GiB → ClickHouse 空间占用约为 Elasticsearch 的 1/4.9510B: ClickHouse 496.84 GiB 对比 Elasticsearch 2.40 TiB → ClickHouse 空间占用约为 Elasticsearch 的 1/4.9550B: ClickHouse 2.43 TiB 对比 Elasticsearch 12.01 TiB→ ClickHouse 空间占用约为 Elasticsearch 的 1/4.95列式存储空间占用主要列式存储结构本身就存在巨大差异。仅 Elasticsearch 的 doc_values 所占用的空间就远超 ClickHouse 的列文件。1B: ClickHouse 39.33 GiB对比 Elasticsearch 102.49 GiB → ClickHouse 存储空间仅为 Elasticsearch 的 1/2.6110B: ClickHouse 393.54 GiB 对比 Elasticsearch 1.00 TiB → ClickHouse 存储空间仅为 Elasticsearch 的 1/2.6150B: ClickHouse 1.92 TiB 对比 Elasticsearch 5.02 TiB → ClickHouse 存储空间仅为 Elasticsearch 的 1/2.61值得一提的是ClickHouse 在其列文件中包含了所有的 OTel 日志字段而数据集中最大的字段 Body 则被排除在 Elasticsearch 的 doc_values 之外。这是因为 Body 被映射为 text类型因此仅存储在倒排索引中。ClickHouse 的压缩效率这已经揭示了整体存储差距的主要原因ClickHouse 对其列文件进行了极致高效的压缩。1B: 未压缩 642.42 GiB → 已压缩 39.33 GiB→ 16.33 倍压缩比10B: 未压缩 6.26 TiB → 已压缩 393.54 GiB→ 16.29 倍压缩比50B: 未压缩 31.31 TiB → 已压缩 1.92 TiB→ 16.29 倍压缩比请注意当专门针对压缩优化数据类型和数据在磁盘上的存储顺序时可以实现更高的压缩比。例如在一个 Nginx 日志案例中ClickHouse 实现了高达 178 倍的压缩比。存储结构细分下表汇总了在两种系统及全部三种规模下不同数据结构在磁盘上的占用空间。为什么 Elasticsearch 的存储占用更大Elasticsearch 索引体积更大部分原因在于它支持更广泛的搜索功能例如短语查询、模糊匹配、通配符搜索以及与排名相关的元数据。而本基准测试中的典型 OTel 日志分析查询通常不依赖这些功能。为了测试这对存储消耗的影响程度我们还运行了功能精简版的 Elasticsearch。一个 中等程度的配置变体通过禁用 norms (norms 参数设为 false) 并将主 Body 文本字段的 index_options 配置为仅文档级别的 postings (index\_options set to docs)仅将总存储占用空间降低了 约 2%。为了实现更大的存储空间缩减磁盘占用减少约 20%但仍比 ClickHouse 大 4 倍需要在额外字段上更 激进地禁用索引功能 (index 参数设为 false)。然而由此生成的配置不再代表典型的 Elasticsearch 日志部署场景例如除了我们的查询套件引用的一小部分字段外在大多数 OTel 字段上执行过滤操作都会变得慢得多。在这两种情况下总查询运行时长仅发生了 微小变化。关于 Query DSL 和 ESQL 在热/冷两种情况下的运行时长更多图表可在我们的 GitHub 仓库 [此处]查看。存储之外的更多优势更精简的占用空间使 ClickHouse 在大规模日志分析方面相比 Elasticsearch 具有多项优势更低的存储成本。 以更小的存储空间存储相同的 OTel 日志数据直接降低了在线保存海量日志数据的成本。更低的查询 I/O。 磁盘上更少的数据量意味着在扫描、过滤和聚合过程中需要读取的数据更少这部分解释了下一节中展示的运行时性能提升。更大的数据摄入能力。 更小的磁盘数据结构减轻了存储子系统的压力为现代可观测性管道中典型的持续写入吞吐量提供了更大的余量。这与上文提到的数据摄入案例相符在 ClickHouse 中500 亿行数据的加载远快于预期。此外ClickHouse OSS 开箱即用地支持其原生 MergeTree 引擎的 S3 后端存储这进一步增强了上述效果使得在线保存海量原始日志数据的成本效益显著提升。OTel 日志查询运行时我们首先分析冷启动的总运行时间然后深入研究每个查询的详细数据以进行解释。最后我们考察热运行阶段以了解数据被缓存后性能如何变化。总冷启动运行时间下面的图表展示了在包含 10 亿、100 亿和 500 亿条存储记录的数据集上完整的 OTel 日志查询套件的总冷启动运行时间。值得注意的是该测试套件反映了 Kibana 或 ClickStack 等工具中典型的日志分析工作负载它将全文搜索与聚合和过滤结合起来用于调查事件、错误和趋势。如前所述在冷运行测试中我们会先完全关闭两个系统清空 Linux 页缓存然后重新启动系统最后再执行查询。这样测得的是没有任何数据缓存时的执行耗时也就是查询引擎必须从磁盘加载所需数据时的表现。OTel 日志查询集合中的每个查询都会在这种冷启动条件下执行上图汇总了所有查询各自的执行耗时。冷查询在可观测性中并非罕见。工程师经常需要调查新出现的事件、查看此前从未涉足的时间范围或者检索较早的留存日志。在这些场景下我们无法指望存在热缓存。总体而言在所有三个规模上ClickHouse 完成完整的冷查询测试都比 Elasticsearch 快得多。10 亿条数据 (1B): ClickHouse 1.54s vs Elasticsearch 9.55s→ ClickHouse 快 6.20 倍100 亿条数据 (10B): ClickHouse 7.41s vs Elasticsearch 30.6s→ ClickHouse 快 4.13 倍500 亿条数据 (50B): ClickHouse 26.2s vs Elasticsearch 111.4s→ ClickHouse 快 4.25 倍那么这种领先优势究竟源自何处接下来我们将按查询类型细分总体的运行时数据。按查询类型划分的冷查询运行时ClickHouse 优势最明显之处从逐个查询的细分结果来看ClickHouse 在冷查询场景下的最大性能提升体现在那些将全文过滤 (full-text filtering) 与更繁重的后续聚合操作相结合的查询上。总体来看工作负载越是从纯粹的数据检索转向搜索加分析这在典型的日志分析查询中尤为常见ClickHouse 的优势就越发明显。Q8–Q9 趋势分析查询 在较大规模下展现出最大的性能差距这类查询需要将大量匹配行按时间段分组并计数。Q6–Q7 服务分解查询 的差距也随着规模的增长而显著扩大这反映了对大型结果集执行多组聚合操作的需求。Q1–Q3 事件下钻查询 的性能表现相对接近因为它们更侧重于数据检索并且涉及较少的过滤后聚合操作。这与我们早前进行的基准测试结果保持一致这些基准测试针对 聚合操作和 JSON 分析ClickHouse 在大规模 GROUP BY 和计数工作负载上显著优于 Elasticsearch。在此次测试中一旦文本匹配完成ClickHouse 在聚合方面的这些优势依然显著。冷启动测试旨在衡量存储效率和纯粹的执行速度。然而可观测性工作负载通常涉及对热数据的重复查询因此我们接下来将比较系统的热运行表现。总热运行时间下图展示了在包含 10 亿、100 亿和 500 亿条存储记录的数据集上运行 完整 OTel 日志查询套件 所需的总热运行时间。需要注意的是与之前的冷启动测试不同热启动测试是指在多次执行之间系统保持运行状态因此 Linux 页缓存持续可用。对于每个查询我们连续执行三次相同的查询。在此过程中两个系统的 查询结果缓存都被禁用但其对应的 过滤器评估缓存保持启用。最终我们取三次运行中最快的一次作为热启动结果。OTel 日志查询套件中的每个查询都在这些条件下进行了测量上图汇总了由此产生的每个查询的运行时间总和。热查询在可观测性领域同样至关重要。仪表盘会自动刷新故障排查会重新应用相似的过滤器并且交互式下钻操作也常常会重复访问相同的数据集。在暖缓存条件下两者之间的差距有所缩小但 ClickHouse 在所有规模下完成整个查询套件的速度依然快于 Elasticsearch。1B: ClickHouse 0.68s vs Elasticsearch 1.78s→ ClickHouse 快 2.62 倍10B: ClickHouse 4.54s vs Elasticsearch 7.89s→ ClickHouse 快 1.74 倍50B: ClickHouse 20.3s vs Elasticsearch 34.2s→ ClickHouse 快 1.69 倍为理解其原因我们再次按查询类型对结果进行细分。查询热运行时表现缓存缩小了差距但效果并非统一在缓存预热后部分查询性能差距显著缩小但按查询类型细分结果显示缓存并未完全消除两个系统之间潜在的执行模型差异。总体而言缓存缩小了检索密集型查询的性能差距但对搜索与分析工作负载则不然在这类场景中下游聚合操作仍然占据主导地位。Q1–Q3 事件钻取查询 在热执行条件下表现更为接近这与两个系统均受益于缓存谓词predicate评估的特点相符。尽管如此等效缓存在粒度上并非完全相同Elasticsearch 缓存的是哪些文档此前匹配了过滤器而 ClickHouse 则在 granules行块级别缓存过滤结果。因此ClickHouse 可以快速跳过整个 granules但仍需在剩余的 granules 中识别具体的匹配行。Q6–Q9 服务分解和趋势分析查询 仍然展现出 ClickHouse 的明显优势尤其是在大规模场景下因为这些查询在识别出匹配行后仍然需要在下游聚合操作中耗费大量时间。在更大的规模下Elasticsearch 细粒度过滤缓存带来的热运行性能优势似乎也会减弱。一个合理的解释是缓存压力增加随着数据量和不同工作集的增多文档级过滤结果的缓存保留效率可能降低从而削弱了细粒度缓存的实际效益。开源OSS比较已完成。接下来我们快速了解 ClickHouse Cloud 如何简化相同工作负载的扩展。额外内容在 ClickHouse Cloud 中扩展相同工作负载在许多分析工作负载中物化视图 (materialized views)等技术可以预先聚合数据从而减少查询需要扫描的数据量。日志分析则有所不同。在事件响应期间工程师通常需要原始日志事件搜索错误消息、检查相关日志、定位受影响的主机、按服务细分结果并根据新的过滤条件反复进行透视分析。这使得激进的预聚合策略在传统 BI (Business Intelligence) 工作负载中的效用大打折扣。当原始数据仍需被查询时提升查询速度的实用方法很简单增加更多计算资源。在 ClickHouse Cloud中计算与存储是分离的因此新增的副本节点复制的是计算能力而非数据无需预先重排数据即可即时加入。所有节点都从相同的共享对象存储中读取数据。并行副本 (Parallel replicas)通过将数据读取分布到副本节点集群中使得查询执行能够实现 横向扩展 (scale horizontally)。随着更多节点参与相同的查询可以在更多机器上并行执行从而缩短运行时间。下图展示了这对 500 亿行查询套件的影响。相比于 OSS 单节点基准线 (19.1s)相同的工作负载在 3 个节点上可降至 12.5s在 9 个节点上降至 6.45s在 20 个节点上降至 3.27s。实际效果是无论是人工探索 ClickStack仪表板还是代理循环查询日志日志搜索和分析都感觉更具交互性。引入 索引分片 (index sharding) 后这一优势将更加显著。正如存储部分所展示的针对 50 亿行 OTel 数据集的全文索引已达到约 0.5 TiB (515.78 GiB)。索引分片将该索引的分析任务分散到整个副本集群 (replica fleet) 中其方式与并行副本 (parallel replicas) 分散数据读取的方式如出一辙。对于一个 50 亿行的数据表ClickHouse 经 测定全文索引分析获得了 5.8 倍的加速。云端横向扩展 (Cloud scale-out) 是一个额外优势。即便没有它单节点 OSS 基准测试也已清楚地说明了问题。全貌这次基准测试完善了全貌首先ClickHouse 在聚合 (aggregations) 方面击败了 Elasticsearch接着在 JSON 分析方面也取得了胜利现在它又在全文分析搜索方面表现出色。ClickHouse 现在不仅支持搜索功能而且依然保持其世界级的聚合引擎。ClickHouse 全文搜索功能专为分析和可观测性 (observability) 而设计支持对数十亿乃至数万亿行数据进行快速的多令牌搜索和聚合 (aggregations)。这项基准测试证实在高达 500 亿行 的真实 OpenTelemetry 日志工作负载中ClickHouse 始终展现出更优异的整体表现。存储占用大幅减少 — 磁盘空间减少约 5 倍这意味着更低的存储成本、更低的查询 I/O并为持续数据摄入提供更大空间。冷查询速度显著提升 — 当数据需要从磁盘读取时速度提升 4 到 6 倍。这一点至关重要鉴于冷查询在可观测性 (Observability) 领域是常态。热查询速度更快 — 在缓存预热的情况下速度仍快约 1.7 到 2.6 倍确保仪表板、向下钻取 (drill-down) 和重复分析保持响应。性能差距最大的情况出现在那些结合了文本搜索、分组、计数和时间序列分析的工作负载中。在可观测性 (Observability) 领域搜索通常并非查询的最终目的。征稿启示面向社区长期正文文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出图文并茂。质量合格的文章将会发布在本公众号优秀者也有机会推荐到 ClickHouse 官网。关于我们ClickHouse 是全球速度最快资源利用最高效的在线分析列式数据库管理系统。现在ClickHouse可以作为一个安全可扩展的无服务器应用在云中提供服务。通过云服务ClickHouse使得任何人都能轻松获取高效的实时分析处理能力。
ClickHouse 填平 Elasticsearch 护城河?日志分析新选择!
发布时间:2026/7/6 14:52:39
本文字数17316估计阅读时间44分钟作者Tom Schreiber and Lionel PalacinTL;DR (摘要)ClickHouse 现已推出专为分析和可观测性构建的全新全文搜索功能在一个引擎中结合了快速多词条搜索和大规模聚合。这使得它成为 Elasticsearch 在日志分析领域一个极具吸引力的替代方案。本基准测试将揭示其原因。最后一块“护城河”被填平多年来人们的选择很简单Elasticsearch 用于文本搜索ClickHouse 用于分析。现在 ClickHouse 二者兼具。ClickHouse 现已 集成了一个 重新设计的、由倒排索引 (inverted indexes) 驱动的全文搜索功能。但与传统搜索引擎不同的是匹配的文档会直接送入其原有的向量化分析引擎 (vectorized analytical engine)该引擎在过滤、聚合和大规模扫描方面已 表现出色。这种结合在搜索仅仅是第一步时显得尤为重要。在 可观测性领域尤其是在日志分析中搜索很少仅仅是为了查找文本。用户通常会先搜索某个错误模式然后统计其出现次数、按服务分组、深入更小的时间范围或者隔离受影响的主机。换句话说日志是恰好包含文本的分析数据。在本次基准测试中我们将在真实的 OpenTelemetry 日志工作负载下对比 ClickHouse 和 Elasticsearch 的开源版本 (OSS versions) 在高达 500 亿行的数据集上的表现。抢先看在所有测试的数据集规模上ClickHouse 执行全文分析工作负载的速度比 Elasticsearch 快 2-6 倍。此外ClickHouse 存储 OpenTelemetry 日志数据集的效率也远高于 Elasticsearch。完整的基准测试是端到端可复现的源数据、Schema、查询、数据摄入脚本和测量结果均已发布在我们的 公共 GitHub 仓库中(https://github.com/ClickHouse/TextBench/tree/main) 。接下来我们将阐述基准测试的设置和方法然后探讨这两个系统如何在磁盘上存储 OpenTelemetry 日志最后比较它们的存储占用和查询执行时间。基准测试设置在揭晓结果之前以下是完整的基准测试设置数据集、查询、硬件和系统配置。如果您更关注结果可以直接跳转至存储占用和查询执行时间部分。Dataset该基准测试采用由我们的 OpenTelemetry 演示应用程序生成的真实 OpenTelemetry日志数据集该数据集产生的结构化服务日志与现代可观测性管道中常见的日志类似。为确保基准测试完全可重现所有源数据均以Parquet 文件的形式发布在一个公共 Amazon S3 存储桶中。区域eu-west-3 (欧洲 — 巴黎)公共存储桶s3://public-pme/text\_bench直接 URLhttps://public-pme.s3.eu-west-3.amazonaws.com/text\_bench/part\_{000..009}.parquet文件结构每个 Parquet 文件包含 10 亿条日志记录并按时间戳排序。提示建议在 eu-west-3 区域运行 EC2 基准测试实例以避免跨区域数据摄取延迟和出口费用。基于这些源数据我们以三种不同的规模将相同的基准数据集加载到 ClickHouse 和 Elasticsearch 中数据集行数小型10 亿中型100 亿大型500 亿通过这种方式我们能够评估这两个系统从十亿行级别的部署到应对大规模生产可观测性工作负载时的表现。查询为了评估实际的全文分析搜索性能我们使用了一套包含九个 OpenTelemetry 日志查询的集合。每个查询均基于单词或多词的全文搜索构建并常常伴随过滤、计数、分组、排序或基于时间的聚合操作。这些查询均使用各系统原生的查询语言实现ClickHouse 使用 SQLElasticsearch 使用 Query DSL 和 ES|QL。这套查询旨在反映 Kibana 等工具中典型的日志分析工作流程即用户搜索错误消息后立即对其进行过滤、计数、分组、排序或随时间进行分析。查询组合涵盖了四种常见的调查模式Q1–Q3事件深入分析与日志检索定位匹配给定术语的日志行应用过滤器并查看相关事件。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ1(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L1)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L3)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L3)Q2(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L12)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L25)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L8)Q3(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L25)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L50)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L13)Q4–Q5总体错误和匹配计数计算匹配记录或比较各子集之间的匹配量。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ4(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L33)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L64)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L18)Q5(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L39)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L75)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L23)Q6–Q7服务级别细分根据服务名称、主机或严重性等维度对匹配日志进行分组以识别问题集中之处。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ6(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L45)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L88)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L28)Q7(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L53)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L105)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L33)Q8–Q9: 基于时间的趋势分析将匹配项按时间段聚合以揭示峰值、回落或重复模式。QueryClickHouse SQLElasticsearch Query DSLElasticsearch ESQLQ8(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L61)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L122)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L38)Q9(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/clickhouse/queries.sql#L70)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries.json#L146)(https://github.com/ClickHouse/TextBench/blob/a7bb4e024f4648e90a30b6f0d00ef1223fd7d7e5/elasticsearch/queries_esql.json#L43)综合来看这些查询全面模拟了日志分析中的典型任务涵盖从选择性日志检索到大规模分析搜索。硬件和系统版本两个系统都在相同且独立的单节点环境中进行了基准测试以确保进行公平的同类比较。每个引擎都在其各自的专用 EC2 实例上运行并采用相同的 CPU、内存和存储配置。系统配置ClickHouseClickHouse 使用了一个标准的 MergeTree 表其 OpenTelemetry 日志 模式 包含了时间戳、数值、字符串和映射的原生数据类型。该表按以下方式 排序(ServiceName, Timestamp)此排序键提高了针对按服务和时间范围过滤的常见日志分析查询的数据局部性同时还改进了压缩。在 Body 列上 创建了一个 全文索引。ElasticsearchElasticsearch 使用了一个等效的 索引映射具有相同的逻辑模式和匹配的 物理排序顺序index.sort (ServiceName ASC, Timestamp ASC)主要映射选择Body映射为 text 类型并使用标准分析器支持全文搜索结构化字符串维度映射为 keyword 类型类 Map 的属性字段映射为 flattened 类型TraceFlags 和 SeverityNumber 映射为 byte 类型启用 codec: best_compression 以最小化磁盘占用在 Elasticsearch 允许的最大范围内此配置尽可能地复刻了 ClickHouse 的语义同时遵循了存储最佳实践。为了确保稳定的单节点性能我们使用了这些 JVM和 OS 设置堆内存固定为 30 GiB (-Xms30g -Xmx30g) 以保留 CompressedOopsbootstrap.memory_lock: truevm.max_map_count262144分片布局该基准测试使用了单节点存储优化布局两个系统中均无副本。针对每个数据集ClickHouse 使用了单个分片即单表而 Elasticsearch 则采用了多个分片这遵循了实现最佳分片大小的行业最佳实践每个分片 50GB。在测量之前所有 Elasticsearch 分片都依照最佳实践被强制合并使每个分片只包含一个段。这不仅提升了存储效率也不会阻碍并行搜索的执行因为 Lucene 在查询时仍能逻辑上对单个段进行分区。数据加载ClickHouse 通过其原生的 Parquet 摄入能力直接加载了 Parquet 文件。Elasticsearch 不原生支持读取 Parquet 文件因此数据需要从 Parquet 文件中进行流式传输转换为 NDJSON 格式然后通过 Bulk API 摄入。关于数据摄入的简要说明 本文侧重于分析性日志搜索性能因此我们没有进行全面、系统的摄入基准测试。然而在数据集准备阶段将 50B OTel 日志记录加载到单节点 ClickHouse 实例中开箱即用不到 4 小时。对于类似的单节点 Elasticsearch 配置我们需要调整摄入管道和相关设置才能达到可接受的吞吐量即便如此完成同样的数据加载也耗费了数天大约 5 天。数据摄入吞吐量是可观测性系统在生产环境中需要重点关注的关键问题因此我们可能会在专门的后续基准测试中针对 OTel 日志摄入方面进行深入探讨。在数据成功加载到两个系统后接下来我们将介绍用于公平比较查询性能的方法。方法论为真实反映可观测性工作流的场景我们对两个系统分别在冷启动和热启动两种条件下进行了基准测试。冷启动运行 (Cold runs) 模拟对以前从未查询过的时间范围进行的首次查询此时所需的日志数据必须从磁盘加载。热启动运行 (Hot runs) 模拟当相同数据已被缓存后进行的重复执行。本基准测试中考虑的缓存层级有三个缓存层可能影响查询延迟以下是您的翻译内容1. Linux 页缓存。这是操作系统的文件缓存旨在避免从磁盘重复读取数据。2. 过滤器评估缓存。这些是引擎级别的缓存用于记住先前的条件或过滤器结果以加速重复的筛选工作。ClickHouse: 查询条件缓存(https://clickhouse.com/docs/operations/query-condition-cache)Elasticsearch: 节点查询缓存(https://www.elastic.co/docs/reference/elasticsearch/configuration-reference/node-query-cache-settings)3. 全查询结果缓存。这些缓存用于存储针对相同重复查询的完整响应。ClickHouse: 查询缓存(https://clickhouse.com/docs/operations/query-cache)Elasticsearch: 分片请求缓存(https://www.elastic.co/docs/reference/elasticsearch/rest-apis/shard-request-cache)为了专注于核心执行性能我们在基准测试期间禁用了全查询结果缓存。否则我们测量的将主要是重复的内存结果查找速度这在此并非我们关注的重点。然而我们保持过滤器评估缓存处于启用状态因为它们是引擎正常执行路径的一部分。测量冷运行对于冷运行我们首先完全关闭两个系统清空 Linux 页缓存然后重启服务器在此之后才执行查询。这意味着没有数据页被缓存在内存中引擎必须从磁盘加载所需数据运行时反映了存储效率、剪枝能力以及原始执行速度OTel 日志查询套件中的每个查询都在这些冷启动条件下执行而报告的冷运行总计则是所有单个查询运行时间的总和。测量热运行在热运行测试中系统在各次执行之间保持运行状态并且没有清空 Linux 页缓存。对于每个查询相同的查询会连续执行三次全查询结果缓存保持禁用状态过滤器评估缓存保持启用状态三次运行中最快的一次被记录为热运行结果这种方式可以隔离重复查询的性能同时又不允许完整的查询结果重用。OTel 日志查询套件中的每个查询都在这些条件下进行测量而报告的热运行总计则是所有单个查询运行时间的总和。Elasticsearch Query DSL 与 ES|QL主要图表中的 Elasticsearch 结果均采用 Query DSL。我们还在 ES|QL 中实现了所有功能但在测试中发现在其运行时间持续较慢因此在整个主要基准测试中Query DSL 被用作更可靠的 Elasticsearch 基线。公共基准测试仓库中包含了 Query DSL 与 ES|QL 对应的冷启动和热启动的查询性能对比图。在确定了基准测试方法后我们将深入探讨这两个系统如何在磁盘上存储 OTel 日志。这种磁盘布局是理解后续结果的关键背景信息。OTel 日志在磁盘上的存储方式为了更好地理解下一节中的存储占用空间结果我们首先审视 Elasticsearch 和 ClickHouse 如何在磁盘上存储和压缩已摄入的 OTel 日志。以下图表提供了一个简化示意图。在这两个系统中已摄入的 OTel 日志数据最终都会被写入不可变的磁盘存储单元Elasticsearch 中的 Lucene segmentsClickHouse 中的 data parts这些单元在逻辑上属于分片图中未显示并在后台持续合并成更大的存储单元。通常Segments 会增长到大约 5 GBparts 则增长到大约 150 GB尽管这两个系统都支持更大规模的强制合并。在 Elasticsearch 中分片进而组成了索引详细信息可参见此处https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-vs-elasticsearch/on-disk-format-and-insert-processing#elasticsearchClickHouse 分片的描述可参见此处https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-vs-elasticsearch/on-disk-format-and-insert-processing#clickhouse。在这些磁盘存储单元内部两个系统都将数据组织成专门的数据结构主要用于实现四项功能快速聚合、全文搜索、返回原始文档以及在查询执行期间剪除不相关数据。用于快速聚合的列式存储两个系统都使用列式存储 (columnar storage)聚合查询仅读取所引用的列由于每列均经过压缩因此扫描的字节数更少并能在连续数据上执行向量化 (SIMD) 操作。在 Elasticsearch 的 doc\_values(https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/doc-values) 中每列都会根据其数据类型和基数自动使用 delta 和 gcd 等专用编解码器进行单独编码。然而它并未应用 lz4 或 zstd 等通用压缩算法。在 ClickHouse 中压缩编解码器也会应用于每个 列文件。ClickHouse 支持通用 (general-purpose) (例如 lz4 和 zstd)、专用 (specialized)(例如 delta 和 gcd) 和加密 (encryption) 编解码器 (例如 AES\_128)并且这些编解码器可以按列进行链式组合 (chained) 使用。全文搜索的倒排索引两个系统都使用倒排索引 (inverted index) 作为全文搜索的基本数据结构。存储字段和 \_source在 Elasticsearch 中存储字段 (stored fields)用作文档存储用于在查询响应中返回原始字段值。默认情况下它们还会存储 \_source其中包含原始摄入的 JSON 文档。存储字段的压缩算法由 index.codec 设置定义默认情况下为 lz4若追求更高的压缩率也可选用 zstd但其性能会相对较慢。为什么日志数据需要 _source对于日志分析而言返回原始摄入文档通常至关重要。在 Elasticsearch OSS 中这使得在实践中很难避免使用 _source而企业版则可以使用 合成 _source (synthetic _source)(https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-source-field.html#synthetic-source)。在 ClickHouse 中没有独立的等效结构原始行直接从存储在列文件中的值重建。稀疏索引用于剪枝 (Pruning)ClickHouse 使用稀疏索引由于 OTel 日志记录在磁盘上以排序顺序存储引擎可以将它们分组到块中并在 ③ 稀疏主索引 (sparse primary index)中记录每个块的值范围从而跳过完全超出请求范围的块。Lucene 具有针对排序数据的相关稀疏索引能力但 Elasticsearch 在用于本次比较的 \_disk\_usage 输出中并未将其作为单独的存储类别暴露出来。还需要注意的是在 Elasticsearch 中倒排索引 (inverted index) 不仅用于全文搜索 (full-text search)。对于除 Body 之外的所有字符串字段我们使用了 keyword 类型而 Timestamp 使用 date 类型数字字段则使用 numeric 类型。所有这些类型默认情况下也会为精确匹配过滤 (exact-match filtering) 填充倒排索引其值按原样索引且不进行分析 (analysis)。这意味着对这些字段的过滤可以通过倒排索引高效地解决使其成为本次比较中与 ClickHouse 稀疏主索引最接近的对应物。用于过滤和评分的点 (Points) 和范数 (norms)在 Elasticsearch 中④ 点 (points) 支持对数字和日期字段进行高效过滤和范围查询而 范数 (norms) 则存储每个文档的评分因子以衡量文本相关性。ClickHouse 不使用独立的评分结构数值和日期过滤通过列式扫描结合稀疏主索引和跳跃索引进行处理。ClickHouse 目前也不对全文搜索结果进行评分这与我们当前的日志分析用例无关。既然存储的基础组件已经明确接下来我们将探讨它们对磁盘使用量的综合影响。OTel 日志存储占用上述存储结构解释了数据字节的存储方式。为了公平地比较整体占用空间我们首先统一了最主要影响磁盘使用量的几个变量1. 相同的磁盘排序顺序数据在磁盘上按相同的键进行排序——在 ClickHouse 中通过排序键按 (ServiceName, Timestamp) 排序在 Elasticsearch 中则通过在相同字段上的索引排序实现。2. 相同的压缩算法存储原始日志内容的核心结构使用相同的压缩算法。具体来说ClickHouse 列文件和 Elasticsearch 存储字段均采用 ZSTD。3. 相同的全文倒排索引范围两个系统都仅在 Body 字段上构建全文倒排索引。在 Elasticsearch 中所有其他字符串字段都被映射为 keyword 类型这意味着它们支持精确匹配过滤但不进行全文搜索分析。最后正如之前(https://clickhouse.com/blog/elasticsearch-log-analytics-clickhouse#shard-layout)所述本次比较采用了存储优化的单节点配置两个系统中均无副本ClickHouse 使用一个分片而 Elasticsearch 则采用多个分片同时遵循最佳实践以实现最优分片大小每个分片 50GB并且强制合并为每个分片一个段。考虑到以上因素下方的图表展示了两个系统在存储 10 亿、100 亿和 500 亿条 OTel 日志记录时的存储占用情况。为了便于解读总体数据图表将这些数据细分为上一节介绍的各个磁盘上的数据结构。图例将每个彩色区域映射到其在 Elasticsearch 和 ClickHouse 中对应的结构而这些底层数据的大小则分别取自 Elasticsearch 的 \_disk\_usage API 和 ClickHouse 的 parts system table。注ClickHouse 的稀疏主索引 (sparse primary index) 已计入总数但在此规模下并不明显 (6.47 MiB / 64.26 MiB/ 320.56 MiB。总体存储空间占用总体而言ClickHouse 存储相同 OTel 日志数据所需的空间约为 Elasticsearch 的五分之一。这一结论在所有这三个规模下均保持一致。1B: ClickHouse 49.49 GiB对比 Elasticsearch 245.06 GiB → ClickHouse 空间占用约为 Elasticsearch 的 1/4.9510B: ClickHouse 496.84 GiB 对比 Elasticsearch 2.40 TiB → ClickHouse 空间占用约为 Elasticsearch 的 1/4.9550B: ClickHouse 2.43 TiB 对比 Elasticsearch 12.01 TiB→ ClickHouse 空间占用约为 Elasticsearch 的 1/4.95列式存储空间占用主要列式存储结构本身就存在巨大差异。仅 Elasticsearch 的 doc_values 所占用的空间就远超 ClickHouse 的列文件。1B: ClickHouse 39.33 GiB对比 Elasticsearch 102.49 GiB → ClickHouse 存储空间仅为 Elasticsearch 的 1/2.6110B: ClickHouse 393.54 GiB 对比 Elasticsearch 1.00 TiB → ClickHouse 存储空间仅为 Elasticsearch 的 1/2.6150B: ClickHouse 1.92 TiB 对比 Elasticsearch 5.02 TiB → ClickHouse 存储空间仅为 Elasticsearch 的 1/2.61值得一提的是ClickHouse 在其列文件中包含了所有的 OTel 日志字段而数据集中最大的字段 Body 则被排除在 Elasticsearch 的 doc_values 之外。这是因为 Body 被映射为 text类型因此仅存储在倒排索引中。ClickHouse 的压缩效率这已经揭示了整体存储差距的主要原因ClickHouse 对其列文件进行了极致高效的压缩。1B: 未压缩 642.42 GiB → 已压缩 39.33 GiB→ 16.33 倍压缩比10B: 未压缩 6.26 TiB → 已压缩 393.54 GiB→ 16.29 倍压缩比50B: 未压缩 31.31 TiB → 已压缩 1.92 TiB→ 16.29 倍压缩比请注意当专门针对压缩优化数据类型和数据在磁盘上的存储顺序时可以实现更高的压缩比。例如在一个 Nginx 日志案例中ClickHouse 实现了高达 178 倍的压缩比。存储结构细分下表汇总了在两种系统及全部三种规模下不同数据结构在磁盘上的占用空间。为什么 Elasticsearch 的存储占用更大Elasticsearch 索引体积更大部分原因在于它支持更广泛的搜索功能例如短语查询、模糊匹配、通配符搜索以及与排名相关的元数据。而本基准测试中的典型 OTel 日志分析查询通常不依赖这些功能。为了测试这对存储消耗的影响程度我们还运行了功能精简版的 Elasticsearch。一个 中等程度的配置变体通过禁用 norms (norms 参数设为 false) 并将主 Body 文本字段的 index_options 配置为仅文档级别的 postings (index\_options set to docs)仅将总存储占用空间降低了 约 2%。为了实现更大的存储空间缩减磁盘占用减少约 20%但仍比 ClickHouse 大 4 倍需要在额外字段上更 激进地禁用索引功能 (index 参数设为 false)。然而由此生成的配置不再代表典型的 Elasticsearch 日志部署场景例如除了我们的查询套件引用的一小部分字段外在大多数 OTel 字段上执行过滤操作都会变得慢得多。在这两种情况下总查询运行时长仅发生了 微小变化。关于 Query DSL 和 ESQL 在热/冷两种情况下的运行时长更多图表可在我们的 GitHub 仓库 [此处]查看。存储之外的更多优势更精简的占用空间使 ClickHouse 在大规模日志分析方面相比 Elasticsearch 具有多项优势更低的存储成本。 以更小的存储空间存储相同的 OTel 日志数据直接降低了在线保存海量日志数据的成本。更低的查询 I/O。 磁盘上更少的数据量意味着在扫描、过滤和聚合过程中需要读取的数据更少这部分解释了下一节中展示的运行时性能提升。更大的数据摄入能力。 更小的磁盘数据结构减轻了存储子系统的压力为现代可观测性管道中典型的持续写入吞吐量提供了更大的余量。这与上文提到的数据摄入案例相符在 ClickHouse 中500 亿行数据的加载远快于预期。此外ClickHouse OSS 开箱即用地支持其原生 MergeTree 引擎的 S3 后端存储这进一步增强了上述效果使得在线保存海量原始日志数据的成本效益显著提升。OTel 日志查询运行时我们首先分析冷启动的总运行时间然后深入研究每个查询的详细数据以进行解释。最后我们考察热运行阶段以了解数据被缓存后性能如何变化。总冷启动运行时间下面的图表展示了在包含 10 亿、100 亿和 500 亿条存储记录的数据集上完整的 OTel 日志查询套件的总冷启动运行时间。值得注意的是该测试套件反映了 Kibana 或 ClickStack 等工具中典型的日志分析工作负载它将全文搜索与聚合和过滤结合起来用于调查事件、错误和趋势。如前所述在冷运行测试中我们会先完全关闭两个系统清空 Linux 页缓存然后重新启动系统最后再执行查询。这样测得的是没有任何数据缓存时的执行耗时也就是查询引擎必须从磁盘加载所需数据时的表现。OTel 日志查询集合中的每个查询都会在这种冷启动条件下执行上图汇总了所有查询各自的执行耗时。冷查询在可观测性中并非罕见。工程师经常需要调查新出现的事件、查看此前从未涉足的时间范围或者检索较早的留存日志。在这些场景下我们无法指望存在热缓存。总体而言在所有三个规模上ClickHouse 完成完整的冷查询测试都比 Elasticsearch 快得多。10 亿条数据 (1B): ClickHouse 1.54s vs Elasticsearch 9.55s→ ClickHouse 快 6.20 倍100 亿条数据 (10B): ClickHouse 7.41s vs Elasticsearch 30.6s→ ClickHouse 快 4.13 倍500 亿条数据 (50B): ClickHouse 26.2s vs Elasticsearch 111.4s→ ClickHouse 快 4.25 倍那么这种领先优势究竟源自何处接下来我们将按查询类型细分总体的运行时数据。按查询类型划分的冷查询运行时ClickHouse 优势最明显之处从逐个查询的细分结果来看ClickHouse 在冷查询场景下的最大性能提升体现在那些将全文过滤 (full-text filtering) 与更繁重的后续聚合操作相结合的查询上。总体来看工作负载越是从纯粹的数据检索转向搜索加分析这在典型的日志分析查询中尤为常见ClickHouse 的优势就越发明显。Q8–Q9 趋势分析查询 在较大规模下展现出最大的性能差距这类查询需要将大量匹配行按时间段分组并计数。Q6–Q7 服务分解查询 的差距也随着规模的增长而显著扩大这反映了对大型结果集执行多组聚合操作的需求。Q1–Q3 事件下钻查询 的性能表现相对接近因为它们更侧重于数据检索并且涉及较少的过滤后聚合操作。这与我们早前进行的基准测试结果保持一致这些基准测试针对 聚合操作和 JSON 分析ClickHouse 在大规模 GROUP BY 和计数工作负载上显著优于 Elasticsearch。在此次测试中一旦文本匹配完成ClickHouse 在聚合方面的这些优势依然显著。冷启动测试旨在衡量存储效率和纯粹的执行速度。然而可观测性工作负载通常涉及对热数据的重复查询因此我们接下来将比较系统的热运行表现。总热运行时间下图展示了在包含 10 亿、100 亿和 500 亿条存储记录的数据集上运行 完整 OTel 日志查询套件 所需的总热运行时间。需要注意的是与之前的冷启动测试不同热启动测试是指在多次执行之间系统保持运行状态因此 Linux 页缓存持续可用。对于每个查询我们连续执行三次相同的查询。在此过程中两个系统的 查询结果缓存都被禁用但其对应的 过滤器评估缓存保持启用。最终我们取三次运行中最快的一次作为热启动结果。OTel 日志查询套件中的每个查询都在这些条件下进行了测量上图汇总了由此产生的每个查询的运行时间总和。热查询在可观测性领域同样至关重要。仪表盘会自动刷新故障排查会重新应用相似的过滤器并且交互式下钻操作也常常会重复访问相同的数据集。在暖缓存条件下两者之间的差距有所缩小但 ClickHouse 在所有规模下完成整个查询套件的速度依然快于 Elasticsearch。1B: ClickHouse 0.68s vs Elasticsearch 1.78s→ ClickHouse 快 2.62 倍10B: ClickHouse 4.54s vs Elasticsearch 7.89s→ ClickHouse 快 1.74 倍50B: ClickHouse 20.3s vs Elasticsearch 34.2s→ ClickHouse 快 1.69 倍为理解其原因我们再次按查询类型对结果进行细分。查询热运行时表现缓存缩小了差距但效果并非统一在缓存预热后部分查询性能差距显著缩小但按查询类型细分结果显示缓存并未完全消除两个系统之间潜在的执行模型差异。总体而言缓存缩小了检索密集型查询的性能差距但对搜索与分析工作负载则不然在这类场景中下游聚合操作仍然占据主导地位。Q1–Q3 事件钻取查询 在热执行条件下表现更为接近这与两个系统均受益于缓存谓词predicate评估的特点相符。尽管如此等效缓存在粒度上并非完全相同Elasticsearch 缓存的是哪些文档此前匹配了过滤器而 ClickHouse 则在 granules行块级别缓存过滤结果。因此ClickHouse 可以快速跳过整个 granules但仍需在剩余的 granules 中识别具体的匹配行。Q6–Q9 服务分解和趋势分析查询 仍然展现出 ClickHouse 的明显优势尤其是在大规模场景下因为这些查询在识别出匹配行后仍然需要在下游聚合操作中耗费大量时间。在更大的规模下Elasticsearch 细粒度过滤缓存带来的热运行性能优势似乎也会减弱。一个合理的解释是缓存压力增加随着数据量和不同工作集的增多文档级过滤结果的缓存保留效率可能降低从而削弱了细粒度缓存的实际效益。开源OSS比较已完成。接下来我们快速了解 ClickHouse Cloud 如何简化相同工作负载的扩展。额外内容在 ClickHouse Cloud 中扩展相同工作负载在许多分析工作负载中物化视图 (materialized views)等技术可以预先聚合数据从而减少查询需要扫描的数据量。日志分析则有所不同。在事件响应期间工程师通常需要原始日志事件搜索错误消息、检查相关日志、定位受影响的主机、按服务细分结果并根据新的过滤条件反复进行透视分析。这使得激进的预聚合策略在传统 BI (Business Intelligence) 工作负载中的效用大打折扣。当原始数据仍需被查询时提升查询速度的实用方法很简单增加更多计算资源。在 ClickHouse Cloud中计算与存储是分离的因此新增的副本节点复制的是计算能力而非数据无需预先重排数据即可即时加入。所有节点都从相同的共享对象存储中读取数据。并行副本 (Parallel replicas)通过将数据读取分布到副本节点集群中使得查询执行能够实现 横向扩展 (scale horizontally)。随着更多节点参与相同的查询可以在更多机器上并行执行从而缩短运行时间。下图展示了这对 500 亿行查询套件的影响。相比于 OSS 单节点基准线 (19.1s)相同的工作负载在 3 个节点上可降至 12.5s在 9 个节点上降至 6.45s在 20 个节点上降至 3.27s。实际效果是无论是人工探索 ClickStack仪表板还是代理循环查询日志日志搜索和分析都感觉更具交互性。引入 索引分片 (index sharding) 后这一优势将更加显著。正如存储部分所展示的针对 50 亿行 OTel 数据集的全文索引已达到约 0.5 TiB (515.78 GiB)。索引分片将该索引的分析任务分散到整个副本集群 (replica fleet) 中其方式与并行副本 (parallel replicas) 分散数据读取的方式如出一辙。对于一个 50 亿行的数据表ClickHouse 经 测定全文索引分析获得了 5.8 倍的加速。云端横向扩展 (Cloud scale-out) 是一个额外优势。即便没有它单节点 OSS 基准测试也已清楚地说明了问题。全貌这次基准测试完善了全貌首先ClickHouse 在聚合 (aggregations) 方面击败了 Elasticsearch接着在 JSON 分析方面也取得了胜利现在它又在全文分析搜索方面表现出色。ClickHouse 现在不仅支持搜索功能而且依然保持其世界级的聚合引擎。ClickHouse 全文搜索功能专为分析和可观测性 (observability) 而设计支持对数十亿乃至数万亿行数据进行快速的多令牌搜索和聚合 (aggregations)。这项基准测试证实在高达 500 亿行 的真实 OpenTelemetry 日志工作负载中ClickHouse 始终展现出更优异的整体表现。存储占用大幅减少 — 磁盘空间减少约 5 倍这意味着更低的存储成本、更低的查询 I/O并为持续数据摄入提供更大空间。冷查询速度显著提升 — 当数据需要从磁盘读取时速度提升 4 到 6 倍。这一点至关重要鉴于冷查询在可观测性 (Observability) 领域是常态。热查询速度更快 — 在缓存预热的情况下速度仍快约 1.7 到 2.6 倍确保仪表板、向下钻取 (drill-down) 和重复分析保持响应。性能差距最大的情况出现在那些结合了文本搜索、分组、计数和时间序列分析的工作负载中。在可观测性 (Observability) 领域搜索通常并非查询的最终目的。征稿启示面向社区长期正文文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出图文并茂。质量合格的文章将会发布在本公众号优秀者也有机会推荐到 ClickHouse 官网。关于我们ClickHouse 是全球速度最快资源利用最高效的在线分析列式数据库管理系统。现在ClickHouse可以作为一个安全可扩展的无服务器应用在云中提供服务。通过云服务ClickHouse使得任何人都能轻松获取高效的实时分析处理能力。