Chapter 20: I/O and Filesystem Tuning for Production
Chapter 20: I/O and Filesystem Tuning for Production
Storage bottlenecks are among the most frequent causes of tail latency degradation in stateful systems. Without deliberate device and filesystem configuration, fast hardware SSDs spend substantial time waiting on software locks, synchronous write stalls, excessive journal commits, and uncoordinated background discards.
This chapter provides a production guide to configuring I/O schedulers, filesystem mount flags, block queue depths, dirty page thresholds, and NVMe driver tuning.
I/O Scheduler Selection by Workload
Configure the optimal block I/O scheduler per device type via udev rules:
# /etc/udev/rules.d/60-io-schedulers.rules
# NVMe drives: use 'none' (direct hardware submission)
ACTION=="add|change", KERNEL=="nvme[0-9]*n[0-9]*", ATTR{queue/scheduler}="none"
# SATA SSDs and fast cloud virtual disks: use 'mq-deadline'
ACTION=="add|change", KERNEL=="sd[a-z]|vd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# Mechanical hard drives (rotational): use 'bfq'
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"Apply immediately without rebooting:
sudo udevadm trigger --subsystem-match=blockFilesystem Mount Options for Performance
When mounting production filesystems for databases, message queues, and high-throughput logging:
Recommended XFS Mount Options
# /etc/fstab entry for high-performance XFS database volume
UUID=... /var/lib/postgresql xfs defaults,noatime,nodiratime,allocsize=64M,logbufs=8,logbsize=256k 0 2noatime,nodiratime: Eliminates access time write amplification.allocsize=64M: Sets delayed allocation pre-allocation buffer size, preventing extent fragmentation during large appends.logbufs=8,logbsize=256k: Maximizes in-memory journal buffer size before flushing transactions to disk.
Recommended ext4 Mount Options
# /etc/fstab entry for high-performance ext4
UUID=... /data ext4 defaults,noatime,data=ordered,delalloc,commit=30 0 2commit=30: Batches journal commits to disk every 30 seconds instead of the default 5 seconds, dramatically reducingjbd2journal write frequency.
Writeback and Dirty Page Tuning
On systems with 64GB to 512GB+ RAM, default percentage-based dirty ratios cause catastrophic multi-second write stalls:
# /etc/sysctl.d/99-storage-writeback.conf
# Start background asynchronous writeback at 256 MB of dirty data
vm.dirty_background_bytes = 268435456
# Force synchronous blocking writeback if dirty pages reach 1 GB
vm.dirty_bytes = 1073741824
# Expire dirty pages after 15 seconds
vm.dirty_expire_centisecs = 1500
# Wakeup writeback flusher threads every 2 seconds
vm.dirty_writeback_centisecs = 200This enforces smooth, continuous background streaming of dirty pages to persistent storage, preventing massive multi-gigabyte flush bursts that overwhelm disk controller queues.
Device-Level Parameters: Queue Depth and Read-Ahead
Tune block layer device queues:
# Increase block layer request queue depth to prevent request starvation
echo 1024 | sudo tee /sys/block/nvme0n1/queue/nr_requests
# Tune read-ahead based on workload:
# For random I/O (OLTP databases): set read-ahead to 0 to avoid wasted reads
echo 0 | sudo tee /sys/block/nvme0n1/queue/read_ahead_kb
# For sequential streaming (Kafka, Hadoop, video): set read-ahead to 512KB
echo 512 | sudo tee /sys/block/nvme0n1/queue/read_ahead_kbSSD and NVMe-Specific Tuning
Disable Continuous Discard (
nodiscard): Real-time TRIM on every file deletion incurs severe synchronous latency penalties. Mount withnodiscardand execute scheduled periodic trims viafstrim.timer:sudo systemctl enable --now fstrim.timerNVMe Interrupt Polling (
io_poll): For sub-10\(\mu\)s database latency, enable polling queues on high-end NVMe drives:echo 1 | sudo tee /sys/block/nvme0n1/queue/io_pollHardware Sector Size: Ensure the NVMe drive is formatted with native 4096-byte LBA sectors (4Kn) rather than emulated 512-byte sectors (512e) to eliminate Read-Modify-Write penalties inside the flash controller:
sudo nvme id-ns -H /dev/nvme0n1 | grep -i "lba format"
Validating I/O Performance Improvements
Execute before-and-after tests using fio and biolatency to verify that queue times and p99 completion latency dropped:
# 1. Measure disk I/O latency distribution in real time using eBPF
sudo biolatency-bpfcc -m 5 1
# 2. Execute standardized 4KB random write benchmark
fio --name=randwrite --filename=/data/test.bin --size=10G --bs=4k \
--rw=randwrite --ioengine=io_uring --direct=1 --iodepth=32 \
--numjobs=4 --runtime=60 --group_reporting --time_basedA properly tuned storage stack should show: - 0% multi-second latency outliers in biolatency. - Tightly clustered p99 latency in fio (< 200\(\mu\)s on NVMe). - Predictable steady-state write throughput without periodic dips.