Linux Performance Tuning, Kernel Parameters, and Resource Limits

Maximizing Linux server performance requires identifying system bottlenecks (CPU, Memory, Disk I/O, Network), tuning kernel runtime parameters (sysctl), enforcing user/process resource limits (ulimit, cgroups), and profiling latency. This guide covers production performance tuning, kernel configuration, and system profiling.


⚡ Quick Dive

Performance Diagnostics & Tuning Cheat Sheet

Domain Command Action Example
Kernel Tunables sysctl -p Reload /etc/sysctl.conf or /etc/sysctl.d/*.conf sudo sysctl -p /etc/sysctl.d/99-perf.conf
Query Parameter sysctl <param> Check active kernel parameter value sysctl vm.swappiness
User Limits ulimit -n / -u View max open files / max user processes ulimit -n (file descriptors)
CPU Priority nice -n <val> <cmd> Launch command with custom niceness (-20 to 19) nice -n 10 tar -czf backup.tar.gz /data
Modify Priority renice -n <val> -p <pid> Change priority of a live running process sudo renice -n -5 -p 1840
I/O Priority ionice -c <class> <cmd> Launch process with specific I/O scheduler class ionice -c 3 backup_job.sh (idle class)
Memory Bottleneck vmstat 1 5 Monitor memory swapping (si/so) and context switches vmstat 1 5
Disk I/O Wait iostat -xz 1 5 Monitor disk saturation (%util) and await latency iostat -xz 1 5
Historic Metrics sar -u 1 5 Collect and report historic OS activity (sysstat) sar -r (memory trends)

Recommended Production Kernel Profile (/etc/sysctl.d/99-performance.conf)

# Maximize file descriptor & socket allocations
fs.file-max = 2097152

# Reduce memory swapping aggressive paging (default 60; 10 recommended for servers)
vm.swappiness = 10

# Increase incoming network connection backlog queue
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# Enable TCP BBR Congestion Control (requires Linux 4.9+)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# Increase TCP read/write buffer memory (min, default, max in bytes)
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# Enable fast socket reuse for high-throughput proxies
net.ipv4.tcp_tw_reuse = 1

📖 Extended Guide

1. Kernel Runtime Tuning via sysctl

Parameters in /proc/sys/ can be adjusted live using sysctl.

# View active value of a parameter
sysctl vm.max_map_count

# Temporarily modify a parameter in memory
sudo sysctl -w vm.swappiness=10

# Permanently apply changes via drop-in file
sudo sysctl --system

Key Kernel Parameters for Servers:

  1. vm.swappiness (0 to 100):
    • Controls how aggressively the kernel swaps anonymous RAM pages to disk.
    • Default is 60. Set to 10 on database and application servers to avoid latency spikes while maintaining swap emergency headroom.
  2. vm.dirty_ratio & vm.dirty_background_ratio:
    • Percentage of system memory that can hold unwritten disk changes before kernel forces writes to disk. Lowering values smooths out I/O spikes.
  3. fs.file-max:
    • System-wide ceiling for open file handles across all processes.

2. User & Process Resource Limits: ulimit and limits.conf

Operating systems impose limits on the resources consumed by user accounts and processes to prevent Denial-of-Service or accidental fork bombs.

Types of Limits:

  • Soft Limit: The value currently enforced by the kernel (can be increased by user up to the hard limit).
  • Hard Limit: The ceiling ceiling set by root (cannot be exceeded).

Configuration File: /etc/security/limits.conf

Format: <domain> <type> <item> <value>

# Increase open file descriptors for user 'appuser'
appuser  soft  nofile  65536
appuser  hard  nofile  65536

# Increase max processes for group 'developers'
@developers  hard  nproc  4096

# Set unlimited locked-in-memory size for database engines (Redis/MongoDB)
redis  soft  memlock  unlimited
redis  hard  memlock  unlimited

[!IMPORTANT] Systemd services ignore /etc/security/limits.conf. To set resource limits for a systemd service, define LimitNOFILE=65536 or LimitNPROC=4096 inside the unit file's [Service] block.


3. Process Scheduling Priorities: nice and ionice

CPU Priority with nice

  • Niceness ranges from -20 (highest priority, least nice) to 19 (lowest priority, most nice).
  • Default process niceness is 0.
# Run CPU-heavy backup task without impacting web server latency
nice -n 19 tar -czf backup.tar.gz /data

# Elevate critical daemon priority (requires root for negative values)
sudo renice -n -10 -p $(pidof haproxy)

Disk I/O Scheduling with ionice

  • Class 1 (Real Time): First access to disk.
  • Class 2 (Best Effort): Default priority (levels 0-7).
  • Class 3 (Idle): Only gets disk access when disk has zero active I/O.
# Run log compressor only when disk is completely idle
ionice -c 3 gzip /var/log/large_dump.sql

4. Identifying Performance Bottlenecks

Bottleneck Symptoms Matrix:
┌─────────────────┬──────────────────────────┬────────────────────────────┐
│ Bottleneck Type │ Diagnostic Tool          │ Symptom Trigger            │
├─────────────────┼──────────────────────────┼────────────────────────────┤
│ CPU Saturation  │ uptime, top, mpstat      │ %user + %system near 100%  │
│ Memory Starved  │ free -h, vmstat 1        │ si (swap in) / so > 0      │
│ Disk I/O Wait   │ iostat -xz 1, top        │ %wa (iowait) > 10%, %util  │
│ File Descriptor │ lsof | wc -l             │ "Too many open files"      │
└─────────────────┴──────────────────────────┴────────────────────────────┘

Deep Diagnostics Commands

# 1. Inspect per-CPU core utilization
mpstat -P ALL 1 3

# 2. Check which processes are causing disk I/O reads/writes
sudo iotop -o -b -n 3

# 3. Profile CPU cycles and identify kernel/user functions consuming CPU
sudo perf top