在 ClickHouse Cloud 中,复制由系统代为管理。创建表时请不要添加参数。例如,在下文中,您应将:替换为:
- ReplicatedSummingMergeTree
- ReplicatedCoalescingMergeTree
- ReplicatedVersionedCollapsingMergeTree
- ReplicatedCollapsingMergeTree
- ReplicatedGraphiteMergeTree
- ReplicatedMergeTree
- ReplicatedReplacingMergeTree
- ReplicatedAggregatingMergeTree
INSERT 和 ALTER 查询中的压缩数据会被复制 (更多信息请参见 ALTER 文档) 。
CREATE、DROP、ATTACH、DETACH 和 RENAME 查询只在单台服务器上执行,不会被复制:
CREATE TABLE查询会在执行该查询的服务器上创建一个新的可复制表。如果该表已存在于其他服务器上,则会新增一个副本。DROP TABLE查询会删除执行该查询的服务器上的副本。RENAME查询会重命名某个副本上的表。换句话说,复制表在不同副本上可以有不同的名称。
请勿忽视安全设置。ClickHouse 支持 ZooKeeper 安全子系统的
digest ACL scheme。SELECT 查询,因为复制不会影响 SELECT 的性能,查询速度与非复制表相同。查询分布式复制表时,ClickHouse 的行为由设置 max_replica_delay_for_distributed_queries 和 fallback_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/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 上的那个副本。
故障后的恢复
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 并写入任意内容,或者运行以下命令以恢复所有复制表:
完全数据丢失后的恢复
- 在该服务器上安装 ClickHouse。如果使用了替换,请在包含分片标识符和副本信息的 config 文件中正确进行定义。
- 如果你有未复制的表,且这些表需要在各服务器之间手动复制,请从某个副本复制其数据 (位于目录
/var/lib/clickhouse/data/db_name/table_name/中) 。 - 从某个副本复制位于
/var/lib/clickhouse/metadata/中的表定义。如果表定义中显式指定了分片或副本标识符,请将其改为与当前副本对应。 (或者,启动 server,并执行所有本应写入/var/lib/clickhouse/metadata/中 .sql 文件的ATTACH TABLE查询。) - 要开始恢复,请创建 ClickHouse Keeper 节点
/path_to_table/replica_name/flags/force_restore_data并写入任意内容,或者运行以下命令以恢复所有复制表:sudo -u clickhouse touch /var/lib/clickhouse/flags/force_restore_data
/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 表加载。
此查询可用于获取表的数据路径。如果表有多个数据路径,则必须使用第一个。
default_replica_path 和 default_replica_name 设置的值来创建。
要在其他副本上创建转换后的表,需要在 ReplicatedMergeTree 引擎 的第一个 argument 中显式指定其 path。可以使用以下查询获取该 path。
ReplicatedMergeTree 表。
将旧表中的数据移动到新表数据目录 (/var/lib/clickhouse/data/db_name/table_name/) 下的 detached 子目录中。
然后在其中一个副本上运行 ALTER TABLE ATTACH PARTITION,将这些数据分区片段添加到活动数据集中。
从 ReplicatedMergeTree 转换为 MergeTree
ReplicatedMergeTree 表附加为 MergeTree 表。
另一种方法需要重启服务器。先创建一个名称不同的 MergeTree 表。将 ReplicatedMergeTree 表数据目录中的所有数据移动到新表的数据目录中。然后删除 ReplicatedMergeTree 表并重启服务器。
如果你想在不启动服务器的情况下移除 ReplicatedMergeTree 表:
- 删除元数据目录 (
/var/lib/clickhouse/metadata/) 中对应的.sql文件。 - 删除 ClickHouse Keeper 中对应的路径 (
/path_to_table/replica_name) 。
MergeTree 表,将数据移动到其目录中,然后再次重启服务器。