在一台多核CPU的web服务器上,存在负载不均衡问题,其中,其中CPU0的负载明显高于其他CPUx,进一步调查表明PHP-FPM的嫌疑最大
让我们在一台四核服务器上采样分析一下数据确认看看是否存在负载不均衡问题:
shell> mpstat -P ALL 1 10
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
如上命令的含义就是每秒一次mpstat,一共采样10次取平均值,可以明显看出CPU0的空闲idel明显小于其他CPUx,而且大部分消耗在user上面
再让我们通过pidstat来确认一下是不是PHP-FRM导致的CPU0负载问题:
shell> pidstat | grep php-fpm | awk '{print $(NF-1)}' | sort | uniq -c
157 0
34 1
34 2
32 3
可见分配给CPU0的PHP-FPM进程比其他三个CPUx总和还要多,为什么大部分进程被分配给CPU0?可能是操作系统偏爱使用CPU0的原因,但是问题总要解决,既然PHP-FPM没有类似Nginx那么CPU亲缘性绑定的指令,那么我们可以使用taskset绑定PHP-FPM进程到固定的CPUx来解决问题:
#!/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
如上脚本运行后,我们再来看各个CPU负载分配情况:
shell> mpstat -P ALL 1 10
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
终于平均了,不过需要提醒的是,一旦PHP-FPM处理请求数超过了max-requests的设置,那么对应的进程将自动重启,先前的taskset设置也将失效,所以为了一直有效,我们需要把taskset脚本添加到CRON配置中去,例如每分钟自动设置一遍