dm-zoned¶
dm-zoned 设备映射器目标将分区块设备(符合 ZBC 和 ZAC 标准的设备)公开为常规块设备,没有任何写入模式约束。 实际上,它实现了一个驱动器管理的分区块设备,该设备向用户(文件系统或执行原始块设备访问的应用程序)隐藏了主机管理的分区块设备的顺序写入约束,并且可以缓解由于主机感知分区块设备上的过度随机写入而导致的潜在设备端性能下降。
有关分区块设备模型及其约束的更详细描述,请参阅(对于 SCSI 设备)
https://www.t10.org/drafts.htm#ZBC_Family
和(对于 ATA 设备)
dm-zoned 的实现很简单,并且最大限度地减少了系统开销(CPU 和内存使用以及存储容量损失)。 对于一个具有 256 MB 分区的 10TB 主机管理磁盘,每个磁盘实例的 dm-zoned 内存使用量最多为 4.5 MB,并且内部将使用最少 5 个分区来存储元数据和执行回收操作。
dm-zoned 目标设备使用以下位置提供的 dmzadm 实用程序进行格式化和检查
https://github.com/hgst/dm-zoned-tools
算法¶
dm-zoned 实现了一个磁盘缓冲方案,以处理对分区块设备顺序分区的非顺序写入访问。 传统分区用于缓存以及存储内部元数据。 它还可以将常规块设备与分区块设备一起使用; 在这种情况下,常规块设备将在逻辑上拆分为与分区块设备大小相同的分区。 这些分区将放置在分区块设备的分区前面,并且将像传统分区一样进行处理。
设备的区域分为 2 种类型
1) 元数据分区:这些是用于存储元数据的传统分区。 元数据分区不会作为可用容量报告给用户。
2) 数据分区:所有剩余的分区,其中绝大多数将是专门用于存储用户数据的顺序分区。 设备的传统分区也可能用于缓冲用户随机写入。 这些分区中的数据可以直接映射到传统分区,但稍后会移动到顺序分区,以便传统分区可以重新用于缓冲传入的随机写入。
dm-zoned 公开的逻辑设备扇区大小为 4096 字节,无论正在使用的后端分区块设备的物理扇区大小如何。 这允许减少管理有效块(已写入的块)所需的元数据量。
磁盘上的元数据格式如下
1) 找到的第一个传统分区的第一个块包含超级块,该超级块描述了磁盘上元数据块的数量和位置。
2) 在超级块之后,使用一组块来描述逻辑设备块的映射。 映射是按块进行的,块大小等于分区块设备的大小。 映射表按块号索引,每个映射条目指示存储数据块的设备的分区号。 每个映射条目还可以指示是否使用传统分区的分区号来缓冲对数据分区的随机修改。
3) 一组用于存储位图的块,指示数据分区中块的有效性,在映射表之后。 有效块定义为已写入且未丢弃的块。 对于缓冲的数据块,块始终仅在映射块的数据分区或该块的缓冲区分区中有效。
对于映射到传统分区的逻辑块,所有写入操作都通过直接写入分区来处理。 如果映射分区是顺序分区,则只有当逻辑块中的写入偏移量等于顺序数据分区中的写入指针偏移量时,才会直接处理写入操作(即,写入操作与分区写入指针对齐)。 否则,写入操作会使用缓冲区分区间接处理。 在这种情况下,将分配一个未使用的传统分区并将其分配给正在访问的块。 将块写入块的缓冲区分区将自动使映射块的顺序分区中的同一块无效。 如果顺序分区的所有块都变为无效,则该分区将被释放,并且块缓冲区分区将成为映射块的主分区,从而产生类似于常规块设备的本机随机写入性能。
读取操作会根据位图提供的块有效性信息进行处理。 有效块可以从映射块的顺序分区中读取,或者如果该块被缓冲,则从分配的缓冲区分区中读取。 如果访问的块没有映射,或者访问的块无效,则读取缓冲区将被清零并且读取操作终止。
一段时间后,可用的传统分区数量可能会耗尽(全部用于映射块或缓冲顺序分区),并且无法对未缓冲的块进行不对齐的写入。 为避免这种情况,回收过程会定期扫描已使用的传统分区,并尝试通过将缓冲区分区的有效块复制到空闲的顺序分区来回收最近最少使用的分区。 复制完成后,将更新块映射以指向顺序分区,并且释放缓冲区分区以供重用。
元数据保护¶
为了在突然断电或系统崩溃的情况下保护元数据免受损坏,使用了两组元数据区域。一组,即主集合,用作主要的元数据区域,而辅助集合用作暂存区。修改后的元数据首先被写入到辅助集合中,并通过更新辅助集合中的超级块进行验证,一个生成计数器用于指示该集合包含最新的元数据。一旦此操作完成,就可以在主元数据集内进行元数据块的就地更新。这确保了其中一个集合始终保持一致(所有修改都已提交或完全没有提交)。刷新操作被用作提交点。在接收到刷新请求时,元数据修改活动将被暂时阻止(包括传入的 BIO 处理和回收过程),并且所有脏元数据块都会被暂存和更新。然后恢复正常操作。因此,刷新元数据只会暂时延迟写入和丢弃请求。在执行元数据刷新的同时,可以并行处理读取请求。
如果将常规设备与分区块设备一起使用,则会将第三组元数据(不包含区域位图)写入分区块设备的开头。此元数据的生成计数器为“0”,并且在正常操作期间永远不会更新;它仅用于识别目的。元数据的第一份和第二份副本位于常规块设备的开头。
使用¶
必须首先使用 dmzadm 工具格式化分区块设备。这将分析设备区域配置,确定将元数据集合放置在设备上的位置,并初始化元数据集合。
例如
dmzadm --format /dev/sdxx
如果要使用两个驱动器,则必须指定两个设备,并将常规块设备作为第一个设备。
例如
dmzadm --format /dev/sdxx /dev/sdyy
也可以使用 dmzadm 实用程序启动格式化后的设备。
例如
dmzadm --start /dev/sdxx /dev/sdyy
有关内部布局和区域当前使用情况的信息可以通过 dmsetup 中的“status”回调获得
例如
dmsetup status /dev/dm-X
将返回一行
0 <大小> zoned <区域数> zones <未映射随机区数>/<随机区总数> random <未映射顺序区数>/<顺序区总数> sequential
其中 <区域数> 是区域的总数,<未映射随机区数> 是未映射(即空闲)的随机区域的数量,<随机区总数> 是随机区域的总数,<未映射顺序区数> 是未映射的顺序区域的数量,而 <顺序区总数> 是顺序区域的总数。
通常,一旦空闲随机区域少于 50%,就会启动回收过程。为了在达到此阈值之前手动启动回收过程,可以使用 'dmsetup message' 函数
例如
dmsetup message /dev/dm-X 0 reclaim
将启动回收过程,随机区域将移动到顺序区域。