作者:小胖


前言


凌晨一点,正整着炸鸡的小胖,微信一呼“你的服务器CPU持续超载 … “

麻溜的连上服务器,先把CPU负载摁下来。仔细一想,最近1分钟平均负载很大,但CPU利用率却≤30%,不经陷入了深思,打开学习之门…

1 理解CPU平均负载


啥是CPU平均负载呢?

日常运维我们常用

uptimetop命令查看系统当前负载,也可以使用 cat /proc/loadavg

# uptime16:04:00 up 6 days, 19 min,  1 user,  load average: 3.13, 3.25, 3.50  最近1,5,15分钟平均负载

# cat /proc/loadavg
I.33 3.26 3.49 6/434 10737解释说明:3.33 3.26 3.49 最近1,5,15分钟平均进程数
6/434           正在运行进程数6  当前进程总数434(含线程数)10737           最后运行进程PID

严肃点说平均负载是指

: 某段时间内,内核标记为可运行状态或不可中断状态的平均进程数。

(1) 可运行状态:正在使用CPU或等待CPU,即R状态进程(Running或Runnable)

(2) 不可中断状态:等待某种资源可用(通常是I/O),即D状态进程(不含wait状态)

具体算法在 /usr/src/kernels/${内核版本}/include/linux/sched.h 函数CALC_LOAD(load,exp,n)

打个比方

以单核CPU为例,单核CPU就像一条单行隧道,每个进程是行驶的小汽车。


Load=0   隧道无车

Load=0.5  隧道有车不多,顺畅

Load=1.0    隧道满载,整齐不拥塞

Load=1.7  隧道过载,有车等待塞车

小胖不禁发问 平均负载究竟多少比较合理?

(1) 原理上讲对于多核CPU,负载均值是基于CPU逻辑核数决定的;参考同胞经验值,一般认为单个核心负载0.7是警戒线,例如16核警戒线为16*0.7=11.2

(2) 实际业务对CPU需求各不相同,有些业务系统常年低负载/高负载,比较合理的做法是分析历史负载数据和趋势变化设置警戒线

(3) 综合分析最近1/5/15分钟系统平均负载,如果三个值相近则说明系统平稳;如果最近1分钟负载大、最近15分钟负载小,则可能只是短暂业务波峰

2 理解CPU使用率


看完CPU负载,咱接着捣鼓下CPU使用率又是啥?

先敲下top命令瞅瞅

# top
top - 09:44:51 up 188 days, 23:26,  5 users,  load average: 1.03, 1.62, 1.82Tasks: 829 total,   1 running, 597 sleeping,   0 stopped,   1 zombie
Cpu(s):  2.7%us,  0.6%sy,  0.0%ni, 96.6%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

CPU使用率(算法)是指:单位时间内CPU繁忙情况,可以通过 /proc/stat来计算

# cat /proc/stat
cat /proc/stat |head -10cpu  2151316982 13676 447705255 75666027843 24397883 0 21422133 0 0 0cpu0 133476771  224   19023291  1464635099  1418955  0 5724087  0 0 0…
intr 72766406248 237 0 0 1 ...
ctxt 328779743449btime 1559701088processes 1262614693procs_running 3procs_blocked 0softirq 106621687400 21 557059987 6834440 …

CPU行数据说明(以cpu第一行为例)

user[2151316982] : 用户态的CPU时间(单位:jiffies = 0.01秒) ,不包含 nice值为负进程

nice[13676] : 低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU 时间。

这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。  

system[447705255]: 内核态时间

idle[75666027843]: 除IO等待时间以外其它等待时间

iowait[24397883] : IO等待时间

irq[0]: 处理硬中断时间

softirq[21422133]: 处理软中断时间

steal[0]:当系统运行在虚拟机时,被其他虚拟机抢占的CPU时间

guest[0]:虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间

guest_nice[0]:以低优先级运行虚拟机的时间

CPU时间=user+system+nice+idle+iowait+irq+softirq

[intr]:第一个值为自系统启动以来,发生的所有的中断的次数;然后每个数对应一个特定的中断自系统启动以来所发生的次数。

[ctxt]:系统启动以来CPU发生的上下文交换的次数。

[btime]:系统启动到现在为止的时间,单位为秒。

[processes (total_forks)]:系统启动以来所创建的任务的个数目。

[procs_running]:当前运行队列的任务的数目。

[procs_blocked]:当前被阻塞的任务的数目。

Linux进程运行又分用户态和内核态。CPU使用率通常是指:CPU执行非系统空闲进程的时间/CPU总的执行时间,公式如下:

计算CPU使用率脚本参考 https://blog.51cto.com/13466287/2349823

看了这么多枯燥的文字,小胖想知道CPU平均负载和CPU使用率到底有没有联系?

上文提到平均负载统计的是处于可运行状态和不可中断状态的进程数。这包括正在使用CPU的,等待使用CPU的和等待某种资源(比如I

/ O)的进程。 从进程特点看: (1)  CPU密集型进程,会大量真实占用CPU时间分片,负载和使用率均高; (2)  IO密集型进程,平均负载高(等待IO资源),而使用率不一定高 举个例子:假设某个计算进程,运行期间CPU使用率100 %, 执行单个进程时,负载1,CPU使用率100 %; 同时执行2个进程时,负载2,CPU使用率仍100 %( 需要在不同进程间切换,仅为方便理解、实际切换也有开销 )。 原来平均负载和使用率没有必然联系,平均负载高可能只是等待繁忙的I/O,可以使用t op、 p s、 pidstat等命令来排查定位。CPU使用率除了进程自身消耗(用户态、内核态),还包括对软硬中断处理、上下文切换、等待IO资源等。 3 CPU使用率过高分析

线上CPU使用率/负载飙升,通过top、pidstat等命令一般可以快速定位到进程。那么如何进一步分析是哪段函数 或者哪些系统调用引起的呢?

L inux上进程追踪和调试常见有g db, strace, perf 等等。

(1) GDB调试时经常需要中断程序执行(断点),以查看执行和上下文,对于线上作业难以接受;(2) strace和perf都支持运行时追踪。perf已经成为linux内置性能分析工具,相比strace功能更完善。

perf小试牛刀

17985# perf top –g –p

可以追踪指定已运行进程的调用关系,最终定位到进程、函数段。

perf + FlameGraph还能生成火焰图,更直观、交互的分析程序性能

详细参考   http://www.brendangregg.com/flamegraphs.html

来左边跟我一起画个龙,在你终端画一道火焰红!想不到还能如此酷炫吧!

小胖还曾遇到过CPU使用率高却定位不到进程的情况?比如

# top
top - 12:05:48 up 99 days, 14:18,  1 user,  load average: 2.48, 2.38, 2.23Tasks: 356 total,   2 running, 175 sleeping,   0 stopped,   0 zombie
Cpu(s):  83.2%us,  1.6%sy,  3.1%ni, 86.9%id,  4.4%wa,  0.0%hi,  3.9%si,  0.0%st
Mem:  65960848k total, 57092092k used,  8868756k free,   340300k buffers
Swap: 12582908k total,  3632460k used,  8950448k free,  1437352k cached

PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
22248 www       20   0  191m 107m 6440 S  5.3  0.2 336:05.66 nginx
22249 www       20   0  179m  94m 6416 S  3.3  0.1 246:14.41 nginx

备注:此处top已按照进程cpu使用率排序

遇到这类奇怪问题,有一些思路可以尝试下:


(1) 首先使用其他性能分析命令如mpstat、ps等,排除命令自身问题;

(2) 仔细观察实时统计信息,比如top要打开线程统计,是否有频繁被调用、执行时间很短的外部程序占用了大量CPU资源;

(3) 仍未定位到,则检查系统日志/业务进程日志,是否存在异常。曾遇到过业务进程异常无法启动,被守护进程反复拉起崩溃导致占用大量CPU。

4 CPU优化常见方法


经过层层剖析,最终定位到性能问题的瓶颈后,小胖理了下思路,觉得不应该急着操作:

(1) 首先明确是硬件问题,还是软件问题,比如CPU是否开了节能模式、是否被锁频?IO慢导致iowait满载,通过更换高速硬盘、阵列缓存、程序内存缓冲区是否可以解决?而不是上来就动刀子;软件问题也需要针对应用程序排查日志、性能分析;

(2) 性能问题通常彼此关联,可能同时暴露多个性能问题,需要我们抓住核心矛盾;一个水桶无论多高,它盛水的高度取决于其中最低的那块木板;

(3) 

实际优化以业务指标为导向,业务角度关注请求延迟、并发数等指标;运维角度关注CPU负载、使用率等指标!优化前后做好指标的量化和对比。 回到CPU负载高本身,我们也从前辈处GET到一些切实可行的软优化手段:

(1) 优化中断:默认软中断由cpu0处理,通过启用irqbalance服务 或 配置smp_affinity,将中断分散到多个cpu核心上,比如针对网卡软中断优化;

(2) cpu绑定:将进程绑定到一个或者多个指定核上,提高cpu缓存命中率,减少上下文切换,最常见的是nginx cpu绑定

(3) nice调整:调整进程的nice值,提高核心业务进程的CPU优化级

(4) CGroup:基于内核cgroup功能来配额资源,包括CPU、内存等

(5) Numa优化:多CPU架构中,BIOS开启numa后,使用numactl来优化内存分配,让CPU尽可能只访问本地内存

看到这里,相信你和小胖一样已经对CPU负载、使用率的问题有了更深刻的认识!这些运维小彩蛋还有很多、藏得很深,如果有更好的思路经验,也可以寄信给小胖,一起学习酷炫!

近期文章

  1. 图说k8s
  2. 推荐一款简单易用线上引流测试工具:GoReplay
  3. 从内心挣扎到豁然开朗,拥抱MySQL5.7!
  4. nginx的location if是如何工作的
  5. 基友的服务器又被黑了
  6. DevSecOps简述

END