DoubleCloud 即将停止服务。迁移到 ClickHouse,享受限时免费迁移服务。立即联系我们 ->->

博客 / 产品

ClickHouse Cloud 通过 SharedMergeTree 和轻量级更新提升性能

author avatar
Tom Schreiber
2023年8月17日

引言

ClickHouse 是用于实时应用和分析的最快、最高效的数据库。MergeTree 表引擎家族中的表是 ClickHouse 快速数据处理能力的核心组件。在这篇文章中,我们描述了这个家族中一个新成员——SharedMergeTree 表引擎的动机和机制。

此表引擎是 ClickHouse Cloud 中 ReplicatedMergeTree 表引擎的更高效的直接替代品,专为云原生数据处理而设计和优化。我们深入研究了这个新表引擎的内部机制,解释了它的优势,并通过基准测试演示了它的效率。我们还有一个好消息要告诉你。我们正在引入与 SharedMergeTree 具有协同效应的轻量级更新。

MergeTree 表引擎是 ClickHouse 的核心

MergeTree 家族中的表引擎是 ClickHouse 中主要的表引擎。它们负责存储插入查询接收到的数据,在后台合并这些数据,应用引擎特定的数据转换等等。大多数 MergeTree 家族中的表都通过 ReplicatedMergeTree 基本表引擎的复制机制支持自动数据复制

在传统的无共享 ClickHouse集群 中,通过 ReplicatedMergeTree 进行复制用于数据可用性,并且可以使用分片 来扩展集群。 ClickHouse Cloud 采用了一种新的方法来构建基于 ClickHouse 的云原生数据库服务,我们将在下面介绍。

ClickHouse Cloud 登场

ClickHouse Cloud 于 2022 年 10 月进入公开测试阶段,它采用了完全不同的架构,该架构针对云进行了优化(我们解释过我们如何在一年内从头构建它)。通过将数据存储在实际上无限的共享对象存储 中,存储和计算分离:所有横向纵向可扩展的 ClickHouse 服务器都可以访问相同的数据,并且实际上是单个无限分片 的多个副本。
smt_01.png

共享对象存储用于数据可用性

由于 ClickHouse Cloud 将所有数据存储在共享对象存储中,因此无需在不同的服务器上显式创建数据的物理副本。对象存储实现(如 Amazon AWS 的简单存储服务、Google GCP 的云存储 和 Microsoft Azure 的Blob 存储)确保存储具有高可用性和容错性。

请注意,ClickHouse Cloud 服务具有多层读穿写穿缓存(位于本地NVMe SSD 上),旨在原生在对象存储之上工作,以提供快速的分析查询结果,尽管底层主要数据存储的访问延迟较慢。对象存储的访问延迟较慢,但提供高度并发吞吐量和大聚合带宽。ClickHouse Cloud 通过利用多个 I/O 线程来访问对象存储数据,并通过异步预取数据来利用这一点。

自动集群扩展

ClickHouse Cloud 允许用户简单地增加在共享且实际上无限的对象存储之上运行的服务器的大小和数量,而不是使用分片来扩展集群大小。这增加了 INSERT 和 SELECT 查询的数据处理并行性。

请注意,ClickHouse Cloud 服务器实际上是单个无限分片的多个副本,但它们不像无共享集群中的副本服务器。这些服务器可以访问存储在共享对象存储中的相同数据,而不是包含相同数据的本地副本。这将这些服务器转变为动态计算单元或计算节点,其大小和数量可以轻松地适应工作负载。可以通过手动或完全自动方式进行。该图说明了这一点:smt_02.png ① 通过扩展和 ② 缩减操作,我们可以更改节点的大小(CPU 内核和 RAM 的数量)。并且根据 ③ 横向扩展,我们可以增加参与并行数据处理的节点数量。无需任何物理分片或数据重新平衡,我们就可以自由地添加或删除节点。

对于这种集群扩展方法,ClickHouse Cloud 需要一个表引擎来支持更多数量的服务器访问相同的数据。

在 ClickHouse Cloud 中运行 ReplicatedMergeTree 遇到的挑战

ReplicatedMergeTree 表引擎并不适合 ClickHouse Cloud 的预期架构,因为它的复制机制旨在在少量副本服务器上创建数据的物理副本。而 ClickHouse Cloud 需要一个支持在共享对象存储之上运行大量服务器的引擎。

不需要显式数据复制

我们简要解释一下 ReplicatedMergeTree 表引擎的复制机制。此引擎使用ClickHouse Keeper(也称为“Keeper”)作为通过复制日志进行数据复制的协调系统。Keeper 充当复制特定元数据和表模式的中央存储,以及分布式操作的一致性系统。Keeper 确保按顺序分配顺序块号以用于分区名称。使用 Keeper 提供的一致性机制将合并变异分配到特定副本服务器。

下图描绘了一个包含 3 个副本服务器的无共享 ClickHouse 集群,并展示了 ReplicatedMergeTree 表引擎的数据复制机制:smt_03.png 当① server-1 接收插入查询时,② server-1 会在本地磁盘上创建一个包含查询数据的新数据分区。③ 通过复制日志,其他服务器(server-2、server-3)会被告知 server-1 上存在一个新的分区。在④,其他服务器会独立地从 server-1 下载(“获取”)该分区到它们自己的本地文件系统。在创建或接收分区后,所有三个服务器还会更新它们在 Keeper 中描述其分区集的元数据。

请注意,我们只展示了新创建的分区是如何复制的。分区合并(以及变异)的复制方式类似。如果一个服务器决定合并一组分区,则其他服务器会自动在其本地分区副本上执行相同的合并操作(或者只是下载合并后的分区)。

如果本地存储完全丢失或添加新的副本时,ReplicatedMergeTree 会从现有副本克隆数据。

ClickHouse Cloud 使用持久化的共享对象存储来保证数据可用性,不需要 ReplicatedMergeTree 的显式数据复制。

不需要分片来进行集群扩展

无共享 ClickHouse 集群 的用户可以将复制与分片结合使用,以处理包含更多服务器的大型数据集。表数据以分片(表数据分区的不同子集)的形式分布在多个服务器上,并且每个分片通常有 2 或 3 个副本以确保存储和数据可用性。通过添加更多分片可以提高数据摄取和查询处理的并行度。请注意,ClickHouse 将具有更复杂拓扑结构的集群抽象到分布式表下,以便您可以像执行本地查询一样执行分布式查询。

ClickHouse Cloud 不需要分片来进行集群扩展,因为所有数据都存储在实际上无限大的共享对象存储中,并且可以通过添加能够访问共享数据的其他服务器来简单地提高并行数据处理级别。但是,ReplicatedMergeTree 的复制机制最初设计为在无共享集群架构和少量副本服务器的本地文件系统之上工作。拥有大量 ReplicatedMergeTree 副本是一种反模式,服务器会在复制日志上产生过多的争用,并在服务器间通信上产生开销。

零拷贝复制无法解决这些挑战

ClickHouse Cloud 提供服务器的自动垂直扩展 - 服务器的 CPU 内核和 RAM 会根据 CPU 和内存压力自动适应工作负载。我们最初每个 ClickHouse Cloud 服务都配置了固定的 3 台服务器,并最终引入了横向扩展到任意数量的服务器。

为了支持在共享存储和 ReplicatedMergeTree 之上进行这些高级扩展操作,ClickHouse Cloud 使用了一种称为零拷贝复制的特殊修改,以使 ReplicatedMergeTree 表的复制机制能够在共享对象存储之上工作。

这种适配使用几乎相同的原始复制模型,只是数据在对象存储中只存储一份副本。因此称为零拷贝复制。服务器之间没有复制数据。相反,我们只复制元数据:smt_04.png 当① server-1 接收插入查询时,② 服务器会以分区形式将插入的数据写入对象存储,并③ 将有关分区的元数据(例如,分区在对象存储中的存储位置)写入其本地磁盘。④ 通过复制日志,其他服务器会被告知 server-1 上存在一个新的分区,尽管实际数据存储在对象存储中。并且⑤ 其他服务器会独立地从 server-1 下载(“获取”)元数据到它们自己的本地文件系统。为了确保数据在所有副本删除指向同一对象的元数据之前不会被删除,使用了分布式引用计数机制:在创建或接收元数据后,所有三个服务器还会更新它们在 ClickHouse Keeper 中的元数据分区集信息。

为此,以及为了将合并和变异等操作分配给特定的服务器,零拷贝复制机制依赖于在 Keeper 中创建独占。这意味着这些操作可能会互相阻塞,并且需要等待当前正在执行的操作完成。

零拷贝复制并没有充分解决共享对象存储上 ReplicatedMergeTree 的挑战

  • 元数据仍然与服务器耦合:元数据存储没有与计算分离。零拷贝复制仍然需要每个服务器上的本地磁盘来存储有关分区的信息。本地磁盘是额外的故障点,可靠性取决于副本数量,而副本数量又与高可用性的计算开销相关。
  • 零拷贝复制的持久性取决于 3 个组件的保证:对象存储、Keeper 和本地存储。这些组件数量增加了复杂性和开销,因为此堆栈是在现有组件之上构建的,而不是作为云原生解决方案重新设计的。
  • 这仍然是为少量服务器设计的:使用最初为无共享集群架构和少量副本服务器设计的相同复制模型更新元数据。大量服务器会在复制日志上产生过多的争用,并在锁和服务器间通信上产生高开销。此外,实现复制和从一个副本克隆数据到另一个副本的代码中存在大量复杂性。并且由于元数据是独立更改的,因此无法对所有副本进行原子提交。

用于云原生数据处理的 SharedMergeTree

我们决定(并且从一开始就计划)为 ClickHouse Cloud 从头实现一个新的表引擎,称为SharedMergeTree - 设计用于在共享存储之上工作。SharedMergeTree 是我们实现以下目标的云原生方式:(1)使 MergeTree 代码更简单易维护,(2)支持服务器的垂直和水平自动扩展,以及(3)为我们的云用户启用未来的功能和改进,例如更高的一致性保证、更好的持久性、时间点恢复、数据时间旅行等等。

在这里,我们简要描述了SharedMergeTree 如何原生支持 ClickHouse Cloud 的自动集群扩展模型。提醒一下:ClickHouse Cloud 服务器是能够访问相同共享数据的计算单元,其大小和数量可以自动更改。对于此机制,SharedMergeTree 完全将数据和元数据的存储与服务器分离,并使用接口与 Keeper 交互,以便从所有服务器读取、写入和修改共享元数据。每个服务器都有一个包含元数据子集的本地缓存,并通过订阅机制自动获取有关数据更改的信息。

此图描绘了如何将新的服务器添加到使用 SharedMergeTree 的集群中:smt_05.png 当 server-3 被添加到集群时,此新服务器① 订阅 Keeper 中的元数据更改并将其部分当前元数据获取到其本地缓存中。这不需要任何锁定机制;新服务器基本上只是说,“我来了。请随时向我告知所有数据更改”。新添加的 server-3 几乎可以立即参与数据处理,因为它通过仅从 Keeper 获取必要的共享元数据集来了解数据存在的位置和对象存储中的位置。

下图显示了所有服务器如何了解新插入的数据:smt_06.png 当① server-1 接收插入查询时,② 服务器会以分区形式将查询数据写入对象存储。③ Server-1 还会将其本地缓存和 Keeper 中存储有关分区的信息(例如,哪些文件属于分区以及与文件对应的 Blob 驻留在对象存储中的什么位置)。之后,④ ClickHouse 向查询发送方确认插入操作。其他服务器(server-2、server-3)通过 Keeper 的订阅机制⑤ 自动收到有关对象存储中存在新数据的信息,并将元数据更新获取到其本地缓存中。

请注意,插入查询的数据在步骤④之后是持久化的。即使 Server-1 崩溃,或者任何或所有其他服务器崩溃,该分区也存储在高可用对象存储中,并且元数据存储在 Keeper 中(Keeper 至少有 3 台服务器的高可用设置)。

从集群中删除服务器也是一个简单快速的运维操作。为了实现优雅删除,服务器只需从 Keeper 中注销自己,以便在没有服务器丢失警告消息的情况下正确处理正在进行的分布式查询。

ClickHouse Cloud 用户的优势

在 ClickHouse Cloud 中,SharedMergeTree 表引擎是 ReplicatedMergeTree 表引擎更高效的替代方案。为 ClickHouse Cloud 用户带来以下强大的优势。

无缝集群扩展

ClickHouse Cloud 将所有数据存储在实际上无限大、持久且高度可用的共享对象存储中。SharedMergeTree 表引擎为所有表组件添加了共享元数据存储。它可以实现实际上无限扩展在该存储之上运行的服务器。服务器实际上是无状态的计算节点,我们可以几乎立即更改其大小和数量。

示例

假设 ClickHouse Cloud 用户当前正在使用三个节点,如下图所示:smt_07.png 通过将每个节点的大小加倍或(例如,当每个节点的最大大小达到时)将节点数量从三个加倍到六个,可以(手动或自动)轻松地将计算量加倍:smt_08.png使摄取吞吐量加倍。对于 SELECT 查询,增加节点数量会提高并发查询执行和单个查询的并发执行的并行数据处理级别。请注意,在 ClickHouse Cloud 中增加(或减少)节点数量不需要任何实际数据的物理分片或重新平衡。我们可以自由地添加或删除节点,其效果与无共享集群中的手动分片相同。

更改无共享集群中的服务器数量需要更多工作和时间。如果集群当前由三个分片组成,每个分片有两个副本:smt_09.png 那么将分片数量加倍需要对当前存储的数据进行分片和重新平衡:smt_10.png

自动增强插入查询的持久性

使用 ReplicatedMergeTree,您可以使用 insert_quorum 设置来确保数据持久性。您可以配置插入查询仅在查询数据(对于零拷贝复制,则是元数据)存储在指定数量的副本上时才返回给发送方。对于 SharedMergeTree,不需要 insert_quorum。如上所示,当插入查询成功返回给发送方时,查询数据将存储在高可用对象存储中,元数据将集中存储在 Keeper 中(Keeper 具有至少 3 个 Keeper 服务器的高可用设置)。

更轻量级的 SELECT 查询强一致性

如果您的用例需要保证每个服务器都提供相同的查询结果的一致性,则可以运行 SYNC REPLICA 系统语句,这对于 SharedMergeTree 来说是一个更轻量级的操作。每个服务器只需要从 Keeper 获取元数据的当前版本,而不是在服务器之间同步数据(或使用零拷贝复制同步元数据)。

改进后台合并和修改的吞吐量和可扩展性

使用 SharedMergeTree,服务器数量增加不会导致性能下降。只要 Keeper 有足够的资源,后台合并的吞吐量就会随着服务器数量的增加而增加。对于 修改 也是如此,修改是通过显式触发和(默认)异步执行的合并来实现的。

这对 ClickHouse 中的其他新功能(例如 轻量级更新)具有积极影响,这些功能从 SharedMergeTree 获得了性能提升。类似地,引擎特定的 数据转换AggregatingMergeTree 的聚合,ReplacingMergeTree 的去重等)也受益于 SharedMergeTree 更好的合并吞吐量。这些转换在后台部分合并期间增量应用。为了确保在可能存在未合并部分的情况下查询结果的正确性,用户需要在查询时通过利用 FINAL 修饰符或使用带有聚合的显式 GROUP BY 子句来合并未合并的数据。在这两种情况下,这些查询的执行速度都受益于更好的合并吞吐量。因为这样查询就需要更少的查询时数据合并工作。

新的 ClickHouse Cloud 默认表引擎

SharedMergeTree 表引擎现在已普遍可用,并作为 ClickHouse Cloud 中新开发层服务的默认表引擎。如果您想使用 SharedMergeTree 表引擎创建新的生产层服务,请联系我们。

ClickHouse Cloud 支持的所有来自 MergeTree 系列的表引擎都自动基于 SharedMergeTree。例如,当您创建 ReplacingMergeTree 表时,ClickHouse Cloud 会在后台自动创建一个 SharedReplacingMergeTree 表。

CREATE TABLE T (id UInt64, v String)
ENGINE = ReplacingMergeTree
ORDER BY (id);

SELECT engine
FROM system.tables
WHERE name = 'T';

┌─engine───────────────────┐
│ SharedReplacingMergeTree │
└──────────────────────────┘

请注意,现有服务将随着时间的推移从 ReplicatedMergeTree 迁移到 SharedMergeTree 引擎。如果您想讨论此事,请联系 ClickHouse 支持团队。

另请注意,SharedMergeTree 的当前实现尚未支持 ReplicatedMergeTree 中存在的更高级功能,例如 异步插入的去重 和静态加密,但这些功能计划在未来版本中提供支持。

SharedMergeTree 实战

在本节中,我们将演示 SharedMergeTree 无缝的摄取性能扩展功能。我们将在另一篇博文中探讨 SELECT 查询的性能扩展。

摄取场景

在我们的示例中,我们 加载 了 2022 年前六个月来自 WikiStat 数据集(托管在 S3 存储桶中)的数据到 ClickHouse Cloud 中的一个 。为此,ClickHouse 需要从大约 4300 个压缩文件(一个文件代表特定一天的特定一小时)中加载约 260 亿条记录。我们结合使用 s3Cluster 表函数parallel_distributed_insert_select 设置来利用集群的所有计算节点。我们使用了四种配置,每种配置都有不同的节点数。每个节点有 30 个 CPU 内核和 120 GB 内存。

  • 3 个节点
  • 10 个节点
  • 20 个节点
  • 80 个节点

请注意,前两个集群配置都使用一个专用的 3 节点 ClickHouse Keeper 服务,每个节点有 3 个 CPU 内核和 2 GB 内存。对于 20 节点和 80 节点配置,我们将 Keeper 的大小增加到每个节点 6 个 CPU 内核和 6 GB 内存。我们在数据加载运行期间监控 Keeper,以确保 Keeper 资源不是瓶颈。

结果

我们并行使用的节点越多,数据加载的速度(希望)就越快,但同时,每个时间单位创建的部分也越多。为了获得 SELECT 查询 的最大性能,需要 最小化 处理的部分数量。为此,每个 ClickHouse MergeTree 系列表引擎都在 后台 持续 合并 数据部分到 更大的 部分。表的默认健康部分数量(每个表 分区)为 3000(以前为 300)。

因此,我们测量了每个数据加载运行所需的时间(从每个数据加载开始),以使引擎将加载过程中创建的部分合并到少于 3000 个部分的健康数量。为此,我们使用了一个 SQL 查询 在 ClickHouse 系统表 上进行内省(并可视化)部分数量随时间的变化 活动 部分。

请注意,我们还可选地包括了使用具有零拷贝复制的 ReplicatedMergeTree 引擎进行数据摄取运行的数字。如上所述,此引擎并非设计用于支持大量副本服务器,我们希望在此强调这一点。

此图表显示了将所有部分合并到少于 3000 个部分的健康数量所需的时间(以秒为单位):smt_11.png SharedMergeTree 支持无缝的集群扩展。我们可以看到,在我们的测试运行中,后台合并的吞吐量与节点数量呈线性关系。当我们将节点数量从 3 增加到 10(大约三倍)时,吞吐量也增加了三倍。当我们再次将节点数量增加到 20 个节点(两倍),然后增加到 80 个节点(四倍)时,吞吐量也分别大约增加了两倍和四倍。正如预期的那样,具有零拷贝复制的 ReplicatedMergeTree 的扩展性不如 SharedMergeTree(甚至随着副本节点数量的增加而降低摄取性能)。因为它的复制机制从未设计用于处理大量副本。

为了完整起见,此图表显示了合并到剩余部分少于 300 个部分所需的时间:smt_12.png

详细结果

3 个节点

下图显示了活动部分的数量、成功加载数据所需的时间(参见 摄取完成 标记)以及在具有 3 个副本节点的集群上进行基准测试运行期间将部分合并到少于 3000 个和 300 个活动部分所需的时间:smt_13.png 我们看到,这里两个表引擎的性能非常相似。

我们可以看到,两个引擎在数据加载期间执行的合并操作数量大致相同:smt_14.png

10 个节点

在我们的 10 个副本节点的集群上,我们可以看到一些差异:smt_15.png 摄取时间仅差 19 秒。但是,对于两个表引擎,摄取完成后活动部分的数量差异很大。对于具有零拷贝复制的 ReplicatedMergeTree,数量高出三倍多。使用 ReplicatedMergeTree 将部分合并到少于 3000 个和 300 个部分所需的时间是 SharedMergeTree 的两倍。这意味着我们可以更快地获得 SharedMergeTree 的查询性能。摄取完成后约 4000 个活动部分仍然可以查询。而约 15000 个则不可行。

两个引擎创建了相同数量的约 23000 个初始部分,大小约为 10 MB,包含约 100 万 行,用于从 WikiStat 数据子集中摄取约 260 亿行。

WITH
    'default' AS db_name,
    'wikistat' AS table_name,
    (
        SELECT uuid
        FROM system.tables
        WHERE (database = db_name) AND (name = table_name)
    ) AS table_id
SELECT
    formatReadableQuantity(countIf(event_type = 'NewPart')) AS parts,
    formatReadableQuantity(avgIf(rows, event_type = 'NewPart')) AS rows_avg,
    formatReadableSize(avgIf(size_in_bytes, event_type = 'NewPart')) AS size_in_bytes_avg,
    formatReadableQuantity(sumIf(rows, event_type = 'NewPart')) AS rows_total
FROM clusterAllReplicas(default, system.part_log)
WHERE table_uuid = table_id;

┌─parts──────────┬─rows_avg─────┬─size_in_bytes_avg─┬─rows_total────┐
│ 23.70 thousand │ 1.11 million │ 9.86 MiB          │ 26.23 billion │
└────────────────┴──────────────┴───────────────────┴───────────────┘

并且约 23000 个初始部分的创建在 10 个副本节点上均匀分布。

WITH
    'default' AS db_name,
    'wikistat' AS table_name,
    (
        SELECT uuid
        FROM system.tables
        WHERE (database = db_name) AND (name = table_name)
    ) AS table_id
SELECT
    DENSE_RANK() OVER (ORDER BY hostName() ASC) AS node_id,
    formatReadableQuantity(countIf(event_type = 'NewPart')) AS parts,
    formatReadableQuantity(sumIf(rows, event_type = 'NewPart')) AS rows_total
FROM clusterAllReplicas(default, system.part_log)
WHERE table_uuid = table_id
GROUP BY hostName()
    WITH TOTALS
ORDER BY node_id ASC;

┌─node_id─┬─parts─────────┬─rows_total───┐
│       12.44 thousand │ 2.69 billion │
│       22.49 thousand │ 2.75 billion │
│       32.34 thousand │ 2.59 billion │
│       42.41 thousand │ 2.66 billion │
│       52.30 thousand │ 2.55 billion │
│       62.31 thousand │ 2.55 billion │
│       72.42 thousand │ 2.68 billion │
│       82.28 thousand │ 2.52 billion │
│       92.30 thousand │ 2.54 billion │
│      102.42 thousand │ 2.68 billion │
└─────────┴───────────────┴──────────────┘

Totals:
┌─node_id─┬─parts──────────┬─rows_total────┐
│       123.71 thousand │ 26.23 billion │
└─────────┴────────────────┴───────────────┘

但是 SharedMergeTree 引擎在数据加载运行期间更有效地合并部分:smt_16.png

20 个节点

当 20 个节点并行插入数据时,具有零拷贝复制的 ReplicatedMergeTree 难以应对每个时间单位新创建的部分数量:smt_17.png 尽管 ReplicatedMergeTree 比 SharedMergeTree 提前完成了数据摄取过程,但活动部分的数量继续增加到约 10000 个部分。因为引擎仍然在 队列 中有插入操作需要在 20 个节点之间复制。请参阅 复制队列中的插入 行,我们使用此 查询 获取了这些值。处理此队列花费了将近 45 分钟。20 个节点在每个时间单位创建大量新创建的部分会导致复制日志上的过多争用以及锁和服务器间通信上的过高开销。缓解此问题的一种方法是手动调整插入查询的一些设置来限制新创建的部分数量。例如,您可以 减少 每个节点的并行插入线程数并 增加 写入每个新部分的行数。请注意,后者会增加主内存使用量。

请注意,Keeper 硬件在测试运行期间未过载。以下屏幕截图显示了两个表引擎的 Keeper 的 CPU 和内存使用情况:smt_19.png

80 个节点

在我们的 80 个节点的集群上,我们仅将数据加载到 SharedMergeTree 表中。我们已经在上面展示了具有零拷贝复制的 ReplicatedMergeTree 并非设计用于更大的副本节点数量。

smt_18.png

260 亿行的插入在 67 秒内完成,这相当于每秒 3.88 亿行。

介绍由 SharedMergeTree 加速的轻量级更新

SharedMergeTree 是一个强大的构建模块,我们将其视为云原生服务的基石。它使我们能够构建新的功能并改进现有的功能,而这些功能在之前是不可能实现或过于复杂的。许多功能都受益于在 SharedMergeTree 之上运行,并使 ClickHouse Cloud 更加高效、持久且易于使用。其中一项功能是“轻量级更新”——一种优化,它允许在使用更少资源的情况下立即提供 ALTER UPDATE 查询的结果。

传统分析型数据库中的更新是重量级操作

ALTER TABLE … UPDATE 查询在 ClickHouse 中被实现为 mutation。mutation 是一种重量级操作,会同步或异步地重写数据部分。

同步 mutation

smt_20.png 在我们上面的示例场景中,ClickHouse ① 接收一个插入查询,用于初始为空的表,② 将查询的数据写入存储上的新数据部分,并 ③ 确认插入操作。接下来,ClickHouse ④ 接收一个更新查询,并通过 ⑤ 变异 Part-1 来执行该查询。该部分加载到主内存中,进行修改,并将修改后的数据写入存储上的新 Part-2(删除 Part-1)。只有当该部分重写完成后,⑥ 更新查询的确认才会返回给更新查询的发送方。其他更新查询(也可以删除数据)以相同的方式执行。对于较大的部分,这是一个非常重量级的操作。

异步 mutation

通过 默认设置,更新查询以异步方式执行,以便将接收到的多个更新融合到单个 mutation 中,以减轻重写部分对性能的影响:smt_21.png 当 ClickHouse ① 接收一个更新查询时,该更新会被添加到 队列 中并异步执行,以及 ② 更新查询立即获得更新确认。

请注意,在更新 ⑤ 通过后台 mutation 物化之前,对表的 SELECT 查询看不到该更新。

另外,请注意,ClickHouse 可以将排队的更新融合到单个部分重写操作中。因此,最佳实践是批量更新并使用单个查询发送数百个更新。

轻量级更新

上述显式更新查询批量操作不再需要,从用户的角度来看,即使异步物化,单个更新查询的修改也会立即发生。

此图概述了 ClickHouse 中新的轻量级和即时更新 机制smt_22.png 当 ClickHouse ① 接收一个更新查询时,该更新会被添加到队列中并异步执行。② 此外,更新查询的更新表达式会被放入主内存中。更新表达式也会存储在 Keeper 中并分发到其他服务器。当 ③ ClickHouse 在更新通过部分重写物化之前接收 SELECT 查询时,ClickHouse 将照常执行 SELECT 查询 - 使用 主键索引 减少需要从部分流式传输到内存的行数,然后 ② 中的更新表达式会即时应用于流式传输的行。这就是我们称这种机制为 即时 mutation 的原因。当 ④ 接收另一个更新查询时,⑤ 该查询的更新(在本例中为删除)表达式再次保存在主内存中,⑥ 后续的 SELECT 查询将通过将两个(② 和 ⑤)更新表达式即时应用于流式传输到内存的行来执行。当 ⑦ 所有排队的更新通过下一个后台 mutation 物化时,即时更新表达式将从内存中删除。⑧ 新接收的更新和 ⑩ SELECT 查询按上述方式执行。

只需将 apply_mutations_on_fly 设置设置为 1 即可启用此新机制。

优势

用户无需等待 mutation 物化。ClickHouse 立即提供更新的结果,同时使用更少的资源。此外,这使得更新更容易被 ClickHouse 用户使用,他们可以发送更新而无需考虑如何批量处理它们。

与 SharedMergeTree 的协同作用

从用户的角度来看,轻量级更新的修改会立即发生,但在更新物化之前,用户会体验到 SELECT 查询性能略有下降,因为更新是在查询时在内存中对流式传输的行执行的。随着更新作为后台合并操作的一部分物化,对查询延迟的影响会消失。SharedMergeTree 表引擎具有 改进的后台合并和 mutation 的吞吐量和可扩展性,因此 mutation 完成得更快,轻量级更新后的 SELECT 查询也会更快恢复到完全速度。

下一步

我们上面描述的轻量级更新机制仅仅是第一步。我们已经在计划实施的其他阶段,以进一步提高轻量级更新的性能并消除当前的 限制

总结

在这篇博文中,我们探讨了新的 ClickHouse Cloud SharedMergeTree 表引擎的机制。我们解释了为什么需要引入一个新的表引擎,该引擎原生支持 ClickHouse Cloud 架构,其中垂直和水平可扩展的计算节点与存储在几乎无限共享对象存储中的数据分离。SharedMergeTree 使得在存储之上无缝且几乎无限地扩展计算层成为可能。插入和后台合并的吞吐量可以轻松扩展,这有利于 ClickHouse 中的其他功能,例如轻量级更新和引擎特定的数据转换。此外,SharedMergeTree 为插入提供了更强的持久性,并为 select 查询提供了更轻量级的强一致性。最后,它为新的云原生功能和改进打开了大门。我们通过基准测试证明了该引擎的效率,并描述了由 SharedMergeTree 推动的新功能,称为轻量级更新。

我们期待看到这个新的默认表引擎在行动中,以提升您的 ClickHouse Cloud 使用案例的性能。

立即开始使用 ClickHouse Cloud 并获得 300 美元的信用额度。在 30 天试用期结束时,继续使用按需付费计划,或 联系我们 了解有关我们基于容量的折扣的更多信息。请访问我们的 定价页面 获取详细信息。

分享此帖子

订阅我们的新闻通讯

随时了解功能发布、产品路线图、支持和云产品!
加载表单...
关注我们
Twitter imageSlack imageGitHub image
Telegram imageMeetup imageRss image