Tuned Profiles
Why use tuned:
- Red Hat's system tuning daemon
- Pre-configured profiles for different workloads
- Dynamic tuning based on system state
- Easy to customize
Install and enable tuned:
sudo dnf install -y tuned tuned-utils
sudo systemctl enable --now tuned
Available profiles:
# List available profiles
sudo tuned-adm list
# Recommended profiles for storage:
# - throughput-performance: Maximum throughput
# - latency-performance: Minimum latency
# - network-latency: Network-optimized
Apply profile:
# For maximum throughput
sudo tuned-adm profile throughput-performance
# For minimum latency
sudo tuned-adm profile latency-performance
# Verify active profile
sudo tuned-adm active
Custom Tuned Profile for NVMe-TCP
Create custom profile optimized for NVMe-TCP storage:
# Create custom profile directory
sudo mkdir -p /etc/tuned/nvme-tcp-storage
# Create profile configuration
sudo tee /etc/tuned/nvme-tcp-storage/tuned.conf > /dev/null <<'EOF'
[main]
summary=Optimized for NVMe-TCP storage workloads
include=throughput-performance
[cpu]
governor=performance
energy_perf_bias=performance
min_perf_pct=100
[sysctl]
# Network tuning
net.core.rmem_max=134217728
net.core.wmem_max=134217728
net.core.rmem_default=16777216
net.core.wmem_default=16777216
net.ipv4.tcp_rmem=4096 87380 67108864
net.ipv4.tcp_wmem=4096 65536 67108864
net.core.netdev_max_backlog=30000
net.core.somaxconn=4096
net.ipv4.tcp_window_scaling=1
net.ipv4.tcp_timestamps=0
net.ipv4.tcp_sack=1
# VM tuning
vm.dirty_ratio=10
vm.dirty_background_ratio=5
vm.swappiness=10
# ARP cache
net.ipv4.neigh.default.gc_thresh1=4096
net.ipv4.neigh.default.gc_thresh2=8192
net.ipv4.neigh.default.gc_thresh3=16384
# ARP settings for same-subnet multipath (CRITICAL)
# Prevents ARP responses on wrong interface when multiple NICs share same subnet
# See: Network Concepts documentation for detailed explanation
net.ipv4.conf.all.arp_ignore=2
net.ipv4.conf.default.arp_ignore=2
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.default.arp_announce=2
# Interface-specific (adjust interface names as needed)
net.ipv4.conf.ens1f0.arp_ignore=2
net.ipv4.conf.ens1f1.arp_ignore=2
net.ipv4.conf.ens1f0.arp_announce=2
net.ipv4.conf.ens1f1.arp_announce=2
[disk]
# I/O scheduler for NVMe
elevator=none
[script]
script=${i:PROFILE_DIR}/script.sh
EOF
# Create script for NIC tuning
sudo tee /etc/tuned/nvme-tcp-storage/script.sh > /dev/null <<'EOF'
#!/bin/bash
. /usr/lib/tuned/functions
start() {
# Tune storage NICs (adjust interface names)
for iface in ens1f0 ens1f1; do
if [ -d "/sys/class/net/$iface" ]; then
# Ring buffers
ethtool -G $iface rx 4096 tx 4096 2>/dev/null || true
# Interrupt coalescing
ethtool -C $iface rx-usecs 50 tx-usecs 50 2>/dev/null || true
# Offloads
ethtool -K $iface tso on gso on gro on 2>/dev/null || true
# Flow control
ethtool -A $iface rx on tx on 2>/dev/null || true
fi
done
return 0
}
stop() {
return 0
}
process $@
EOF
# Make script executable
sudo chmod +x /etc/tuned/nvme-tcp-storage/script.sh
# Apply custom profile
sudo tuned-adm profile nvme-tcp-storage
# Verify
sudo tuned-adm active
The values in this custom tuned profile are starting points for testing. Actual optimal values depend on:
-
Driver/firmware limitations: Check NIC and storage driver documentation for supported buffer sizes and queue depths.
-
Hardware capabilities: Use
ethtool -g <interface>to verify ring buffer limits. -
Workload characteristics: Sequential vs. random I/O, block sizes, concurrency.
Always validate with performance monitoring (iostat -x 1, sar -n DEV 1, perf, vendor telemetry) before deploying to production. Measure baseline performance first, then test changes incrementally.
IRQ Affinity for Storage NICs
Automatic IRQ distribution:
# Install irqbalance
sudo dnf install -y irqbalance
# Configure for storage workload
sudo tee /etc/sysconfig/irqbalance > /dev/null <<EOF
IRQBALANCE_BANNED_CPUS=00000001
IRQBALANCE_ARGS="--policyscript=/usr/local/bin/irq-policy.sh"
EOF
# Enable and start
sudo systemctl enable --now irqbalance
Manual IRQ affinity (for specific control):
# Find storage NIC IRQs
grep ens1f0 /proc/interrupts | awk '{print $1}' | sed 's/://'
# Pin IRQs to specific CPUs (example: CPUs 2-5)
#!/bin/bash
INTERFACE="ens1f0"
CPU_START=2
for IRQ in $(grep $INTERFACE /proc/interrupts | awk '{print $1}' | sed 's/://'); do
MASK=$(printf "%x" $((1 << $CPU_START)))
echo $MASK > /proc/irq/$IRQ/smp_affinity
echo "IRQ $IRQ -> CPU $CPU_START (mask: $MASK)"
CPU_START=$((CPU_START + 1))
done
NUMA Optimization
Check NUMA topology:
# Install numactl
sudo dnf install -y numactl
# Show NUMA topology
numactl --hardware
# Show NIC NUMA node
cat /sys/class/net/ens1f0/device/numa_node
Optimize for NUMA:
# Pin NVMe-TCP connections to NUMA node with storage NICs
# Example: Identify NUMA node for network interfaces
# Find NUMA node for your NVMe interface
cat /sys/class/net/eth1/device/numa_node
# Set IRQ affinity for NVMe interfaces to matching NUMA node
# See IRQ affinity section below
NVMe-TCP uses native NVMe multipathing, not dm-multipath. There is no multipathd service to tune for NVMe-TCP.
Kernel Boot Parameters
Edit GRUB configuration:
# Edit /etc/default/grub
sudo vi /etc/default/grub
# Add to GRUB_CMDLINE_LINUX:
# isolcpus=2,3,10,11 nohz_full=2,3,10,11 rcu_nocbs=2,3,10,11 intel_iommu=on iommu=pt
# Update GRUB
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # BIOS
# OR
sudo grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg # UEFI
# Reboot
sudo reboot
Parameter explanations:
-
isolcpus- Isolate CPUs from scheduler (dedicate to storage I/O) -
nohz_full- Disable timer ticks on isolated CPUs -
rcu_nocbs- Offload RCU callbacks from isolated CPUs -
intel_iommu=on iommu=pt- Enable IOMMU passthrough
These are general CPU and NUMA optimizations that improve overall system performance for I/O-intensive workloads. They do not directly affect NVMe-TCP protocol behavior. Measure baseline performance before and after changes to validate impact in your environment. The nvme_core.multipath=Y parameter (if not already set) directly affects NVMe multipath behavior.