Replicated* 表引擎
在 ClickHouse Cloud 中,复制由您管理。请在不添加参数的情况下创建表。例如,在下面的文本中,您将替换
为
复制仅支持 MergeTree 系列中的表
- ReplicatedMergeTree
- ReplicatedSummingMergeTree
- ReplicatedReplacingMergeTree
- ReplicatedAggregatingMergeTree
- ReplicatedCollapsingMergeTree
- ReplicatedVersionedCollapsingMergeTree
- ReplicatedGraphiteMergeTree
复制在单个表级别进行,而不是整个服务器。服务器可以同时存储复制和非复制的表。
复制不依赖于分片。每个分片都有其自己的独立复制。
INSERT 和 ALTER 查询的压缩数据会被复制(有关更多信息,请参阅 ALTER 的文档)。
CREATE、DROP、ATTACH、DETACH 和 RENAME 查询在单个服务器上执行,并且不会被复制
CREATE TABLE查询在运行查询的服务器上创建新的可复制表。如果此表已存在于其他服务器上,它将添加一个新的副本。DROP TABLE查询删除运行查询的服务器上的副本。RENAME查询在其中一个副本上重命名表。换句话说,复制的表在不同的副本上可以具有不同的名称。
ClickHouse 使用 ClickHouse Keeper 存储副本元信息。可以使用 ZooKeeper 版本 3.4.5 或更高版本,但建议使用 ClickHouse Keeper。
要使用复制,请在 zookeeper 服务器配置部分设置参数。
不要忽视安全设置。ClickHouse 支持 ZooKeeper 安全子系统的 digest ACL 方案。
设置 ClickHouse Keeper 集群地址的示例
ClickHouse 还支持将副本元信息存储在辅助 ZooKeeper 集群中。通过提供 ZooKeeper 集群名称和路径作为引擎参数来执行此操作。换句话说,它支持将不同表的元数据存储在不同的 ZooKeeper 集群中。
设置辅助 ZooKeeper 集群地址的示例
要将表元数据存储在辅助 ZooKeeper 集群中而不是默认 ZooKeeper 集群中,我们可以使用 SQL 创建具有 ReplicatedMergeTree 引擎的表,如下所示
您可以指定任何现有的 ZooKeeper 集群,系统将在其上使用一个目录来存储其自身的数据(目录在创建可复制表时指定)。
如果未在配置文件中设置 ZooKeeper,则无法创建复制的表,并且任何现有的复制的表都将变为只读。
ZooKeeper 不用于 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 集群总共每秒有几百个 INSERTs。数据插入的吞吐量(每秒行数)与非复制数据一样高。
对于非常大的集群,您可以使用不同的 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 参数
| 参数 | 描述 |
|---|---|
zoo_path | ClickHouse Keeper 中表的路径。 |
replica_name | ClickHouse Keeper 中的副本名称。 |
other_parameters | 用于创建复制版本的引擎的参数,例如 ReplacingMergeTree 中的版本。 |
示例
弃用语法的示例
如示例所示,这些参数可以在花括号中包含替换。替换值来自配置文件的 macros 部分。
示例
ClickHouse Keeper 中的表路径对于每个复制的表都应是唯一的。不同分片上的表应具有不同的路径。在这种情况下,路径由以下部分组成
/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。但是,只会删除一个副本——位于你运行查询的服务器上的副本。
故障恢复
如果服务器启动时 ClickHouse Keeper 不可用,复制表将切换到只读模式。系统会定期尝试连接到 ClickHouse Keeper。
如果在 INSERT 期间 ClickHouse Keeper 不可用,或者与 ClickHouse Keeper 交互时发生错误,则会抛出异常。
连接到 ClickHouse Keeper 后,系统会检查本地文件系统中的数据集合是否与预期的集合匹配(ClickHouse Keeper 存储此信息)。如果有轻微的不一致,系统将通过与副本同步来解决它们。
如果系统检测到损坏的数据部分(文件大小不正确)或未识别的部分(写入文件系统但未记录在 ClickHouse Keeper 中),它会将它们移动到 detached 子目录(不会删除)。任何缺失的部分将从副本复制过来。
请注意,ClickHouse 不会执行任何破坏性操作,例如自动删除大量数据。
当服务器启动(或与 ClickHouse Keeper 建立新会话)时,它只会检查所有文件的大小和数量。如果文件大小匹配,但字节在中间的某个地方发生了更改,则不会立即检测到,而仅在尝试读取 SELECT 查询的数据时检测到。该查询会抛出一个关于压缩块的校验和或大小不匹配的异常。在这种情况下,数据部分将添加到验证队列中,并在必要时从副本复制过来。
如果本地数据集合与预期集合差异太大,则会触发安全机制。服务器会将此信息记录到日志中并拒绝启动。原因是这种情况可能表明配置错误,例如,如果分片上的副本被意外配置为不同分片上的副本。但是,此机制的阈值设置得相对较低,并且这种情况可能在正常的故障恢复期间发生。在这种情况下,数据将通过“按下按钮”进行半自动恢复。
要开始恢复,在 ClickHouse Keeper 中创建节点 /path_to_table/replica_name/flags/force_restore_data,内容任意,或者运行恢复所有复制表的命令
然后重启服务器。启动时,服务器会删除这些标志并开始恢复。
完全数据丢失后的恢复
如果一台服务器上的所有数据和元数据都消失了,请按照以下步骤进行恢复
- 在服务器上安装 ClickHouse。如果使用替换,请在包含分片标识符和副本的配置文件中正确定义替换。
- 如果你有需要在服务器上手动复制的非复制表,请从副本复制它们的数据(在目录
/var/lib/clickhouse/data/db_name/table_name/中)。 - 从副本复制位于
/var/lib/clickhouse/metadata/中的表定义。如果表定义中明确定义了分片或副本标识符,请更正它,使其与此副本相对应。(或者,启动服务器并执行/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
然后启动服务器(如果已在运行,则重启)。数据将从副本下载。
另一种恢复选项是从 ClickHouse Keeper 中删除丢失副本的信息(/path_to_table/replica_name),然后按照“创建复制表”中的描述重新创建副本。
在恢复过程中对网络带宽没有限制。请记住这一点,如果你一次恢复多个副本。
从 MergeTree 转换为 ReplicatedMergeTree
我们使用术语 MergeTree 指的是 MergeTree family 中的所有表引擎,与 ReplicatedMergeTree 相同。
如果你有一个手动复制的 MergeTree 表,你可以将其转换为复制表。你可能需要这样做,因为你已经在 MergeTree 表中收集了大量数据,现在你想启用复制。
ATTACH TABLE ... AS REPLICATED 语句允许将分离的 MergeTree 表作为 ReplicatedMergeTree 附加。
如果 convert_to_replicated 标志在表的目录(对于 Atomic 数据库,为 /store/xxx/xxxyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/)中设置,则 MergeTree 表可以在服务器重启时自动转换。创建空 convert_to_replicated 文件,并在下一次服务器重启时加载该表作为复制表。
可以使用此查询获取表的路径。如果表有多个数据路径,则需要使用第一个路径。
请注意,ReplicatedMergeTree 表将使用 default_replica_path 和 default_replica_name 设置的值创建。要在其他副本上创建转换后的表,需要在 ReplicatedMergeTree 引擎的第一个参数中显式指定其路径。可以使用以下查询获取其路径。
还有一种手动方法可以做到这一点。
如果各个副本上的数据不同,请先同步它,或删除除一个副本之外的所有副本上的数据。
重命名现有的 MergeTree 表,然后使用旧名称创建一个 ReplicatedMergeTree 表。将数据从旧表移动到新表数据目录内的 detached 子目录(/var/lib/clickhouse/data/db_name/table_name/)。然后,在其中一个副本上运行 ALTER TABLE ATTACH PARTITION 以将这些数据部分添加到工作集中。
从 ReplicatedMergeTree 转换为 MergeTree
使用 ATTACH TABLE ... AS NOT REPLICATED 语句将分离的 ReplicatedMergeTree 表作为 MergeTree 附加到单个服务器。
另一种方法涉及服务器重启。创建一个具有不同名称的 MergeTree 表。将所有数据从 ReplicatedMergeTree 表的数据目录移动到新表的目录。然后删除 ReplicatedMergeTree 表并重启服务器。
如果你想在不启动服务器的情况下删除 ReplicatedMergeTree 表
- 删除元数据目录(
/var/lib/clickhouse/metadata/)中的相应.sql文件。 - 删除 ClickHouse Keeper 中的相应路径(
/path_to_table/replica_name)。
之后,你可以启动服务器,创建 MergeTree 表,将数据移动到其目录,然后重启服务器。
当 ClickHouse Keeper 集群中的元数据丢失或损坏时恢复
如果 ClickHouse Keeper 中的数据丢失或损坏,你可以通过将其移动到非复制表(如上所述)来保存数据。
参见