Filesystem-level compression sounds like free disk space, and on a small VPS with a 25-40 GB root volume it often is. The catch is CPU cost and the write-amplification that comes with copy-on-write. This article compares btrfs with zstd against plain ext4 across throughput, space savings, and CPU overhead, using a reproducible benchmark so you can rerun it on your own box rather than trusting a blog post.
Why ext4 Cannot Compress
ext4 is a mature, journaling, in-place filesystem. It has no compression layer, so every byte written lands on disk 1:1. Its strengths are predictable latency, low CPU overhead, and tooling that never surprises you. comprerssion on ext4 is only possible through a stacked device (dm-verity variants, or a FUSE layer), both of which add latency and complexity that a small VPS cannot afford.
btrfs builds compression into the filesystem. Data and metadata are compressed before they hit the extent tree, and checksums protect every block. Set it once at mount time or per-file with chattr, and it applies transparently.
Setting Up a Comparable Test
Mount btrfs with zstd and compression level 3, then create the ext4 volume of the same nominal size. Use the same backing device class on both so the numbers are comparable.
# btrfs with zstd
mkfs.btrfs -f /dev/vdb
mount -o compress=zstd:3,noatime,ssd /dev/vdb /mnt/btrfs
# enable inherited compression for future files
chattr +c /mnt/btrfs/data
# ext4 baseline
mkfs.ext4 -F /dev/vdc
mount -o noatime /dev/vdc /mnt/ext4
Benchmark Results
Test box: 2 vCPU, 4 GB RAM, NVMe under QEMU. Two workloads: a source tree of 120,000 small text files (4.1 GB inflated), and a database-style single file written with fio at 4k random. Numbers are medians of three runs.
| Workload | ext4 | btrfs+zstd:3 | Delta |
|---|---|---|---|
| Text tree space used | 4.10 GB | 1.62 GB | -60% |
| Sequential write (1M) | 410 MB/s | 352 MB/s | -14% |
| Sequential read (1M) | 498 MB/s | 566 MB/s | +14% |
| 4k random write IOPS | 21,800 | 13,900 | -36% |
| CPU during write | ~8% | ~54% | +46 pts |
The headline: 60% disk saved on text, but 36% fewer random-write IOPS and a sixfold jump in CPU load during sustained writes. That CPU cost is the real constraint on a 2 vCPU box, and it also shows up as disk-write amplification if you have enabled snapshots.
When Each Choice Wins
Pick btrfs + zstd when your disk is dominated by compressible data: source code, logs, JSON, HTML, documentation, container layers. You trade CPU and random-write IOPS for capacity and often faster sequential reads, because reading compressed data pulls fewer bytes from the device.
Pick ext4 when your workload is write-heavy and random, or when CPU is the scarce resource. Databases with 4k random writes and any service that fsyncs frequently will feel the btrfs penalty directly. On a 1 vCPU instance, do not enable zstd on the database volume.
A hybrid is common and effective: ext4 or raw btrfs for the database, and a separate zstd-compressed subvolume for logs and web roots. Use chattr +c to keep the choice per-directory without repartitioning.
Measuring Your Own Numbers
# space
compsize /mnt/btrfs/data
# io profile
fio --name=rw4k --rw=randwrite --bs=4k --numjobs=4 --size=1G \
--directory=/mnt/btrfs/fio --runtime=30 --time_based --group_reporting
# per-file compression ratio
btrfs filesystem du -s --human-readable /mnt/btrfs/data/*
Run the same fio job against both mounts before you commit. If you are provisioning a new instance and want to size the volume against the workload rather than the other way around, the disk and CPU tradeoffs are laid out in the cloud VPS benefits comparison. And if you later find writes amplifying beyond what the data justifies, the method in the managed versus unmanaged operations overview will help you trace it back to snapshots or scrubm, not just the filesystem.




Leave a Reply
You must be logged in to post a comment.