面向Linux 非逻辑卷块设备的快照系统①
2022-06-27宋东平胡晓勤谢俊峰钱禹航
宋东平, 胡晓勤, 谢俊峰, 钱禹航
1(四川大学 网络空间安全学院, 成都 610207)
2(成都云祺科技有限公司, 成都 610041)
快照是关于指定数据集在某个时间点的完全可拷贝映像, 可以作为一种备份方法使系统中的数据得到有效保护[1-3]. 常用的快照实现方法有写时拷贝(copyon-write, COW)和写重定向 (redirect-on-write, ROW).两种快照方法均可实现在线快照并生成快照卷[4,5].COW[6]不改变源卷的数据分布, 在即将写入新数据时将源卷中指定区域的数据拷贝至快照卷, 因此COW不影响源卷的读效率, 而写效率会造成额外的两倍开销. ROW[7]将新写入的数据存储于快照卷, 随着写入次数增多, 源卷的数据分布发生变化, 读效率下降.
现有Linux 操作系统可对基于逻辑卷(logicalvolume)的块设备在不添加额外块设备的场景下创建快照[8,9], 但非逻辑卷块设备缺少成熟的快照技术支撑,定时备份缺少一致性支持. 为解决这一问题, 有学者[10,11]指出非逻辑卷块设备快照可在文件系统层或块设备层实现. 文件系统层快照对于源数据的获取以及快照数据的存取和解析有着较高的效率, 但需要针对特定的文件系统实现; 块设备层快照可分为在通用块层和物理块层实现, 二者均可屏蔽上层文件系统的差异, 较前者更具灵活性, 但物理块层快照不可屏蔽具体磁盘协议, 而通用块层快照无需考虑磁盘协议, 较物理块层快照更加灵活. 耿芳忠[12]提出了一种基于ROW 的Linux存储卷的快照方法, 但是该方法需要添加真实块设备作为快照卷存储数据. 刘志勇[13]利用添加缓冲卷的方法改进了COW 效率低下的问题, 但并未解决需要额外块设备的问题. 张权等[14]提出了一种Linux 标准分区的快照方法, 但方法仍然有上述需要添加额外块设备存储数据的问题. 开源软件dattobd[15]基于块层利用虚拟文件系统读写方法实现了非逻辑卷块设备的快照并将快照数据存储于快照源设备, 但是该软件只能创建一个快照, 并且创建快照后快照源设备的写效率低下, 对于实际生产的影响较大. 逻辑卷快照[16]的实现方案同样会在快照创建后对于原始块设备的写效率影响比较大.
本文基于COW, 结合通用块层的优势, 设计实现了一种面向Linux 非逻辑卷块设备的快照系统, 能够在不添加额外块设备的场景下为Linux 非逻辑卷块设备创建快照, 并且快照对于快照源设备的写速率影响较低.
1 系统设计
1.1 快照节点存储结构设计
为对不同的块设备创建多个快照, 本文设计了一种链式快照存储结构, 如图1 所示. 建立一个head 节点作为全局快照链的头节点, 仅用于快照链寻址. 建立device_head 链作为主块设备链(例如: sdx1 的主设备为sdx), 通过访问该链上的节点实现对具体快照头结点的查找. 建立snap_head 链作为快照链头结点链, 通过访问该链上的节点实现对快照源设备(具体到分区,例如: sdx1)的确定和快照链的确定. 建立snap 链作为快照链, 通过访问该链上的节点实现相同块设备的不同快照的确定. 该结构实现了对于不同块设备、同一块设备内部不同分区以及不同快照的记录. 快照节点信息将根据该结构进行保存.
图1 快照存储结构图
1.2 Bitmap 存储结构设计
为记录块设备的拷贝映射信息, 本文设计了一种广义Bitmap 结构进行存储, 如图2 所示. 一条Bitmap记录占18 字节, 从左起第1 字节作为标志位, 用于标记当前拷贝块(一次COW 拷贝多少数据, 自定义大小,不同于操作系统的数据块)有无拷贝记录, 第2-9 字节用于记录该拷贝块在快照源设备中的逻辑扇区号即拷贝源地址, 第10 字节为保留位, 第11-18 字节用于记录该拷贝块拷贝后的逻辑扇区号即拷贝目的地址. 通过该Bitmap 存储结构可以记录原始拷贝块的拷贝标记和拷贝块的拷贝前后地址映射.
图2 Bitmap 存储结构图
1.3 架构设计
快照系统设计为前后端模式, 分别对应应用层程序和内核层程序, 内核层程序主要位于通用块层. 前端程序主要处理用户命令以及文件操作, 后端程序主要执行快照底层逻辑, 系统模块组成及其关系如图3 所示. 快照处理模块由命令接口和快照管理两部分构成.命令接口属于前端程序, 用于接收用户的快照创建或删除命令, 然后依照该命令对快照文件进行相应的操作(快照文件由位图文件.bit 和数据文件.data 组成), 完成后将该命令发送到快照管理. 快照管理属于后端程序, 用于接收并解析命令接口发送的命令, 然后依照该命令进行快照设备及过滤器的创建或删除, 快照设备为内存块设备, 其数据存储于快照源设备上. 过滤器、COW 模块以及快照设备的读模块属于后端程序. 过滤器在创建后对快照源设备进行通用块层的I/O 请求(block input outpu, bio)截获, 并将截获到的写bio 转发到COW 模块, 将读bio 转发回快照源设备. COW 模块根据接收到的bio 进行数据拷贝操作, 然后将该bio 转发回快照源设备以完成COW. 快照设备的读模块将发送到快照设备的读bio 重定向到快照源设备以完成快照设备的读请求处理.
图3 快照系统架构图
2 系统实现
2.1 快照创建与删除
快照创建与删除工作主要由快照处理模块完成.模块包含命令接口和快照管理两部分. 命令接口用于对用户传入的命令进行解析, 快照管理用于对命令接口发送的命令进行通用块层的处理, 快照创建与删除流程如图4 所示.
创建流程如图4(a)所示. 命令接口首先查询设备是否存在, 不存在则结束创建, 存在则查询快照源设备的设备大小、设备挂载点以及设备的主次设备号等有关该设备的基本信息, 随后在设备挂载点下创建一组空洞文件作为快照文件并获取该组文件在块设备上的逻辑扇区分布(其中.bit 文件用于存储Bitmap 数据,.data 文件用于存储COW 过程中拷贝的数据), 目的是为了在通用块层进行数据拷贝时从通用块层存取Bitmap 记录以及定位数据的存储位置. 然后注册信号处理回调, 回调用于处理快照管理发送的创建信号以及删除信号. 随后发送创建命令到快照管理. 快照管理在接收到创建快照命令后依次创建一个快照设备和一个快照源设备bio 过滤器(一个快照源设备只对应一个过滤器, 如果存在则不创建), 随后将其添加到全局快照链中, 然后将块设备大小按照拷贝块划分, 将各个拷贝块的起始扇区号作为原始数据所在扇区号按照Bitmap 存储结构存储于.bit 文件所对应的逻辑扇区上,将数据拷贝后所在扇区号置0, 随后发送创建结束信号到命令接口触发该信号的处理回调, 创建快照过程结束.删除流程如图4(b)所示. 命令接口首先查询该快照是否存在, 不存在则结束删除, 存在则发送删除命令到快照管理. 快照管理接收到删除命令后将过滤器和快照设备删除(如果该快照源设备还存在快照, 则不删除过滤器), 随后将其从全局快照链中移除, 然后发送删除结束信号到命令接口触发该信号的处理回调, 删除快照过程结束.
图4 快照创建与删除流程图
2.2 快照写
快照写工作主要由过滤器和COW 模块完成, 其中过滤器用于快照源设备bio 的截获, 然后对其按读写类型进行分类, COW 模块主要进行数据拷贝操作. 流程如图5 所示.
过滤器的创建方法为首先获取快照源设备的设备对象, 根据设备对象获取通用块层入口函数指针, 使用自定义的函数对其进行替换, 至此过滤器创建成功. 在过滤流程中, 对于读bio, 处理方式为转发到快照源设备; 对于写bio, 处理方式为转发到COW 模块. 过滤流程如图5(a)所示.
COW 模块在接收到bio 后从Bitmap 中查询该bio 所指向的数据块所在的拷贝块有无拷贝记录. 对于有拷贝记录的拷贝块, 处理方法为转发该bio 到快照源设备; 对于没有拷贝记录的拷贝块, 处理方法为先进行逻辑上的拷贝再进行物理上的拷贝. 逻辑上的拷贝首先根据截获到的bio 和已拷贝的数据块大小计算出拷贝块的拷贝源地址和拷贝目的地址, 然后对Bitmap 进行更新. 物理上的拷贝首先对该拷贝块进行通用块层的数据读取, 然后将数据在通用块层写入拷贝目的地址中. 通用块层的数据读写方法即为构造bio 进行数据读写. 拷贝完成后再将该bio 转发回快照源设备. COW流程如图5(b) 所示. 其中, 拷贝源地址可通过式(1)计算得出:
图5 快照写流程图
2.3 快照读
快照读工作主要由快照设备中的读模块完成, 读流程如图6. 模块在接收到读bio 后从中获取该bio 指向的数据块在块设备中的偏移, 依据偏移查询Bitmap 以获得该数据块所在拷贝块的拷贝记录. 对于没有拷贝记录的拷贝块, 处理方法为重定向该bio 到快照源设备. 对于有拷贝记录的拷贝块, 处理方法为先从Bitmap 中获取该拷贝块的拷贝目的地址, 然后将bio 重定向到该拷贝目的地址, 因此读模块获取到的数据即快照之前的数据.
图6 快照读流程图
3 实验分析
由于COW 对快照源设备的读速率没有影响, 并且已经进行了COW 的数据块在覆盖写过程中不会产生性能损耗, 因此本文实验仅依据快照源设备的新增写速率损耗便可衡量系统性能, 损耗量与系统性能成反比. 其中新增写为每创建一个快照就向快照源设备写一个指定大小的全新文件. 本文设计了3 个实验, 分别为快照数据的正确性验证实验、拷贝块大小对系统性能的影响测试实验以及快照个数对比实验. 所有实验均在虚拟化环境中进行, 采用直接I/O 的方式将数据写入块设备上的文件, 单次I/O 块文件大小为4 KB,具体实验环境如表1 所示. 其中块设备1 名为/dev/sdb1,为非逻辑卷块设备, 挂载点为/sdb1. 块设备2 名为/dev/sdc1, 为逻辑卷块设备, 逻辑卷为/dev/vg_1/lv_test.
表1 实验环境配置表
3.1 正确性
本实验在对块设备/dev/sdb1 创建快照前在其挂载点/sdb1 目录下创建一个1 GB 的文件test_1G, 计算该文件的MD5. 在对/dev/sdb1 创建快照后修改test_1G文件, 随后将生成的快照设备/dev/sdb1-snapshot1 挂载于/snap 目录下, 计算/snap 目录下的 test_1G 文件的MD5. MD5 记录如表2 所示.
表2 文件MD5 表
表2 表明, 对/dev/sdb1 创建快照后快照设备/dev/sdb1-snapshot1 中的test_1G 文件的MD5 值与快照前快照源设备中的test_1G 文件的MD5 值一致, 这说明快照设备中的文件内容与快照源设备快照前的文件内容一致, 进而证明了本系统创建的非逻辑卷块设备快照能够确保数据的正确性.
3.2 拷贝块大小对系统性能的影响
本实验选用了1 MB、2 MB、4 MB 和8 MB 大小的拷贝块进行快照源设备的写速率比较进而衡量系统性能, 针对每一种拷贝块大小, 均在拷贝后向快照源设备写入一个1 GB 的全新文件, 测试其平均写速率. 平均写速率与拷贝块大小的关系如图7 所示.
图7 表明当拷贝块为4 MB 大小时快照源设备写速率最高, 同等条件下其速率损耗最小, 而随着拷贝块增大或减小都会使速率损耗增大. 这是因为拷贝块粒度过细会导致COW 操作过于频繁, 从而引起真实I/O 操作过多耗时, 拷贝块粒度过粗会导致单次COW 过程中读写数据量过大而引起耗时, 二者都会成为影响快照源设备写速率的因素. 因此本系统4 MB 拷贝块大小下对于快照源设备新增写速率影响最小, 性能表现最佳.
图7 拷贝块大小对写速率的影响
3.3 快照个数对比
本实验分为单快照子实验和多快照子实验. 在单快照子实验中将本系统与其他同类系统均创建1 个快照进行新增写速率损耗对比. 在多快照实验中利用本系统创建多个快照, 然后进行速率损耗自我对比. 实验均采用4 MB 作为本系统的拷贝块大小.
3.3.1 单快照
本实验对块设备/dev/sdb1 分别利用本系统和开源软件dattobd 创建单个快照, 然后向其中新增写1 GB文件, 对逻辑卷/dev/vg_1/lv_test 利用逻辑卷的快照方法创建单个快照, 然后同样向其中新增写1 GB 文件,记录三者所创建快照存在的情况下快照源设备的新增写速率并计算出速率损耗, 实验结果如表3 所示.
表3 不同系统下快照对新增写速率的影响
表3 表明, 在只创建一个快照的情况下, 本系统对于快照源设备的新增写速率损耗低于7%, 开源软件dattobd 的速率损耗高于35%, 逻辑卷的速率损耗高于55%. 这是因为本系统在通用块层进行COW, 而dattobd和逻辑卷分别在虚拟文件系统层和逻辑卷管理层进行COW, 二者在Linux 内核中的层次均高于通用块层, 因此通用块层I/O 落盘速率远高于上层, 因此本系统对于快照源设备的新增写速率影响较已经存在的两种系统有明显下降, 本系统性能优于已有的两种快照方案.
3.3.2 多快照
本实验对块设备/dev/sdb1 创建9 个快照并进行新增写, 新增写文件大小为1 GB, 记录不同快照个数下快照源设备的新增写速率及其损耗百分比, 实验结果如表4 所示.
表4 新增写速率及损耗
4 结束语
本文设计实现了一种面向Linux 非逻辑卷块设备的快照系统. 系统依赖于COW 技术, 结合通用块层的优势, 实现了在不添加额外块设备的场景下对Linux非逻辑卷块设备创建快照, 并且较已有的快照方案有明显的新增写速率损耗降低, 满足了Linux 非逻辑卷块设备定时备份过程中对于快照的需求. 系统性能在拷贝块为4 MB 大小, 快照个数为1 时最优, 快照个数少于5 时表现良好. 但本系统存在当快照个数过多时性能变差, 对于快照源设备的新增写性能损耗偏大问题, 后续可对系统结构和数据存储方案进行优化.