ZFS Calculator: RAIDZ & dRAID Pool Planner

Given an inventory of heterogeneous disks (HDD, SATA/SAS SSD, NVMe), each with its own capacity and performance figures, this tool computes the usable capacity of a ZFS pool exactly as zfs list reports it, for stripe, mirror, RAIDZ1–3 and dRAID1–3 vdevs. It estimates sequential throughput, random IOPS and rebuild time, ranks candidate layouts for a given workload and emits the corresponding zpool create command. The capacity model follows the OpenZFS allocator as documented at jro.io/capacity; see Method.

Setup:   Name:  
Stored in this browser; the current setup is restored automatically.

1 Disk inventory

Table 1: Disk groups. All figures per disk; defaults are typical values, adjust them to your drives.
GroupTypeCountSize [TB]Seq. read [MB/s]Seq. write [MB/s]Read [IOPS]Write [IOPS]by-id

2 Parameters

ashift:   recordsize:   target fill [%]:   swap per disk [GiB]:

3 Pool layout

Mode:

Table 2: vdevs. Width = disks per vdev (dRAID: children); stripe = single-disk vdevs.
ClassLayoutDisk groupWidthvdevsdRAID datadRAID spares

4 Results

5 zpool create

Pool name:


  

Disks are assigned to vdevs in inventory order. Find the IDs with ls -l /dev/disk/by-id/ | grep -v -- -part; pasting several lines into one field fills the following disks.

Method

Most ZFS calculators assume a handful of identical disks. This one starts from the hardware actually at hand: any mix of HDDs, SATA/SAS SSDs and NVMe drives, each group with its own size and performance figures. From that inventory you build data vdevs (stripe, mirror, RAIDZ1, RAIDZ2, RAIDZ3, dRAID1–3) and support vdevs (special, SLOG, L2ARC cache, hot spares).

Exact RAIDZ and dRAID capacity

Per disk of vendor size S: after the optional swap partition the partition is aligned to 256 KiB, then four vdev labels and the boot block (4.5 MiB) are subtracted:

(1)   s = floor((S − Sswap) / 256 KiB) · 256 KiB − 4.5 MiB

A vdev of width w has A = w·s bytes (mirror: A = s), split into metaslabs of 2m bytes as in vdev_metaslab_set_size(); the remainder is lost:

(2)   A′ = floor(A / 2m) · 2m

A block of nd = ceil(ψ / 2ashift) data sectors (ψ = recordsize) occupies on RAIDZ with parity p, and on dRAID with d data disks per group:

(3)   nRAIDZ = ceil((nd + p·ceil(nd / (w − p))) / (p + 1)) · (p + 1),   ndRAID = ceil(nd / d) · (d + p)

i.e. RAIDZ pads to a multiple of p + 1 and dRAID always writes full stripes. zfs list reports space as if every block were 128 KiB, with the deflate ratio quantised to 1/512:

(4)   ρ = floor(217 / (n128K · 2ashift−9)) / 512,   C = ∑ A′·ρ

dRAID children additionally reserve 32 MiB for reflow and are rounded to 16 MiB rows; the spares form the distributed spare. Finally the pool keeps a slop reservation:

(5)   Cslop = max(min(C/32, 128 GiB), min(C/2, 128 MiB)),   Cusable = C − Cslop

The test suite reproduces the published reference values (7-wide RAIDZ2: ρ = 341/512; dRAID2:5d:20c:1s: ρ = 334/512).

dRAID

dRAID layouts are written draid<p>:<d>d:<c>c:<s>s. Compared with RAIDZ they trade a fixed minimum allocation of d·2ashift bytes, which wastes space for small blocks, for a much faster sequential rebuild onto the distributed spare.

Performance and rebuild

Per data vdev: a stripe delivers one disk; an n-way mirror reads at n× and writes at 1×; RAIDZ streams at (w − p)× but has the random IOPS of one disk; dRAID streams at (c − s)·d/(d + p)× with (c − s)/(d + p)× the IOPS. Pool figures are sums over data vdevs. With fill level f and per-disk bandwidth B:

(6)   tresilver = f·S / B,   tdRAID = f·S·(d + 1) / ((c − 1)·B)

These are lower bounds for comparison: ARC, compression, fragmentation and network limits are not modelled.

Recommendation

For each disk group all sensible mirrors, RAIDZ widths and (from ten disks) dRAID geometries are enumerated; single parity on HDDs ≥ 8 TB is excluded. Candidates are scored by a workload-specific weighted sum of capacity, log-scaled throughput and IOPS, fault tolerance and rebuild speed. SSDs next to an HDD pool are proposed as special vdev or SLOG.