NVMe RAID0 Stripe and Chunk Size for Game Saves: Write Amplification Measured

Two NVMe drives in RAID0 can double sequential throughput or make autosaves slower, depending on the stripe and chunk size you pick. Game saves are not large sequential files; they are a mix of 4K metadata writes, 64K to 1M region files, and periodic full-world snapshots. Setting a 512K chunk size for a workload dominated by 4K journal writes multiplies the write amplification, cuts drive endurance, and raises the tail latency on every save.

This article measures write amplification for common chunk sizes against a game-save pattern and gives the layout that keeps saves under two seconds at 5 GB world size. It assumes enterprise TLC drives with power-loss protection, the kind found in bare-metal game server hardware with NVMe storage, because consumer QLC behaves very differently under sustained writes.

Why RAID0 changes the write pattern

In RAID0 the controller or mdadm splits each write into chunks and distributes them across drives. A 4K write inside a 512K chunk still touches one drive, but the drive must write at least a page, and often an entire 16K or 32K indirection unit. If the file system then issues a 128K journal write that straddles a chunk boundary, it becomes two partial writes, each of which may require a read-modify-write on the SSD side.

That read-modify-write is the amplification. A 4K logical write becomes 4K read plus 16K to 32K write, and on TLC the host write is followed by an internal program/erase cycle that is not visible at the device counters but shows up in endurance and latency.

The save workload in numbers

A 5 GB Valheim world writes 4K metadata updates every few seconds, 64K to 256K region files as players build, and a full 5 GB snapshot on the autosave interval. A Rust save is worse, with 30,000 to 90,000 entity records and a snapshot every 300 to 600 seconds. The mix matters more than the total bytes: 70% of the operations are small and random.

Save component Size Pattern Share of ops
Metadata/journal 4K Random write 55%
Region/entity files 64-256K Mixed 35%
Full snapshot 2-8 GB Sequential 10%

Optimizing the 10% sequential case at the expense of the 55% random case is how you get a configuration that benchmarks well on a file copy and stalls during a fight.

Measured amplification by chunk size

We ran a 20-minute fio profile mimicking that mix against two 1.92 TB enterprise TLC drives in mdadm RAID0, measuring host writes against logical writes. All runs used ext4 with a 4K block size and the same 15 GB data set.

Chunk size Write amp 4K p99 latency Snapshot time (5 GB) Verdict
16K 1.9x 1.4 ms 9.1 s Poor sequential
64K 1.35x 0.9 ms 6.4 s Balanced
128K 1.22x 0.7 ms 4.9 s Best overall
256K 1.18x 0.8 ms 4.1 s Good
512K 1.15x 1.3 ms 3.8 s Hurts small IO

The 128K chunk gives the best balance for this mix. At 512K the amplification is slightly lower because large writes align better, but the 4K p99 climbs by 40% because small writes now queue behind 512K chunk allocations on a single drive.

Why 16K chunks lose despite alignment

The intuition is that a 16K chunk matches the SSD indirection unit, so there should be no read-modify-write. In practice, 16K chunks spread each file across both drives at very fine granularity, which halves the effective write coalescing window in the drive’s SLC cache. The drives see many small writes to the same logical region interleaved with writes to the other drive, and the cache fills with partial pages.

The measured result was 1.9x write amplification, nearly double the 128K layout. Sequential throughput also fell, from 6.4 GB/s to 4.1 GB/s, because each drive’s write stream is fragmented. Fine-grained striping suits large database scans, not save files.

File system and alignment settings

Create the array with mdadm --create --level=0 --chunk=128 --raid-devices=2, then make the file system with a stride matching the chunk: mkfs.ext4 -E stride=32,stripe-width=64 for a 4K block. Misaligned ext4 on a 128K chunk wastes one full chunk per metadata write and can add 10 to 15% amplification on its own.

Disable atime updates with the noatime mount option, and keep the journal on the same array rather than on a separate small partition. A separate journal partition on drive 1 only doubles the single-drive write rate and cuts endurance on that drive by a third. For XFS, use su=128k and sw=2 at mkfs time instead.

Endurance budget with amplification included

The measured amplification is not a theoretical penalty; it sets your replacement schedule. Multiply logical save traffic by the amplification factor, divide by the array width, and compare against the drive’s daily write endurance. A layout that looks comfortable at 1.15x can be past its rating at 1.9x, and the drives that die first are always the ones carrying the journal.

Take a 5 GB world that snapshots every 10 minutes and receives 200 MB of incremental writes per hour. That is 30 GB of snapshots per hour plus 0.2 GB of increments, or roughly 726 GB per day. At 1.22x amplification the drives absorb 886 GB per day, split across two drives at 443 GB each. A 1 DWPD 1.92 TB drive handles 1.92 TB per day, so you are at 23% of endurance.

The margin disappears with a 30-second autosave interval, which raises snapshot traffic to 14 TB per day and pushes you past 3 drive writes per day. That is the point where RAID0 stops being a cost saving and starts being a replacement schedule.

Mirror versus stripe for the live world

If a single save freeze above two seconds is unacceptable, or if losing both drives on a rebuild is a business risk, use a mirror and put the snapshot on a separate drive. RAID1 halves the write throughput advantage but keeps the array alive through one drive failure, and game saves are small enough that 3 GB/s is plenty.

A mirror also removes the chunk-size question entirely: chunk size has no effect on RAID1 write alignment, so there is nothing to tune and nothing to misconfigure. For most survival servers a two-drive mirror plus an off-box snapshot is the layout that costs the least sleep.

When RAID0 is the wrong answer

Striping the live world is a bet that both drives stay healthy and that you can rebuild a 5 GB save from elsewhere when they do not. On a rented node that usually means a provider-side replacement window of four to twenty-four hours, which is longer than most communities will tolerate mid-wipe.

RAID0 makes sense for the snapshot target and the mod cache, not for the live world if you cannot tolerate the failure mode. Keep the save on a mirror and the striping for data you can regenerate. When comparing dedicated servers with dual NVMe bays for game save arrays, check that the chassis exposes both drives as separate devices so you can choose the layout rather than inheriting a vendor preset.

Leave a Reply