跳转到主要内容
在 ClickHouse Cloud 中,复制由系统代为管理。创建表时请不要添加参数。例如,在下文中,您应将:
替换为:
复制仅支持 MergeTree 家族中的表
  • ReplicatedSummingMergeTree
  • ReplicatedCoalescingMergeTree
  • ReplicatedVersionedCollapsingMergeTree
  • ReplicatedCollapsingMergeTree
  • ReplicatedGraphiteMergeTree
  • ReplicatedMergeTree
  • ReplicatedReplacingMergeTree
  • ReplicatedAggregatingMergeTree
复制是在单表级别进行的,而不是在整个服务器级别。一个服务器可以同时存储复制表和非复制表。 复制不依赖分片。每个分片都有各自独立的复制机制。 INSERTALTER 查询中的压缩数据会被复制 (更多信息请参见 ALTER 文档) 。 CREATEDROPATTACHDETACHRENAME 查询只在单台服务器上执行,不会被复制:
  • CREATE TABLE 查询会在执行该查询的服务器上创建一个新的可复制表。如果该表已存在于其他服务器上,则会新增一个副本。
  • DROP TABLE 查询会删除执行该查询的服务器上的副本。
  • RENAME 查询会重命名某个副本上的表。换句话说,复制表在不同副本上可以有不同的名称。
ClickHouse 使用 ClickHouse Keeper 存储副本元信息。也可以使用 3.4.5 或更高版本的 ZooKeeper,但推荐使用 ClickHouse Keeper。 要使用复制,请在服务器配置的 zookeeper 部分中设置相关参数。
请勿忽视安全设置。ClickHouse 支持 ZooKeeper 安全子系统的 digest ACL scheme
ClickHouse Keeper 集群 地址配置示例:
ClickHouse 还支持将副本元信息存储在辅助 ZooKeeper 集群中。为此,请将 ZooKeeper 集群名称和 path 作为 engine 参数传入。 换句话说,它支持将不同表的元数据存储在不同的 ZooKeeper 集群中。 设置辅助 ZooKeeper 集群地址的示例:
要将表元数据存储在辅助 ZooKeeper 集群中,而不是默认的 ZooKeeper 集群中,我们可以使用 SQL 按如下方式创建使用 ReplicatedMergeTree engine 的表:
您可以指定任何现有的 ZooKeeper 集群,系统会使用其中的一个目录来存储自身数据 (该目录在创建可进行复制的表时指定) 。 如果未在配置文件中设置 ZooKeeper,您将无法创建复制表,且任何现有的复制表都将处于只读状态。 ZooKeeper 不参与 SELECT 查询,因为复制不会影响 SELECT 的性能,查询速度与非复制表相同。查询分布式复制表时,ClickHouse 的行为由设置 max_replica_delay_for_distributed_queriesfallback_to_stale_replicas_for_distributed_queries 控制。 对于每个 INSERT 查询,大约会通过多个事务向 ZooKeeper 添加十个条目。 (更准确地说,这是针对每个插入的数据块;一条 INSERT 查询包含一个块,或者每 max_insert_block_size = 1048576 行包含一个块。) 因此,与非复制表相比,INSERT 的延迟会略高一些。但如果遵循建议,以批次方式插入数据,并将频率控制在每秒不超过一次 INSERT,就不会造成任何问题。用于协调单个 ZooKeeper 集群的整个 ClickHouse 集群,总共可以达到每秒数百次 INSERT。数据插入的吞吐量 (即每秒插入的行数) 与非复制数据一样高。 对于非常大的集群,可以为不同分片使用不同的 ZooKeeper 集群。不过根据我们的经验,基于约 300 台服务器的生产集群来看,这并无必要。 复制是异步且多主的。INSERT 查询 (以及 ALTER) 可以发送到任何可用服务器。数据先写入执行该查询的服务器,然后再复制到其他服务器。由于是异步的,最近插入的数据会在一段延迟后才出现在其他副本上。如果部分副本不可用,则会在它们恢复可用后写入数据。如果某个副本可用,则延迟就是通过网络传输压缩数据块所需的时间。执行复制表后台任务的线程数可通过设置 background_schedule_pool_size 进行配置。 ReplicatedMergeTree 引擎为复制拉取使用单独的线程池。该线程池的大小受设置 background_fetches_pool_size 限制,可在重启服务器时调整。 默认情况下,一条 INSERT 查询只会等待一个副本确认数据写入。如果数据只成功写入一个副本,而承载该副本的服务器随后不复存在,那么已存储的数据将会丢失。若要启用多个副本的数据写入确认,请使用 insert_quorum 选项。 每个数据块都会以原子方式写入。INSERT 查询会被拆分为多个块,每个块最多 max_insert_block_size = 1048576 行。换句话说,如果 INSERT 查询少于 1048576 行,它就是原子执行的。 数据块会去重。对于同一个数据块的多次写入 (大小相同、包含相同行且顺序相同的数据块) ,该块只会写入一次。这样设计的原因是,在发生网络故障时,客户端应用可能不知道数据是否已写入数据库,因此可以直接重试 INSERT 查询。带有相同数据的 INSERT 发送到哪个副本并不重要。INSERT 是幂等的。去重参数由 merge_tree 服务器设置控制。 复制期间,只有待插入的源数据会通过网络传输。后续的数据转换 (合并) 会以相同方式在所有副本上协调并执行。这可以最大限度减少网络使用量,因此即使副本位于不同数据中心,复制也能良好运行。 (请注意,在不同数据中心保留数据副本正是复制的主要目标。) 同一份数据可以有任意数量的副本。根据我们的经验,在生产环境中,一个相对可靠且便于使用的方案是采用双副本复制,并让每台服务器使用 RAID-5 或 RAID-6 (某些情况下使用 RAID-10) 。 系统会监控各副本之间的数据同步状态,并能在故障后恢复。故障转移可以是自动的 (当数据差异较小时) ,也可以是半自动的 (当数据差异过大时,这可能表明存在配置错误) 。

创建复制表

在 ClickHouse Cloud 中,复制由系统自动完成。创建表时,请使用不带复制参数的 MergeTree。系统会在内部将 MergeTree 重写为 SharedMergeTree,以实现复制和数据分布。请避免使用 ReplicatedMergeTree 或指定复制参数,因为复制由平台统一管理。

Replicated*MergeTree 参数

示例:
如示例所示,这些参数中可以包含 {} 形式的替换内容。替换后的值取自配置文件的 macros 部分。 示例:
ClickHouse Keeper 中的表路径对于每个 Replicated 表都应唯一。不同分片上的表应使用不同的路径。 在这种情况下,路径由以下部分组成: /clickhouse/tables/ 是通用前缀。我们建议严格使用这个前缀。 {shard} 会扩展为分片标识符。 table_name 是 ClickHouse Keeper 中该表对应节点的名称。最好将它设为与表名相同。之所以显式定义它,是因为它与表名不同,在执行 RENAME 查询后不会发生变化。 提示:你也可以在 table_name 前加上数据库名。例如:db_name.table_name 可以使用两个内置替换 {database}{table},它们会分别扩展为数据库名和表名 (除非这些宏是在 macros 部分中定义的) 。因此,ZooKeeper 路径可以指定为 '/clickhouse/tables/{shard}/{database}/{table}'。 使用这些内置替换时,要特别注意表重命名。ClickHouse Keeper 中的路径无法更改,而当表被重命名时,这些宏会扩展为不同的路径,导致该表引用 ClickHouse Keeper 中不存在的路径,并进入只读模式。 副本名称用于标识同一张表的不同副本。你可以像示例中那样使用服务器名称。该名称只需在每个分片内唯一即可。 你可以显式定义这些参数,而不是使用替换。这样做在测试以及配置小型集群时可能更方便。不过,在这种情况下你不能使用分布式 DDL 查询 (ON CLUSTER)。 在处理大型集群时,我们建议使用替换,因为这样可以降低出错的概率。 你可以在服务器配置文件中为 Replicated 表引擎指定默认参数。例如:
在这种情况下,创建表时可省略参数:
相当于:
在每个副本上运行 CREATE TABLE 查询。该查询会创建一个新的复制表,或向现有复制表添加一个新副本。 如果在其他副本上的该表已经包含一些数据之后再添加新副本,那么运行该查询后,数据会从其他副本复制到新副本。换句话说,新副本会自动与其他副本同步。 要删除一个副本,请运行 DROP TABLE。但是,只会删除一个副本——也就是你运行该查询所在 server 上的那个副本。

故障后的恢复

如果服务器启动时 ClickHouse Keeper 不可用,复制表会切换为只读模式。系统会定期尝试连接 ClickHouse Keeper。 如果在 INSERT 过程中 ClickHouse Keeper 不可用,或者与 ClickHouse Keeper 交互时发生错误,则会抛出异常。 连接到 ClickHouse Keeper 后,系统会检查本地文件系统中的数据集是否与预期数据集一致 (这些信息存储在 ClickHouse Keeper 中) 。如果存在轻微不一致,系统会通过与各副本同步数据来解决。 如果系统检测到损坏的数据分区片段 (文件大小不正确) 或无法识别的 parts (已写入文件系统但未记录到 ClickHouse Keeper 中) ,会将其移动到 detached 子目录中 (不会删除) 。任何缺失的 parts 都会从各副本复制。 请注意,ClickHouse 不会执行任何破坏性操作,例如自动删除大量数据。 当服务器启动时 (或与 ClickHouse Keeper 建立新会话时) ,它只检查所有文件的数量和大小。如果文件大小一致,但中间某处的字节发生了变化,这种情况不会立即被检测到,而只会在尝试为 SELECT 查询读取数据时才会发现。该查询会抛出校验和不匹配或压缩块大小不匹配的异常。在这种情况下,数据分区片段会被加入校验队列,并在必要时从各副本复制。 如果本地数据集与预期数据集差异过大,就会触发安全机制。服务器会将此情况记入日志并拒绝启动。原因是,这种情况可能表明存在配置错误,例如某个分片上的副本被误配置成另一个分片上的副本。不过,这一机制的阈值设得相当低,因此这种情况也可能在正常的故障恢复过程中出现。在这种情况下,数据会以半自动方式恢复——即“按下一个按钮”。 要开始恢复,请在 ClickHouse Keeper 中创建节点 /path_to_table/replica_name/flags/force_restore_data 并写入任意内容,或者运行以下命令以恢复所有复制表:
然后重启服务器。启动时,服务器会清除这些标志并开始恢复。

完全数据丢失后的恢复

如果某台服务器上的所有数据和元数据都丢失了,请按以下步骤进行恢复:
  1. 在该服务器上安装 ClickHouse。如果使用了替换,请在包含分片标识符和副本信息的 config 文件中正确进行定义。
  2. 如果你有未复制的表,且这些表需要在各服务器之间手动复制,请从某个副本复制其数据 (位于目录 /var/lib/clickhouse/data/db_name/table_name/ 中) 。
  3. 从某个副本复制位于 /var/lib/clickhouse/metadata/ 中的表定义。如果表定义中显式指定了分片或副本标识符,请将其改为与当前副本对应。 (或者,启动 server,并执行所有本应写入 /var/lib/clickhouse/metadata/ 中 .sql 文件的 ATTACH TABLE 查询。)
  4. 要开始恢复,请创建 ClickHouse Keeper 节点 /path_to_table/replica_name/flags/force_restore_data 并写入任意内容,或者运行以下命令以恢复所有复制表:sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data
然后启动 server (如果已经在运行,则重启) 。数据将从其他副本下载。 另一种恢复方式是从 ClickHouse Keeper 中删除丢失副本的信息 (/path_to_table/replica_name) ,然后按照“创建复制表”中的说明重新创建该副本。 恢复期间不会限制网络带宽。如果你要同时恢复多个副本,请留意这一点。

从 MergeTree 转换为 ReplicatedMergeTree

这里的 MergeTree 一词指的是 MergeTree 家族中的所有表引擎,ReplicatedMergeTree 也是同理。 如果你有一个通过手动方式进行复制的 MergeTree 表,可以将其转换为复制表。如果你已经在 MergeTree 表中积累了大量数据,现在想启用复制,就可能需要这样做。 ATTACH TABLE … AS REPLICATED 语句允许将处于 detached 状态的 MergeTree 表 Attach 为 ReplicatedMergeTree 如果在表的数据目录中设置了 convert_to_replicated 标志,MergeTree 表可以在 server 重启时自动转换 (对于 Atomic database,目录为 /store/xxx/xxxyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/) 。 创建一个空的 convert_to_replicated 文件后,该表会在下一次 server 重启时作为 replicated 表加载。 此查询可用于获取表的数据路径。如果表有多个数据路径,则必须使用第一个。
请注意,ReplicatedMergeTree 表会使用 default_replica_pathdefault_replica_name 设置的值来创建。 要在其他副本上创建转换后的表,需要在 ReplicatedMergeTree 引擎 的第一个 argument 中显式指定其 path。可以使用以下查询获取该 path。
也可以手动完成此操作。 如果各个副本上的数据不一致,请先进行同步,或者删除除一个副本外所有副本上的这些数据。 先重命名现有的 MergeTree 表,然后使用原来的名称创建一个 ReplicatedMergeTree 表。 将旧表中的数据移动到新表数据目录 (/var/lib/clickhouse/data/db_name/table_name/) 下的 detached 子目录中。 然后在其中一个副本上运行 ALTER TABLE ATTACH PARTITION,将这些数据分区片段添加到活动数据集中。

从 ReplicatedMergeTree 转换为 MergeTree

使用 ATTACH TABLE … AS NOT REPLICATED 语句,可在单台服务器上将处于 detached 状态的 ReplicatedMergeTree 表附加为 MergeTree 表。 另一种方法需要重启服务器。先创建一个名称不同的 MergeTree 表。将 ReplicatedMergeTree 表数据目录中的所有数据移动到新表的数据目录中。然后删除 ReplicatedMergeTree 表并重启服务器。 如果你想在不启动服务器的情况下移除 ReplicatedMergeTree 表:
  • 删除元数据目录 (/var/lib/clickhouse/metadata/) 中对应的 .sql 文件。
  • 删除 ClickHouse Keeper 中对应的路径 (/path_to_table/replica_name) 。
完成后,你可以启动服务器,创建一个 MergeTree 表,将数据移动到其目录中,然后再次重启服务器。

ClickHouse Keeper 集群中的元数据丢失或损坏时的恢复

如果 ClickHouse Keeper 中的数据丢失或损坏,可以按上述说明将数据移动到非复制表中,以保留数据。 另请参阅
最后修改于 2026年6月12日