赞
踩
CPU使用率高一直是工程师头疼的问题,也是面试题中的常客,几乎所有的大厂在面试的时候都问过此类问题。
可能每个同学都看到过,甚至有过开发同学写到过的更加详细的分析过程。但是今天,小编会从一个运维的视角来告诉你该如何回答。
插播一条我自己的广告:如果您即将毕业,如果 您最近正面临跳槽找工作,那不妨关注我,这里整理了近几百道运维相关面试题,还在持续更新,面试前刷刷八股,提高面试通过率
先处理问题,再排查原因
对于线上业务,作为运维,永远需要以保障线上业务稳定为第一要务。绝不可以无限期的以追查根因为目标来处理线上问题。当然非在线业务,则需要竭尽全力追查元凶
最可能保留现场
在响应和处理CPU高的问题时,要尽可能采集和保留当前系统环境,如系统资源状态,连接信息,进程内存dump信息等
迅速隔离
对于线上问题,单点cpu异常,则可以断定出现了偶发性问题,问题节点应该在保留现场后迅速隔离(如从线上离线、重启等),多节点通用问题,优先立即扩容
隔离方法:
离线还原及复现
线上节点在隔离之后,就已经失去了故障发生时的状态,所以对于一些复杂问题,就需要在线上根据故障现场信息,进行环境重建和场景复现,分析和测试问题可能的原因
以上仅代表我个人过去多年运维经验的总结,如有更好或不同意见,请留言讨论。
标记1 的行,为CPU的使用率详情,其中每个不同的指标一般代表着不同的原因
user
(us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
system
(sy),代表内核态 CPU 时间
nice
(ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。idle
(id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait),这个占用高代表的是空闲,而不是使用率,一般我们在配置告警的时候,也常会使用(1-id%)来计算CPU的使用率iowait
(wa),代表等待 I/O 的 CPU 时间
irq
(hi),代表处理硬中断的 CPU 时间
softirq
(si),代表处理软中断的 CPU 时间。
steal
(st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
标记2/3代表的是当前系统内存及swap交换分区使用情况,从左向右依次为,总内存,剩余内存,使用内存,用于buffer或cache的内存。
标记4 为每个进程占用CPU的比率,top会进行倒叙排列
标记5为top1的进程名称。
以上是我们在发现CPU异常时,可以通过top命令快速采集当前CPU占用最多的进程,以及具体是CPU的哪一部分占用高,根据以上的信息,我们需要能够快速的判断方向。
代码死循环是出现频率很高的问题,对于一些循环的判断条件判断有误,循环无法跳出。在我们当前的生产环境下,之前就发生了在一个多层循环的最内层查询大量数据,而引发CPU耗尽
比如下边这个例子就会迅速让我们的CPU耗尽
import multiprocessing import os def process_task(): while True: pass if __name__ == "__main__": num_processes = multiprocessing.cpu_count() processes = [] for _ in range(num_processes): p = multiprocessing.Process(target=process_task) p.start() processes.append(p) for p in processes: p.join()
在生产环境下,当工作线程需要访问外部资源的时候,如果外部资源响应非常慢,就会让我们的工作线程一直处于等待状态,只要这样的等待任务够多,cpu就会被耗尽。
程序多个线程如果一直等待一个不被释放的锁,就会出现死锁,死锁实际上是一个无线等待。在之前做LVS负载军时,CPU访问共享连接表(竞争资源操作需要加锁)就会使用自旋锁,发生流量突发时,就会出现大量CPU消耗在自旋锁等待上。
在我们当前的业务代码中,因为历史原因就存在大量的冗余逻辑,比如同步调用外部接口,同步执行大量的文件读写,无效数据库查询。
一般业务代码常会采用多进程或者多线程模型,系统中如果并发创建了非常多的线程,那线程间切换,线程对竞争资源的锁争用就会愈发明显。因为CPU是有限的,则cpu就不得不在众多的进程/线程间来回切换,最后cpu都消耗在了上下文切换上
解决思路:进程池或者线程池限制并发量
这是一种常规性的cpu消耗,比如搜索推荐场景的模型训练、和推理,视频、图片编解码,大数据计算如hadoop的MapReduce任务,spark任务等,这些场景都是CPU密集型的业务。
碰到这种CPU密集型的业务,CPU 100%是很正常的,不必担忧,任务跑完之后,CPU自会下来。作为运维我们需要做的是将CPU密集型的业务尽可能独立于其他在线业务部署,或者通过cgroup对这些应用所使用的CPU进行限制。保证业务间不要相互影响
在我们前边讲到的Top中有一项是si
,软中断,多数情况都是服务器当前存在有网络请求突发。对于一些网络转发行的应用,比如典型的TCP层的负载均衡设备(LVS/Nginx/Haproxy)等,其核心能力就是数据包转发。
如果出现瞬间的网络流量突发,就会触发大量网卡中断,那SI的数量就可能会非常多,将CPU资源耗尽。在多核CPU下,网卡中断需要均匀的绑定到每一个CPU核心上,如果绑定不均,CPU的中断消耗就会不均,则经常会出现CPU核心一个接一个被依次打死【如下右图】。
cat /proc/interrupts |grep -i eth 可以查看当前各个CPU核心的网卡中断消耗
如下图是在互联网中广泛存在的代理架构,比如我们haproxy,nginx等,正常情况下客户端连接proxy,proxy负载与后端的service节点建立连接,所以一个请求proxy需要建立两个连接。
正常情况下后端服务正常快速返回没有问题,但是如果后端服务出现慢请求一直等待,那proxy向后的连接就会一直被占用;还有客户端可能会因为访问超时而出现大量的重试请求。一般现在的proxy层都会分别与client和service维护长连接,那这个时候服务器上的连接数会被迅速拉升。
维护TCP连接数本身就会消耗一定的内存和CPU资源,再加上服务器的端口是有限的,在新建连接的时候tcp会从整个端口中查询可用端口(受local_port_range限制),这个过程在端口占用量很高的情况下,是非常消耗CPU的。
解决办法:
在内存不足时,如果程序需要申请内存,系统就会进行内存swap,将内存的一部分数据交换出去,存储到磁盘的swap分区中,回收内存以满足程序的内存升级。
此时会有诸多原因造成CPU使用突发:
实际上很多语言都有GC(垃圾回收)的过程,其中java最具代表性,java的gc过程是非常消耗CPU资源的。
如果硬盘故障,硬盘写入带宽不足,或者IOPS不足的情况下,如果碰上大量的随机读写,或者IOPS不足的情况下,CPU会出现大量的io wait,最终整个CPU会消耗殆尽。
如下图是我们在AWS上使用的RDS mysql实例,我们在创建之初使用的磁盘类型是gp2
,使用过aws的同学可能知道,这个类型的云盘iops是磁盘容量乘以3,也就是我100GB的磁盘空间,最高只有300 iops。
在iops不足的情况下,mysql的cpu就直接到了100%,后边的磁盘空间是aws rds为了满足需要的iops,进行了磁盘的自动扩容。
当然除了磁盘本身的性能限制之外,如果碰上磁盘故障,SSD写寿命到期,SSD写入不均衡,Raid卡设置或硬件异常(如raid缓存失效,或者配置了Write Through)都会造成磁盘读写性能下降,最终cpu耗尽。
怎么查询IO消耗:
解决方案:
这也会经常单独出现在各大厂的面试题中,因为java在大厂应用比较多
1、通过top找到CPU占用率高的进程
2、通过top -Hp pid命令查看CPU占比靠前的线程ID
3、再把线程ID转化为16进制
printf "0x%x" <thread_id>
如:printf "0x%x" 32 ==> 0x20
4、通过jstack生成线程dump文件
jstack -l <PID> > dump.log
5、分析线程dump文件
grep "0x<十六进制线程ID>" dump.log
如:grep "0x20" dump.log
这将显示包含该线程ID的线程栈信息。分析这些线程栈,找到可能导致CPU高占用的代码
生产环境下下cpu 100%是一个常见问题,原因有非常多,作为运维当秉承着保障在线业务稳定性第一的原则,优先解决问题,而后协同研发排查。
至于cpu 100%的原因,常见的业务代码问题,网络突发,服务器容量不足,连接数超限,内存不足等等,生产环境下导致最终cpu 100%的原因还有很多,还需要各位同学在生产环境中多积累和总结。
运维相关岗位面试时涉及到知识面非常广,所以复习起来会有无从下手的感觉。为了让同学们面试不迷茫,都能找到一份好工作,我们整理了运维面试的高频面试题,关注我们回复“面试题”免费领取。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。