重磅-ClickHouse 通过SharedMergeTree和Lightweight Update提升性能

图片

简介

ClickHouse是用于实时应用和分析的最快和资源效率最高的数据库。MergeTree表引擎系列中的表是ClickHouse快速数据处理能力的核心组件。在本文中,我们将描述这个家族的新成员SharedMergeTree表引擎的动机和机制。

这个表引擎是ClickHouse Cloud中ReplicatedMergeTree表引擎的更高效的即插即用替代品,专为云原生数据处理而设计和优化。我们将深入了解这个新表引擎,解释其优势,并通过基准测试展示其效率。另外,我们还有一个消息要告诉您。我们正在引入Lightweight Upgrade ,这与SharedMergeTree具有协同效应。

MergeTree表引擎是ClickHouse的核心

MergeTree系列的表引擎是ClickHouse中的主要表引擎。它们负责存储由插入查询接收的数据,在后台进行数据合并,应用特定于引擎的数据转换等操作。大多数MergeTree家族中的表都支持自动数据复制,通过 ReplicatedMergeTree 基表引擎的复制机制实现。

在传统的Share nothing 的 ClickHouse集群中,通过ReplicatedMergeTree进行复制以实现数据可用性,通过分片实现集群扩展。ClickHouse Cloud采用了一种新方法,基于ClickHouse构建了云原生数据库服务,我们将在下面进行描述。

ClickHouse Cloud登场

ClickHouse Cloud于2022年10月进入公共测试阶段,采用了完全不同的优化云架构(我们解释了如何在一年内从零开始构建它)。通过在几乎无限的共享对象存储中存储数据,存储和计算被分离:所有水平和垂直可扩展的ClickHouse服务器都可以访问相同的物理数据,实际上是单个无限分片的多个副本:

图片

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

因为ClickHouse Cloud将所有数据存储在共享对象存储中,所以不需要在不同服务器上显式地创建数据的物理副本。像Amazon AWS Simple Storage Service、Google GCP Cloud Storage和Microsoft Azure Blob Storage等对象存储实现确保存储具有高可用性和容错性。

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

自动集群扩展

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

请注意,ClickHouse Cloud服务器实际上是单个无限分片的多个副本,但它们不像共享无关集群中的复制服务器。这些服务器不包含相同数据的本地副本,而是可以访问存储在共享对象存储中的相同数据。这将这些服务器分别转化为动态计算单元或计算节点,其大小和数量可以轻松适应工作负载,要么手动,要么完全自动。这个图示说明了这一点:

图片

① 通过扩展操作和 ② 缩小操作,我们可以更改节点的大小(CPU核心数和RAM数量)。而通过 ③ 扩展,我们可以增加参与并行数据处理的节点数量。无需进行任何物理重分片或数据再平衡,我们可以自由地添加或删除节点。

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

在ClickHouse Cloud中运行ReplicatedMergeTree的挑战

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

不需要显式的数据复制

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

下图概述了一个具有3个复制服务器的share nothing 的 ClickHouse集群,并显示了ReplicatedMergeTree表引擎的数据复制机制:

图片

当 ① 服务器-1 接收到插入查询时,② 服务器-1 在其本地磁盘上创建一个包含查询数据的新数据分段。通过复制日志,其他服务器(服务器-2、服务器-3)被告知服务器-1上存在一个新的分段。在 ④ 处,其他服务器独立地从服务器-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表的复制机制适应共享对象存储。

这种适应使用几乎相同的原始复制模型,只有一个副本的数据存储在对象存储中。因此,名为零拷贝复制。在服务器之间不会复制任何数据。相反,我们只复制元数据:

图片

当 ① 服务器-1 接收到插入查询时,② 服务器将插入的数据以部分的形式写入对象存储,并 ③ 将关于该部分的元数据(例如,部分存储在对象存储中的位置)写入其本地磁盘。通过复制日志,其他服务器被通知服务器-1上存在一个新的部分,尽管实际数据存储在对象存储中。⑤ 其他服务器独立地从服务器-1下载(“提取”)元数据到自己的本地文件系统。为确保在所有副本删除指向相同对象的元数据之前,不删除数据,使用分布式引用计数机制:在创建或接收元数据后,所有三台服务器还会在 ClickHouse Keeper 中更新自己的元数据部分信息集。

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

零拷贝复制并不能充分解决 ReplicatedMergeTree 在共享对象存储上面临的挑战:

  • 元数据仍与服务器耦合:元数据存储与计算没有分离。零拷贝复制仍需要每个服务器上的本地磁盘来存储有关部分的元数据。本地磁盘是附加的故障点,可靠性取决于副本数量,这与高可用性的计算开销相关。

  • 零拷贝复制的持久性取决于 3 个组件的保证:对象存储、Keeper 和本地存储。这些组件的数量增加了复杂性和开销,因为这个堆栈是在现有组件之上构建的,而不是作为云原生解决方案重新设计的。

  • 这仍然设计用于少量服务器:元数据使用相同的复制模型进行更新,该模型最初设计用于具有少量副本服务器的共享无关集群架构。大量服务器在复制日志上创建过多的争用,并在锁和服务器间通信上产生高开销。此外,在实现数据从一个副本克隆到另一个副本的复制和克隆代码中存在很多复杂性。并且由于元数据独立更改,无法对所有副本进行原子提交。

SharedMergeTree 用于云原生数据处理

我们决定(并从一开始就计划)为 ClickHouse Cloud 从头开始实现一个名为 SharedMergeTree 的新表引擎 - 专为在共享存储上工作而设计。SharedMergeTree 是云原生方式,可以使我们(1)使 MergeTree 代码更加简单易维护,(2)支持垂直和水平自动扩展服务器,(3)为我们的云用户提供未来的功能和改进,如更高的一致性保证,更好的耐用性,点对点还原,通过数据进行时间旅行等。

在这里,我们简要介绍了 SharedMergeTree 如何本地支持 ClickHouse Cloud 的自动集群扩展模型。提醒一下:ClickHouse Cloud 服务器是具有访问相同共享数据权限的计算单元,其大小和数量可以自动更改。对于此机制,SharedMergeTree 完全将数据和元数据的存储与服务器分开,并使用 Keeper 接口从所有服务器读取、写入和修改共享元数据。每个服务器都有一个带有子集元数据的本地缓存,并通过订阅机制自动通知数据更改。

这个图示描述了如何使用 SharedMergeTree 将新服务器添加到集群中:

图片

当服务器-3 添加到集群时,这个新服务器 ① 订阅 Keeper 中的元数据更改并将当前元数据部分提取到其本地缓存中。这不需要任何锁定机制;新服务器基本上只需说:“我在这里。请随时通知我所有数据更改”。新添加的服务器-3 可以几乎立即参与数据处理,因为它通过从 Keeper 中提取必要的共享元数据集,找出了哪些数据存在以及在对象存储中的位置。

以下图示显示了所有服务器如何了解新插入的数据:

图片

当 ① 服务器-1 接收到插入查询后,② 服务器将查询的数据以部分的形式写入对象存储。③ 服务器-1 还将关于该部分的信息存储在其本地缓存和 Keeper 中(例如,哪些文件属于该部分,以及与文件对应的块位于对象存储中的位置)。之后,④ ClickHouse 向查询的发送者确认插入。其他服务器(服务器-2、服务器-3)通过 Keeper 的订阅机制 ⑤ 自动被通知对象存储中存在新数据,并将元数据更新提取到其本地缓存中。

请注意,在步骤 ④ 之后,插入查询的数据是持久的。即使服务器-1 崩溃,或其他任何服务器,部分都存储在高可用的对象存储中,元数据存储在 Keeper 中(Keeper 具有至少 3 个 Keeper 服务器的高可用设置)。

从集群中移除服务器也是一个简单且快速的操作。为了优雅地移除服务器,服务器只需从 Keeper 中注销,以便在处理进行中的分布式查询时不会出现缺少服务器的警告信息。

ClickHouse Cloud 用户的好处

在 ClickHouse Cloud 中,SharedMergeTree 表引擎是 ReplicatedMergeTree 表引擎的更高效的即插即用替代品。为 ClickHouse Cloud 用户带来以下强大的好处。

无缝集群扩展

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

示例

假设 ClickHouse Cloud 用户当前正在使用三个节点,如下图所示:

图片

通过简单地(手动或自动)将每个节点的大小翻倍,或者(例如,当达到每个节点的最大大小时)将节点数量从三个翻倍到六个,用户可以实现计算能力的翻倍:

图片

这将使摄入吞吐量翻倍。对于 SELECT 查询,增加节点数会增加并发查询的执行级别,以及单个查询的并发执行。请注意,在 ClickHouse Cloud 中增加(或减少)节点的数量不需要进行物理数据重分片或重新平衡。我们可以自由地添加或删除节点,其效果与在共享无关集群中手动分片相同。

而在共享无关集群中更改服务器数量需要更多的工作和时间。如果一个集群当前由三个分片,每个分片由两个副本组成:

图片

然后翻倍分片数量需要对当前存储的数据进行重分片和重新平衡:

图片

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

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

更轻量级的强一致性选择查询

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

改进的后台合并和变更的吞吐量和可伸缩性

通过 SharedMergeTree,高数量的服务器不会导致性能下降。在 Keeper 有足够资源的情况下,后台合并的吞吐量随着服务器数量的增加而增加。对于变更(默认情况下为异步执行的显式触发合并)也是如此。

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

新的 ClickHouse Cloud 默认表引擎

SharedMergeTree 表引擎现在已经作为 ClickHouse Cloud 中新的 Development 层级服务的默认表引擎提供。如果您想要使用 SharedMergeTree 表引擎创建新的 Production 层级服务,请与我们联系。

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 个部分的健康数量所花费的时间。为此,我们使用 ClickHouse 系统表上的 SQL 查询来检查(并可视化)随时间变化的活动部分数量的变化。

请注意,我们还可选择包含使用零拷贝复制的 ReplicatedMergeTree 引擎进行的数据摄入运行的数字。如上所述,这个引擎并未设计用于支持高数量的副本服务器,我们希望在这里强调这一点。

以下图表显示了将所有部分合并为少于 3000 个健康部分所花费的时间(以秒为单位):

图片

SharedMergeTree 支持无缝的集群扩展。我们可以看到,在我们的测试中,后台合并的吞吐量与节点数量呈线性关系。当我们将节点数量从 3 倍增至 10 时,吞吐量也将增加三倍。当我们将节点数量再次增加 2 倍至 20,然后增加 4 倍至 80 时,吞吐量也分别增加了约两倍和四倍。正如预期的那样,使用零拷贝复制的 ReplicatedMergeTree 在随着副本节点数量的增加时无法很好地扩展(甚至在较大的集群大小下会减少摄入性能),而SharedMergeTree 则随着副本节点数量的增加而获得更好的扩展。因为它的复制机制从未设计用于处理大量副本。

为了完整起见,下图显示了将部分合并至少少于 300 个所花费的时间:

图片

详细结果

3 个节点

下图可视化了在具有 3 个副本节点的集群上进行基准测试期间活动部分的数量,成功加载数据所花费的秒数(见 Ingest finished 标记),以及在将部分合并至少 3000 和 300 个活动部分时所花费的秒数:smt_13.png我们可以看到两种引擎的性能在这里非常相似。

图片

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

图片

10 个节点

在具有 10 个副本节点的集群中,我们可以看到不同之处:

图片

摄入时间的差异只有 19 秒。然而,当摄入完成时,两种表引擎的活动部分数量是非常不同的。对于使用零拷贝复制的 ReplicatedMergeTree,该数量要多三倍以上。并且将部分合并至少 3000 和 300 个活动部分所花费的时间也要多两倍。这意味着我们可以更早地通过 SharedMergeTree 获得更快的查询性能。当摄入完成时,大约 4 千个活动部分的数量仍可以进行查询。而大约 15 千个则是不可行的。

对于从 WikiStat 数据子集摄入约 260 亿行的任务,这两种引擎都会创建大约 23 千个初始部分,每个部分大小约为 10 MB,包含大约 100 万行数据:

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 │
└────────────────┴──────────────┴───────────────────┴───────────────┘

大约 23 千个初始部分的创建均匀分布在这 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───┐
│       1 │ 2.44 thousand │ 2.69 billion │
│       2 │ 2.49 thousand │ 2.75 billion │
│       3 │ 2.34 thousand │ 2.59 billion │
│       4 │ 2.41 thousand │ 2.66 billion │
│       5 │ 2.30 thousand │ 2.55 billion │
│       6 │ 2.31 thousand │ 2.55 billion │
│       7 │ 2.42 thousand │ 2.68 billion │
│       8 │ 2.28 thousand │ 2.52 billion │
│       9 │ 2.30 thousand │ 2.54 billion │
│      10 │ 2.42 thousand │ 2.68 billion │
└─────────┴───────────────┴──────────────┘

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

但是 SharedMergeTree 引擎在数据加载过程中更有效地合并了这些部分:

图片

20 个节点

当 20 个节点并行插入数据时,使用零拷贝复制的 ReplicatedMergeTree 无法应对每单位时间内新创建的部分数量:

图片

尽管 ReplicatedMergeTree 在 SharedMergeTree 之前完成了数据插入过程,但活动部分的数量仍然持续增加到约 1 万个部分。因为引擎仍然在队列中有需要在这 20 个节点之间复制的插入操作。通过这个查询我们获取了在复制队列中的插入行数。处理该队列花费了将近 45 分钟。20 个节点每单位时间创建大量新部分会导致复制日志上的竞争过于激烈,并且锁和节点间通信的开销过高。减轻这种情况的方法是通过手动调整插入查询的一些设置来限制新创建部分的数量。例如,您可以减少每个节点的并行插入线程数,并增加写入每个新部分的行数。需要注意的是,后者会增加主内存使用。

需要注意的是,测试运行期间 Keeper 的硬件负载并未过载。以下截图显示了两种表引擎的 Keeper 的 CPU 和内存使用情况:

图片

80 个节点

在我们的 80 个节点集群中,我们只将数据加载到一个 SharedMergeTree 表中。我们已经在上面显示了使用零拷贝复制的 ReplicatedMergeTree 并不适用于更高的副本节点数。

图片

插入 260 亿行的过程在 67 秒内完成,平均速度为每秒 3.88 亿行。

介绍Lightweight Upgrade ,受 SharedMergeTree 提升

SharedMergeTree 是我们认为是云原生服务基础的一个强大构建块。它使我们能够在以前无法或过于复杂以实现的情况下构建新的功能和改进现有功能。许多功能从在 SharedMergeTree 顶部工作中受益,使 ClickHouse Cloud 更具性能、耐用性和易用性。其中一个特点就是“Lightweight Upgrade ” - 一种优化,可以在使用更少资源的情况下立即使 ALTER UPDATE 查询的结果可用。

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

ClickHouse 中的 ALTER TABLE … UPDATE 查询是通过变异实现的。变异是一个重型操作,可以同步或异步地重写部分。

同步变异

图片

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

异步变异

默认情况下,为了将几个收到的更新融合到单个变异中,更新查询是异步执行的,以减轻重写部分对性能的影响:

图片

当 ClickHouse ① 接收到更新查询时,更新会被添加到队列中并异步执行,② 更新查询立即获得更新的确认。

请注意,在变异被材料化为部分重写之前,表中的 SELECT 查询不会看到更新⑤。

此外,注意 ClickHouse 可以将排队的更新融合到单个部分重写操作中。因此,最好的做法是将更新批量处理,并通过单个查询发送数百个更新。

Lightweight Upgrade 

不再需要显式地对更新查询进行批处理,从用户的角度来看,即使在异步材料化时,来自单个更新查询的修改也会立即发生。

这个图表概述了 ClickHouse 中的新轻量级和即时更新机制:

图片

当 ClickHouse ① 接收到更新查询时,更新会被添加到队列并异步执行。② 此外,将更新查询的更新表达式放入主内存中。更新表达式也存储在 Keeper 中,并分发到其他服务器。当 ③ ClickHouse 在更新通过部分重写材料化之前接收到 SELECT 查询时,ClickHouse 将按照通常的方式执行 SELECT 查询 - 使用主索引来减少需要从部分流到内存的行的集合,然后在流式传输的行上实时应用来自 ② 的更新表达式。这就是我们称之为 on [the] fly 变异的机制。当 ④ 另一个更新查询被 ClickHouse 接收时,⑤ 查询的更新(在这种情况下是删除)表达式再次保留在主内存中,然后 ⑥ 后续的 SELECT 查询将被执行,通过将(② 和 ⑤)更新表达式应用于流式传输到内存的行。当 ⑦ 所有排队的更新都通过下一个后台变异材料化时,on-the-fly 更新表达式将从内存中删除。⑧ 新接收的更新和 ⑩ SELECT 查询将按照上述所述执行。

这个新的机制可以通过简单地将 apply_mutations_on_fly 设置为 1 来启用。

优势

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

与 SharedMergeTree 的协同作用

从用户的角度来看,Lightweight Upgrade 的修改会立即发生,但在材料化更新时,用户会稍微降低 SELECT 查询的性能,因为更新在流式传输的行上在查询时间执行。由于更新在后台的合并操作中被材料化,对查询延迟的影响会消失。SharedMergeTree 表引擎具有改进的后台合并和变异的吞吐量和可扩展性,因此变异完成得更快,Lightweight Upgrade 后的 SELECT 查询将更快地恢复到全速。

接下来的计划

我们上面描述的Lightweight Upgrade 的机制只是第一步。我们已经计划了进一步的实施阶段,以进一步改进Lightweight Upgrade 的性能并消除当前的限制。

总结

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

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

如果您是我们的海外客户,可以立即开始试用 ClickHouse Cloud。点这里注册:https://clickhouse.cloud/signUp?loc=blog-cta-footer&utm_source=twitter&utm_medium=social&utm_campaign=workshop&ajs_aid=a1b137f6-4a8e-43e7-8cee-1d8cf6c7c4ce

如果您是我们在中国大陆的客户,敬请期待我们在阿里云上的企业版本发布以及免费测试计划。

图片

联系我们

手机号:13910395701

邮箱:[email protected]

满足您所有的在线分析列式数据库管理需求

猜你喜欢

转载自blog.csdn.net/ClickHouseDB/article/details/132391768