Performance tuning on Ubuntu Server is far more than applying a collection of sysctl values or switching governors. At its core, it involves understanding the fundamental trade-offs built into each subsystem of the modern Linux kernel and deciding — consciously or unconsciously — which side of each trade-off best serves the workload’s dominant requirements.
The following sections explain the most important theoretical conflicts and invariants that explain why certain tunings produce dramatic improvements in specific scenarios while causing regressions or instability in others.
1. CPU Frequency & Scheduling – The Prediction vs Worst-Case Dilemma
Since kernel 5.17–6.8 (Ubuntu 24.04+), the default combination is EEVDF scheduler + schedutil governor.
schedutil’s central assumption is that recent CPU utilization is a reasonable predictor of near-future demand. It uses the PELT (Per-Entity Load Tracking) signal to estimate load and adjust frequency accordingly.
In server workloads this assumption frequently breaks:
- Request arrivals are bursty and highly variable.
- Individual request processing times are short (< 5–20 ms).
- Utilization spikes are transient and unpredictable.
As a result, schedutil often reacts too slowly: frequency ramps up after the burst has already started to tail off, leaving many requests executed at sub-optimal (lower) frequencies. This produces pronounced tail-latency degradation under load.
Switching to the performance governor resolves this by removing prediction entirely:
It trades idle power and average utilization efficiency for deterministic worst-case latency behavior.
The performance governor locks the CPU at maximum sustainable frequency (subject only to thermal & power limits), eliminating the frequency-ramp delay from the critical path of every request. This is why it remains — in 2026 — the single most impactful tuning for latency-sensitive, always-loaded server applications (databases, API gateways, reverse proxies, message brokers).
Conversely, when the workload is throughput-oriented with long-running, CPU-bound tasks (batch processing, scientific computing, model training), schedutil or even powersave can be superior because it allows opportunistic frequency reduction during naturally occurring idle periods without harming overall throughput.
2. Memory Reclaim – Three Competing Resource Pools
The page reclaim subsystem (kswapd + direct reclaim) constantly arbitrates between three major memory consumers:
- File-backed page cache (dentries, inodes, mapped file pages)
- Anonymous memory (process private pages, heap/stack)
- Kernel slab / other metadata
The kernel uses a global pressure signal (pressure stall information — PSI) and per-zone watermarks to decide when and what to reclaim.
Three tunable axes control this arbitration:
- vfs_cache_pressure Controls the relative eagerness to reclaim page cache vs anonymous memory. Default = 100 (equal treatment). Lower values (50–10) bias protection toward the page cache → strongly beneficial for workloads that repeatedly read the same set of files (web servers, content delivery, build farms, source-code repositories). Higher values favor anonymous memory protection → useful in memory-heavy in-memory databases or JVM-based applications where heap pressure is the dominant threat.
- Dirty page writeback throttling The interplay of dirty_ratio / dirty_background_ratio / dirty_expire_centisecs determines how aggressively dirty pages are written back to storage. Modern NVMe drives deliver extremely high sequential write bandwidth but suffer sharp drops under concurrent random writes. If too many dirty pages accumulate, a sudden global flush (triggered when dirty_ratio is exceeded) causes severe write-latency spikes that stall foreground tasks. Lowering dirty_ratio (10–20%) and dirty_background_ratio (2–5%) forces earlier, more gradual writeback → smoothing write latency at the cost of slightly higher steady-state CPU usage by kswapd/flusher threads.
- Overcommit policy vm.overcommit_memory = 1 + overcommit_ratio = 80–100 This policy assumes that processes routinely over-request virtual memory compared to their actual working set size (RSS). By allowing overcommitment, the kernel defers the failure point from malloc()/mmap() time to actual page-fault time, giving OOM killer or swap a chance to intervene. This model is almost mandatory for large Java heaps, Redis, PostgreSQL, or any application that uses sparse address space aggressively.
3. Network Stack – Bandwidth-Delay Product & Congestion Control Philosophy
The dominant change in server networking since ~2018 is the widespread adoption of TCP BBR (Bottleneck Bandwidth and Round-trip propagation time).
BBR departs from loss-based congestion control (Cubic, Reno) in a philosophically important way:
- Loss-based algorithms treat packet loss as the primary congestion signal → they fill queues until drops occur (bufferbloat friendly but high latency).
- BBR estimates bottleneck bandwidth and minimum RTT independently → it tries to operate just at the knee of the bandwidth-delay curve, keeping queues almost empty.
For most internet-facing and inter-DC workloads in 2026, BBR delivers superior throughput × latency product compared to Cubic, especially on long-fat pipes (high BDP links).
However, BBR is not universally superior:
- On very shallow-buffered switches (common in some HPC fabrics), BBR can be too aggressive and cause unfairness or instability.
- In lossy wireless or mobile-edge environments, loss-based control sometimes recovers faster.
4. I/O Path – Scheduler, Queue Depth & Readahead Trade-offs
Modern block-layer defaults (mq-deadline or none on NVMe) already reflect lessons learned over the past decade:
- mq-deadline provides decent merge behavior and latency bounding without the complexity of BFQ or Kyber.
- none maximizes parallelism on high-queue-depth devices (enterprise NVMe, RAID arrays with hardware RAID controllers).
Readahead size (blockdev –setra) trades prefetch efficiency against memory pressure and useless I/O:
- Small readahead (128–512 sectors) → better for random I/O dominant workloads.
- Large readahead (2048–8192 sectors) → strong win for sequential scan-heavy workloads (backup, analytics, log processing).
Closing Perspective
Effective tuning is the art of identifying which of the kernel’s built-in trade-offs most mismatches the workload’s requirements, then shifting that balance point toward the workload’s dominant need (throughput, tail latency, power, fairness, predictability).
The most powerful single-line change remains:
Use the performance governor + TuneD throughput-performance profile + BBR + moderate dirty-page throttling
… for the majority of latency-sensitive, always-busy server applications in 2026.
But the real skill lies in measuring first (critical path analysis, perf/bpftrace, PSI metrics, stall detectors), understanding why the current defaults underperform, and making the smallest number of changes that move the needle most — while preserving debuggability and upgrade safety.
Over-tuning almost always creates more problems than it solves. Under-tuning leaves performance on the table. The sweet spot is usually closer to “measured defaults + 3–5 targeted deviations” than to the 50-line sysctl.conf approach still seen in some legacy guides.