Linux System Optimization: A Performance Tuning Guide
Practical techniques for optimizing Linux systems — from kernel parameters and I/O schedulers to memory management and process tuning.
Linux System Optimization: A Performance Tuning Guide
Linux gives you granular control over system performance, but knowing where to look and what to tune requires experience. This guide covers the techniques I use regularly on both servers and my daily-driver Arch Linux workstation.
Rule Zero: Measure First
Never optimize blindly. Profile, identify the bottleneck, then optimize. The tools:
# System overview
htop # Interactive process viewer
btop # Modern alternative to htop
vmstat 1 # Virtual memory statistics (1-second interval)
iostat -x 1 # I/O statistics
# Detailed analysis
perf top # Real-time CPU profiling
perf record -g ./my_program && perf report # Profile a specific program
strace -c ./program # System call summary
Kernel Parameters (sysctl)
Memory Management
# Reduce swappiness (default: 60)
# Lower = prefer keeping processes in RAM
# For workstations with plenty of RAM:
vm.swappiness = 10
# For servers running databases:
vm.swappiness = 1
# VFS cache pressure (default: 100)
# Lower = keep directory/inode caches longer
vm.vfs_cache_pressure = 50
# Dirty page writeback — when to start writing dirty pages to disk
vm.dirty_ratio = 15 # % of RAM before sync write
vm.dirty_background_ratio = 5 # % of RAM before async write
Network Tuning
# Increase network buffer sizes
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# Enable TCP BBR congestion control
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr
# Connection handling
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
Apply with:
# Temporary (until reboot)
sudo sysctl -w vm.swappiness=10
# Persistent — add to /etc/sysctl.d/99-custom.conf
sudo sysctl --system # Reload all
I/O Schedulers
Modern NVMe drives work best with specific schedulers:
# Check current scheduler
cat /sys/block/nvme0n1/queue/scheduler
# For NVMe SSDs: 'none' or 'mq-deadline'
echo "none" | sudo tee /sys/block/nvme0n1/queue/scheduler
# For SATA SSDs: 'mq-deadline'
echo "mq-deadline" | sudo tee /sys/block/sda/queue/scheduler
# For HDDs: 'bfq' (Budget Fair Queueing)
echo "bfq" | sudo tee /sys/block/sdb/queue/scheduler
Make persistent with a udev rule (/etc/udev/rules.d/60-iosched.rules):
# NVMe
ACTION=="add|change", KERNEL=="nvme[0-9]*", ATTR{queue/scheduler}="none"
# SATA SSD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="0", ATTR{queue/scheduler}="mq-deadline"
# HDD
ACTION=="add|change", KERNEL=="sd[a-z]", ATTR{queue/rotational}=="1", ATTR{queue/scheduler}="bfq"
CPU Performance
Governor and Frequency Scaling
# Check current governor
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
# For maximum performance (servers, benchmarking)
echo "performance" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
# For desktop use — schedutil is ideal (frequency scales with load)
echo "schedutil" | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
Process Priority and CPU Affinity
# Run CPU-intensive task with high priority
nice -n -10 ./heavy_computation
# Pin process to specific cores (useful for NUMA or isolating workloads)
taskset -c 0-3 ./my_process
# Real-time priority (use with caution)
chrt -f 50 ./realtime_process
Memory Optimization
Transparent Huge Pages
For most workloads, THP helps. For databases (Redis, MongoDB), it can hurt:
# Check current state
cat /sys/kernel/mm/transparent_hugepage/enabled
# Disable for databases
echo "never" | sudo tee /sys/kernel/mm/transparent_hugepage/enabled
zswap/zram
Compress memory before swapping to disk — especially useful on machines with limited RAM:
# Enable zswap (compresses swap in RAM)
echo 1 | sudo tee /sys/module/zswap/parameters/enabled
echo lz4 | sudo tee /sys/module/zswap/parameters/compressor
echo 20 | sudo tee /sys/module/zswap/parameters/max_pool_percent
# Or use zram (compressed RAM block device as swap)
sudo modprobe zram
echo lz4 | sudo tee /sys/block/zram0/comp_algorithm
echo 4G | sudo tee /sys/block/zram0/disksize
sudo mkswap /dev/zram0
sudo swapon -p 100 /dev/zram0
Filesystem Tuning
Mount Options
# /etc/fstab optimizations for ext4 on SSD
/dev/nvme0n1p2 / ext4 noatime,commit=60 0 1
# For btrfs
/dev/nvme0n1p2 / btrfs noatime,compress=zstd:1,ssd,space_cache=v2 0 0
noatime avoids writing access timestamps on every read — a simple but effective optimization.
Monitoring and Alerts
Set up basic monitoring to catch issues before they become problems:
# Simple disk space alert (add to crontab)
#!/bin/bash
threshold=90
usage=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$usage" -gt "$threshold" ]; then
echo "Disk usage critical: ${usage}%" | mail -s "Disk Alert" admin@example.com
fi
My Arch Linux Workstation Config
Key optimizations on my daily driver:
- Kernel: linux-zen (optimized for desktop responsiveness)
- Scheduler: schedutil governor, none I/O scheduler for NVMe
- Memory: swappiness=10, zram with lz4
- Filesystem: btrfs with zstd compression and noatime
- Network: TCP BBR congestion control
Conclusion
Linux performance tuning is about understanding your workload and matching the system configuration to it. There's no one-size-fits-all — a database server needs different tuning than a desktop workstation. Always measure before and after changes, and make one change at a time so you can attribute improvements correctly.