Category: Device mapper

使用Linux kernel dm-mirror实现设备间同步

本文同步自(最佳显示效果请点击):https://zohead.com/archives/dm-mirror-sync-device/ 在某些场合下,用户需要在 Linux 系统中实现直接的块设备同步方式,需要将一个裸设备中的内容完全同步到另一个裸设备,有时甚至需要能自定义位移和大小进行同步,这时 Linux 自带的 dm-mirror 模块很可能是比较好的实现方案。 dm-mirror 是 Linux kernel 中 device-mapper(DM)模块(device-mapper 内部称为 target)中的一个,可以实现多个块设备间的数据同步,并支持通过 dm-log 模块保存同步时的元数据信息,方便在关机和重启之后能够继续之前的进度进行同步,而且 dm-mirror 的元数据可以选择保存在内存中或者固定的块设备中。LVM 逻辑卷管理中的 pvmove 命令可以在卷组中替换物理卷,pvmove 命令正是基于 dm-mirror 模块实现的。Linux kernel 中还包含了其它的一些 device-mapper target 模块,例如 dm-linear(用于实现 LVM 逻辑卷管理)、dm-crypt(加密数据)、dm-snapshot(用于实现即时快照)等。 dm-mirror 的主要实现代码在 Linux kernel 代码树的 drivers/md/dm-raid1.c 中,dm-mirror 的日志元数据记录功能通过 dm-log 模块实现,同步的区块划分由 dm-region-hash 模块实现,底层的同步实现则由 kcopyd 来实现。kcopyd 的功能就是从一个块设备拷贝一定扇区的数据到另一个或多个块设备,kcopyd 支持异步的完成通知功能,目前主要被 dm-snapshot 和 dm-mirror 模块使用。有关 Linux kernel 中 kcopyd 的说明请参考这里:http://www.kernel.org/doc/Documentation/device-mapper/kcopyd.txt。 dm-mirror 设备的装载通过 dmsetup 命令来实现,以下说明的地址都是以扇区为单位(固定为 512 个字节),先看看 dm-mirror target 的 table 格式: start length mirror log_type #logargs logarg1 … logargN #devs device1 offset1 … deviceN offsetN [#features <features>] 对每个值分别说明如下: start 为虚拟设备起始扇区地址,一般固定为 0 length 为 dm-mirror 设备的大小,也就是同步的总扇区大小 mirror 值固定,表示这是一个 dm-mirror 设备 log_type 指定日志元数据类型,常用的是 core 和 disk 两种类型 #logargs 表示后面的 logarg1 … logargN 一共有多少个 #devs 表示需要同步的设备个数,每个设备都有一个 device 值和一个 offset 值 deviceN offsetN 为每个需要同步的设备的设备路径(或者设备号)和偏移地址 #features 和 features 为可选的值,#features 表示可选项个数 如果指定了 #features,则必须为 1,且 features 必须为 handle_errors(表示 dm-mirror 会自动进行错误处理,即同步出错时自动停止同步并删除 dm-mirror 虚拟设备) 然后是 core 和 disk 两种日志元数据类型的介绍(另外有 clustered_core 和 clustered_disk 两种适用于集群的日志类型,有兴趣可以自己去了解下哦): core 类型(内存): 日志保存在内存中,关机或者重启之后会丢失,因此安全性较差,但由于元数据存放在内存中,性能相对 disk 类型来说是非常好的。#logargs 个数为 1-2 个,日志参数格式为: regionsize [[no]sync]regionsize 为日志区块的大小(512 个字节的扇区为单位),可选的 sync 和 nosync 用于指定 dm-mirror 是否已经同步过。 disk 类型(磁盘): 日志保存在磁盘(块设备)中,因此可以在关机或重启之后继续之前的同步进度,当然性能比 core 类型肯定是要差一些的。#logargs 个数为 2-3 个,日志参数格式为: logdevice regionsize [[no]sync]logdevice 指定日志元数据存放在哪个块设备上,可以使用设备路径或者主从设备号形式,其它参数与 core 类型相同。 Linux 系统中 dm-mirror 具体使用步骤举例如下: 首先加载 dm-mirror 模块: modprobe dm-mirror  准备好需要同步的设备,假设是实际应用中的一种常见需求:Linux 系统盘为 /dev/sda,系统中另外有个数据盘 /dev/sdb。但由于磁盘 /dev/sdb 寿命快到了,需要将 /dev/sdb 磁盘上的数据同步到 /dev/sdc 上,/dev/sdc 的容量比 /dev/sdb 要大。先得到 /dev/sdb 和 /dev/sdc 的容量大小(以 512 个字节的扇区为单位): blockdev --getsz /dev/sdb blockdev --getsz /dev/sdc假设分别为 209715200(100G) 和 314572800(150G)。 在系统中通过文件方式产生 loop 设备用作 dm-mirror 同步存放日志元数据的设备,防止关机或重启之后同步进度丢失,1MB 的文件已完全足够保存日志元数据:dd if=/dev/zero of=meta.dat bs=1024k count=1运行完成将产生一个 1MB 大小的 meta.dat 文件。 准备 loop 设备:losetup -f 得到空闲的 loop 设备名,假设为 /dev/loop0;losetup /dev/loop0 meta.dat 装载 loop 设备。 运行 dmsetup create 命令创建 dm-mirror 设备进行同步:echo “0 209715200 mirror disk 2 /dev/loop0 16384 2 /dev/sdb 0 /dev/sdc 0 1 handle_errors” | dmsetup create mirror0运行成功之后将产生名称为 mirror0 的虚拟 dm-mirror 设备。echo 中间的字符串即为 dm-mirror 的 table 格式:209715200 为同步的大小,disk 指定元数据保存在磁盘中,/dev/loop0 为元数据设备,16384 为区块大小(这里指定为 8MB 为提高同步性能),后面的参数指定将 /dev/sdb(源设备,起始地址为 0)的数据同步到 /dev/sdc(目标设备,起始地址为 0),1 和 handle_errors 表示不忽略同步错误。 查询同步状态和进度:dmsetup status mirror0输出类似下面:mirror0: 0 209715200 mirror 2 8:16 8:32 417/12800 1 AA 3 disk 7:0 A8:16 […]