Disclaimer: This content is for reference only. Always consult official vendor documentation for your distribution. Test thoroughly in a lab environment before production use. In case of conflicts, vendor documentation takes precedence.
Network Performance Optimization
MTU Configuration (Jumbo Frames)
Why use jumbo frames:
- Reduces CPU overhead by lowering packet count and interrupt rate
- Improves throughput for large sequential I/O (actual gains vary by workload)
- Lowers interrupt rate
- Recommended for high-performance storage (validate with benchmarks)
Configuration:
# Set MTU 9000 on storage interfaces
ip link set eth0 mtu 9000
ip link set eth1 mtu 9000
# Verify
ip link show eth0 | grep mtu
TCP Tuning
Optimize TCP for storage traffic:
# /etc/sysctl.d/99-iscsi-tuning.conf
# Increase TCP buffer sizes
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
# Increase connection tracking
net.netfilter.nf_conntrack_max = 1048576
# Optimize for low latency
net.ipv4.tcp_low_latency = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_timestamps = 1
# Apply settings
sysctl -p /etc/sysctl.d/99-iscsi-tuning.conf
iSCSI Session Tuning
Queue Depth
Increase queue depth for better performance:
# Check current queue depth
cat /sys/block/sda/device/queue_depth
# Increase queue depth (per device)
echo 128 > /sys/block/sda/device/queue_depth
# Make persistent via udev rule (adjust vendor to match your storage)
# /etc/udev/rules.d/99-iscsi-queue-depth.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{device/vendor}=="VENDOR*", ATTR{device/queue_depth}="128"
Recommended values:
- SSD/Flash storage: 128-256
- HDD storage: 32-64
Session Parameters
Optimize iSCSI session settings:
# Increase max receive data segment length
iscsiadm -m node -T <target_iqn> -p <portal_ip> \
-o update -n node.conn[0].iscsi.MaxRecvDataSegmentLength -v 262144
# Increase first burst length
iscsiadm -m node -T <target_iqn> -p <portal_ip> \
-o update -n node.session.iscsi.FirstBurstLength -v 262144
# Increase max burst length
iscsiadm -m node -T <target_iqn> -p <portal_ip> \
-o update -n node.session.iscsi.MaxBurstLength -v 1048576
# Enable immediate data
iscsiadm -m node -T <target_iqn> -p <portal_ip> \
-o update -n node.conn[0].iscsi.ImmediateData -v Yes
# Increase number of outstanding R2Ts
iscsiadm -m node -T <target_iqn> -p <portal_ip> \
-o update -n node.session.iscsi.MaxOutstandingR2T -v 1
I/O Scheduler Optimization
For SSD/Flash storage:
# Use 'none' or 'noop' scheduler for flash storage
echo none > /sys/block/sda/queue/scheduler
# Make persistent via udev rule
# /etc/udev/rules.d/99-iscsi-scheduler.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="none"
For HDD storage:
# Use 'mq-deadline' for HDD
echo mq-deadline > /sys/block/sda/queue/scheduler
CPU and IRQ Optimization
IRQ Affinity
Distribute interrupts across CPUs:
# Install irqbalance
# RHEL/Rocky/AlmaLinux:
dnf install -y irqbalance
# Debian/Ubuntu:
apt install -y irqbalance
# Enable and start
systemctl enable --now irqbalance
# Or manually set IRQ affinity
# Find IRQ for network interface
grep eth0 /proc/interrupts
# Set IRQ to specific CPU (example: IRQ 45 to CPU 2)
echo 4 > /proc/irq/45/smp_affinity # 4 = binary 0100 = CPU 2
CPU Isolation (Advanced)
Dedicate CPUs to storage I/O:
# Edit kernel boot parameters
# /etc/default/grub
GRUB_CMDLINE_LINUX="isolcpus=2,3,10,11"
# Update grub
# RHEL/Rocky/AlmaLinux:
grub2-mkconfig -o /boot/grub2/grub.cfg
# Debian/Ubuntu:
update-grub
# Reboot required
reboot
Note: CPU isolation (isolcpus) is a general system optimization for I/O-intensive workloads. It does not directly affect iSCSI protocol behavior. Measure baseline performance before and after changes to validate impact in your environment.
Read-Ahead Tuning
Optimize read-ahead for workload:
# Check current read-ahead
blockdev --getra /dev/sda
# For random I/O workloads (databases):
blockdev --setra 256 /dev/sda # 128 KB
# For sequential I/O workloads (file servers):
blockdev --setra 8192 /dev/sda # 4 MB
# Make persistent via udev rule (adjust vendor to match your storage)
# /etc/udev/rules.d/99-iscsi-readahead.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{device/vendor}=="VENDOR*", ATTR{bdi/read_ahead_kb}="128"
Monitoring Performance
Key metrics to monitor:
# I/O statistics
iostat -x 1
# Network statistics
sar -n DEV 1
# iSCSI session statistics
iscsiadm -m session -P 3 | grep -A 20 "iSCSI Session State"
# Multipath I/O statistics
dmsetup status
# System-wide I/O
vmstat 1
Performance indicators:
- Low latency: < 1ms for flash storage
- High throughput: Near line speed (10Gbps = ~1.2 GB/s)
- Low CPU wait: iowait < 5%
- Balanced paths: Even I/O distribution across all paths
System-Level Optimizations
CPU Isolation for I/O Threads
Isolate CPUs for storage processing:
# In /etc/default/grub, add to GRUB_CMDLINE_LINUX:
GRUB_CMDLINE_LINUX="isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3"
Note: CPU isolation (isolcpus) is a general system optimization for I/O-intensive workloads. It does not directly affect iSCSI protocol behavior. Measure baseline performance before and after changes to validate impact in your environment.
Best Practice:
- Use
isolcpusonly if CPU contention is observed (high%sysduring I/O) - Monitor with
mpstat -P ALL 1to identify busy cores
Memory Configuration
Hugepages for large I/O buffers:
# /etc/sysctl.d/99-storage-performance.conf
vm.nr_hugepages = 1024
# For transparent hugepages (alternative)
echo always > /sys/kernel/mm/transparent_hugepage/enabled
Disable NUMA balancing for predictable latency:
echo 0 > /proc/sys/kernel/numa_balancing
Network Optimizations
TCP Buffer Tuning
Increase TCP buffer sizes for high throughput:
# /etc/sysctl.d/99-storage-tcp.conf
# TCP buffer sizes (min, default, max)
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Connection queue sizes
net.core.netdev_max_backlog = 30000
net.core.somaxconn = 4096
Network Interface Tuning
Increase ring buffer size:
# Check current settings
ethtool -g ens1f0
# Increase to maximum
ethtool -G ens1f0 rx 4096 tx 4096
Enable receive-side scaling (RSS):
# Check RSS configuration
ethtool -l ens1f0
# Set number of channels
ethtool -L ens1f0 combined 8
Interrupt coalescing for throughput:
# Reduce interrupts for high throughput
ethtool -C ens1f0 rx-usecs 100 tx-usecs 100
# For low latency (more interrupts)
ethtool -C ens1f0 rx-usecs 0 tx-usecs 0
Storage Layer Optimizations
I/O Scheduler Tuning
For SCSI/iSCSI Devices
Recommended: mq-deadline or none
# Check current scheduler
cat /sys/block/sda/queue/scheduler
# Set to mq-deadline (good for mixed workloads)
echo mq-deadline > /sys/block/sda/queue/scheduler
# Or set to none (lowest latency)
echo none > /sys/block/sda/queue/scheduler
Why: Modern storage arrays handle I/O scheduling internally; kernel scheduler adds latency.
Make persistent:
# Create udev rule: /etc/udev/rules.d/60-iosched.rules
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/scheduler}="mq-deadline"
Queue Depth Tuning
# Check current queue depth
cat /sys/block/sda/queue/nr_requests
# Increase to 256 (default is often 64 or 128)
echo 256 > /sys/block/sda/queue/nr_requests
Read-Ahead Configuration
# Check current read-ahead
blockdev --getra /dev/sda
# Set read-ahead (in 512-byte sectors)
# 16384 = 8MB read-ahead (good for sequential workloads)
blockdev --setra 16384 /dev/sda
iSCSI-Specific Tuning
iSCSI Session Parameters
Optimize session settings in /etc/iscsi/iscsid.conf:
# Faster failover
node.session.timeo.replacement_timeout = 20
# Larger MaxRecvDataSegmentLength (up to 16MB)
node.conn[0].iscsi.MaxRecvDataSegmentLength = 262144
# Enable immediate data (reduces latency)
node.session.iscsi.ImmediateData = Yes
node.session.iscsi.FirstBurstLength = 262144
node.session.iscsi.MaxBurstLength = 16776192
Multipath Performance
Configure for throughput in /etc/multipath.conf:
defaults {
path_grouping_policy multibus # Use all paths simultaneously
path_selector "round-robin 0"
failback immediate
no_path_retry queue
}
Monitoring Performance
Real-time I/O monitoring:
# Per-device statistics
iostat -xz 1
# Watch key metrics:
# - await: Average wait time (ms) - should be <20ms for iSCSI
# - %util: Utilization - sustained >80% may indicate bottleneck
# - r/s, w/s: IOPS
# - rkB/s, wkB/s: Throughput
iSCSI session statistics:
# Check session parameters
iscsiadm -m session -P 3 | grep -E "Header|Data|Burst"
RHEL-Specific Tuning
Use tuned for automated tuning:
# Install tuned
sudo dnf install -y tuned tuned-utils
# Enable tuned
sudo systemctl enable --now tuned
# List available profiles
sudo tuned-adm list
# Apply throughput-performance profile
sudo tuned-adm profile throughput-performance
# Or network-latency for low-latency workloads
sudo tuned-adm profile network-latency
# Verify active profile
sudo tuned-adm active
Create custom tuned profile for iSCSI:
# Create custom profile directory
sudo mkdir -p /etc/tuned/iscsi-storage
# Create tuned.conf
sudo tee /etc/tuned/iscsi-storage/tuned.conf > /dev/null <<'EOF'
[main]
summary=Optimized for iSCSI storage workloads
include=throughput-performance
[sysctl]
# Network tuning
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
net.ipv4.tcp_low_latency = 1
# iSCSI tuning
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
[disk]
# I/O scheduler for iSCSI devices
devices_udev_regex=^sd[a-z]+$
elevator=none
[script]
script=${i:PROFILE_DIR}/script.sh
EOF
# Create script
sudo tee /etc/tuned/iscsi-storage/script.sh > /dev/null <<'EOF'
#!/bin/bash
. /usr/lib/tuned/functions
start() {
# Set queue depth for iSCSI devices
for dev in /sys/block/sd*/device/queue_depth; do
if [ -f "$dev" ]; then
echo 128 > "$dev"
fi
done
return 0
}
stop() {
return 0
}
process $@
EOF
# Make script executable
sudo chmod +x /etc/tuned/iscsi-storage/script.sh
# Apply custom profile
sudo tuned-adm profile iscsi-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.
Optimize kernel for iSCSI:
# Create sysctl configuration
sudo tee /etc/sysctl.d/99-iscsi-rhel.conf > /dev/null <<'EOF'
# Network performance
net.core.netdev_max_backlog = 5000
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 67108864
net.ipv4.tcp_wmem = 4096 65536 67108864
# Connection tracking
net.netfilter.nf_conntrack_max = 1048576
# Low latency
net.ipv4.tcp_low_latency = 1
# VM tuning for storage
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.swappiness = 10
# 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
EOF
# Apply settings
sudo sysctl -p /etc/sysctl.d/99-iscsi-rhel.conf