cpu的概念模型
cpu包含控制逻辑单元、算数逻辑单元、寄存器 、一二三级缓存。多核cpu会独占它自己的一级二级缓存,三级缓存是被所有cpu共享。一般在现代cpu芯片上,会将mmu和tlb这两个硬件设备镶嵌在cpu芯片上。
mmu是什么?
cpu在执行程序指令的时候,程序传给cpu的地址是一个虚拟地址,虚拟地址最终要被转变成一个实际的物理地址,才能够在主存上面进行访问,而mmu就是这么一个转换地址的硬件设备。
tlb
tlb是让这种转换的过程达到一个加速的一个硬件设备。
cpu工作的本质只是为了计算,而计算的本质就是加减乘除。其中位运算逻辑是通过算数逻辑单元去完成的。
控制逻辑单元是负责程序指令的存取、分析以及执行,最终你的程序会被编译成一条一条机器指令,而控制逻辑单元则负责执行每一条指令并且将每一条指令的算数逻辑通过算数逻辑单元去完成 。
寄存器,还有cpu的一级二级三级缓存,本质上都是为了存储 ,只不过它们存储的内容可能会有差别,有可能是数据,也有可能是指令。
cache line
说到一级二级三级缓存,就要提到一个概念,叫做cache line(缓存行)。cpu在读区内存的时候,每次会预读一块数据,而这一块数据就叫cache line,是cup缓存的一个最小单位,在64位的操作系统里,一个cache line存储64个字节。
为什么会有并发安全问题的产生?
首先你的数据有可能在一级二级缓存里面的,在多核cpu下,你的数据有可能会被多个cpu的2级缓存所拥有,那一个cpu它去更新数据的时候,怎么能够保证其他cpu的二级缓存里当操作的时候是得到一个最新的数据呢? 所以我们得为这种多个cpu竞争的这种资源去加上锁。
加锁的本质是什么
golang或java等编成语言给共享资源加锁实际上是通过汇编里面去加了一个总线锁,总线锁是能够让其他cpu此时不能对内存去进行读写,因为cpu在内存去进行交互的时候是通过总线完成的,加了总线锁之后,其他cpu不能够通过总线对内存去进行读写了,加锁的cpu的读写操作会直接写入主存里面去,然后会让其他cpu对该内存地址的缓存行失效,在一级二级缓存里面缓存的最小单位是一个缓存行cache line,加锁之后,会让对应的其他cpu该内存地址的缓存行失效,并且cpu写的时候,会写到主存里面去,这样在解锁之后,其他cpu会重新从主存里面拿最新的数据,保证了数据的并发安全,这也是我们为什么要加锁的原因。
为什么程序变慢?
本质是cpu没有做事情或者cpu忙于做事,从而没有执行你的程序指令导致的。
先来看第一种情况,cpu没有做事情,突增的流量不一定会导致cpu忙碌,但是可能会导致cpu使用率增加,但可能达不到使用率瓶颈。如果突增的流量是执行io密集型,可能导致系统更多的阻塞,那系统如果是处于更多的阻塞状态之后,cpu其实是处于一种空闲的状态,这种空闲的状态可能并不会使得cpu使用率增加很多,并且这段空闲的状态会让你的程序阻塞在这里,它的指令并没有执行到,这种就会造成延迟性问题,解决办法就是让cpu忙碌起来,频繁的网络接口操作导致整个系统是处于一种阻塞的状态,而cpu此时的使用率其实并没有上去,所以要解决这种情况的话,应该更好的利用好cpu,提高它的一个使用率,所以要减少这种阻塞的操作,比如将频繁的接口调用改成用内存缓存去代替频繁的接口调用,消除掉了网络调用带来的阻塞,来达到让接口延迟降低的目的。
程序变慢本质第二个原因是cpu忙于做事情,而cpu忙于做事之后使cpu的使用率上升,cpu此时已经是处于一个瓶颈的状态,它来不及去执行你的目的程序的指令,导致你程序会产生一个延迟性问题,而表现在于你的程序的负载可能会有所上升,平时我们在服务维护或监控服务中,会观察到cpu的使用率上升。
该如何去排查呢
首先从系统整体上去把控这个cpu使用率的一个情况,再具体到每一个进程,哪一个进程是最消耗cpu的,通过定位到进程之后,还可以进一步去定位到具体的问题代码。
先看第一步,从整体上把控cpu的情况,一般最常用的是top命令,
它能够很好的去看cpu在系统上面一个宏观情况。
- us是用户态程序占用cpu
- sy是内核态占用cpu
- id是空闲cpu占用量
- wa是等待cpu执行耗时,这个值过高的话,可能要引起注意:可能此时的cpu使用率不高,但是等待cpu执行耗时过高的话,会导致,你的程序有延迟性问题。要减少你程序的一个阻塞,还是要看具体的代码,去减少这种阻塞性的操作。
- hi是硬中断耗时
- si软中断耗时
提到cpu的使用率一般还会看系统的一个负载情况,top命令依然能够显示整个系统的一个负载情况,一般一个4核cpu,负载如果超过4之后,可以认为此时有更多的应用程序或更多的任务处于一种等待的状态,这样的话,你的系统延迟肯定会有所增加的,因为你更多的程序在等待,程序来不及执行目前的机器指令。
负载可以理解为排队等待和正在执行的任务数或进程数,一般四核的话,会以四这个指标作为一个临界点,超过四之后呢,你的整个系统的负载会认为是过大的。
从宏观上把握了cpu的使用情况之后,再来看下从进程的角度看cpu。
在top命令后 ,输入大写P按cpu使用率大小去进行排序,这样就定位到了一个最消耗cpu的一个进程,那具体这个进程是哪一段代码,在golang程序里面可以通过pprof工具去分析cpu的profile文件,去找到是哪一段代码是最消耗cpu的,这样就能够在排查cpu的时候,达到宏观系统层面到进程,再到具体代码段,那整个过程的打通了。
创业项目群,学习操作 18个小项目,添加 微信:923199819 备注:小项目!
如若转载,请注明出处:https://www.zodoho.com/65246.html