解决方案

clickhouse的BACKUP-RESTORE命令介绍

seo靠我 2023-09-25 14:49:41

clickhouse的数据备份和恢复功能在大数据运维中是非常常用的功能,目前也有很多比较优秀的开源方案可供选择,比如clickhouse-backup, 以及clickhouse自带的clickhouSEO靠我se-copier。

本文介绍使用clickhouse自带的BACKUP和RESTORE命令进行备份和恢复。

我认为,一个比较好的备份恢复工具,至少需要满足以下几个功能:可以批量选择表可以增量备份可以比较SEO靠我方便地对数据进行恢复支持集群操作可以选择多个备份目的地,如Local、S3、HDFS等为了方便恢复,元数据也需要一起备份

基本语法

BACKUP|RESTORETABLE [db.]table_name SEO靠我[AS [db.]table_name_in_backup][PARTITION[S] partition_expr [,...]] |DICTIONARY [db.]dictionary_name SEO靠我[AS [db.]name_in_backup] |DATABASE database_name [AS database_name_in_backup][EXCEPT TABLES ...] |TESEO靠我MPORARY TABLE table_name [AS table_name_in_backup] |VIEW view_name [AS view_name_in_backup]ALL TEMPOSEO靠我RARY TABLES [EXCEPT ...] |ALL DATABASES [EXCEPT ...] } [,...][ON CLUSTER cluster_name]TO|FROM File(<SEO靠我path>/<filename>) | Disk(<disk_name>, <path>/) | S3(<S3 endpoint>/<path>, <Access key ID>, <Secret aSEO靠我ccess key>)[SETTINGS base_backup = File(<path>/<filename>) | Disk(...) | S3(<S3 endpoint>/<path>, <ASEO靠我ccess key ID>, <Secret access key>)]

从该语法中,我们大致能读到以下信息:

可以指定某一张表的某个partition进行备份可以指定某个数据库进行备份,且可以剔除该数据SEO靠我库中的某些表不进行备份可以备份临时表,视图可以全量备份所有表,所有数据库(支持黑名单排除)支持在集群上做备份支持备份到File、Disk和S3支持压缩备份支持增量备份

接下来我们以实战的方式,演示一下该SEO靠我命令的一些操作。

备份到文件

准备工作

配置准备

首先,我们需要在配置文件中加入以下内容:

<clickhouse><backups><allowed_path>/data01/backup</allowed_SEO靠我path></backups> </clickhouse>

代表允许备份,且备份目录为/data01/backup。

数据准备

我当前集群信息如下:

该集群有3个节点 ,其中ck93和ck94SEO靠我组成一个分片,ck96单独一个分片。

我们在集群上创建一张表,并导入一些数据:CREATE TABLE t1 ON CLUSTER abc (`id` Int64,`timestamp`SEO靠我 DateTime,`value` Float32 ) ENGINE = ReplicatedMergeTree PARTITION BY toYYYYSEO靠我MMDD(timestamp) ORDER BY (id, timestamp)

并向该表写入了1亿条数据:

数据分布如下:--shard1 ck94 :) select SEO靠我count() from t1;SELECT count() FROM t1Query id: a9b4610b-daa9-48b3-806b-3136657d2d9e┌──countSEO靠我()─┐ │ 50000000 │ └──────────┘1 row in set. Elapsed: 0.002 sec. --shard2 SEO靠我 ck96 :) select count() from t1;SELECT count() FROM t1Query id: f655d9ce-0176-4220-8e35-SEO靠我69d2261fc60d┌──count()─┐ │ 50000000 │ └──────────┘1 row in set. Elapsed: 0.003 sec.

SEO靠我

分别在shard1和shard2上执行backup命令如下:

--shard1 ck94 :) backup table default.t1 to File(20230528);BASEO靠我CKUP TABLE default.t1 TO File(20230528)Query id: c1214b1c-dc84-48f4-9d01-c9adebf21bf3┌─id───────────SEO靠我────────────────────────┬─status─────────┐ │ 1d30a0c9-4094-43b7-b2b6-9645e79d7fc1 │ BACKUP_CSEO靠我REATED │ └──────────────────────────────────────┴────────────────┘1 row in set. Elapsed: 0.0SEO靠我50 sec. --shard2 ck96 :) backup table default.t1 to File(20230528);BACKUP TABLE default.t1 TSEO靠我O File(20230528)Query id: 40df720f-8c2c-47c1-97d1-035186becac2┌─id──────────────────────────────────SEO靠我─┬─status─────────┐ │ 30c9a090-f6a5-4055-a157-5747b1d0772c │ BACKUP_CREATED │ └─────SEO靠我─────────────────────────────────┴────────────────┘1 row in set. Elapsed: 0.049 sec.

执行完成后,在ck94的/datSEO靠我a01/backup目录下,有如下数据生成:

[root@ck94 backup]# tree 20230528/ ├── data │ └── defaSEO靠我ult │ └── t1 │ ├── 20230416_0_20_4 │ │ ├── checksums.txt │ │ ├── colSEO靠我umns.txt │ │ ├── count.txt │ │ ├── default_compression_codec.txt │ │ ├── id.SEO靠我bin │ │ ├── id.mrk2 │ │ ├── minmax_timestamp.idx │ │ ├── partition.dat SEO靠我 │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── SEO靠我value.bin │ │ └── value.mrk2 │ ├── 20230416_21_51_6 │ │ ├── checksums.txt SEO靠我 │ │ ├── count.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── primary.idx SEO靠我 │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── value.bin │ │ └─SEO靠我─ value.mrk2 │ ├── 20230416_52_52_0 │ │ ├── checksums.txt │ │ ├── count.txt SEO靠我 │ │ ├── data.bin │ │ ├── data.mrk3 │ │ ├── minmax_timestamp.idx │ │ SEO靠我└── primary.idx │ ├── 20230416_53_53_0 │ │ ├── checksums.txt │ │ ├── count.tSEO靠我xt │ │ ├── data.bin │ │ ├── data.mrk3 │ │ └── primary.idx │ ├── 2023SEO靠我0423_0_5_1 │ │ ├── checksums.txt │ │ ├── count.txt │ │ ├── id.bin │ SEO靠我│ ├── id.mrk2 │ │ ├── minmax_timestamp.idx │ │ ├── partition.dat │ │ ├── priSEO靠我mary.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── value.bin SEO靠我 │ │ └── value.mrk2 │ ├── 20230423_12_12_0 │ │ ├── checksums.txt │ │ ├── SEO靠我count.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── primary.idx │ │ ├──SEO靠我 timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── value.bin │ │ └── value.mrk2 SEO靠我 │ ├── 20230423_13_13_0 │ │ ├── checksums.txt │ │ ├── id.bin │ │ ├── iSEO靠我d.mrk2 │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 SEO靠我 │ │ ├── value.bin │ │ └── value.mrk2 │ ├── 20230423_14_14_0 │ │ ├── checSEO靠我ksums.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── minmax_timestamp.idx SEO靠我 │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── vSEO靠我alue.bin │ │ └── value.mrk2 │ ├── 20230423_15_15_0 │ │ ├── checksums.txt SEO靠我 │ │ ├── count.txt │ │ ├── data.bin │ │ ├── data.mrk3 │ │ └── primary.idSEO靠我x │ ├── 20230423_16_16_0 │ │ ├── checksums.txt │ │ ├── count.txt │ │SEO靠我 ├── data.bin │ │ ├── data.mrk3 │ │ ├── minmax_timestamp.idx │ │ └── primarySEO靠我.idx │ ├── 20230423_6_11_1 │ │ ├── checksums.txt │ │ ├── id.bin │ │ SEO靠我├── id.mrk2 │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2SEO靠我 │ │ ├── value.bin │ │ └── value.mrk2 │ ├── 20230424_0_5_1 │ │ ├── cSEO靠我hecksums.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── minmax_timestamp.idx SEO靠我 │ │ ├── partition.dat │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├──SEO靠我 timestamp.mrk2 │ │ ├── value.bin │ │ └── value.mrk2 │ ├── 20230424_12_12_0 SEO靠我 │ │ ├── checksums.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── primarySEO靠我.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── value.bin SEO靠我│ │ └── value.mrk2 │ ├── 20230424_13_13_0 │ │ ├── checksums.txt │ │ ├── id.bSEO靠我in │ │ ├── id.mrk2 │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├──SEO靠我 timestamp.mrk2 │ │ ├── value.bin │ │ └── value.mrk2 │ ├── 20230424_14_14_0 SEO靠我 │ │ ├── checksums.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── primarySEO靠我.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── value.bin SEO靠我│ │ └── value.mrk2 │ ├── 20230424_15_15_0 │ │ ├── checksums.txt │ │ ├── id.bSEO靠我in │ │ ├── id.mrk2 │ │ ├── primary.idx │ │ ├── timestamp.bin │ │ ├──SEO靠我 timestamp.mrk2 │ │ ├── value.bin │ │ └── value.mrk2 │ ├── 20230424_16_16_0 SEO靠我 │ │ ├── checksums.txt │ │ ├── id.bin │ │ ├── id.mrk2 │ │ ├── primarySEO靠我.idx │ │ ├── timestamp.bin │ │ ├── timestamp.mrk2 │ │ ├── value.bin SEO靠我│ │ └── value.mrk2 │ └── 20230424_6_11_1 │ ├── checksums.txt │ ├── id.bin SEO靠我 │ ├── id.mrk2 │ ├── primary.idx │ ├── timestamp.bin │ ├── timestamp.mrSEO靠我k2 │ ├── value.bin │ └── value.mrk2 └── metadata└── default└── t1.sql

ck98目录同SEO靠我样也是如此,这里就不贴出来了。

从以上目录结构,可以看出,备份的文件分为data和metadata两个子目录、data用来存储数据,metadata用来存储表结构,并且内部根据数据库、表、partitiSEO靠我on做了层级区分。

看一下ck96上备份目录大小:

[root@ck94 backup]# du -sh 20230528/ 108M 20230528/ [root@cSEO靠我k96 backup]# du -sh 20230528/ 112M 20230528/

可见备份的数据也是压缩后的数据。(压缩前有1.49G)

接下来,我们试试直接在集群层面进行备份:cSEO靠我k94 :) backup table default.t1 on cluster abc to File(abc_20230528);BACKUP TABLE default.t1 ON CLUSTSEO靠我ER abc TO File(abc_20230528)Query id: e0763743-a6bc-430a-a28b-c493c7fd64780 rows in set. Elapsed: 0.SEO靠我188 sec. Received exception from server (version 23.3.1): Code: 655. DB::Exception: ReceivedSEO靠我 from localhost:19000. DB::Exception: Got error from 192%2E168%2E101%2E93:19000. DB::Exception: LockSEO靠我 file .lock suddenly disappeared while writing backup File(abc_20230528). (FAILED_TO_SYNC_BACKUP_OR_SEO靠我RESTORE)

它报了一个错,这个错误在github上有人提了issue:https://github.com/ClickHouse/ClickHouse/issues/41313,大意就是,在集群备SEO靠我份时,选取的备份的目录不能是各个节点自己的目录,需要一个远程共享目录(这一点对于to Disk是同样适用的)。这里我就没有尝试了,下次有暇可以测试一下使用NFS目录在集群层面进行备份。

由以上信息,可以SEO靠我得出以下结论:

备份速度非常快,1亿条数据基本不到1秒就能完成备份的同时,元数据也进行了备份,因此可以快速恢复备份是同比压缩备份的,不会出现数据膨胀无法进行集群级别备份(除非设置为远程共享目录)

恢复

恢复SEO靠我主要使用RESTORE命令。

当原始表有数据时,直接恢复是会报错的:ck94 :) RESTORE TABLE default.t1 FROM File(20230528);RESTORE TABLE SEO靠我default.t1 FROM File(20230528)Query id: e5d3eea4-5a58-4283-b9ce-d2fa9fa5fa1c0 rows in set. Elapsed: SEO靠我0.009 sec. Received exception from server (version 23.3.1): Code: 608. DB::Exception: ReceivSEO靠我ed from localhost:19000. DB::Exception: Cannot restore the table default.t1 because it already contaSEO靠我ins some data. You can set structure_only=true or allow_non_empty_tables=true to overcome that in thSEO靠我e way you want: While restoring data of table default.t1. (CANNOT_RESTORE_TABLE)

原因是原表已经有数据了。解决方案有3个:SEO靠我

方案1:备份到另一张表

具体操作如下:

ck94 :) RESTORE TABLE default.t1 AS default.t2 FROM File(20230528);RESTORE TABLE dSEO靠我efault.t1 AS default.t2 FROM File(20230528)Query id: e39dc666-3a00-4556-b8df-69e0e8d7fb630 rows in sSEO靠我et. Elapsed: 0.017 sec. Received exception from server (version 23.3.1): Code: 253. DB::ExceSEO靠我ption: Received from localhost:19000. DB::Exception: Replica /clickhouse/tables/abc/default/t1/1/repSEO靠我licas/192.168.101.94 already exists: While creating table default.t2. (REPLICA_ALREADY_EXISTS)

上述操作报了SEO靠我一个错,该报错的原因是我们在创建t2表时,zk路径已经存在了。

这是由于我们设置的zk默认路径如下:

<default_replica_name>{replica}</default_replica_naSEO靠我me> <default_replica_path>/clickhouse/tables/{cluster}/{database}/{table}/{shard}</default_rSEO靠我eplica_path>

而我们创建t1表时,指定的engine为ReplicatedMergeTree,没有带任何参数,默认使用的就是这个地址,因此我们创建t2表时,zoopath冲突,导致不能恢复成SEO靠我功。

我们尝试手动建表来恢复,仍然不能成功,原因是我们备份的元数据中,t1表的zoopath已经与t2表不一致了,无法恢复。ck94 :) create table t2 on cluster abc SEO靠我AS t1 ENGINE=ReplicatedMergeTree() PARTITION BY toYYYYMMDD(timestamp) ORDER BY (id, timestamp);CREATSEO靠我E TABLE t2 ON CLUSTER abc AS t1 ENGINE = ReplicatedMergeTree PARTITION BY toYYYYMMDDSEO靠我(timestamp) ORDER BY (id, timestamp)Query id: 61d6f3eb-5c58-4e88-a5aa-63712d538d8c┌─host────SEO靠我───────┬──port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐ │ x.x.x.x │ 19000SEO靠我 │ 0 │ │ 2 │ 0 │ │ x.x.x.x │ 19000 │ 0 │ │ 1 │ 0 │ │ x.x.x.x │ 19000 │ 0 │ │ 0 │ 0 │SEO靠我 └────────────────┴───────┴────────┴───────┴─────────────────────┴──────────────────┘3 rows SEO靠我in set. Elapsed: 0.115 sec. ck94 :) RESTORE TABLE default.t1 AS default.t2 FROM File(20230528);RESTOSEO靠我RE TABLE default.t1 AS default.t2 FROM File(20230528)Query id: fa2086ec-3a65-436e-b871-eb7cf960c11e0SEO靠我 rows in set. Elapsed: 0.007 sec. Received exception from server (version 23.3.1): Code: 608SEO靠我. DB::Exception: Received from localhost:19000. DB::Exception: The table has a different definition:SEO靠我 CREATE TABLE default.t2 (`id` Int64, `timestamp` DateTime, `value` Float32) ENGINE = ReplicatedMergSEO靠我eTree(/clickhouse/tables/{cluster}/default/t2/{shard}, {replica}) PARTITION BY toYYYYMMDD(timestamp)SEO靠我 ORDER BY (id, timestamp) SETTINGS index_granularity = 8192 comparing to its definition in the backuSEO靠我p: CREATE TABLE default.t2 (`id` Int64, `timestamp` DateTime, `value` Float32) ENGINE = ReplicatedMeSEO靠我rgeTree(/clickhouse/tables/{cluster}/default/t1/{shard}, {replica}) PARTITION BY toYYYYMMDD(timestamSEO靠我p) ORDER BY (id, timestamp) SETTINGS index_granularity = 8192: While checking table default.t2. (CANSEO靠我NOT_RESTORE_TABLE)

因此,这个方案无解,除非我们修改掉zoopath的规则。

方案2:设置允许非空表备份

ck94 :) RESTORE TABLE default.t1 FROM FilSEO靠我e(20230528) SETTINGS allow_non_empty_tables=true;RESTORE TABLE default.t1 FROM File(20230528) SETTINSEO靠我GS allow_non_empty_tables = 1Query id: 8bc125ef-5a48-4595-9b1a-977b62e98f4e┌─id─────────────────────SEO靠我──────────────┬─status───┐ │ 7f2662a8-8bab-4b4b-bdc3-24a3df5231f9 │ RESTORED │ └────SEO靠我──────────────────────────────────┴──────────┘1 row in set. Elapsed: 0.114 sec.

这种方案是可行的,但是,我们查询一下恢复后SEO靠我的数据:

ck94 :) select count() from t1;SELECT count() FROM t1Query id: 7510842d-7278-4bf7-9539-4SEO靠我c5c34b38043┌───count()─┐ │ 100000000 │ └───────────┘1 row in set. Elapsed: 0.002 secSEO靠我. ck94 :)

它在原有的数据基础上翻了个倍。等于说数据冗余了一倍,如果设置的不是去重的引擎,那么这些数据将一直存在,将会大大影响磁盘占用和查询效率。

因此,这种手段只适用于原表已经不存在,或者原表数SEO靠我据清空的情况下做恢复。

方案3: 设置仅恢复structure

ck94 :) RESTORE TABLE default.t1 FROM File(20230528) SETTINGS structurSEO靠我e_only=true;RESTORE TABLE default.t1 FROM File(20230528) SETTINGS structure_only = 1Query id: 77ce87SEO靠我fd-2eb3-47df-8a96-3423c248a54d┌─id───────────────────────────────────┬─status───┐ │ a0d63803SEO靠我-4b32-49be-983f-6d71d8c7451f │ RESTORED │ └──────────────────────────────────────┴──────────SEO靠我┘1 row in set. Elapsed: 0.004 sec. ck94 :) select count() from t1;SELECT count() FROM t1QuerSEO靠我y id: cd0404cd-1dd0-49f0-a828-de3e6fa4e8d9┌───count()─┐ │ 100000000 │ └───────────┘1SEO靠我 row in set. Elapsed: 0.003 sec.

该操作数据并没有翻倍,但是,该操作仅仅是同步了表schema,并没有同步数据,假如原表数据因为某种原因缺失了(比如只剩下了100w条),SEO靠我当我们执行restore语句,仍然是100w条数据,而没有把原始的5000w条数据都恢复回来。

ck94 :) select count() from t1;SELECT count() SEO靠我 FROM t1Query id: b8f19f4a-0339-44d7-8618-f3d741ebc679┌─count()─┐ │ 1000000 │ └─────SEO靠我────┘1 row in set. Elapsed: 0.003 sec. ck94 :) RESTORE TABLE default.t1 FROM File(20230528) SETTINGSSEO靠我 structure_only=true;RESTORE TABLE default.t1 FROM File(20230528) SETTINGS structure_only = 1Query iSEO靠我d: 94e70a0d-4910-4802-8af2-3606fc3a7a1e┌─id───────────────────────────────────┬─status───┐ │SEO靠我 d18869cc-880a-42d0-9405-863e6ac33216 │ RESTORED │ └──────────────────────────────────────┴─SEO靠我─────────┘1 row in set. Elapsed: 0.003 sec. ck94 :) select count() from t1;SELECT count() FRSEO靠我OM t1Query id: 32df3010-00c2-48a1-9f3d-cfc42c69ad12┌─count()─┐ │ 1000000 │ └────────SEO靠我─┘1 row in set. Elapsed: 0.002 sec.

如果表不存在,我们使用该命令进行恢复,也仅仅恢复的是表schema,而不是所有数据:

ck94 :) drop table t1 sSEO靠我ync;DROP TABLE t1 SYNCQuery id: f3a596b8-f18e-4606-908d-8da26d5efd37Ok.0 rows in set. Elapsed: 0.022SEO靠我 sec. ck94 :) RESTORE TABLE default.t1 FROM File(20230528) SETTINGS structure_only=true;RESTORE TABLSEO靠我E default.t1 FROM File(20230528) SETTINGS structure_only = 1Query id: 5c27980f-857c-4b87-93ab-70375eSEO靠我f51c78┌─id───────────────────────────────────┬─status───┐ │ 7191ab88-f59a-477b-924f-93ce34edSEO靠我3dea │ RESTORED │ └──────────────────────────────────────┴──────────┘1 row in set. Elapsed: SEO靠我0.606 sec. ck94 :) select count() from t1;SELECT count() FROM t1Query id: 2a11f16e-11ad-44cdSEO靠我-88f7-66e0008f8c16┌─count()─┐ │ 0 │ └─────────┘1 row in set. Elapsed: 0.002 sec.

当然,如SEO靠我果表都不存在了,我们使用最原始的命令就能恢复:

ck94 :) RESTORE TABLE default.t1 FROM File(20230528);RESTORE TABLE default.t1SEO靠我 FROM File(20230528)Query id: efb398bb-8368-4aa8-9efa-dacb316faca0┌─id──────────────────────────────SEO靠我─────┬─status───┐ │ 54a3b913-e91e-456b-84ce-d3aa10237ff6 │ RESTORED │ └─────────────SEO靠我─────────────────────────┴──────────┘1 row in set. Elapsed: 0.146 sec. ck94 :) select count() from tSEO靠我1;SELECT count() FROM t1Query id: a6fa6b7b-834c-4c41-bf9c-658695b19bc7┌──count()─┐ │SEO靠我 50000000 │ └──────────┘1 row in set. Elapsed: 0.003 sec.

增量备份

表的增量备份应该是数据备份最基本的需求,如果每次只支持全量备份SEO靠我,第一,效率上难以保证(虽然这种备份看起来速度很快,因为相当于直接拷贝了数据目录),二来磁盘空间限制,不太可能频繁全量备份。

我们在ck96上插入100条数据:ck96 :) insert into tSEO靠我1 select * from t1 limit 100;INSERT INTO t1 SELECT * FROM t1 LIMIT 100Query id: a451SEO靠我5af0-f32d-4af2-b4ec-fae2b08425e7Ok.0 rows in set. Elapsed: 0.010 sec. ck96 :) select count() from t1SEO靠我;SELECT count() FROM t1Query id: 63c7b438-3dcd-4ea7-bb98-c6ed90021eac┌──count()─┐ │ SEO靠我50000100 │ └──────────┘1 row in set. Elapsed: 0.004 sec.

我们的诉求是只备份这增量的100条数据,而不备份存量的5000w条数据。SEO靠我

我们可以通过设置base_backup来完成,即:在某次备份的基础上进行备份。

操作如下:ck96 :) backup table default.t1 to File(20230529) SETTINSEO靠我GS base_backup = File(20230528);BACKUP TABLE default.t1 TO File(20230529) SETTINGS base_backup = FilSEO靠我e(20230528)Query id: 41e871ae-63bf-420a-956d-254a18c7a4af┌─id───────────────────────────────────┬─stSEO靠我atus─────────┐ │ dd5fcaf4-303c-4246-a255-f75ac664af4d │ BACKUP_CREATED │ └──────────SEO靠我────────────────────────────┴────────────────┘1 row in set. Elapsed: 0.027 sec.

可以看到,在备份目录下,出现了202305SEO靠我29的目录:

[root@ck96 backup]# ll total 8 drwxr-x--- 4 clickhouse clickhouse 4096 May 29 SEO靠我07:06 20230528 drwxr-x--- 3 clickhouse clickhouse 4096 May 29 07:38 20230529 [root@cSEO靠我k96 backup]# du -sh * 112M 20230528 72K 20230529

并且该目录是没有元数据的,只有数据目录:

[root@ck96 backuSEO靠我p]# tree 20230529 20230529 └── data└── default└── t1└── 20230416_55_55_0├── checksumSEO靠我s.txt├── count.txt├── data.bin├── data.mrk3├── minmax_timestamp.idx└── primary.idx

查看count.txt,可见此次备份SEO靠我的数据条数为100条:

[root@ck96 backup]# cat 20230529/data/default/t1/20230416_55_55_0/count.txt 100[rSEO靠我oot@ck96 backup]#

备份到Disk

配置准备

我们在存储策略里增加一个backup的Disk:

<storage_configuration><disks><backup><path>/datSEO靠我a01/ssd1/</path><type>local</type></backup></disks></storage_configuration>

然后在backups中增加允许备份的磁盘:

<bacSEO靠我kups><allowed_disk>backup</allowed_disk><allowed_path>/data01/backup</allowed_path></backups>

数据备份

我们仍SEO靠我以t1表为例, 备份命令为:

ck94 :) BACKUP TABLE default.t1 TO Disk(backup, t1.zip);BACKUP TABLE default.t1 TO DisSEO靠我k(backup, t1.zip)Query id: 07df2cf7-de21-4a9a-bf0d-98e96d5e5a08Connecting to localhost:19000 as userSEO靠我 default. Connected to ClickHouse server version 23.3.1 revision 54462.┌─id─────────────────SEO靠我──────────────────┬─status─────────┐ │ e0765c7a-afe4-4475-843c-92769d7b8089 │ BACKUP_CREATEDSEO靠我 │ └──────────────────────────────────────┴────────────────┘1 row in set. Elapsed: 2.754 secSEO靠我.

可以看到,同样是5000w条数据,该操作就比直接备份到File要慢近100倍左右。它这个慢,主要在于,备份到File,是直接目录拷贝,而备份到Disk,则多了压缩的过程。

但是我们同时也看到,备份后的SEO靠我数据是以zip压缩的,压缩后数据大小为69M,比之原始数据的108M要小将近1倍。 [root@ck94 ssd1]# du -sh t1.zip 69M t1.zip

我们将该zip文件SEO靠我解压出来:

[root@ck94 ssd1]# du -sh * 108M data 4.0K metadata 69M t1.zip

可见原始数据仍然是1SEO靠我08M大小 。

至于集群层面备份,以及增量备份 、数据恢复,与File都是一样的,这里就不多做演示了 。

还有一些精细的玩法,如备份到磁盘时对压缩包进行加密,仅备份某一个partition,以及指定压缩算SEO靠我法和压缩等级等。

由于Disk本身的特性,我们甚至可以将Disk设置到HDFS以及S3上,因此可以使用该功能,将数据直接备份到这些对象存储之上。

当然备份到S3,还有另外的方案。BACKUP和RESTORSEO靠我E命令是直接支持了备份到S3的。接下来我们就来演示一下。

备份到S3

S3环境准备

我们使用docker启动一个minio来模拟S3环境。启动命令如下:

docker run --restart=alwaysSEO靠我 -itd --name minio \ --publish 49000:9000 \ --publish 49001:9001 \ --privileSEO靠我ged=true \ -e TZ="Asia/Shanghai" \ -e MINIO_ROOT_USER=minio \ -e MINIO_ROOT_SEO靠我PASSWORD=minio@123 \ -e MINIO_REGION_NAME=zh-west-1 \ bitnami/minio:latest

启动后,进入httpSEO靠我://localhost:49001/browser 即可打开前端页面。

我们在用户名和密码处填写启动docker时传入的环境变量,即: minio/minio@123, 登陆进去后界面如下所示:

数据备SEO靠我份到S3需要以下信息:

endpointAccess key IDSecret access key

endpoint我们已经有了,接下来我们创建一组access key。

如下图所示,依次点击AccessSEO靠我 Keys, Create Access key:

点击Create:

我们需要将这一组access key 和secret key记下来:

数据备份是要备份到bucket下面的,我们需要提前创建好buckSEO靠我et:

如图,我提前创建了一个名为backup的bucket:

至此,准备工作完成。

数据备份

我们依然备份t1表,命令如下:

ck94 :) BACKUP TABLE default.t1 TO S3(httSEO靠我p://192.168.101.94:49000/backup/t1, W0Plkfnyy8clAvPp, oNGbi5vUvJC9huolu0k8lkl05nsUxv6p);BACKUP TABLESEO靠我 default.t1 TO S3(http://192.168.101.94:49000/backup/t1, W0Plkfnyy8clAvPp, oNGbi5vUvJC9huolu0k8lkl05SEO靠我nsUxv6p)Query id: a02479c8-d54e-4bdc-b3f6-0bb638754dcc┌─id───────────────────────────────────┬─statuSEO靠我s─────────┐ │ 040d8cb6-7d2c-45c4-95ad-844aa4e87ce2 │ BACKUP_CREATED │ └─────────────SEO靠我─────────────────────────┴────────────────┘1 row in set. Elapsed: 0.515 sec.

这时,我们上浏览器已经能查看到数据了:

我们尝试在SEO靠我集群上备份数据:ck94 :) BACKUP TABLE default.t1 ON CLUSTER abc TO S3(http://192.168.101.94:49000/backup/t1_aSEO靠我ll, W0Plkfnyy8clAvPp, oNGbi5vUvJC9huolu0k8lkl05nsUxv6p);BACKUP TABLE default.t1 ON CLUSTER abc TO S3SEO靠我(http://192.168.101.94:49000/backup/t1_all, W0Plkfnyy8clAvPp, oNGbi5vUvJC9huolu0k8lkl05nsUxv6p)QuerySEO靠我 id: e88f933b-3f73-47e1-8502-25a44c8727cd┌─id───────────────────────────────────┬─status─────────┐ SEO靠我 │ a846e557-953e-4f9c-bbe2-d512baf0a030 │ BACKUP_CREATED │ └──────────────────────────SEO靠我────────────┴────────────────┘1 row in set. Elapsed: 6.653 sec.

从它的目录排布,它已经自动按照shard做了区分:

由于S3是远程共享目录,SEO靠我是可以执行的,不过整个执行过程比较耗时。1亿一条数据,用时接近6秒。不过从单节点备份只耗时0.5秒来看,该时间并不是随着数据量的增加而正比例递增的,而是主要耗时在与zookeeper的交互,获取元数据SEO靠我上。

增量备份与数据恢复与File类似,此处就不多做介绍了。

总结

BACKUP和RESTORE命令的备份恢复的优点是显而易见的:

无论是备份还是恢复,执行效率都非常高同压缩比备份,支持不同的备份目的地支持增SEO靠我量备份

但缺点也是有的,我认为主要是以下几点:

需要开放配置,操作性上不太友好集群备份到本地时,必须要选共享目录,如果每个分片单独备份,则无法进行数据汇总,存留于节点自身,与没有备份没什么区别,还不如多加SEO靠我副本数据恢复功能尚不太完备

推荐一个零声学院免费教程,个人觉得老师讲得不错,分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,

fastdfs,MongoDB,ZK,流媒体,CDSEO靠我N,P2P,K8S,Docker,

TCP/IP,协程,DPDK等技术内容,点击立即学习: C/C++Linux服务器开发/高级架构师
“SEO靠我”的新闻页面文章、图片、音频、视频等稿件均为自媒体人、第三方机构发布或转载。如稿件涉及版权等问题,请与 我们联系删除或处理,客服邮箱:html5sh@163.com,稿件内容仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同 其观点或证实其内容的真实性。

网站备案号:浙ICP备17034767号-2