ZFS zpool and RAIDZ vdev Administration Guide - 夜莺博客

ZFS zpool and RAIDZ vdev Administration Guide

ZFS is unusual among filesystems because it treats the pool — not the disk — as the unit of management, and because the topology you choose at creation time determines both your redundancy and your ability to expand. A pool built from a single RAIDZ2 vdev can have disks replaced but not vdevs removed, and a pool built from mirrored vdevs scales by adding pairs. Getting that decision wrong is expensive to reverse. This guide covers creating a RAIDZ pool, adding vdevs, replacing failed disks, running scrubs, and reading zpool status the way an operator needs to.

Understanding vdevs and Redundancy

A ZFS pool is a collection of vdevs, and the pool's fault tolerance is determined by the weakest vdev. Three common shapes:

  • Mirror vdev — two or more disks holding identical copies. Survives n-1 failures per vdev, fast rebuilds, best random IOPS per usable terabyte, worst capacity efficiency.
  • RAIDZ1 — single parity. Survives one disk failure per vdev. With multi-terabyte drives the rebuild window is long enough that a second failure during resilver is a real risk.
  • RAIDZ2 / RAIDZ3 — double and triple parity. The standard choice for spinning disks above roughly 4 TB.

Choose topology before you create the pool

Two rules that matter more than any tuning parameter: never mix vdev types in one pool if you care about predictable performance, and never create a pool whose redundancy is n-1 across the whole pool.

Create a RAIDZ2 Pool

# Inspect the disks first, using stable device IDs rather than /dev/sdX
lsblk -o NAME,SIZE,MODEL,SERIAL
ls -l /dev/disk/by-id/

# Create a pool from a single RAIDZ2 vdev (4 data + 2 parity = 6 disks)
zpool create -o ashift=12 tank raidz2 \
    /dev/disk/by-id/wwn-0x5000c500a1b2c3d4 \
    /dev/disk/by-id/wwn-0x5000c500a1b2c3d5 \
    /dev/disk/by-id/wwn-0x5000c500a1b2c3d6 \
    /dev/disk/by-id/wwn-0x5000c500a1b2c3d7 \
    /dev/disk/by-id/wwn-0x5000c500a1b2c3d8 \
    /dev/disk/by-id/wwn-0x5000c500a1b2c3d9

ashift=12 sets a 4 KiB sector size and should be specified for any modern disk; getting it wrong on an advanced-format drive costs a large amount of write amplification and cannot be corrected after the fact. Always use /dev/disk/by-id/ paths — device names like sdb can be reassigned across reboots, which turns an ordinary restart into a degraded pool.

Expand by Adding a vdev

A pool grows by adding complete vdevs, matching the existing topology:

zpool add tank raidz2 \
    /dev/disk/by-id/wwn-0x5000c500b1b2c3d4 \
    /dev/disk/by-id/wwn-0x5000c500b1b2c3d5 \
    /dev/disk/by-id/wwn-0x5000c500b1b2c3d6 \
    /dev/disk/by-id/wwn-0x5000c500b1b2c3d7 \
    /dev/disk/by-id/wwn-0x5000c500b1b2c3d8 \
    /dev/disk/by-id/wwn-0x5000c500b1b2c3d9

RAIDZ vdevs cannot be removed once added (RAIDZ vdev removal was never supported; only mirror vdev removal is). Adding a narrower vdev — for example a 3-disk RAIDZ1 into a pool of 6-disk RAIDZ2 — is legal but reduces the pool's overall redundancy to the weakest member, and new writes will be striped across both.

Replace a Failed Disk

Identify the failed device, then replace it. Using zpool replace with the new by-id path keeps the vdev membership explicit:

zpool status -v tank
zpool replace tank /dev/disk/by-id/wwn-0x5000c500a1b2c3d8 /dev/disk/by-id/wwn-0x5000c500c1b2c3d8
zpool status tank

Resilver progress and priority

Resilver progress is reported inline by zpool status. On a production pool, raise the resilver priority so the rebuild completes faster and the window of reduced redundancy is shorter:

echo 5 > /sys/module/zfs/parameters/zfs_resilver_min_time_ms
zpool resilver tank

If the pool has a spare device, ZFS will use it automatically on failure:

zpool add tank spare /dev/disk/by-id/wwn-0x5000c500d1b2c3d4

Scrub and Monitor Errors

Scrubbing reads every block and verifies checksums against the redundant copy, which is how ZFS surfaces silent corruption that a normal read would never touch:

zpool scrub tank
zpool status -v tank
zpool status -x
zpool events -v
zpool list -v
zfs list -o name,used,avail,refer,mountpoint

Schedule a monthly scrub with a cron job or a systemd timer, and check zpool status -x from monitoring — it prints "all pools are healthy" when everything is fine and names the pool otherwise, which makes it trivial to alert on.

Reading zpool status

The output is dense, but four fields carry almost all the signal:

zpool status tank

  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 6h12m with 0 errors on Sun Sep 20 03:15:42 2026
config:

        NAME        STATE     READ WRITE CKSUM
        tank        ONLINE       0     0     0
          raidz2-0  ONLINE       0     0     0
            wwn-... ONLINE       0     0     0

The state line tells you whether the pool is ONLINE, DEGRADED, or FAULTED. The per-disk READ, WRITE, and CKSUM counters are cumulative error counts — a CKSUM that keeps incrementing on one disk, even while the pool is ONLINE, means that disk is returning bad data and should be replaced. The scan line records the last scrub or resilver, how much data was repaired, and whether any errors were unrecoverable. A non-zero repaired count after a scrub is worth investigating in the drive's own SMART data before the next scrub.

smartctl -a /dev/sdX | grep -E "Reallocated|Pending|Uncorrectable|Power_On_Hours"

Operational Notes

  • Always reference disks by /dev/disk/by-id/ — never by kernel device name.
  • Set ashift=12 at creation; it cannot be changed later.
  • Keep vdev shapes homogeneous and remember the pool is only as redundant as its weakest vdev.
  • Enable compression (zfs set compression=lz4 tank) and disable access-time updates (atime=off) — both reduce writes with no downside for most workloads.
  • Monitor zpool status -x and per-disk CKSUM counters, and run a scrub on a schedule rather than only when someone remembers.

Related reading: our Linux multipath configuration guide, the SAN HBA queue depth and multipath tuning article, and the Ceph CRUSH map device class rules guide.

原文链接:https://openzfs.github.io/openzfs-docs/man/master/8/zpool.8.html