Snapshot Technique#

Keywords: Snapshot, Backup

Introduction#

之所以我会写这篇博文, 是因为在使用多种 AWS 数据库产品的时候, 发现它们都支持秒级 Point in time (当前时刻状态) 备份. 而且这些备份的底层本质都叫做 Snapshot. 我很早就对 Snapshot 有所了解, 并知道 Snapshot 是进行全盘备份的核心技术. 但一直没有把这项技术的相关信息都写下来讲清楚, 而是每次需要的时候去网上查. 我最近正好有时间, 并且需要用到 Snapshot 进行数据库备份, 所以就准备把相关信息都好好整理一下. 而之所以我将其放在了 RDS 目录下是因为 RDS 是 AWS 的核心关系数据库服务, 是 Snapshot 的典型案例.

在详细介绍之前, 我们需要先了解一些前置知识. 我们知道我们的内存底层是数据块, 一个数据块的默认大小是 4K, 一个数据块有两部分组成, header 和 body. header 部分保存的是元数据, 元数据就是描述数据的数据, 例如数据的位置, id 等. 举个例子, 我们的个人信息表就是我们的元数据, 我们本身这个人就是数据. 所以 header 中保存的是元数据, body 中保存的是真实数据, header 和 body 是一一指向关系.

知道了数据块之后我们在说文件, 文件在系统中也分为两部分, 一部分叫 inode, 一部分叫 block. inode: index node. 索引 node 信息, 这里边存的也是元数据, block 里边存的则是真实数据. 他们之间也是指向关系.

接下来我们可以深入了解了.

Backup vs Snapshot#

Backup 是备份, Snapshot 是快照, 人们对 Backup 一般更熟悉一些. 两者经常出现在同一语境下, 但是含义缺常常被人弄混淆, 这里我来做一个简单的区分.

  • Backup 备份 则是数据存储的某一个时刻的副本. 副本可能是逻辑意义上的, 例如备份可能并不是按照你的磁盘的状态一模一样的备份, 而是把数据导出成了 CSV 文件.

  • Snapshot 快照 是数据存储的某一时刻的状态记录. 按 存储网络行业协会 (SNIA) 对快照的定义是: 对指定数据集合的一个完全可用拷贝, 该拷贝包含源数据在拷贝时间点的静态影像. 简单来说这些数据的状态跟原始数据集是一模一样的, 插上即可使用.

Backup 原理#

顾名思义备份就是对数据做一个全量的拷贝, 把数据复制一份出来. 原数据丢失后可以直接从备份把数据拷贝回来. 这非常好理解. 可问题是如果数据量很大, 拷贝这个过程是很耗时的. 拷贝的过程中为了避免出错会对数据进行锁定, 此时数据处于只读不写的状态, 会影响使用. 所以这才引出了 Snapshot 快照技术.

Snapshot 核心原理#

现代的存储系统的原理都包含一个概念 block, 也就是最小的数据单位. 所谓最小数据单位的意思是你无法对其进行部分修改, 每次写都是完全覆盖.

在不同的系统上这个 block 有不同的术语, 但是工作原理都是类似的. 例如在机械硬盘上最小的存储单位是 4096 字节一个的 Disk sector (扇区), 在 Linux 文件系统中最小的单位是 4096 字节一个的 Page (页), 在数据库领域可能是一个 Block, 例如 Hadoop 上一个 Block = 64MB. 每个 block 都会有对应的 磁盘地址.

而当你需要全量备份一个系统的存储时, 无论这个系统是 App, 数据库, 甚至是你的整个操作系统, 无论你在文件系统的视角看来目录结构有多么复杂, 本质上是许许多多的 block.

快照的核心原理是 对数据存储在某一时刻的状态记录, 也就是这个快照中包含了哪些 block, 实际快照中储存的是这些 block 的地址. 并且快照一旦创建后这些 block 就会处于锁定状态. 如果要对这些 block 中的数据进行修改, 就要复制一份出来再在新的 block 上修改. 对全量数据创建快照的本质就是把一堆 block 的地址的数据记录下来作为备份, 并不会保存真实的数据, 只会保存地址, 所以这个速度是很快的, 基本上是秒级. 并且每次全量快照时很可能只需要对增量数据进行快照. 注意, 增量数据跟全量数据相比是很小的, 所以我们可以做到几乎是实时跟踪所有变化的 block. 这里有专门的算法来快速鉴别哪些 block 是增量, 就不展开说了.

由于快照本质是 block 地址的集合, 但快照本身不包含数据, 如果磁盘坏了, 数据还是会丢. 所以现代的备份技术通常是先短暂锁定系统, 创建快照, 恢复系统的使用. 然后再在后台根据快照的映射慢慢复制出来作为备份. 由于快照记录的 block 都是只读状态, 所以不用担心系统的使用过程中会对其进行修改. 等备份完成, snapshot 的作用就仅限于用于增量 snapshot 备份了.

AWS 中的 Snapshot 备份技术#

AWS 的数据库底层一般用的是块存储, AWS 会用自家的 EBS (Elastic Block Storage) 作为高可用存储. 这些 Block 本身是跨可用区 (AZ) 自动复制的, 能达到 99.999% 的 durability. 而一旦创建 Snapshot 之后这些数据会被打包自动上传到 S3 有 (99.999999999% 11 个 9) 的 durability. 只要你定期打上 Snapshot, 你的数据丢失的概率哪怕在 10 年的时间长度内也几乎是 0. 而由于底层的 EBS 已经是有冗余备份的了, 那么传统的先创建 Snapshot 索引, 然后慢慢复制的过程也会很快, 并且不存在慢慢复制的过程中整个磁盘挂掉的情况, 因为有冗余备份.

COW and ROW#

快照里面有两种关键技术, 根据应用场景你的系统中只能选一个:

  • COW: copy on write. 写时复制. 简单来说就是如果你要对某个块修改, 那么先创建一个要被修改的块的拷贝 (读一次, 写一次), 然后将新数据写到原始块中. 你还要更新 snapshot 中对于该快的索引, 将其指向我们创建的拷贝. 由于一读两写, 写入性能比较差. 该技术主要应用在存储 LUN, 裸设备等存储设备.

  • ROW: redirect on write. 写时重定向. 简单来说就是写的时候不动以前的 block, 而是在一个专用的区域进行, 这样只有一次写. 所以写入性能较好. row 技术主要应用在我们的 fusioncompute, vmware 中, 也就是偏应用一端. 因为应用端写入频率会较高.

COW 详解#

当我们拍了一个快照之后, 就会创建一个 COW 区域, 用于 track 之后快照中那些被修改的 block. 如果你要对某个块修改, 那么先在 COW 区域创建一个要被修改的块的拷贝 (读一次, 写一次), 然后将新数据写到原始块中. 并更新 snapshot 中对于该快的索引, 将其指向我们创建的拷贝.

  • delete: 直接删除 inode 即可, inode 对应的 block 由于是只读, 保持不变.

  • create: 跟没有用快照是一样的.

  • update: 在 COW 区域中创建一份被修改的 block 的拷贝, 然后用新数据覆盖原始的 block, 并更新 snapshot 中的索引.

  • create another snapshot: 创建一个新的 COW 区域用于 track 之后快照中那些被修改的 block.

  • recover from snapshot: 按照索引读数据即可, 会需要从 COW 区域中读数据.

  • 优点: 读 (从快照恢复时) 性能高, 因为读数据只会在一个源卷和一个 COW 区域读, 均为顺序读.

  • 缺点: 写性能差, 因为要 1 读 2 写.

ROW 详解#

当我们拍了一个快照之后, 所有的 block 就会变为只读. 而同时会创建一个差分卷, 之后所有的修改都在这里进行.

  • delete: 直接删除 inode 即可, inode 对应的 block 由于是只读, 保持不变.

  • create: 新的数据写入到差分卷中的 block 里.

  • update: 新的数据写入到差分卷中的 block 里, 并修改 inode 指向新 block, snapshot 不变.

  • create another snapshot: 把之前的差分卷也设为只读, 并创建一个新的差分卷用于容纳之后的修改.

  • recover from snapshot: snapshot 中的数据可能分布在原始卷和多个差分卷中, 用索引去读数据即可.

  • 优点: 写性能高, 因为只需要一写.

  • 缺点: 由于快照中的数据可能分散在多个差分卷中, 所以顺序读变成了随机读, 性能差.

Reference#