Explore plans starting at ₹699/mo →
Performance & Monitoring

NVMe SSD Performance Tuning for Databases: Maximize IOPS and Throughput

S
ServerRaja
9 min read
#Linux#SSD#NVMe#Database#Storage#PostgreSQL#Performance#IOPS#MySQL
NVMe SSD Performance Tuning for Databases: Maximize IOPS and Throughput

Why NVMe SSD Tuning Matters

NVMe SSDs deliver dramatically higher IOPS and lower latency than traditional SSDs or HDDs. However, default Linux settings are often not optimized for NVMe drives. Without proper tuning, you may be leaving 30-50% of potential performance on the table.

ServerRaja cloud servers offer NVMe SSD storage that can deliver hundreds of thousands of IOPS. This guide shows you how to extract maximum performance from your NVMe drives for database workloads.

Verifying Your NVMe Drive

First, confirm you have an NVMe drive and check its capabilities:

# List NVMe devices
sudo nvme list

# Get detailed device information sudo nvme id-ctrl /dev/nvme0n1

# Check current firmware version sudo nvme fw-log /dev/nvme0n1

# View SMART health data sudo nvme smart-log /dev/nvme0n1

# Check current I/O statistics cat /proc/diskstats | grep nvme iostat -x 1 5 | grep nvme ```

I/O Scheduler Configuration

The I/O scheduler determines how read and write requests are queued. For NVMe drives, the `none` (noop) scheduler is optimal since NVMe has its own internal scheduling:

# Check current scheduler
cat /sys/block/nvme0n1/queue/scheduler

# Set to none (noop) for NVMe echo none | sudo tee /sys/block/nvme0n1/queue/scheduler

# Make permanent via udev rule cat <<EOF | sudo tee /etc/udev/rules.d/60-nvme-scheduler.rules ACTION=="add|change", KERNEL=="nvme[0-9]*n[0-9]", ATTR{queue/scheduler}="none" EOF

# Reload udev rules sudo udevadm control --reload-rules sudo udevadm trigger ```

Filesystem Optimization

Using XFS for Database Workloads

XFS is generally the best filesystem for database workloads on NVMe:

# Create XFS filesystem with optimized options
sudo mkfs.xfs -f -d agcount=32 -l size=128m /dev/nvme0n1p1

# Mount with performance options sudo mount -o noatime,nodiratime,logbufs=8,logbsize=256k,allocsize=64m /dev/nvme0n1p1 /data

# Add to /etc/fstab for persistence echo '/dev/nvme0n1p1 /data xfs noatime,nodiratime,logbufs=8,logbsize=256k,allocsize=64m 0 0' | sudo tee -a /etc/fstab ```

Using ext4 as an Alternative

# Create ext4 filesystem
sudo mkfs.ext4 -O ^has_journal -E stride=128,stripe-width=256 /dev/nvme0n1p1

# Or with journal (for data safety) sudo mkfs.ext4 -E stride=128,stripe-width=256 /dev/nvme0n1p1

# Mount with optimizations sudo mount -o noatime,nodiratime,data=writeback,barrier=0,commit=60 /dev/nvme0n1p1 /data ```

Kernel I/O Parameters

Optimize kernel parameters for NVMe performance:

# /etc/sysctl.d/99-nvme-performance.conf

# Increase the maximum number of I/O requests vm.nr_requests = 4096

# Reduce dirty page writeback frequency vm.dirty_ratio = 40 vm.dirty_background_ratio = 10

# Set dirty page writeback interval (centiseconds) vm.dirty_writeback_centisecs = 3000 vm.dirty_expire_centisecs = 6000

# Increase max sectors per I/O request # (check current: cat /sys/block/nvme0n1/queue/max_sectors_kb) ```

sudo sysctl -p /etc/sysctl.d/99-nvme-performance.conf

# Increase queue depth for NVMe echo 1024 | sudo tee /sys/block/nvme0n1/queue/nr_requests

# Increase read-ahead buffer echo 256 | sudo tee /sys/block/nvme0n1/queue/read_ahead_kb ```

Database-Specific Tuning

PostgreSQL on NVMe

Optimize PostgreSQL configuration for NVMe storage:

# postgresql.conf

# Shared buffers - 25% of total RAM shared_buffers = 4GB

# Effective cache size - 75% of total RAM effective_cache_size = 12GB

# Increase WAL buffers for write performance wal_buffers = 64MB

# Use direct I/O for better performance effective_io_concurrency = 200 maintenance_io_concurrency = 200

# Async commit for better write throughput (trade durability for speed) # synchronous_commit = off # Only for non-critical data

# Random page cost - lower for SSDs (default is 4.0 for HDD) random_page_cost = 1.1 seq_page_cost = 1.0

# Increase work memory for complex queries work_mem = 256MB

# Parallel query settings max_parallel_workers_per_gather = 4 max_parallel_workers = 8 max_worker_processes = 16

# Checkpoint tuning checkpoint_completion_target = 0.9 max_wal_size = 4GB min_wal_size = 1GB ```

MySQL/MariaDB on NVMe

Optimize InnoDB for NVMe storage:

# /etc/mysql/mysql.conf.d/nvme-optimizations.cnf

[mysqld] # InnoDB buffer pool - 70-80% of available RAM innodb_buffer_pool_size = 12G innodb_buffer_pool_instances = 12

# Use O_DIRECT for I/O (bypasses OS cache) innodb_flush_method = O_DIRECT

# Increase I/O capacity for NVMe innodb_io_capacity = 10000 innodb_io_capacity_max = 20000

# Flush neighbors setting - 0 for NVMe (no need to flush adjacent pages) innodb_flush_neighbors = 0

# Increase log file size for better write performance innodb_log_file_size = 2G innodb_log_buffer_size = 256M

# Doublewrite buffer can be disabled on NVMe with battery-backed cache # innodb_doublewrite = off

# Increase read/write I/O threads innodb_read_io_threads = 16 innodb_write_io_threads = 16

# Adaptive hash index innodb_adaptive_hash_index = ON

# Change buffer innodb_change_buffer_max_size = 25

# Page size - consider 16K (default) or 64K for NVMe innodb_page_size = 16K ```

Benchmarking Database Performance

PostgreSQL Benchmarking with pgbench

# Initialize pgbench
pgbench -i -s 100 mydb

# Run standard benchmark pgbench -c 32 -j 8 -T 300 mydb

# Read-only benchmark pgbench -c 32 -j 8 -T 300 -S mydb ```

MySQL Benchmarking with sysbench

# Prepare benchmark tables
sysbench oltp_read_write \
  --mysql-host=localhost \
  --mysql-user=root \
  --mysql-password=password \
  --mysql-db=sbtest \
  --tables=10 \
  --table-size=1000000 \
  prepare

# Run read-write benchmark sysbench oltp_read_write \ --mysql-host=localhost \ --threads=32 \ --time=300 \ --report-interval=10 \ run

# Run read-only benchmark sysbench oltp_read_only \ --mysql-host=localhost \ --threads=32 \ --time=300 \ run ```

Monitoring NVMe Health

Set up SMART monitoring for your NVMe drives:

# Install smartmontools
sudo apt install smartmontools

# Enable NVMe monitoring sudo smartctl -a /dev/nvme0n1

# Set up automatic monitoring cat <<EOF | sudo tee /etc/smartd.conf /dev/nvme0n1 -a -o on -S on -s (S/../.././02|L/../../6/03) -m [email protected] EOF

sudo systemctl enable --now smartd ```

Conclusion

NVMe SSDs are a game-changer for database performance, but only when properly configured. Set the I/O scheduler to `none`, use an optimized filesystem mount, tune your database configuration for SSD characteristics, and benchmark regularly. ServerRaja NVMe cloud servers provide the raw performance; these optimizations help your databases fully utilize it.

NVMe SSD Tuning for Databases | ServerRaja