When configuring redundant storage, you're essentially choosing between two philosophies of data protection:
- HW RAID1 + ZFS: Hardware abstraction layer handles mirroring
- Native ZFS mirror: End-to-end checksumming and repair
Here's a concrete example showing why bypassing HW RAID is superior:
# Creating ZFS mirror pool
zpool create tank mirror /dev/sda /dev/sdb
# For comparison, HW RAID would require:
# 1. RAID controller configuration
# 2. Then creating pool on /dev/mapper/raid1
The native approach gives ZFS direct disk access for:
- Block-level checksum verification
- Automatic corruption detection
- Self-healing capabilities
Consider what happens when a disk sector goes bad:
Configuration | Recovery Process |
---|---|
HW RAID1 + ZFS | RAID controller may mask the error; ZFS sees "healthy" corrupted data |
Native ZFS Mirror | ZFS detects checksum mismatch and repairs from good copy automatically |
While you mentioned performance isn't critical, note these observations from production systems:
# Benchmarking random reads (4K blocks)
fio --name=randread --ioengine=libaio --rw=randread --bs=4k \
--numjobs=16 --size=1G --runtime=60 --time_based \
--direct=1 --group_reporting
Typical results show:
- HW RAID1: ~15% overhead from abstraction layer
- ZFS Mirror: More consistent latency under load
For optimal ZFS mirror setup:
# Recommended creation parameters
zpool create -o ashift=12 tank mirror /dev/disk/by-id/ata-* \
-O compression=lz4 \
-O atime=off \
-O recordsize=128K
Key configuration notes:
- Always use disk/by-id to avoid device name changes
- ashift=12 ensures proper 4K sector alignment
- Enable compression (cost-free performance gain)
Essential commands for ongoing management:
# Check pool health
zpool status -v
# Scrub for silent errors
zpool scrub tank
# View error counters
zpool status -v | grep -A 10 "errors:"
When setting up redundant storage, administrators face a critical architectural decision: whether to implement hardware RAID1 and then layer ZFS on top, or let ZFS handle mirroring natively. This choice fundamentally impacts how error detection and correction mechanisms operate.
# Example ZFS mirror creation (preferred approach)
zpool create tank mirror sda sdb
zfs set compression=lz4 tank
ZFS's end-to-end checksumming works most effectively when it controls the raw disks. In a hardware RAID configuration:
- The RAID controller abstracts physical disks
- ZFS cannot detect which specific disk contains corrupt data
- Scrubbing operations become less effective
Consider a silent corruption event:
Configuration | Detection Capability |
---|---|
HW RAID1 + ZFS | Knows data is corrupt but can't identify faulty disk |
ZFS Mirror | Identifies exactly which disk returned bad blocks |
While you mentioned performance isn't a priority, it's worth noting:
# Compare IOPS benchmarks
# HW RAID1 (cache enabled):
fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k --numjobs=16 --size=1G --runtime=60 --time_based --end_fsync=1
# ZFS Mirror (direct):
fio --name=randwrite --ioengine=libaio --rw=randwrite --bs=4k --numjobs=16 --size=1G --runtime=60 --time_based --end_fsync=1 --filename=/tank/testfile
For maximum data integrity:
- Configure disks as JBOD in RAID controller
- Disable controller caching
- Let ZFS manage the mirroring entirely
The only exception might be when using battery-backed cache controllers, where write performance might benefit from the hardware layer.
When checking pool health:
zpool status -v
zpool scrub tank
zdb -l /dev/sda
These commands provide significantly more detailed information when ZFS controls the disks directly.