Tuning for Workloads — defaults are for nobody.
Default ZFS settings are not optimized for any specific workload. Databases have completely different needs than media storage. Compression, ARC settings, record sizes, and logbias all dramatically affect performance. Here's how to tune for each.
Databases (PostgreSQL, MySQL)
The database recipe
zfs create -o recordsize=16K \
-o logbias=throughput \
-o primarycache=metadata \
-o compression=lz4 \
-o atime=off \
rpool/srv/postgres
Why 16K? PostgreSQL operates in 8K blocks. Using the default 128K recordsize causes massive read/write amplification — ZFS reads 128K to service an 8K request. 16K gives the best balance (8K works too but 16K handles mixed workloads better).
SLOG recommended. Databases use sync writes heavily. Without an SLOG, every commit waits for the write to hit spinning rust. An enterprise NVMe SLOG with power loss protection drops commit latency from milliseconds to microseconds.
VM storage
The VM recipe
# Use ZVOLs, not datasets, for VM disks
zfs create -V 40G -s \
-o volblocksize=16K \
-o compression=lz4 \
rpool/srv/vms/my-vm
# NEVER use RAIDZ for VM storage. Use mirrors.
Why ZVOLs? VMs need raw block access. Datasets add a POSIX layer that VMs don't need and that adds overhead. ZVOLs give the guest OS direct block access through ZFS.
Why not RAIDZ? VMs generate random I/O patterns. RAIDZ's read-modify-write penalty destroys VM performance. Mirrors handle random I/O linearly.
Media & large files
The media recipe
zfs create -o recordsize=1M \
-o compression=zstd \
-o atime=off \
rpool/srv/media
Why 1M recordsize? Large sequential files (video, images, backups) benefit from large records. ZFS reads and writes in bigger chunks, reducing metadata overhead and improving throughput. For small files, 128K (default) is fine. For media, 1M is optimal.
Note on compression: Already-compressed media (MP4, FLAC, JPEG) won't compress further. But metadata, subtitles, NFO files, and text will compress 3-5x. ZSTD gives better ratios than LZ4 with slightly more CPU. For media servers, the tradeoff is worth it.
General file storage
The general recipe
zfs create -o compression=lz4 \
-o atime=off \
rpool/srv/data
LZ4 compression is nearly free in terms of CPU and typically gives 1.5-2x space savings.
There is almost no reason to leave compression off. Disabling atime prevents
unnecessary disk writes every time a file is read.
Quick reference
| Workload | Storage Type | recordsize | Compression | SLOG? | VDEV Type |
|---|---|---|---|---|---|
| PostgreSQL | Dataset or ZVOL | 8K-16K | lz4 | Yes | Mirrors |
| MySQL | Dataset or ZVOL | 16K | lz4 | Yes | Mirrors |
| VM disks | ZVOL | volblocksize=16K | lz4 | Recommended | Mirrors |
| NFS shares | Dataset | 128K | lz4 | Yes | Mirrors or RAIDZ2 |
| Media files | Dataset | 1M | zstd | No | RAIDZ2 |
| Backups/archives | Dataset | 1M | zstd or gzip | No | RAIDZ2/3 |
| Containers | Dataset | 128K | lz4 | No | Mirrors + Special |
| General files | Dataset | 128K | lz4 | No | Any |