Operations 6 min read

How to Fix CPU0 Overload on Multi‑Core Web Servers Using taskset and PHP‑FPM

This article shows how to detect a CPU0 load imbalance on a multi‑core web server, confirms PHP‑FPM as the cause with mpstat and pidstat, and provides a Bash script that uses taskset to evenly distribute PHP‑FPM processes across all CPUs, plus a cron tip to keep the setting persistent.

ITPUB
ITPUB
ITPUB
How to Fix CPU0 Overload on Multi‑Core Web Servers Using taskset and PHP‑FPM

During a discussion the author noticed that on a four‑core web server CPU0 was consistently much busier than the other cores, and the suspicion fell on PHP‑FPM processes.

Running mpstat -P ALL 1 10 produced the following snapshot, clearly showing CPU0’s idle time far lower than the others:

CPU    %usr   %nice   %sys %iowait   %irq   %soft ... %idle
all   17.57    0.03    1.78    0.00    0.35    0.23 ... 80.04
0     43.17    0.00    4.12    0.00    1.41    1.00 ... 50.30
1      9.80    0.00    0.81    0.00    0.00    0.00 ... 89.39
2      9.31    0.00    1.20    0.00    0.00    0.00 ... 89.49
3      7.94    0.10    0.80    0.00    0.00    0.00 ... 91.16

To verify that PHP‑FPM was responsible, the author used pidstat combined with grep and awk:

pidstat | grep php-fpm | awk '{print $(NF-1)}' | sort | uniq -c

157 0
 34 1
 34 2
 32 3

The output shows that the majority of PHP‑FPM workers were scheduled on CPU0, explaining the imbalance. Since PHP‑FPM lacks an explicit affinity option like Nginx, the solution is to bind each worker to a specific CPU using taskset.

The following Bash script enumerates all CPUs, finds the PIDs of PHP‑FPM worker processes, and assigns each worker to a CPU in a round‑robin fashion:

#!/bin/bash

CPUs=$(grep -c processor /proc/cpuinfo)
PIDs=$(ps aux | grep "php-fpm[:] pool" | awk '{print $2}')

let i=0
for PID in $PIDs; do
    CPU=$(echo "$i % $CPUs" | bc)
    let i++
    taskset -pc $CPU $PID
done

After executing the script, a new mpstat run shows a much more balanced distribution of load across all four CPUs:

CPU    %usr   %nice   %sys %iowait   %irq   %soft ... %idle
all   15.73    0.03    1.61    0.00    0.20    0.23 ... 82.20
0     16.28    0.10    1.62    0.10    0.81    0.91 ... 80.18
1     16.16    0.10    1.51    0.00    0.00    0.10 ... 82.13
2     14.46    0.10    1.71    0.00    0.00    0.00 ... 83.73
3     15.95    0.00    1.71    0.00    0.00    0.00 ... 82.35

One caveat: when a PHP‑FPM worker reaches the max_requests limit it is automatically restarted, which clears any affinity set by taskset. To keep the binding permanent, the script should be scheduled via cron (e.g., run every minute).

In practice the distribution can be tuned; for example, if CPU0 remains heavily loaded, you may choose to assign workers only to CPUs 1‑3.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

php-fpmcpu_affinitympstatpidstattaskset
ITPUB
Written by

ITPUB

Official ITPUB account sharing technical insights, community news, and exciting events.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.