运维面试八股--大厂面试必问,CPU 100%了你该怎么办

CPU使用率高一直是工程师头疼的问题,也是面试题中的常客,几乎所有的大厂在面试的时候都问过此类问题。

可能每个同学都看到过,甚至有过开发同学写到过的更加详细的分析过程。但是今天,小编会从一个运维的视角来告诉你该如何回答。

插播一条我自己的广告:如果您即将毕业,如果 您最近正面临跳槽找工作,那不妨关注我,这里整理了近几百道运维相关面试题,还在持续更新,面试前刷刷八股,提高面试通过率

面试提示

  • 面试过程应该中,对于此类开放性问题,应优先给出解决和排查思路
  • 至于具体的原因,需要根据自身掌握的知识体系选择性作答,不推荐回复自己完全陌生领域的内容,比如java gc,如果你不是java栈,或者没有接触过,那就灵活替换成自己熟悉的技术栈
  • 不推荐回答自己陌生领域,也就意味着我推荐大家在回答问题的时候,有意识将问题引导向自己熟悉的领域

1 CPU占用高的分析脑图

在这里插入图片描述

2 面对CPU 100%后的通用法则

  1. 先处理问题,再排查原因

    对于线上业务,作为运维,永远需要以保障线上业务稳定为第一要务。绝不可以无限期的以追查根因为目标来处理线上问题。当然非在线业务,则需要竭尽全力追查元凶

  2. 最可能保留现场

    在响应和处理CPU高的问题时,要尽可能采集和保留当前系统环境,如系统资源状态,连接信息,进程内存dump信息等

  3. 迅速隔离

    对于线上问题,单点cpu异常,则可以断定出现了偶发性问题,问题节点应该在保留现场后迅速隔离(如从线上离线、重启等),多节点通用问题,优先立即扩容

    隔离方法:

    • 节点从线上离线
    • kill 进程ID
    • 服务器重启
  4. 离线还原及复现

    线上节点在隔离之后,就已经失去了故障发生时的状态,所以对于一些复杂问题,就需要在线上根据故障现场信息,进行环境重建和场景复现,分析和测试问题可能的原因

以上仅代表我个人过去多年运维经验的总结,如有更好或不同意见,请留言讨论。

3 状态采集及分析

3.1 了解我们的top命令

在这里插入图片描述

标记1 的行,为CPU的使用率详情,其中每个不同的指标一般代表着不同的原因

  • user(us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
    • us高则代表为某个用户进程占用的cpu过多,比如上图的标记 5 行,top会按照实际的CPU使用率进行排序,可以很方便的看到具体是哪一个进程占用的CPU过多
  • system(sy),代表内核态 CPU 时间
    • 内核空间的cpu时间占用过多,包括系统调用、中断、驱动、内核级服务或者守护进程占用等
  • nice(ni),代表低优先级用户态 CPU 时间,也就是进程的 nice 值被调整为 1-19 之间时的 CPU时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
  • idle(id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait),这个占用高代表的是空闲,而不是使用率,一般我们在配置告警的时候,也常会使用(1-id%)来计算CPU的使用率
  • iowait(wa),代表等待 I/O 的 CPU 时间
    • wa占用过多,这个大部分都是在等待磁盘I/O,如磁盘带宽、IOPS不足,或者I/O调度不合理或者文件系统问题等等
  • irq(hi),代表处理硬中断的 CPU 时间
    • 硬中断数,一般硬中断引起的cpu使用率高的概率不多,因为一般设备硬中断的时间很少
  • softirq(si),代表处理软中断的 CPU 时间。
    • 软中断高,一般都会是网卡出现了数据包突发,如网络pps突增,网卡中断绑定不均等
  • steal(st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU 时间。
    • 这个一般在虚拟机化,云计算IaaS层会发生,当物理机出现cpu超售的时候,cpu被其他虚拟机争用的时候会出现。如果出现了这个高,请选择非突发性实例

标记2/3代表的是当前系统内存及swap交换分区使用情况,从左向右依次为,总内存,剩余内存,使用内存,用于buffer或cache的内存。

标记4 为每个进程占用CPU的比率,top会进行倒叙排列

标记5为top1的进程名称。

以上是我们在发现CPU异常时,可以通过top命令快速采集当前CPU占用最多的进程,以及具体是CPU的哪一部分占用高,根据以上的信息,我们需要能够快速的判断方向。

4 CPU 100%的原因分析

4.1 代码问题

4.1.1 业务死循环

代码死循环是出现频率很高的问题,对于一些循环的判断条件判断有误,循环无法跳出。在我们当前的生产环境下,之前就发生了在一个多层循环的最内层查询大量数据,而引发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()
4.1.2 死锁和等待

在生产环境下,当工作线程需要访问外部资源的时候,如果外部资源响应非常慢,就会让我们的工作线程一直处于等待状态,只要这样的等待任务够多,cpu就会被耗尽。

程序多个线程如果一直等待一个不被释放的锁,就会出现死锁,死锁实际上是一个无线等待。在之前做LVS负载军时,CPU访问共享连接表(竞争资源操作需要加锁)就会使用自旋锁,发生流量突发时,就会出现大量CPU消耗在自旋锁等待上。

在这里插入图片描述

4.1.3 冗余的不必要的业务逻辑

在我们当前的业务代码中,因为历史原因就存在大量的冗余逻辑,比如同步调用外部接口,同步执行大量的文件读写,无效数据库查询。

4.2 性能及容量问题

4.2.1 大量的并发任务

一般业务代码常会采用多进程或者多线程模型,系统中如果并发创建了非常多的线程,那线程间切换,线程对竞争资源的锁争用就会愈发明显。因为CPU是有限的,则cpu就不得不在众多的进程/线程间来回切换,最后cpu都消耗在了上下文切换上

在这里插入图片描述

解决思路:进程池或者线程池限制并发量

4.2.2 业务密集的CPU计算任务

这是一种常规性的cpu消耗,比如搜索推荐场景的模型训练、和推理,视频、图片编解码,大数据计算如hadoop的MapReduce任务,spark任务等,这些场景都是CPU密集型的业务。

碰到这种CPU密集型的业务,CPU 100%是很正常的,不必担忧,任务跑完之后,CPU自会下来。作为运维我们需要做的是将CPU密集型的业务尽可能独立于其他在线业务部署,或者通过cgroup对这些应用所使用的CPU进行限制。保证业务间不要相互影响

4.2.3 大量的网络请求

在我们前边讲到的Top中有一项是si,软中断,多数情况都是服务器当前存在有网络请求突发。对于一些网络转发行的应用,比如典型的TCP层的负载均衡设备(LVS/Nginx/Haproxy)等,其核心能力就是数据包转发。

如果出现瞬间的网络流量突发,就会触发大量网卡中断,那SI的数量就可能会非常多,将CPU资源耗尽。在多核CPU下,网卡中断需要均匀的绑定到每一个CPU核心上,如果绑定不均,CPU的中断消耗就会不均,则经常会出现CPU核心一个接一个被依次打死【如下右图】。

在这里插入图片描述

cat /proc/interrupts  |grep -i eth 可以查看当前各个CPU核心的网卡中断消耗

在这里插入图片描述

4.2.4 大量的TCP连接占用

如下图是在互联网中广泛存在的代理架构,比如我们haproxy,nginx等,正常情况下客户端连接proxy,proxy负载与后端的service节点建立连接,所以一个请求proxy需要建立两个连接。

正常情况下后端服务正常快速返回没有问题,但是如果后端服务出现慢请求一直等待,那proxy向后的连接就会一直被占用;还有客户端可能会因为访问超时而出现大量的重试请求。一般现在的proxy层都会分别与client和service维护长连接,那这个时候服务器上的连接数会被迅速拉升。

维护TCP连接数本身就会消耗一定的内存和CPU资源,再加上服务器的端口是有限的,在新建连接的时候tcp会从整个端口中查询可用端口(受local_port_range限制),这个过程在端口占用量很高的情况下,是非常消耗CPU的。

在这里插入图片描述

在这里插入图片描述

解决办法:

  • 配置合理的连接超时时间,让连接可以快速回收,并配合使用tcp timewait reuse
  • 合理配置与客户端以及与后端服务的长连接配置,合理控制长连接idle的超时时间
  • 增加后端service的数量,IP或者端口,让五元组组合数更多
  • 在service服务固定的情况下,可以增加proxy的source ip来临时性的解决连接数量的问题

4.3 资源问题

4.3.1 内存不足

在内存不足时,如果程序需要申请内存,系统就会进行内存swap,将内存的一部分数据交换出去,存储到磁盘的swap分区中,回收内存以满足程序的内存升级。

此时会有诸多原因造成CPU使用突发:

  • 瞬间大量的内存数据交换到磁盘,I/O读写会很高,这个时候大量的CPU可能会消耗在wa上
  • 现在大部分服务器是没有swap分区的,当没有足够内存的时候,会调用kswapd0内核线程执行内存交换,但是又没有swap分区可用,可能就会陷入一个死循环,如下图

在这里插入图片描述

4.3.2 Java进程的频繁GC

实际上很多语言都有GC(垃圾回收)的过程,其中java最具代表性,java的gc过程是非常消耗CPU资源的。

在这里插入图片描述

4.3.3 硬盘异常或I/O性能不足

如果硬盘故障,硬盘写入带宽不足,或者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消耗:

  • top中的cpu wa数量高,即可以判断是磁盘IO问题
  • iotop工具分析io使用量最高的进程

解决方案:

  • 检查硬盘硬件是否异常,读写性能(如通过smart,raid卡提供的工具等查看磁盘性能及状态信息)
  • 选择性能更好的磁盘,如nvme ssd。对于高IO的业务,推荐使用本地盘服务器,而非云盘
  • 对于云盘IO与磁盘空间相关的时候,为了获取更高的IOPS,可能就需要扩展更多的云盘空间了。

5 Java程序CPU问题该如何分析

这也会经常单独出现在各大厂的面试题中,因为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高占用的代码

6 总结

生产环境下下cpu 100%是一个常见问题,原因有非常多,作为运维当秉承着保障在线业务稳定性第一的原则,优先解决问题,而后协同研发排查

至于cpu 100%的原因,常见的业务代码问题,网络突发,服务器容量不足,连接数超限,内存不足等等,生产环境下导致最终cpu 100%的原因还有很多,还需要各位同学在生产环境中多积累和总结。

7 写在最后

运维相关岗位面试时涉及到知识面非常广,所以复习起来会有无从下手的感觉。为了让同学们面试不迷茫,都能找到一份好工作,我们整理了运维面试的高频面试题,关注我们回复“面试题”免费领取。
在这里插入图片描述
在这里插入图片描述

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值