ZFS弄乱了镜像

wma*_*tly 2 raid zfs

我在 RAID10 中有一个带有 6 个驱动器的 ZFS 池——嗯,它曾经是。

我试图将 146GB 驱动器升级到 1TB 驱动器,但搞砸了。

root@x7550:~# zpool status
  pool: stuffpool
 state: ONLINE
  scan: scrub repaired 0 in 0h6m with 0 errors on Mon May  9 15:26:39 2016
config:

    NAME                                               STATE     READ WRITE CKSUM
    stuffpool                                          ONLINE       0     0     0
      mirror-0                                         ONLINE       0     0     0
        ata-HGST_HTS721010A9E630_JR10004M0LGN6E-part1  ONLINE       0     0     0
        ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1  ONLINE       0     0     0
      mirror-1                                         ONLINE       0     0     0
        ata-HGST_HTS541010A9E680_JA1000102MG9UR-part1  ONLINE       0     0     0
        ata-HGST_HTS541010A9E680_JA1009C03158BP-part1  ONLINE       0     0     0
      scsi-35000c50016ebcdfb-part1                     ONLINE       0     0     0
      ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1    ONLINE       0     0     0
Run Code Online (Sandbox Code Playgroud)

scsi-35000c50016ebcdfb-part1ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1曾经在 mirror-2 中,并且是我试图添加到 mirror-2 的驱动器。

我能做些什么来解决这个问题吗?

我在 ubuntu 16.04 上运行

root@x7550:~# zpool history stuffpool | tail -n50
History for 'stuffpool':
2016-03-27.01:56:12 zpool create stuffpool mirror ata-HGST_HTS721010A9E630_JR10004M0LGN6E-part1 ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1 -f
2016-03-27.01:57:41 zpool add stuffpool mirror /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA1000102MG9UR-part1 /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA1009C03158BP-part1 -f
2016-03-27.01:59:25 zpool add stuffpool mirror /dev/disk/by-id/scsi-35000c50016ebcdfb-part1 /dev/disk/by-id/scsi-35000c50017675203-part1 -f
2016-03-27.02:12:38 zpool import -c /etc/zfs/zpool.cache -aN
2016-03-27.23:48:32 zfs create stuffpool/stuff
2016-03-27.23:54:47 zpool import -c /etc/zfs/zpool.cache -aN
2016-03-28.00:02:23 zfs create stuffpool/backup
2016-03-30.23:18:04 zpool scrub stuffpool
2016-04-03.01:06:06 zpool import -c /etc/zfs/zpool.cache -aN
2016-04-03.01:15:33 zfs create -p -o mountpoint=/var/lib/lxd/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9.zfs stuffpool/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9
2016-04-03.01:15:53 zfs set readonly=on stuffpool/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9
2016-04-03.01:15:54 zfs snapshot -r stuffpool/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9@readonly
2016-04-03.01:16:00 zfs clone -p -o mountpoint=/var/lib/lxd/containers/ux-1.zfs stuffpool/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9@readonly stuffpool/containers/ux-1
2016-04-08.01:31:47 zpool import -c /etc/zfs/zpool.cache -aN
2016-04-08.01:43:48 zpool import -c /etc/zfs/zpool.cache -aN
2016-04-19.00:00:30 zpool import -c /etc/zfs/zpool.cache -aN
2016-04-21.18:14:15 zfs create -p -o mountpoint=/var/lib/lxd/images/9b03bacc30bcfbe3378e8803daa48ca2d32baa99d111efada484876750e5cc20.zfs stuffpool/images/9b03bacc30bcfbe3378e8803daa48ca2d32baa99d111efada484876750e5cc20
2016-04-21.18:14:35 zfs set readonly=on stuffpool/images/9b03bacc30bcfbe3378e8803daa48ca2d32baa99d111efada484876750e5cc20
2016-04-21.18:14:36 zfs snapshot -r stuffpool/images/9b03bacc30bcfbe3378e8803daa48ca2d32baa99d111efada484876750e5cc20@readonly
2016-04-21.18:14:36 zfs set mountpoint=none stuffpool/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9
2016-04-21.18:14:41 zfs rename -p stuffpool/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9 stuffpool/deleted/images/f96b6b5d7587150b880e96f872393b7fee53741046b40a76c6db22ed40886bc9
2016-04-24.22:54:03 zpool scrub stuffpool
2016-05-07.22:55:42 zpool import -c /etc/zfs/zpool.cache -aN
2016-05-09.15:20:27 zpool scrub stuffpool
2016-05-17.22:56:53 zfs create -p -o mountpoint=/var/lib/lxd/images/4f7a1fe6b71446eba6ee56f49698bd6592f193f731f1c0d9d51b1d199b9b75a5.zfs stuffpool/images/4f7a1fe6b71446eba6ee56f49698bd6592f193f731f1c0d9d51b1d199b9b75a5
2016-05-17.22:57:12 zfs set readonly=on stuffpool/images/4f7a1fe6b71446eba6ee56f49698bd6592f193f731f1c0d9d51b1d199b9b75a5
2016-05-17.22:57:13 zfs snapshot -r stuffpool/images/4f7a1fe6b71446eba6ee56f49698bd6592f193f731f1c0d9d51b1d199b9b75a5@readonly
2016-05-17.22:57:18 zfs destroy -r stuffpool/images/9b03bacc30bcfbe3378e8803daa48ca2d32baa99d111efada484876750e5cc20
2016-05-21.16:47:49 zpool import -c /etc/zfs/zpool.cache -aN
2016-06-09.22:59:47 zpool import -c /etc/zfs/zpool.cache -aN
2016-06-13.20:59:10 zpool import -c /etc/zfs/zpool.cache -aN
2016-06-13.20:59:34 zfs create -p -o mountpoint=/var/lib/lxd/images/49fc7d0d6f01a7639129308b73ad27f5fb7b9d3bb783d905393b6b9e9c4bf1c5.zfs stuffpool/images/49fc7d0d6f01a7639129308b73ad27f5fb7b9d3bb783d905393b6b9e9c4bf1c5
2016-06-13.20:59:54 zfs set readonly=on stuffpool/images/49fc7d0d6f01a7639129308b73ad27f5fb7b9d3bb783d905393b6b9e9c4bf1c5
2016-06-13.20:59:54 zfs snapshot -r stuffpool/images/49fc7d0d6f01a7639129308b73ad27f5fb7b9d3bb783d905393b6b9e9c4bf1c5@readonly
2016-06-13.21:00:00 zfs destroy -r stuffpool/images/4f7a1fe6b71446eba6ee56f49698bd6592f193f731f1c0d9d51b1d199b9b75a5
2016-06-18.02:18:55 zpool import -c /etc/zfs/zpool.cache -aN
2016-06-18.02:27:08 zpool offline stuffpool 1759097636360003165
2016-06-18.02:33:28 zpool detach stuffpool 1759097636360003165
2016-06-18.12:23:26 zpool export stuffpool
2016-06-18.12:24:38 zpool import stuffpool
2016-06-18.12:27:34 zpool add -f stuffpool ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1
2016-06-18.12:31:05 zpool export stuffpool
2016-06-18.13:19:17 zpool import stuffpool
Run Code Online (Sandbox Code Playgroud)

所有 ATA 驱动器均为 1tb,SCSI 驱动器为 146GB

这是使用信息

root@x7550:~# zpool list
NAME        SIZE  ALLOC   FREE  EXPANDSZ   FRAG    CAP  DEDUP  HEALTH  ALTROOT
stuffpool  2.85T   162G  2.69T         -     2%     5%  1.00x  ONLINE  -
Run Code Online (Sandbox Code Playgroud)

这是我的个人服务器,所以停机不是问题。

use*_*ser 6

好吧,你把自己搞得一团糟,但看起来它是可以修复的。

您犯的第一个错误是zpool add新驱动器,而不是zpool attach(将附加设备附加到镜像),甚至更好zpool replace的是旧设备仍然存在于池元数据中。更换设备的正确方法是

# zpool replace stuffpool 1759097636360003165 ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1
Run Code Online (Sandbox Code Playgroud)

或者甚至更好,如果你有物理能力,zpool replace旧设备和新设备都连接(在整个过程中保持池冗余)。

此时,您的旧池基本上已损坏无法修复:添加后无法从池中删除 vdev(不匹配的 vdev 冗余级别可能是您需要-f将新磁盘放入池的原因),并且您没有没有将两个非冗余 vdev 变成双向镜像的硬件。

但是,您可以利用现有资源创建一个新池。

在您采取任何行动之前通读所有这些内容,并确保您了解每个步骤的内容和原因。你真的不想再搞砸了。

首先,绝对确保您拥有最新的、可靠的数据备份。鉴于您只存储了 160 GB 多一点,这应该不是什么大问题。我还非常强烈建议您zpool scrub确保池中存储的所有数据都没有任何错误。使用 160 GB,并且如您之前的清理所示,应该不需要很长时间即可完成。

然后,将一个驱动器与镜像分离,释放它。例如,要将 mirror-0 分开并使用那里的驱动器之一,您可能

# zpool detach stuffpool ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1
Run Code Online (Sandbox Code Playgroud)

这将为您留下stuffpool由三个单设备 vdev 和一个双向镜像 vdev (mirror-1) 组成。然后清除与镜像分离的驱动器上的所有 ZFS 标签,以便您可以重新利用它:

# zpool labelclear /dev/disk/by-id/ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1
Run Code Online (Sandbox Code Playgroud)

此时,ZFS 不会将该驱动器识别为旧池的一部分。您可能需要-fzpool labelclear,但是不要盲目添加它; 确保您了解您可能需要它的原因。

重命名旧池(假设您要保留名称,否则根据需要在下面进行调整):

# zpool export stuffpool
# zpool import stuffpool stuffpoolold
Run Code Online (Sandbox Code Playgroud)

在释放的驱动器上创建一个新池:

# zpool create -o ashift=12 -O checksum=sha256 -m none -f stuffpool /dev/disk/by-id/ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1
Run Code Online (Sandbox Code Playgroud)

我建议使用 SHA-256 进行校验和,但如果您不想,可以省略该-O checksum=sha256部分。-o ashift=12告诉 ZFS 使用 4,096 字节块作为最小分配单元,这在较小的存储空间成本下与“高级格式”驱动器配合使用效果更好。

如果您不使用池上的根文件系统来存储数据,则某些故障情况更容易恢复。我建议你在池上创建一个代理根文件系统:

# zfs create -o mountpoint=/mnt/stuffpoolnew stuffpool/data
Run Code Online (Sandbox Code Playgroud)

现在,将所有内容从旧池转移到新池。首先创建旧池当前状态的快照:

# zfs snapshot stuffpoolold@transfer -r
Run Code Online (Sandbox Code Playgroud)

确保快照创建成功。然后:

# zfs send -R stuffpoolold@transfer | zfs receive -uvF stuffpool/data
Run Code Online (Sandbox Code Playgroud)

这将需要一段时间。让它运行到完成,然后抓住在此期间改变的任何东西:

# zfs snapshot stuffpoolold@transfer2 -r
# zfs send -I stuffpoolold@transfer stuffpoolold@transfer2 -Rv | zfs receive stuffpool/data -uv
Run Code Online (Sandbox Code Playgroud)

在这一点上,池上的数据在所有意图和目的上都应该是相同的。如果您有 cron 作业或类似的东西在运行写入池,请考虑制作第二个快照和zfs send -I ...来自单用户模式,以降低将数据添加到池中的风险。

设置新池以代替旧池:

# zfs get mountpoint stuffpoolold
... this will give you a mountpoint directory ...
# zpool export stuffpoolold
# zfs set mountpoint=...mountpoint_directory_from_above... stuffpool/data
# zpool export stuffpool
# zpool import stuffpool
Run Code Online (Sandbox Code Playgroud)

此时,您的新 zpool 只包含一个设备。擦洗它以确保数据正常:

# zpool scrub stuffpool
Run Code Online (Sandbox Code Playgroud)

当它完成而没有发现任何错误时,继续将旧磁盘迁移到新池。从旧的剩余镜像 1 对的第二个驱动器开始(因为我们使用了上面镜像 0 的第二个驱动器),以尽可能长时间地保持旧池的可导入性:

# zpool labelclear /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA1009C03158BP-part1
# zpool attach stuffpool /dev/disk/by-id/ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1 /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA1009C03158BP-part1
Run Code Online (Sandbox Code Playgroud)

检查zpool status stuffpool以确保您现在拥有一个由单个双向镜像 vdev 组成的池,如下所示:

root@x7550:~# zpool status stuffpool
  pool: stuffpool
 state: ONLINE
  scan: scrub repaired 0 in 0h6m with 0 errors on ...
config:

    NAME                                               STATE     READ WRITE CKSUM
    stuffpool                                          ONLINE       0     0     0
      mirror-0                                         ONLINE       0     0     0
        ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1  ONLINE       0     0     0
        ata-HGST_HTS541010A9E680_JA1009C03158BP-part1  ONLINE       0     0     0
Run Code Online (Sandbox Code Playgroud)

现在继续添加两个镜像 vdev,首先按照您想要的方式添加它们。您需要先标记清除设备(否则 ZFS 会抱怨它们已经是导出池的一部分)。同样,你可能需要-fzpool labelclear,但绝对不盲目添加-fzpool add。(如果你必须这样做,那么我在某个地方犯了一个错误。)

# zpool labelclear /dev/disk/by-id/ata-HGST_HTS721010A9E630_JR10004M0LGN6E-part1
# zpool labelclear /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA1000102MG9UR-part1
# zpool labelclear /dev/disk/by-id/scsi-35000c50016ebcdfb-part1
# zpool labelclear /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1
# zpool add stuffpool mirror /dev/disk/by-id/ata-HGST_HTS721010A9E630_JR10004M0LGN6E-part1 /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA1000102MG9UR-part1
# zpool add stuffpool mirror /dev/disk/by-id/scsi-35000c50016ebcdfb-part1 /dev/disk/by-id/ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1
Run Code Online (Sandbox Code Playgroud)

再次擦洗(因为每个人都喜欢干净整洁的游泳池):

# zpool scrub stuffpool
Run Code Online (Sandbox Code Playgroud)

此时,您的池应该看起来像您从一开始就想要的:

root@x7550:~# zpool status
  pool: stuffpool
 state: ONLINE
  scan: scrub repaired 0 in 0h6m with 0 errors on ...
config:

    NAME                                               STATE     READ WRITE CKSUM
    stuffpool                                          ONLINE       0     0     0
      mirror-0                                         ONLINE       0     0     0
        ata-HGST_HTS721010A9E630_JR10004M0M17TE-part1  ONLINE       0     0     0
        ata-HGST_HTS541010A9E680_JA1009C03158BP-part1  ONLINE       0     0     0
      mirror-1                                         ONLINE       0     0     0
        ata-HGST_HTS721010A9E630_JR10004M0LGN6E-part1  ONLINE       0     0     0
        ata-HGST_HTS541010A9E680_JA1000102MG9UR-part1  ONLINE       0     0     0
      mirror-2                                         ONLINE       0     0     0
        scsi-35000c50016ebcdfb-part1                   ONLINE       0     0     0
        ata-HGST_HTS541010A9E680_JA109NDW206MAS-part1  ONLINE       0     0     0
Run Code Online (Sandbox Code Playgroud)

您的池现在是不平衡的(几乎所有的数据是上镜0,并且将一直保留,直到改写;虽然ZFS没有任何类似的btrfs rebalance,你仍然可以解决这个问题,如果使用得当的zfs send ... | zfs receive),但它的布局和冗余你当你开始的时候打算。

这是一个漫长的过程,有很多步骤,但如果你慢慢来,仔细想想每一步你在做什么,它并不是特别危险。

优点是池上的数据比任何一个驱动器都填满的数据要少得多。如果您的池几乎已满,则情况会复杂得多。