流数据为许多实时分析应用程序提供数据,从物流跟踪到实时个性化。事件流,例如点击流、物联网数据和其他时间序列数据,是这些应用程序的常见数据来源。Apache Kafka 的广泛采用有助于使这些事件流更易于访问。来自 OLTP 数据库的变更数据捕获 (CDC)流可以提供销售、人口统计或库存数据,是实时分析用例的另一个有价值的数据来源。在这篇文章中,我们比较了事件和 CDC 流实时分析的两个选项:Rockset 和 ClickHouse。
架构
ClickHouse 于 2008 年开始开发,用于处理俄罗斯 Yandex 的网络分析用例。该软件随后于 2016 年开源。 Rockset 于 2016 年启动,以满足开发人员构建实时数据应用程序的需求。Rockset 利用 RocksDB,一个高性能的键值存储,在 2010 年左右作为 Facebook 的一个开源项目开始,并基于谷歌的早期工作。RocksDB 用作 Apache Cassandra、CockroachDB 等数据库的存储引擎。Flink、Kafka 和 MySQL。
作为实时分析数据库,Rockset 和 ClickHouse 专为大型数据集的低延迟分析而构建。它们拥有分布式架构,允许可扩展性以处理性能或数据量要求。ClickHouse 集群倾向于扩展,使用较少数量的大型节点,而 Rockset 是一个无服务器的横向扩展数据库。两者都提供 SQL 支持,并且能够从 Kafka 摄取流数据。
存储格式
虽然 Rockset 和 ClickHouse 都是为分析应用程序设计的,但它们的方法存在显着差异。ClickHouse 的名称来源于“Clickstream Data Warehouse”,它在构建时考虑了数据仓库,因此 ClickHouse 在其实现中借鉴了许多相同的想法——列方向、重压缩和不可变存储——也就不足为奇了。众所周知,列方向是 OLAP 工作负载(如大规模聚合)的更好存储格式,并且是 ClickHouse 性能的核心。
相比之下,Rockset 的基本思想是为快速分析建立数据索引。Rockset 构建了一个 Converged Index ™,它在所有字段上都具有多种类型的索引(行、列和倒排)的特征。与 ClickHouse 不同,Rockset 是一个可变数据库。
计算与存储分离
云设计是 Rockset 和 ClickHouse 存在分歧的另一个领域。ClickHouse 作为软件提供,可以在本地或云基础设施上自我管理。一些供应商还提供 ClickHouse 的云版本。Rockset 专为云而设计,并作为完全托管的云服务提供。
ClickHouse 使用无共享架构,计算和存储紧密耦合。这有助于减少争用并提高性能,因为集群中的每个节点都在其本地存储中处理数据。这也是 Teradata 和 Vertica 等知名数据仓库采用的设计。

Rockset 采用Aggregator-Leaf-Tailer (ALT)架构,由 Facebook、LinkedIn 和 Google 等网络公司推广。Tailers 从数据源获取新数据,Leaves 索引和存储数据,Aggregator 以分布式方式执行查询。Rockset 不仅将计算和存储分开,还分解了摄取和查询计算,因此该架构中的每一层都可以独立扩展。

在以下部分中,我们将研究其中一些架构差异如何影响 Rockset 和 ClickHouse 的功能。
数据摄取
流式与批量摄取
虽然 ClickHouse 提供了多种与 Kafka 集成以摄取事件流的方法,包括本机连接器,但 ClickHouse 分批摄取数据。对于处理高摄取率的列存储,它需要以足够大的批量加载数据,以最小化开销并最大化列压缩。ClickHouse 文档建议在至少 1000 行的数据包中插入数据,或者每秒不超过一个请求。这意味着用户需要在加载到 ClickHouse 之前配置他们的流以批处理数据。
Rockset 具有本地连接器,可从 Kafka 和 Kinesis 中提取事件流,以及从 MongoDB、DynamoDB、Postgres 和 MySQL 等数据库中提取 CDC 流。在所有这些情况下,Rockset 以每条记录为基础进行摄取,而不需要批处理,因为 Rockset 旨在尽可能快地提供实时数据。在流式摄取的情况下,从生成数据到在 Rockset 中可查询,通常需要 1-2 秒。
数据模型
在大多数情况下,ClickHouse 将要求用户为他们创建的任何表指定架构。为了帮助简化此操作,ClickHouse 最近引入了使用 JSON 对象类型处理半结构化数据的更大能力。这与使用表中总行的子集从 JSON 推断模式的附加功能相结合。动态推断的列有一些限制,例如无法用作主键或排序键,因此用户仍需要配置某种级别的显式模式定义以获得最佳性能。
Rockset 将对所有传入数据执行无模式摄取,并将接受具有混合类型、嵌套对象和数组、稀疏字段和空值的字段,而无需用户执行任何手动规范。Rockset 根据集合中存在的确切字段和类型自动生成模式,而不是数据的子集。

ClickHouse 数据通常是非规范化的,以避免必须进行 JOIN,并且用户评论说这样做所需的数据准备可能很困难。相比之下,不建议对 Rockset 中的数据进行非规范化处理,因为 Rockset 可以很好地处理 JOIN。
更新和删除
正如架构部分简要提到的,ClickHouse 将数据写入不可变文件,称为“部件”。虽然这种设计有助于 ClickHouse 实现更快的读取和写入,但这样做是以牺牲更新性能为代价的。

ClickHouse 支持更新和删除操作,称为突变。它们不直接更新或删除数据,而是异步重写和合并数据部分。在异步突变正在进行时运行的任何查询都可能从突变和非突变部分获得混合数据。
此外,这些突变可能会变得昂贵,因为即使是很小的变化也会导致整个部分的大量重写。ClickHouse 文档指出这些是繁重的操作,不建议经常使用它们。因此,通常包含更新和删除的数据库 CDC 流由 ClickHouse 处理的效率较低。
相反,存储在 Rockset 集合中的所有文档都是可变的,并且可以在字段级别进行更新,即使这些字段深深嵌套在数组和对象中。只有文档中属于更新请求一部分的字段需要重新索引,而文档中的其余字段保持不变。
Rockset 使用 RocksDB,这是一种高性能的键值对存储,使突变变得微不足道。RocksDB 支持跨不同键的原子写入和删除。由于其设计,Rockset 是少数可以从数据库 CDC 流中有效摄取的实时分析数据库之一。
摄取转换和汇总
能够在摄取流数据时对其进行转换和汇总是很有用的。ClickHouse 有几个可以预先聚合数据的存储引擎。SummingMergeTree对对应于相同主键的行求和,并将结果存储为单行。AggregatingMergeTree 类似,并将聚合函数应用于具有相同主键的行以生成单行作为其结果。

Rockset 支持在摄取点应用于所有文档的 SQL 转换。用户可以通过使用 SQL 来指定更多类型的转换。摄取转换的常见用途包括删除字段、字段屏蔽和散列以及类型强制。
Rockset 中的汇总是一种特殊类型的转换,可在摄取时聚合数据。使用汇总可减少存储大小并提高查询性能,因为只存储和查询聚合数据。
查询和性能
索引
ClickHouse 的性能主要源于存储优化,例如列方向、积极压缩和按主键对数据进行排序。ClickHouse 也使用索引来加速查询,但与其存储优化相比,其方式更为有限。
ClickHouse 中的主索引是稀疏索引。它们不会索引每一行,而是每组行有一个索引条目。稀疏索引不是返回与查询匹配的单行,而是用于定位可能匹配的行组。
同样,ClickHouse 利用二级索引(称为数据跳过索引)来使 ClickHouse 能够跳过与查询不匹配的读取块。ClickHouse 然后扫描缩减的数据集以完成查询的执行。
Rockset 针对计算效率进行了优化,因此索引是其查询速度背后的主要驱动力。Rockset 的聚合索引结合了行索引、列索引和倒排索引。这使得 Rockset 的 SQL 引擎可以优化使用索引来加速各种分析查询,从高度选择性的查询到大规模的聚合。聚合索引也是一个覆盖索引,这意味着所有查询都可以仅通过索引来解决,无需任何额外的查找。

ClickHouse 和 Rockset 管理索引的方式有很大不同。在 ClickHouse 中,用户有责任了解需要哪些索引才能配置主索引和二级索引。默认情况下,Rockset 会索引以聚合索引提供的不同方式摄取的所有数据。
加入
虽然 ClickHouse 支持 JOIN 功能,但许多用户报告了 JOIN 的性能挑战,尤其是在大型表上。ClickHouse 无法有效优化这些 JOIN,因此建议使用替代方法,例如预先对数据进行非规范化以避免 JOIN。
在支持全功能 SQL 时,Rockset 在设计时考虑了 JOIN 性能。Rockset 对 JOIN 进行分区,这些分区在分布式聚合器上并行运行,如果需要可以横向扩展。它还有 多种执行 JOIN 的方式:
- 哈希连接
- 嵌套循环加入
- 广播加入
- 查找加入
在分析跨不同数据库系统和实时数据流的数据时,在 Rockset 中加入数据的能力特别有用。例如,可以使用 Rockset 将 Kafka 流与 MySQL 中的维度表连接起来。在许多情况下,预先加入数据不是一种选择,因为数据新鲜度很重要,或者需要执行即席查询的能力。
运行
集群管理
ClickHouse 集群可以在自我管理模式下运行,也可以通过将 ClickHouse 商业化为云服务的公司运行。在自我管理的集群中,ClickHouse 用户需要安装和配置 ClickHouse 软件以及所需的服务,如 ZooKeeper 或 ClickHouse Keeper。云版本将有助于消除一些硬件和软件供应负担,但用户仍然需要配置节点、分片、软件版本、复制等。用户需要干预升级集群,在此期间他们可能会遇到停机或性能下降的情况。
相比之下,Rockset 是完全托管和无服务器的。集群和服务器的概念被抽象出来,因此不需要配置,用户也不必自己管理任何基础设施。软件升级在后台进行,因此用户可以轻松利用最新版本的软件。
缩放和再平衡
虽然开始使用 ClickHouse 的单节点版本相当简单,但扩展集群以满足性能和存储需求需要一些努力。例如,设置分布式 ClickHouse涉及在每个单独的服务器上创建一个分片表,然后通过另一个 create 命令定义分布式视图。
正如架构概述中所讨论的,计算和存储在 ClickHouse 节点和集群中相互绑定。用户需要以固定比例扩展计算和存储,缺乏独立扩展资源的灵活性。这可能导致资源利用率欠佳,其中计算或存储被过度配置。
计算和存储的紧密耦合也导致了可能出现不平衡或热点的情况。将节点添加到 ClickHouse 集群时会出现一种常见情况,这需要重新平衡数据以填充新添加的节点。ClickHouse 文档指出,ClickHouse 集群不具有弹性,因为它们不支持自动分片重新平衡。相反,重新平衡是一个高度复杂的过程,其中可能包括手动加权写入以偏向写入新数据的位置、手动重新定位现有数据分区,甚至将数据复制和导出到新集群。
缺乏计算存储分离的另一个副作用是大量的小查询会影响整个集群。ClickHouse 建议使用双层分片来限制这些小查询的影响。
Rockset 中的扩展涉及较少的工作量,因为它分离了计算和存储。随着数据大小的增长,存储会自动扩展,而计算可以通过指定虚拟实例大小来扩展,该大小控制系统中可用的总计算和内存资源。用户可以独立扩展资源,以更有效地利用资源。由于 Rockset 的计算节点从其共享存储访问数据,因此无需重新平衡。
复制
由于 ClickHouse 的无共享架构,副本具有双重目的:可用性和持久性。虽然副本具有提高查询性能的潜力,但它们对于防止数据丢失至关重要,因此 ClickHouse 用户必须承担额外的复制成本。在 ClickHouse 中配置复制还涉及部署 ZooKeeper 或 ClickHouse Keeper(ClickHouse 的服务版本)以进行协调。
在 Rockset 的云原生架构中,它使用云对象存储来确保持久性,而无需额外的副本。多个副本可以提高查询性能,但只有在有活动查询请求时,这些副本才能按需联机。通过使用更便宜的云对象存储来实现持久性,并且只在需要性能时为副本增加计算和快速存储,Rockset 可以提供更好的性价比。
概括
Rockset 和 ClickHouse 都是流数据的实时分析选项,但它们的底层设计完全不同。它们的技术差异体现在以下方面。
- 流式写入和更新的效率:ClickHouse 不鼓励小型流式写入和频繁更新,因为它建立在不可变的列式存储之上。Rockset 作为一个可变数据库,可以更有效地处理流式摄取、更新和删除,使其适合作为事件和数据库 CDC 流的目标。
- 数据和查询灵活性:ClickHouse 通常需要对数据进行非规范化,因为大规模的 JOIN 性能不佳。Rockset 对半结构化数据进行操作,无需模式定义或非规范化,并支持包括 JOIN 在内的全功能 SQL。
- 运营:Rockset 从一开始就是为云构建的,而 ClickHouse 是可以部署在本地或云基础设施上的软件。Rockset 的分解式云原生架构最大限度地减少了用户的运营负担,并实现了快速轻松的横向扩展。
由于这些原因,许多组织选择在 Rockset 的基础上进行构建,而不是投资于更繁重的数据工程以使其他解决方案发挥作用。
原文标题:Comparing ClickHouse vs Rockset for Event and CDC Streams
原文作者:Kevin Leong
原文链接:https://rockset.com/blog/comparing-clickhouse-vs-rockset-for-event-and-cdc-streams/




