Chapter 08Lesson 05~55 minutes

Priorities, nice, cgroups, and Resource Limits

Control process competition with niceness, per-process limits, and cgroup-based CPU, memory, task, and I/O policy.

SchedulingcgroupsHands-on lab

Learning objectives

By the end of this lesson

  • Explain what niceness changes and what it does not guarantee.
  • Inspect and modify scheduling priority for processes you own.
  • Use shell resource limits to constrain descriptors, processes, CPU time, and memory-related resources.
  • Explain why cgroups are the foundation for container and service resource governance.
  • Run a controlled workload inside a transient systemd scope when supported.

1. Resource controls shape competition and failure

Linux runs many workloads on finite CPUs, memory, storage, and kernel objects. Resource policy should prevent one process from degrading the whole host, while preserving enough capacity for critical services and recovery tools. Different controls operate at different layers: scheduler priority influences CPU competition, resource limits constrain individual process behavior, and control groups govern collections of processes.

nice / renice

Relative CPU scheduling preference

Influences fair-scheduler competition among runnable tasks; it is not a CPU quota or reservation.

rlimits

Per-process ceilings

Bound resources such as open files, process count, core size, locked memory, or CPU time.

cgroups

Hierarchical workload policy

Group processes for CPU, memory, task, I/O, and accounting controls used by services and containers.

2. Niceness is a hint within scheduler policy

For normal fair-scheduled tasks, niceness commonly ranges from -20, higher priority, to 19, lower priority. Ordinary users can usually increase the nice value of their own processes, making them less favored, but decreasing it normally requires privilege or a capability. Niceness matters when runnable tasks compete for CPU; it does not create a hard maximum.

# Launch a low-priority workload.
nice -n 15 bash -c 'while :; do :; done' &
pid=$!

# Inspect policy, niceness, priority, CPU placement, and use.
ps -o pid,ppid,cls,pri,ni,psr,stat,pcpu,comm,args -p "$pid"

# Make the process even less favored.
renice -n 19 -p "$pid"
ps -o pid,cls,pri,ni,stat,pcpu,comm -p "$pid"

kill -TERM "$pid"
wait "$pid" 2>/dev/null || true
Niceness is not isolation

A low-priority process can still consume an idle CPU fully, allocate excessive memory, saturate storage, open many files, or create many children. Combine controls according to the failure mode.

3. Resource limits constrain each process lineage

Shells expose inherited resource limits through ulimit; programs can inspect and adjust permitted limits through system calls. A soft limit is the current enforced value. A hard limit is the ceiling an unprivileged process can set for its soft limit. Children inherit limits across process creation and program replacement.

LimitShell viewOperational use
Open filesulimit -nBound descriptors for files, sockets, pipes, and event handles
User processesulimit -uReduce fork-bomb and runaway worker risk per identity
CPU secondsulimit -tTerminate a process after accumulated CPU time
Core sizeulimit -cControl diagnostic dump generation and storage exposure
Locked memoryulimit -lBound pages that cannot be reclaimed or swapped
# Show current soft limits in a subshell.
(
  ulimit -Sa
  printf 'open_files_soft=%s\n' "$(ulimit -Sn)"
  printf 'open_files_hard=%s\n' "$(ulimit -Hn)"
)

# Demonstrate a narrow open-file limit without changing the parent shell.
(
  ulimit -Sn 64
  printf 'child_open_file_limit=%s\n' "$(ulimit -Sn)"
  grep -E 'Max open files|Max processes|Max cpu time' "/proc/$$/limits"
)

Do not lower limits in your main interactive shell unless you understand the inheritance effect. Use a subshell, service unit, container, or dedicated lab identity.

4. Cgroups govern a workload as a unit

Control groups organize processes into a hierarchy and apply controllers to the group. Modern systems commonly use cgroup v2 with a unified hierarchy. Service managers and container runtimes create cgroups automatically, which lets operators manage an entire service or container rather than chasing individual worker PIDs.

Hierarchical resource governance
flowchart LR
  R["Host cgroup root"] --> S["system.slice"]
  R --> U["user.slice"]
  S --> W["web.service"]
  S --> C["ci-runner.service"]
  U --> L["user-1000.slice"]
  W --> WP["web workers and children"]
  C --> CP["build and test processes"]
  L --> LP["interactive sessions"]
  W -. policy .-> P1["CPU weight, memory max, tasks max"]
  C -. policy .-> P2["CPU quota, I/O weight, memory high"]
# Determine cgroup version and current membership.
stat -fc '%T' /sys/fs/cgroup
cat /proc/self/cgroup

# Inspect the current systemd unit and cgroup path when systemd is present.
if command -v systemctl >/dev/null; then
  systemctl status "$(systemctl --user show -p Id --value 2>/dev/null || true)" 2>/dev/null || true
fi

# Useful service-level properties on systemd systems.
systemctl show --property=ControlGroup,CPUWeight,CPUQuotaPerSecUSec,MemoryCurrent,MemoryMax,TasksCurrent,TasksMax 2>/dev/null | head

Key cgroup v2 controls include CPU weight and maximum, memory high and maximum, task limits, I/O weights and maximums, and pressure/accounting files. Availability depends on enabled controllers, delegation, service-manager policy, and privileges.

5. Match the control to the failure mode

01CPU fairness

Use CPU weight or niceness when workloads should share spare capacity proportionally.

02CPU ceiling

Use a cgroup CPU quota when a workload must not exceed a defined share over time.

03Memory protection

Use memory high/max and application-aware sizing; observe reclaim and OOM behavior.

04Fork containment

Use TasksMax or pids controller limits for whole workloads, plus identity-level limits where appropriate.

05Descriptor control

Use LimitNOFILE or rlimits, sized from concurrency and connection design.

Resource controls can create new failure modes. A tight memory maximum may trigger OOM termination; a low descriptor limit may cause connection failures; an aggressive CPU quota may increase latency. Test under realistic load and ensure monitoring explains which limit was reached.

6. Transient scopes make controlled experiments safer

On a systemd host, systemd-run --scope can place a command in a transient scope with resource properties. User-manager support and delegation differ by distribution and session configuration.

lab="$HOME/devops-academy/linux/chapter08/lesson05"
mkdir -p "$lab"

if command -v systemd-run >/dev/null && systemctl --user show-environment >/dev/null 2>&1; then
  unit="da-ch8-l5-$RANDOM.scope"
  systemd-run --user --scope --unit="$unit" \
    -p CPUWeight=10 \
    -p MemoryMax=128M \
    -p TasksMax=32 \
    bash -c '
      printf "pid=%s\n" "$$"
      printf "cgroup:\n"
      cat /proc/self/cgroup
      printf "limits:\n"
      grep -E "Max open files|Max processes" /proc/self/limits
      sleep 5
    ' | tee "$lab/transient-scope.txt"
else
  printf 'User systemd scope unavailable; inspect limits in a subshell instead.\n'
  (
    ulimit -Sn 128
    grep -E 'Max open files|Max processes' "/proc/$$/limits"
    cat /proc/self/cgroup
  ) | tee "$lab/subshell-limits.txt"
fi
Do not stress production hosts casually

Memory, process, CPU, and I/O experiments can destabilize a machine. Use a disposable lab VM and conservative limits. Never test fork bombs or uncontrolled allocation.

7. Hands-on lab: compare priority and limits

Run two controlled CPU loops with different niceness values, record repeated snapshots, inspect inherited limits, then clean up both processes.

lab="$HOME/devops-academy/linux/chapter08/lesson05"
mkdir -p "$lab"

nice -n 0 bash -c 'while :; do :; done' &
normal=$!
nice -n 19 bash -c 'while :; do :; done' &
low=$!

cleanup() {
  kill -TERM "$normal" "$low" 2>/dev/null || true
  wait "$normal" 2>/dev/null || true
  wait "$low" 2>/dev/null || true
}
trap cleanup EXIT

{
  printf 'normal_pid=%s low_priority_pid=%s\n' "$normal" "$low"
  for sample in 1 2 3 4 5; do
    printf '\n=== sample %s ===\n' "$sample"
    ps -o pid,ppid,cls,pri,ni,psr,stat,pcpu,time,comm \
      -p "$normal" -p "$low"
    sleep 1
  done
  printf '\n=== inherited limits ===\n'
  grep -E 'Max cpu time|Max processes|Max open files|Max locked memory' "/proc/$normal/limits"
  printf '\n=== cgroup membership ===\n'
  cat "/proc/$normal/cgroup"
} > "$lab/priority-comparison.txt"

less "$lab/priority-comparison.txt"
cleanup
trap - EXIT

Verification checklist

8. Common mistakes

Using nice as a CPU quota

Niceness changes relative scheduling preference under contention; it does not impose a hard ceiling.

Setting limits without load tests

Low limits can convert normal demand into confusing application failures.

Managing only the main PID

Workers and grandchildren may escape PID-by-PID control. Use service cgroups for workload-wide policy.

Ignoring OOM and throttling evidence

When a limit is reached, inspect cgroup events, pressure, service logs, and kernel messages.

9. Knowledge check

Question 1. Does niceness cap a process at a fixed CPU percentage?

Question 2. Why are cgroups preferable to tracking worker PIDs individually?

Question 3. What is the relationship between soft and hard rlimits?

10. Summary

Linux resource governance is layered. Niceness shapes relative CPU scheduling, rlimits constrain process resources, and cgroups govern complete workloads with hierarchical accounting and policy. Select controls based on the failure mode, test under realistic demand, monitor limit events, and preserve enough capacity for observability and recovery.

Next chapter

Package Formats, Repositories, and Dependency Resolution

Chapter 9 moves from running processes to trusted software supply, package metadata, repositories, dependency solving, installation state, and update workflows.

11. Further reading

  • nice(1), renice(1), sched(7), and getrlimit(2).
  • systemd.resource-control(5), systemd-run(1), and systemd.exec(5).
  • Linux kernel cgroup v2 and pressure-stall-information documentation.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.