精简配置

简介

本文档描述了一组设备映射器目标,它们之间实现了精简配置和快照。

与之前的快照实现相比,此实现的主要亮点是它允许将许多虚拟设备存储在同一数据卷上。这简化了管理,并允许在卷之间共享数据,从而减少磁盘使用量。

另一个重要特性是支持任意深度的递归快照(快照的快照的快照...)。之前的快照实现通过将查找表链接在一起来实现这一点,因此性能为 O(深度)。这种新实现使用单个数据结构来避免这种随深度下降的性能。然而,在某些情况下,碎片仍然可能是一个问题。

元数据存储在与数据不同的设备上,这为管理员提供了一些自由,例如可以

  • 通过将元数据存储在镜像卷上,但将数据存储在非镜像卷上来提高元数据的弹性。

  • 通过将元数据存储在 SSD 上来提高性能。

状态

这些目标被认为是可用于生产的。但是,不同的用例会有不同的性能特性,例如由于数据卷的碎片化。

如果您发现此软件的性能不如预期,请发送邮件至 dm-devel@redhat.com,提供详细信息,我们将尽力为您改进。

用于检查和修复元数据的用户空间工具已完全开发,并以 ‘thin_check’ 和 ‘thin_repair’ 的形式提供。提供这些实用程序的软件包名称因发行版而异(在 Red Hat 发行版上,它名为 ‘device-mapper-persistent-data’)。

操作指南

本节介绍一些使用精简配置的快速方法。它们使用 dmsetup 程序直接控制设备映射器驱动程序。建议最终用户在使用添加支持后使用更高级别的卷管理器(例如 LVM2)。

池设备

池设备将元数据卷和数据卷绑定在一起。它将 I/O 线性映射到数据卷,并通过两种机制更新元数据

  • 来自精简目标的功能调用

  • 来自用户空间的设备映射器“消息”,用于控制新虚拟设备的创建以及其他事项。

设置新的池设备

设置池设备需要一个有效的元数据设备和一个数据设备。如果您没有现有的元数据设备,可以通过将前 4k 字节归零来指示元数据为空来创建一个。

dd if=/dev/zero of=$metadata_dev bs=4096 count=1

您需要的元数据量将根据精简设备(即通过快照)之间共享的块数而有所不同。如果您共享的内容少于平均水平,则需要一个大于平均水平的元数据设备。

作为指南,我们建议您将元数据设备中要使用的字节数计算为 48 * $data_dev_size / $data_block_size,但如果答案小于 2MB,则将其向上舍入为 2MB。如果您正在创建大量记录大量更改的快照,您可能会发现需要增加此值。

支持的最大大小为 16GB:如果设备大于此值,则会发出警告,并且不会使用多余的空间。

重新加载池表

您可以重新加载池的表,实际上,如果池的空间不足,这是调整池大小的方式。(注意:虽然目前不禁止在重新加载时指定不同的元数据设备,但如果它没有将 I/O 路由到与之前完全相同的磁盘位置,则会出现问题。)

使用现有的池设备

dmsetup create pool \
    --table "0 20971520 thin-pool $metadata_dev $data_dev \
             $data_block_size $low_water_mark"

$data_block_size 给出了可以一次分配的最小磁盘空间单位,以 512 字节扇区为单位表示。$data_block_size 必须介于 128 (64KB) 和 2097152 (1GB) 之间,并且是 128 (64KB) 的倍数。创建精简池后,无法更改 $data_block_size。主要对精简配置感兴趣的人可能想要使用诸如 1024 (512KB) 之类的值。进行大量快照的人可能想要使用较小的值,例如 128 (64KB)。如果您没有将新分配的数据归零,建议使用较大的 $data_block_size,约为 256000 (128MB)。

$low_water_mark 以 $data_block_size 大小的块表示。如果数据设备上的可用空间低于此级别,则会触发 dm 事件,用户空间守护程序应捕获该事件,允许其扩展池设备。只会发送一个这样的事件。

如果刚刚恢复的设备的可用空间低于低水位线,则不会触发特殊事件。但是,恢复设备总是会触发一个事件;用户空间守护程序应在处理此事件时验证可用空间是否超过低水位线。

内核中维护着元数据设备的低水位线,如果元数据设备上的可用空间低于该水位线,则会触发 dm 事件。

更新磁盘上的元数据

每次写入 FLUSH 或 FUA bio 时,都会提交磁盘上的元数据。如果没有发出此类请求,则将每秒发生一次提交。这意味着精简配置目标的行为类似于具有易失性写入缓存的物理磁盘。如果电源丢失,您可能会丢失一些最近的写入。尽管发生任何崩溃,元数据都应始终保持一致。

如果数据空间耗尽,池将根据配置报错或排队 IO(请参阅:error_if_no_space)。如果元数据空间耗尽或元数据操作失败:池将报错 IO,直到池脱机并执行修复以 1) 修复任何潜在的不一致性,以及 2) 清除强制修复的标志。一旦池的元数据设备被修复,就可以调整其大小,这将允许池恢复正常运行。请注意,如果池被标记为需要修复,则在执行修复之前,无法调整池的数据和元数据设备的大小。还应注意的是,当池的元数据空间耗尽时,当前的元数据事务将中止。鉴于池将缓存已向更高 IO 层(例如文件系统)确认完成的 IO,因此强烈建议在需要修复池时对这些层执行一致性检查(例如 fsck)。

精简配置

  1. 创建一个新的精简配置卷。

要创建一个新的精简配置卷,您必须向一个活动的池设备发送消息,在本示例中为 /dev/mapper/pool

dmsetup message /dev/mapper/pool 0 "create_thin 0"

这里的 ‘0’ 是卷的标识符,一个 24 位数字。由调用者来分配和管理这些标识符。如果标识符已在使用中,则消息将失败,并显示 -EEXIST。

  1. 使用精简配置的卷。

使用 ‘thin’ 目标激活精简配置的卷

dmsetup create thin --table "0 2097152 thin /dev/mapper/pool 0"

最后一个参数是精简设备 (thin device) 的标识符。

内部快照

  1. 创建内部快照。

快照通过向池发送另一个消息来创建。

注意:如果您要创建快照的原始设备处于活动状态,则必须在创建快照之前将其挂起,以避免损坏。目前这不会强制执行,因此请务必小心!

dmsetup suspend /dev/mapper/thin
dmsetup message /dev/mapper/pool 0 "create_snap 1 0"
dmsetup resume /dev/mapper/thin

这里 ‘1’ 是卷的标识符,一个 24 位数字。 ‘0’ 是原始设备的标识符。

  1. 使用内部快照。

创建后,用户无需担心原始设备和快照之间的任何连接。实际上,快照与任何其他精简配置设备没有什么不同,并且可以通过相同的方法对其自身进行快照。只激活其中一个快照是完全合法的,并且在激活或移除它们时没有任何顺序要求。(这与传统的设备映射器快照不同。)

以与任何其他精简配置卷完全相同的方式激活它

dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 1"

外部快照

您可以将外部只读设备用作精简配置卷的源。对精简设备未配置区域的任何读取都将传递到源。写入会像往常一样触发新块的分配。

一个用例是 VM 主机希望在精简配置卷上运行访客,但将基本映像放在另一个设备上(可能在多个 VM 之间共享)。

如果使用此技术,则不得写入源设备!当然,您可以写入精简设备并获取精简卷的内部快照。

  1. 创建外部设备的快照

这与创建精简设备相同。在此阶段您不需要提及源。

dmsetup message /dev/mapper/pool 0 "create_thin 0"
  1. 使用外部设备的快照。

在精简目标中附加一个额外的参数,指定源

dmsetup create snap --table "0 2097152 thin /dev/mapper/pool 0 /dev/image"

注意:此快照的所有后代(内部快照)都需要相同的额外源参数。

停用

在使用池的所有设备都必须停用后,池本身才能停用。

dmsetup remove thin
dmsetup remove snap
dmsetup remove pool

参考

“thin-pool”目标

  1. 构造函数

    thin-pool <metadata dev> <data dev> <data block size (sectors)> \
              <low water mark (blocks)> [<number of feature args> [<arg>]*]
    

    可选功能参数

    skip_block_zeroing

    跳过新配置块的清零。

    ignore_discard

    禁用丢弃支持。

    no_discard_passdown

    不要将丢弃传递到底层数据设备,而只是删除映射。

    read_only

    不允许对池元数据进行任何更改。此模式仅在 thin-pool 创建并首次在完全读/写模式下使用后才可用。不能在初始 thin-pool 创建时指定它。

    error_if_no_space

    如果空间不足,则报错 IO,而不是排队。

    数据块大小必须在 64KB (128 个扇区) 和 1GB (2097152 个扇区) 之间(包括两者)。

  2. 状态

    <transaction id> <used metadata blocks>/<total metadata blocks>
    <used data blocks>/<total data blocks> <held metadata root>
    ro|rw|out_of_data_space [no_]discard_passdown [error|queue]_if_no_space
    needs_check|- metadata_low_watermark
    
    事务 ID

    一个 64 位数字,由用户空间用于帮助与卷管理器中的元数据同步。

    已使用数据块 / 总数据块

    如果空闲块的数量降至池的低水位线以下,则会向用户空间发送一个 dm 事件。此事件是边缘触发的,并且在每次恢复后只会发生一次,因此卷管理器写入器应注册该事件,然后检查目标的状态。

    已保持的元数据根

    为用户空间读取访问而“保持”的元数据根的位置(以块为单位)。 “-” 表示没有保持的根。

    discard_passdown|no_discard_passdown

    是否真的将丢弃传递到底层设备。在加载表时启用此功能后,如果底层设备不支持,则可以禁用它。

    ro|rw|out_of_data_space

    如果池遇到某些类型的设备故障,它将进入只读元数据模式,其中不允许更改池元数据(如分配新块)。

    在即使只读模式也被认为不安全的情况下,将不允许进一步的 I/O,并且状态将只包含字符串“Fail”。然后应使用用户空间恢复工具。

    error_if_no_space|queue_if_no_space

    如果池的数据或元数据空间耗尽,则池将对发往数据设备的 IO 进行排队或报错。默认是将 IO 排队,直到添加更多空间或 ‘no_space_timeout’ 过期。可以使用 ‘no_space_timeout’ dm-thin-pool 模块参数来更改此超时 - 默认为 60 秒,但可以使用值 0 禁用。

    needs_check

    元数据操作失败,导致在元数据的超级块中设置了 needs_check 标志。必须停用元数据设备并进行检查/修复,然后 thin-pool 才能再次完全运行。“-” 表示未设置 needs_check。

    metadata_low_watermark

    元数据低水位线的值(以块为单位)。内核在内部设置此值,但用户空间需要知道此值才能确定事件是否由超过此阈值引起。

  3. 消息

create_thin <dev id>

创建一个新的精简配置设备。 <dev id> 是调用者选择的任意唯一 24 位标识符。

create_snap <dev id> <origin id>

创建另一个精简配置设备的新快照。 <dev id> 是调用者选择的任意唯一 24 位标识符。 <origin id> 是新设备将作为快照的精简配置设备的标识符。

delete <dev id>

删除一个精简设备。不可逆转。

set_transaction_id <current id> <new id>

用户空间卷管理器(例如 LVM)需要一种方法来将其外部元数据与池目标的内部元数据同步。 thin-pool 目标提供存储任意 64 位事务 ID,并在目标的状态行中返回它。为避免竞争,在您使用此比较和交换消息更改它时,您必须提供您认为当前的事务 ID 是什么。

reserve_metadata_snap

保留数据映射 btree 的副本,供用户空间使用。这允许用户空间检查执行此消息时的映射。使用池的状态命令来获取与元数据快照关联的根块。

release_metadata_snap

释放以前保留的数据映射 btree 的副本。

“thin”目标

  1. 构造函数

    thin <pool dev> <dev id> [<external origin dev>]
    
    pool dev

    thin-pool 设备,例如 /dev/mapper/my_pool 或 253:0

    dev id

    要激活的设备的内部设备标识符。

    external origin dev

    池外部的可选块设备,将被视为只读快照源:对精简目标未配置区域的读取将映射到此设备。

池不存储任何精简设备的大小。如果您加载的精简目标小于您以前使用的目标,那么您将无法访问映射到末尾之外的块。如果您加载的目标大于以前的目标,那么会根据需要配置额外的块。

  1. 状态

    <映射的扇区数> <最高映射扇区>

    如果池遇到设备错误并发生故障,则状态将只包含字符串“Fail”。然后应使用用户空间恢复工具。

    如果 <映射的扇区数> 为 0,则没有最高映射扇区,并且 <最高映射扇区> 的值未指定。