备份与恢复
命令摘要
BACKUP|RESTORE
TABLE [db.]table_name [AS [db.]table_name_in_backup]
[PARTITION[S] partition_expr [,...]] |
DICTIONARY [db.]dictionary_name [AS [db.]name_in_backup] |
DATABASE database_name [AS database_name_in_backup]
[EXCEPT TABLES ...] |
TEMPORARY TABLE table_name [AS table_name_in_backup] |
VIEW view_name [AS view_name_in_backup]
ALL TEMPORARY TABLES [EXCEPT ...] |
ALL [EXCEPT ...] } [,...]
[ON CLUSTER 'cluster_name']
TO|FROM File('<path>/<filename>') | Disk('<disk_name>', '<path>/') | S3('<S3 endpoint>/<path>', '<Access key ID>', '<Secret access key>')
[SETTINGS base_backup = File('<path>/<filename>') | Disk(...) | S3('<S3 endpoint>/<path>', '<Access key ID>', '<Secret access key>')]
在 ClickHouse 23.4 版本之前,ALL
仅适用于 RESTORE
命令。
背景
虽然 复制 提供了硬件故障保护,但它不能防止人为错误:意外删除数据、删除错误的表或错误集群上的表,以及导致不正确数据处理或数据损坏的软件错误。在许多情况下,此类错误会影响所有副本。ClickHouse 具有内置的安全措施来防止某些类型的错误 — 例如,默认情况下,您不能直接删除包含超过 50 Gb 数据的类 MergeTree 引擎的表。但是,这些安全措施并未涵盖所有可能的情况,并且可以被规避。
为了有效缓解可能的人为错误,您应该提前仔细准备数据备份和恢复策略。
每家公司可用的资源和业务需求都不同,因此没有适用于所有情况的通用 ClickHouse 备份和恢复解决方案。对于 1 GB 数据有效的方法可能不适用于数十 PB 的数据。下面将讨论各种可能的方法及其优缺点。最好使用多种方法而不是仅仅一种方法,以弥补它们各自的缺点。
请记住,如果您备份了一些内容但从未尝试恢复,则很可能在您真正需要它时恢复将无法正常工作(或者至少会花费比业务可以容忍的时间更长的时间)。因此,无论您选择哪种备份方法,请确保自动化恢复过程,并在备用的 ClickHouse 集群上定期练习。
备份到本地磁盘
配置备份目标
在下面的示例中,您将看到像 Disk('backups', '1.zip')
这样指定的备份目标。要准备目标,请在 /etc/clickhouse-server/config.d/backup_disk.xml
中添加一个文件,指定备份目标。例如,此文件定义了一个名为 backups
的磁盘,然后将该磁盘添加到 backups > allowed_disk 列表中
<clickhouse>
<storage_configuration>
<disks>
<backups>
<type>local</type>
<path>/backups/</path>
</backups>
</disks>
</storage_configuration>
<backups>
<allowed_disk>backups</allowed_disk>
<allowed_path>/backups/</allowed_path>
</backups>
</clickhouse>
参数
备份可以是完整备份或增量备份,并且可以包括表(包括物化视图、投影和字典)和数据库。备份可以是同步的(默认)或异步的。它们可以被压缩。备份可以进行密码保护。
BACKUP 和 RESTORE 语句接受 DATABASE 和 TABLE 名称列表、目标(或源)、选项和设置
- 备份的目标,或恢复的源。这基于先前定义的磁盘。例如
Disk('backups', 'filename.zip')
- ASYNC:异步备份或恢复
- PARTITIONS:要恢复的分区列表
- SETTINGS
id
:备份或恢复操作的 ID,如果未手动指定,则使用随机生成的 UUID。如果已存在具有相同id
的正在运行的操作,则会抛出异常。compression_method
和 compression_level- 磁盘上文件的
password
base_backup
:此源先前备份的目标。例如,Disk('backups', '1.zip')
use_same_s3_credentials_for_base_backup
:基本备份到 S3 是否应从查询继承凭据。仅适用于S3
。use_same_password_for_base_backup
:基本备份归档文件是否应从查询继承密码。structure_only
:如果启用,则仅允许备份或恢复 CREATE 语句,而不包含表的数据storage_policy
:正在恢复的表的存储策略。请参阅 使用多个块设备进行数据存储。此设置仅适用于RESTORE
命令。指定的存储策略仅适用于引擎来自MergeTree
系列的表。s3_storage_class
:用于 S3 备份的存储类。例如,STANDARD
azure_attempt_to_create_container
:当使用 Azure Blob Storage 时,如果指定的容器不存在,是否尝试创建它。默认值:true。- 核心设置 也可在此处使用
使用示例
备份然后恢复表
BACKUP TABLE test.table TO Disk('backups', '1.zip')
相应的恢复
RESTORE TABLE test.table FROM Disk('backups', '1.zip')
如果表 test.table
包含数据,则上述 RESTORE 将失败,您必须删除该表才能测试 RESTORE,或使用设置 allow_non_empty_tables=true
RESTORE TABLE test.table FROM Disk('backups', '1.zip')
SETTINGS allow_non_empty_tables=true
可以恢复或备份具有新名称的表
RESTORE TABLE test.table AS test.table2 FROM Disk('backups', '1.zip')
BACKUP TABLE test.table3 AS test.table4 TO Disk('backups', '2.zip')
增量备份
可以通过指定 base_backup
来进行增量备份。
增量备份依赖于基本备份。必须保持基本备份可用,才能从增量备份恢复。
增量存储新数据。设置 base_backup
导致自上次备份以来到 Disk('backups', 'd.zip')
的数据被存储到 Disk('backups', 'incremental-a.zip')
BACKUP TABLE test.table TO Disk('backups', 'incremental-a.zip')
SETTINGS base_backup = Disk('backups', 'd.zip')
从增量备份和基本备份中将所有数据恢复到新表 test.table2
中
RESTORE TABLE test.table AS test.table2
FROM Disk('backups', 'incremental-a.zip');
为备份分配密码
写入磁盘的备份可以对文件应用密码
BACKUP TABLE test.table
TO Disk('backups', 'password-protected.zip')
SETTINGS password='qwerty'
恢复
RESTORE TABLE test.table
FROM Disk('backups', 'password-protected.zip')
SETTINGS password='qwerty'
压缩设置
如果您想指定压缩方法或级别
BACKUP TABLE test.table
TO Disk('backups', 'filename.zip')
SETTINGS compression_method='lzma', compression_level=3
恢复特定分区
如果需要恢复与表关联的特定分区,则可以指定这些分区。要从备份恢复分区 1 和 4
RESTORE TABLE test.table PARTITIONS '2', '3'
FROM Disk('backups', 'filename.zip')
备份为 tar 归档文件
备份也可以存储为 tar 归档文件。该功能与 zip 相同,只是不支持密码。
将备份写入为 tar
BACKUP TABLE test.table TO Disk('backups', '1.tar')
相应的恢复
RESTORE TABLE test.table FROM Disk('backups', '1.tar')
要更改压缩方法,应将正确的文件后缀附加到备份名称。例如,要使用 gzip 压缩 tar 归档文件
BACKUP TABLE test.table TO Disk('backups', '1.tar.gz')
支持的压缩文件后缀为 tar.gz
、.tgz
tar.bz2
、tar.lzma
、.tar.zst
、.tzst
和 .tar.xz
。
检查备份状态
备份命令返回一个 id
和 status
,该 id
可用于获取备份的状态。这对于检查长时间 ASYNC 备份的进度非常有用。下面的示例显示了尝试覆盖现有备份文件时发生的故障
BACKUP TABLE helloworld.my_first_table TO Disk('backups', '1.zip') ASYNC
┌─id───────────────────────────────────┬─status──────────┐
│ 7678b0b3-f519-4e6e-811f-5a0781a4eb52 │ CREATING_BACKUP │
└──────────────────────────────────────┴─────────────────┘
1 row in set. Elapsed: 0.001 sec.
SELECT
*
FROM system.backups
where id='7678b0b3-f519-4e6e-811f-5a0781a4eb52'
FORMAT Vertical
Row 1:
──────
id: 7678b0b3-f519-4e6e-811f-5a0781a4eb52
name: Disk('backups', '1.zip')
status: BACKUP_FAILED
num_files: 0
uncompressed_size: 0
compressed_size: 0
error: Code: 598. DB::Exception: Backup Disk('backups', '1.zip') already exists. (BACKUP_ALREADY_EXISTS) (version 22.8.2.11 (official build))
start_time: 2022-08-30 09:21:46
end_time: 2022-08-30 09:21:46
1 row in set. Elapsed: 0.002 sec.
除了 system.backups
表之外,所有备份和恢复操作也会在系统日志表 backup_log 中跟踪
SELECT *
FROM system.backup_log
WHERE id = '7678b0b3-f519-4e6e-811f-5a0781a4eb52'
ORDER BY event_time_microseconds ASC
FORMAT Vertical
Row 1:
──────
event_date: 2023-08-18
event_time_microseconds: 2023-08-18 11:13:43.097414
id: 7678b0b3-f519-4e6e-811f-5a0781a4eb52
name: Disk('backups', '1.zip')
status: CREATING_BACKUP
error:
start_time: 2023-08-18 11:13:43
end_time: 1970-01-01 03:00:00
num_files: 0
total_size: 0
num_entries: 0
uncompressed_size: 0
compressed_size: 0
files_read: 0
bytes_read: 0
Row 2:
──────
event_date: 2023-08-18
event_time_microseconds: 2023-08-18 11:13:43.174782
id: 7678b0b3-f519-4e6e-811f-5a0781a4eb52
name: Disk('backups', '1.zip')
status: BACKUP_FAILED
error: Code: 598. DB::Exception: Backup Disk('backups', '1.zip') already exists. (BACKUP_ALREADY_EXISTS) (version 23.8.1.1)
start_time: 2023-08-18 11:13:43
end_time: 2023-08-18 11:13:43
num_files: 0
total_size: 0
num_entries: 0
uncompressed_size: 0
compressed_size: 0
files_read: 0
bytes_read: 0
2 rows in set. Elapsed: 0.075 sec.
配置 BACKUP/RESTORE 以使用 S3 端点
要将备份写入 S3 存储桶,您需要三个信息
- S3 端点,例如
https://mars-doc-test.s3.amazonaws.com/backup-S3/
- 访问密钥 ID,例如
ABC123
- 秘密访问密钥,例如
Abc+123
创建 S3 存储桶在 将 S3 对象存储配置为 ClickHouse 磁盘 中介绍,只需在保存策略后返回此文档即可,无需配置 ClickHouse 以使用 S3 存储桶。
备份的目标将像这样指定
S3('<S3 endpoint>/<directory>', '<Access key ID>', '<Secret access key>')
CREATE TABLE data
(
`key` Int,
`value` String,
`array` Array(String)
)
ENGINE = MergeTree
ORDER BY tuple()
INSERT INTO data SELECT *
FROM generateRandom('key Int, value String, array Array(String)')
LIMIT 1000
创建基本(初始)备份
增量备份需要一个 基本 备份作为起点,此示例稍后将用作基本备份。S3 目标的第一个参数是 S3 端点,后跟存储桶中用于此备份的目录。在此示例中,目录名为 my_backup
。
BACKUP TABLE data TO S3('https://mars-doc-test.s3.amazonaws.com/backup-S3/my_backup', 'ABC123', 'Abc+123')
┌─id───────────────────────────────────┬─status─────────┐
│ de442b75-a66c-4a3c-a193-f76f278c70f3 │ BACKUP_CREATED │
└──────────────────────────────────────┴────────────────┘
添加更多数据
增量备份填充了基本备份与正在备份的表的当前内容之间的差异。在进行增量备份之前添加更多数据
INSERT INTO data SELECT *
FROM generateRandom('key Int, value String, array Array(String)')
LIMIT 100
进行增量备份
此备份命令与基本备份类似,但添加了 SETTINGS base_backup
和基本备份的位置。请注意,增量备份的目标与基本备份的目录不同,它是具有存储桶内不同目标目录的相同端点。基本备份在 my_backup
中,增量备份将写入 my_incremental
BACKUP TABLE data TO S3('https://mars-doc-test.s3.amazonaws.com/backup-S3/my_incremental', 'ABC123', 'Abc+123') SETTINGS base_backup = S3('https://mars-doc-test.s3.amazonaws.com/backup-S3/my_backup', 'ABC123', 'Abc+123')
┌─id───────────────────────────────────┬─status─────────┐
│ f6cd3900-850f-41c9-94f1-0c4df33ea528 │ BACKUP_CREATED │
└──────────────────────────────────────┴────────────────┘
从增量备份恢复
此命令将增量备份恢复到新表 data3
中。请注意,恢复增量备份时,也会包含基本备份。恢复时仅指定增量备份
RESTORE TABLE data AS data3 FROM S3('https://mars-doc-test.s3.amazonaws.com/backup-S3/my_incremental', 'ABC123', 'Abc+123')
┌─id───────────────────────────────────┬─status───┐
│ ff0c8c39-7dff-4324-a241-000796de11ca │ RESTORED │
└──────────────────────────────────────┴──────────┘
验证计数
原始表 data
中进行了两次插入,一次插入了 1,000 行,另一次插入了 100 行,总共 1,100 行。验证恢复的表是否具有 1,100 行
SELECT count()
FROM data3
┌─count()─┐
│ 1100 │
└─────────┘
验证内容
这将比较原始表 data
与恢复的表 data3
的内容
SELECT throwIf((
SELECT groupArray(tuple(*))
FROM data
) != (
SELECT groupArray(tuple(*))
FROM data3
), 'Data does not match after BACKUP/RESTORE')
使用 S3 磁盘进行 BACKUP/RESTORE
也可以通过在 ClickHouse 存储配置中配置 S3 磁盘来 BACKUP
/RESTORE
到 S3。通过在 /etc/clickhouse-server/config.d
中添加文件来配置磁盘,如下所示
<clickhouse>
<storage_configuration>
<disks>
<s3_plain>
<type>s3_plain</type>
<endpoint></endpoint>
<access_key_id></access_key_id>
<secret_access_key></secret_access_key>
</s3_plain>
</disks>
<policies>
<s3>
<volumes>
<main>
<disk>s3_plain</disk>
</main>
</volumes>
</s3>
</policies>
</storage_configuration>
<backups>
<allowed_disk>s3_plain</allowed_disk>
</backups>
</clickhouse>
然后像往常一样 BACKUP
/RESTORE
BACKUP TABLE data TO Disk('s3_plain', 'cloud_backup');
RESTORE TABLE data AS data_restored FROM Disk('s3_plain', 'cloud_backup');
但请记住
- 此磁盘不应用于
MergeTree
本身,仅用于BACKUP
/RESTORE
- 如果您的表由 S3 存储支持并且磁盘类型不同,则它不使用
CopyObject
调用将部件复制到目标存储桶,而是下载并上传它们,这非常低效。对于这种情况,首选使用BACKUP ... TO S3(<endpoint>)
语法。
使用命名集合
命名集合可用于 BACKUP/RESTORE
参数。有关示例,请参阅 此处。
替代方案
ClickHouse 将数据存储在磁盘上,并且有很多方法可以备份磁盘。以下是一些过去使用过的替代方案,可能很适合您的环境。
在其他地方复制源数据
通常,摄取到 ClickHouse 中的数据通过某种持久队列(例如 Apache Kafka)传递。在这种情况下,可以配置额外的订阅者集,这些订阅者将在数据写入 ClickHouse 的同时读取相同的数据流,并将其存储在某处的冷存储中。大多数公司已经有一些默认的推荐冷存储,这可以是对象存储或分布式文件系统,例如 HDFS。
文件系统快照
某些本地文件系统提供快照功能(例如,ZFS),但它们可能不是服务实时查询的最佳选择。一种可能的解决方案是使用此类文件系统创建额外的副本,并将它们从用于 SELECT
查询的 Distributed 表中排除。此类副本上的快照将无法被任何修改数据的查询访问。作为奖励,这些副本可能具有特殊的硬件配置,每个服务器连接更多磁盘,这将具有成本效益。
对于较小的数据量,简单的 INSERT INTO ... SELECT ...
到远程表也可能有效。
操作部件
ClickHouse 允许使用 ALTER TABLE ... FREEZE PARTITION ...
查询来创建表分区的本地副本。这是通过硬链接到 /var/lib/clickhouse/shadow/
文件夹实现的,因此它通常不会为旧数据消耗额外的磁盘空间。创建的文件副本不受 ClickHouse 服务器处理,因此您可以将它们留在那里:您将拥有一个不需要任何额外外部系统的简单备份,但它仍然容易受到硬件问题的影响。因此,最好将它们远程复制到另一个位置,然后删除本地副本。分布式文件系统和对象存储仍然是不错的选择,但容量足够大的普通连接文件服务器也可能有效(在这种情况下,传输将通过网络文件系统或可能通过 rsync 进行)。可以使用 ALTER TABLE ... ATTACH PARTITION ...
从备份恢复数据。
有关与分区操作相关的查询的更多信息,请参阅 ALTER 文档。
有一个第三方工具可用于自动化此方法:clickhouse-backup。
禁用并发备份/恢复的设置
要禁用并发备份/恢复,您可以分别使用这些设置。
<clickhouse>
<backups>
<allow_concurrent_backups>false</allow_concurrent_backups>
<allow_concurrent_restores>false</allow_concurrent_restores>
</backups>
</clickhouse>
两者的默认值均为 true,因此默认情况下允许并发备份/恢复。当集群上的这些设置为 false 时,一次只允许在集群上运行 1 个备份/恢复。
配置 BACKUP/RESTORE 以使用 AzureBlobStorage 端点
要将备份写入 AzureBlobStorage 容器,您需要以下信息
- AzureBlobStorage 端点连接字符串/URL,
- 容器,
- 路径,
- 帐户名称(如果指定了 URL)
- 帐户密钥(如果指定了 URL)
备份的目标将像这样指定
AzureBlobStorage('<connection string>/<url>', '<container>', '<path>', '<account name>', '<account key>')
BACKUP TABLE data TO AzureBlobStorage('DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite1:10000/devstoreaccount1/;',
'testcontainer', 'data_backup');
RESTORE TABLE data AS data_restored FROM AzureBlobStorage('DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://azurite1:10000/devstoreaccount1/;',
'testcontainer', 'data_backup');
备份系统表
系统表也可以包含在您的备份和恢复工作流程中,但它们的包含与否取决于您的具体用例。
备份日志表
存储历史数据的系统表,例如带有 _log 后缀的表(例如,query_log
、part_log
),可以像任何其他表一样进行备份和恢复。如果您的用例依赖于分析历史数据—例如,使用 query_log 跟踪查询性能或调试问题—建议将这些表包含在您的备份策略中。但是,如果不需要这些表的历史数据,则可以排除它们以节省备份存储空间。
备份访问管理表
与访问管理相关的系统表,例如 users、roles、row_policies、settings_profiles 和 quotas,在备份和恢复操作期间会受到特殊处理。当这些表包含在备份中时,它们的内容会导出到特殊的 accessXX.txt
文件,该文件封装了用于创建和配置访问实体的等效 SQL 语句。恢复时,恢复过程会解释这些文件并重新应用 SQL 命令以重新创建用户、角色和其他配置。
此功能确保可以备份和恢复 ClickHouse 集群的访问控制配置,作为集群整体设置的一部分。
注意:此功能仅适用于通过 SQL 命令管理的配置(称为 “SQL 驱动的访问控制和帐户管理”)。在 ClickHouse 服务器配置文件(例如 users.xml
)中定义的访问配置不包含在备份中,也无法通过此方法恢复。