共计 8042 个字符,预计需要花费 21 分钟才能阅读完成。
Databend 是一个应用 Rust 研发、开源、齐全面向云架构的旧式数仓,提供极速的弹性扩大能力,致力于打造按需、按量的 Data Cloud 产品体验。具备以下特点:
- 开源 Cloud Data Warehouse 明星我的项目
- Vectorized Execution 和 Pull&Push-Based Processor Model
- 真正的存储、计算拆散架构,高性能、低成本,按需按量应用
- 残缺的数据库反对,兼容 MySQL,Clickhouse 协定
- 欠缺的事务性,反对 Time Travel, Database Clone,Data Share 等性能
- 反对基于同一份数据的多租户读写、共享操作
当初应用 Databend 的用户越来越多后,大家面临一个问题,应用 Databend 如何备份呢?是不是须要如同 MySQL 一样每天做一个物理备份或是逻辑备份呢?答案是:可能还有更好的方法。这篇文章和大家聊一下 Databend 中数据的生命周期,而后再来看 Databend 如何做备份治理。
首先咱们来看一下 Databend 的架构
Databend 的写入操作是有事务性保障,基于事务隔离 RR 实现的,底层的数据存储是基于对象存储,本质上数据的长久化平安也是依赖于底层的对象存储,所以抉择云厂商的 S3, OSS, COS 也是不错的抉择,如果是自建的 minio, ceph 肯定要做集群保障。因为是基于对象存储写入,所以工作的写入都能够了解为是一个增量操作,这也让 Databend 省掉了日志治理,更多的须要把表和对应的 snapshot 关联起来就能够让数据恢复到任意的工夫点。接下来分 4 个方面看看 Databend 如何利用对象存储实现一个毋庸备份,但数据永远不失落的计划。
Databend 数据生命周期外围:Snapshot
在讲 Databend snapshot 之前,抛出来一个问题:
- 如果想拜访一个表 5 分钟前的数据怎么解决,
- 一个 delete from tb ; 没有 where 条件怎么复原?
如果在别的数据库这两个需要,根本都是劫难。但在 Databend 中,这些是十分轻松能够实现的。演示如下:
MySQL [default]> create table d_tb1(c1 int, c2 varchar);
Query OK, 0 rows affected (0.011 sec)
MySQL [default]> insert into d_tb1 values(1,'databend');
Query OK, 0 rows affected (0.018 sec)
MySQL [default]> insert into d_tb1 values(2,'MySQL');
Query OK, 0 rows affected (0.016 sec)
MySQL [default]> insert into d_tb1 values(3,'Hive');
Query OK, 0 rows affected (0.016 sec)
MySQL [default]> insert into d_tb1 values(4,'Hbase');
Query OK, 0 rows affected (0.016 sec)
MySQL [default]> select * from d_tb1;
+------+----------+
| c1 | c2 |
+------+----------+
| 1 | databend |
| 3 | Hive |
| 2 | MySQL |
| 4 | Hbase |
+------+----------+
4 rows in set (0.018 sec)
基于 snapshot 读取数据
总共写入了 4 行数据,咱们来看一下对应的 snapshot 相干的数据:
MySQL [default]> select snapshot_id,previous_snapshot_id, timestamp from fuse_snapshot('default','d_tb1');
+----------------------------------+----------------------------------+----------------------------+
| snapshot_id | previous_snapshot_id | timestamp |
+----------------------------------+----------------------------------+----------------------------+
| b031e57aa06443cc9d3ffadb3023dec6 | 34b8df220edc4d8cb9e3e76118788686 | 2022-08-30 01:19:06.367120 |
| 34b8df220edc4d8cb9e3e76118788686 | 4bb479751b7144d8aa2b53e5b281453f | 2022-08-30 01:18:53.202724 |
| 4bb479751b7144d8aa2b53e5b281453f | a2801ed9656d42c9812f2921214f0795 | 2022-08-30 01:18:35.597615 |
| a2801ed9656d42c9812f2921214f0795 | NULL | 2022-08-30 01:18:21.750208 |
+----------------------------------+----------------------------------+----------------------------+
4 rows in set (0.007 sec)
咱们看到 previouse_snapshot_id 为 NULL 是第一次写入的操作。对应的数据是:insert into d_tb1 values(1,’databend’); 如果想读取这个 snapshot 的数据办法:
MySQL [default]> select * from d_tb1 at(SNAPSHOT=>'a2801ed9656d42c9812f2921214f0795');
+------+----------+
| c1 | c2 |
+------+----------+
| 1 | databend |
+------+----------+
1 row in set (0.010 sec)
看到这里是不是感觉这里充斥了魔法了。同样也能够应用工夫来拜访历史的数据:
MySQL [default]> select * from d_tb1 at(timestamp=>'2022-08-30 01:18:21.750208'::timestamp);
+------+----------+
| c1 | c2 |
+------+----------+
| 1 | databend |
+------+----------+
1 row in set (0.010 sec)
这个工夫不必准确值,只用比当行对应的 timestamp 值大,小于下面一行的 timestamp 就能够获取对应的准确数据。
再来看一下 delete 没有 where 条件的操作:
MySQL [default]> delete from d_tb1;
Query OK, 0 rows affected (0.012 sec)
MySQL [default]> select * from d_tb1;
Empty set (0.010 sec)
MySQL [default]> select snapshot_id,previous_snapshot_id, timestamp from fuse_snapshot('default','d_tb1');
+----------------------------------+----------------------------------+----------------------------+
| snapshot_id | previous_snapshot_id | timestamp |
+----------------------------------+----------------------------------+----------------------------+
| ec52197b4c344f8d8a353eff8a812de7 | b031e57aa06443cc9d3ffadb3023dec6 | 2022-08-30 01:32:03.227960 |
| b031e57aa06443cc9d3ffadb3023dec6 | 34b8df220edc4d8cb9e3e76118788686 | 2022-08-30 01:19:06.367120 |
| 34b8df220edc4d8cb9e3e76118788686 | 4bb479751b7144d8aa2b53e5b281453f | 2022-08-30 01:18:53.202724 |
| 4bb479751b7144d8aa2b53e5b281453f | a2801ed9656d42c9812f2921214f0795 | 2022-08-30 01:18:35.597615 |
| a2801ed9656d42c9812f2921214f0795 | NULL | 2022-08-30 01:18:21.750208 |
+----------------------------------+----------------------------------+----------------------------+
5 rows in set (0.007 sec)
从下面的 snapshot 来看,减少一个新的 snapshot,所以咱们为了拜访 delete 的数据,就能够利用 at 语句拜访前一个 snapshot 就能够,如下:
MySQL [default]> select * from d_tb1 at(snapshot=>'ec52197b4c344f8d8a353eff8a812de7');
Empty set (0.010 sec)
MySQL [default]> select * from d_tb1 at(snapshot=>'b031e57aa06443cc9d3ffadb3023dec6');
+------+----------+
| c1 | c2 |
+------+----------+
| 3 | Hive |
| 4 | Hbase |
| 2 | MySQL |
| 1 | databend |
+------+----------+
4 rows in set (0.011 sec)
复原这个表,也能够思考:
create table d_tb1_new as select * from d_tb1 at(snapshot=>'b031e57aa06443cc9d3ffadb3023dec6');
再进行 rename 操作即可。对于 at 语法参考:https://databend.rs/doc/refer… 这些个性也是依赖于 Databend 应用底层时应用的对象存储,所有的写入都是增量写入。例如:对于 Delete 也只是操作的 meta 并没有真正的删除数据。这也是 Databend 的一个个性:Time travle。
Snapshot 终极大招
在下面的演示中,咱们看到利用 Databend 的 at 语句加上 snapshot 和 timestamp 实现对表任意工夫点和操作前的拜访。在最初复原数据时,咱们还须要借助于建一个新表,而后 Select 进去数据,而后对外拜访。那有没有更快的办法呢?Databend 永远不会让你悲观,当然更快的办法。接下来给你演示一下。首先咱们来一下 d_tb1 和 snapshot_location 对应关系:
MySQL [default]> select snapshot_id, snapshot_location from fuse_snapshot('default','d_tb1');
+----------------------------------+------------------------------------------------------+
| snapshot_id | snapshot_location |
+----------------------------------+------------------------------------------------------+
| ec52197b4c344f8d8a353eff8a812de7 | 1/15967/_ss/ec52197b4c344f8d8a353eff8a812de7_v1.json |
| b031e57aa06443cc9d3ffadb3023dec6 | 1/15967/_ss/b031e57aa06443cc9d3ffadb3023dec6_v1.json |
| 34b8df220edc4d8cb9e3e76118788686 | 1/15967/_ss/34b8df220edc4d8cb9e3e76118788686_v1.json |
| 4bb479751b7144d8aa2b53e5b281453f | 1/15967/_ss/4bb479751b7144d8aa2b53e5b281453f_v1.json |
| a2801ed9656d42c9812f2921214f0795 | 1/15967/_ss/a2801ed9656d42c9812f2921214f0795_v1.json |
+----------------------------------+------------------------------------------------------+
5 rows in set (0.007 sec)
MySQL [default]> show create table d_tb1;
+-------+------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------------------------------------------------+
| d_tb1 | CREATE TABLE `d_tb1` (
`c1` INT,
`c2` VARCHAR
) ENGINE=FUSE SNAPSHOT_LOCATION='1/15967/_ss/ec52197b4c344f8d8a353eff8a812de7_v1.json' |
+-------+------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.006 sec)
从下面的信息中能够看来,每个表前面通过 SNAPSHOT_LOCATION 的对应的版本对应起来。那么如果咱们创立一个基于后面 snapshot_id 对应的 snapshot_location 对应的地位,会怎么样呢?来操作一下:
MySQL [default]> CREATE TABLE `d_tb2` (
-> `c1` INT,
-> `c2` VARCHAR
-> ) ENGINE=FUSE SNAPSHOT_LOCATION='1/15967/_ss/b031e57aa06443cc9d3ffadb3023dec6_v1.json';
Query OK, 0 rows affected (0.013 sec)
MySQL [default]> select * from d_tb2;
+------+----------+
| c1 | c2 |
+------+----------+
| 3 | Hive |
| 1 | databend |
| 2 | MySQL |
| 4 | Hbase |
+------+----------+
4 rows in set (0.010 sec)
能够看到数据又回来了。这样也能够通过 rename 的形式间接对外,提供服务。是不是感觉到更神奇。基于 Snapshot 的援用创立表,也是咱们 Databend 数据 Share 的一个外围。Snapshot 形式的数据管理,也让 Databend 人造具备了 RR 事务隔离级的读写操作。
总结
在下面的文章中咱们演示了 snapshot 在 Databend 对于数据生命周期的访问控制。这里有一个外围就是云对象存储不能炸了。在这个前题下,如果备份 Databend 的数据能够有以下几种办法:
- 每天备份一下对应的表构造。
- 每天备份一下对应表的 fuse_snapshot 对应输入。
- 如果是自建的存储能够减少正本数来减少安全性。
对于 Databend
Databend 是一款开源、弹性、低成本,基于对象存储也能够做实时剖析的旧式数仓。期待您的关注,一起摸索云原生数仓解决方案,打造新一代开源 Data Cloud。
- Databend 文档:https://databend.rs/
- Twitter:https://twitter.com/Datafuse_…
- Slack:https://datafusecloud.slack.com/
- Wechat:Databend
- GitHub:https://github.com/datafusela…
文章首发于公众号:Databend