Chapter 19: CPU and Memory Tuning for Production
Chapter 19: CPU and Memory Tuning for Production
Production performance engineering requires translating profiling discoveries into stable, deterministic host configurations. Leaving server hardware and memory management in their default out-of-the-box states introduces dynamic frequency scaling jitter, memory allocation stalls, and cross-NUMA interconnect thrashing.
This chapter provides battle-tested production recipes for CPU governors, IRQ affinity, task isolation, Huge Pages, and memory sysctl parameters, accompanied by validation tests.
CPU Governor Selection and Configuration
Default distribution power-saving governors (powersave, ondemand) introduce 10\(\mu\)s–100\(\mu\)s latency penalties whenever CPU cores ramp up clock frequency from idle P-states:
# Lock all cores to performance governor
sudo cpupower frequency-set -g performance
# Set Energy Performance Preference (EPP) to maximum performance on Intel/AMD
for f in /sys/devices/system/cpu/cpu*/power/energy_performance_preference; do
echo "performance" | sudo tee "$f" > /dev/null
done
# Restrict deep C-states to prevent sleep exit latency penalties
sudo cpupower idle-set -D 2 # Disables C-states deeper than C1IRQ Affinity and NUMA-Optimal Placement
Hardware devices (NICs, NVMe controllers, RAID adapters) fire interrupts to CPU cores. If irqbalance routes network interrupts to Core 0 while the network worker thread runs on Core 32 on a separate NUMA socket, every received packet traverses the inter-socket interconnect:
# Disable generic irqbalance service on dedicated low-latency hosts
sudo systemctl stop irqbalance
sudo systemctl disable irqbalance
# Manually route IRQ 84 (eth0 RX queue 0) to CPU Core 4 (bitmask: 1 << 4 = 0x10)
echo "10" | sudo tee /proc/irq/84/smp_affinityAlways align IRQ affinities to cores within the same NUMA node as the PCIe device:
# Discover NUMA node of PCIe device
cat /sys/bus/pci/devices/0000:01:00.0/numa_nodeCPU Isolation for Critical Workloads
For deterministic microsecond execution (trading algorithms, packet processing, dedicated database engines), isolate dedicated physical cores via /etc/default/grub:
# Append isolation parameters to GRUB_CMDLINE_LINUX_DEFAULT
# Example: 64-core system, isolate cores 32-63 for dedicated worker threads
GRUB_CMDLINE_LINUX_DEFAULT="... isolcpus=32-63 nohz_full=32-63 rcu_nocbs=32-63"Update GRUB and reboot:
sudo update-grubisolcpus: Excludes cores from CFS/EEVDF automatic load balancing.nohz_full: Disables the scheduler timer interrupt tick whenever a single thread runs on the core.rcu_nocbs: Moves RCU callback processing off isolated cores to housekeeping cores (cores 0–31).
Huge Pages: Configuring and Validating
Huge Pages eliminate TLB cache thrashing for memory-intensive workloads:
Allocating 1GB Static Huge Pages at Boot
In /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="... default_hugepagesz=1G hugepagesz=1G hugepages=32"This reserves 32GB of contiguous physical memory at boot, mapped as 32 1GB pages.
Runtime Allocation of 2MB Huge Pages
# Allocate 4096 2MB huge pages (8 GB total) across NUMA nodes
echo 4096 | sudo tee /proc/sys/vm/nr_hugepages
# Verify allocated and free huge pages
grep -i huge /proc/meminfoMount hugetlbfs for applications:
sudo mkdir -p /mnt/huge
sudo mount -t hugetlbfs nodev /mnt/hugeMemory Sysctl Parameters
Tune kernel virtual memory behavior for production stability:
# /etc/sysctl.d/99-memory-tuning.conf
# Reduce aggressiveness of swapping anonymous memory (default 60)
vm.swappiness = 10
# Keep 5% of memory reserved for kernel atomic allocations to prevent OOM livelock
vm.min_free_kbytes = 1048576
# Regulate dirty page writeback to avoid massive disk stalls on large RAM systems
vm.dirty_background_bytes = 268435456
vm.dirty_bytes = 1073741824
# Maintain balanced inode and dentry cache reclamation
vm.vfs_cache_pressure = 100
# Prevent overcommit memory panics for predictable database sizing
vm.overcommit_memory = 0
vm.overcommit_ratio = 50Apply immediately:
sudo sysctl --systemValidating CPU and Memory Tuning
Verify that your tuning eliminated latency spikes and stabilized throughput:
# 1. Verify CPU frequencies are locked at maximum clock speed
watch -n 1 "grep 'cpu MHz' /proc/cpuinfo"
# 2. Check for timer tick interrupts on nohz_full cores (should be near zero)
cat /proc/interrupts | grep "Local timer interrupts"
# 3. Benchmark memory allocation and access latency before and after
sysbench memory --memory-block-size=2M --memory-total-size=50G --threads=8 run
# 4. Measure tail latency jitter with cyclictest
sudo cyclictest -m -p 90 -t 4 -n -i 1000 -l 100000Under tuned conditions, cyclictest should report maximum latency jitter under 15\(\mu\)s, compared to 150\(\mu\)s+ on stock out-of-the-box installations.