CPU性能分析篇之回炉再造

===============CPU性能篇之回炉再造==============
平均负载:
指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数。

可运行状态进程:
指正在使用CPU或者正在等待CPU的进程,也就是处于R状态的进程

不可中断进程:
指正处于内核关键流程中的进程,并且流程是不可打断的,比如等待硬件设备的io响应,也就是处于D状态的进程。

负载过高涉及到的三个方面:
1.CPU密集型进程,使用大量CPU会导致平均负载过高,此时与CPU使用率过高一致;
2.io密集型进程,等待io会导致平均负载过高,但CPU使用率不一定很高;
3.大量等待CPU的进程调度也会导致平均负载过高,此时与CPU使用率过高一致。

CPU密集型进程模拟:
1.压测CPU使用率
stress --cpu 1 --timeout 600
2.查看负载情况
watch -d uptime
看出负载过高是由于CPU而不是io
3.查看CPU使用率的变化
mpstat -P ALL 5 #监控所有CPU,间隔5秒输出一组数据
用户态CPU使用率明显升高
4.查看具体哪一个进程导致CPU数升高
pidstat -u 5 1 #间隔5秒输出一组数据
可以明显看出是由于stress命令导致CPU上升

I/O密集型进程模拟:
1.模拟io压力,即不停的执行sync
stress -i 1 --timeout 600
2.查看负载情况
watch -d uptime
3.查看CPU使用率变化情况
mpstat -P ALL 5 1
系统态CPU明显上升,iowait明显上升,所以负载过高与io有关,进程在内核态调用
4.查看进程CPU使用情况
pidstat -u 5 1
系统态CPU上升明显,可以发现是stress命令导致的

大量进程场景模拟:
1.多进程压测CPU
stress -c 8 --timeout 600 #模拟8进程对CPU进行压测
2.监控负载情况
watch -d uptime
3.查看CPU的使用情况
mpstat -P ALL 5 1
用户态CPU使用率明显升高,iowait处于正常值
4.查看是哪一个进程导致的
pidstat -u 5 1 #这个效果不明显
pidstat -w -u 5 1 #可以看出stress命令出现大量的非自愿上下文切换,说明CPU在频繁的调度他们,大量stress进程等待被调度
所以问题出在大量stress进程

================================================================================================
CPU方面的概念:
CPU寄存器:是CPU内置的容量小,但速度极快的内存。

程序计数器:是用来存储CPU正在执行的指令的位置、或者即将执行的下一条指令的位置。它们都是运行任何任务之前,必须依赖的环境,也被叫做CPU上下文。

CPU上下文切换:CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。

上下文切换的三种情况:
进程上下文切换、线程上下文切换、中断上下文切换

CPU特权等级:Ring0和Ring3,分别对应着内核空间和用户空间,用户态向系统态的转变需要通过系统调用来完成。
内核空间(Ring 0)具有最高权限,可以直接访问所有资源;
用户空间(Ring3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源

说明:
CPU寄存器里原来用户态的指令位置,需要先保存起来。接着,为了执行内核态代码,CPU寄存器需要更新为内核态指令的新位置。最后才是跳转到内核态运行内核任务。而系统调用结束后,CPU寄存器需要恢复原来保存的用户态,然后再切换到用户空间,继续运行进程。所以,一次系统调用的过程,其实是发生了两次 CPU 上下文切换。但是进程上下文切换是指一个进程切换到另外一个进程运行,而系统调用一直是在同一个进程中,所以系统调用通常称为特权模式转换,我不是上下文切换。但实际上,系统调用过程中,CPU 的上下文切换还是无法避免的。

《==================================================================================》
进程上下文切换:
进程的上下文切换就比系统调用时多了一步:在保存当前进程的内核状态和CPU寄存器之前,需要先把该进程的虚拟内存、栈等保存下来;而加载了下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈。因此在进行上下文切换时涉及到内存资源的保存和恢复,而且本身CPU切换也是需要时间的,另外Linux通过TLB来管理虚拟内存到物理内存的映射关系。当虚拟内存更新后,TLB也需要更新,内存的访问也会随之变慢。特别是在多处理器系统上,缓存是被多个处理器共享的,刷新缓存不仅会影响当前处理器的进程,还会影响共享缓存的其他处理器的进程。

CPU对进程的调度:
Linux 为每个 CPU 都维护了一个就绪队列,将活跃进程(即正在运行和正在等待 CPU的进程)按照优先级和等待 CPU 的时间排序,然后选择最需要 CPU 的进程,也就是优先级最高和等待 CPU 时间最长的进程来运行。

CPU的几种调度情况:
其一,为了保证所有进程可以得到公平调度,CPU时间被划分为一段段的时间片,这些时间片再被轮流分配给各个进程。这样,当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行。

其二,进程在系统资源不足(比如内存不足)时,要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行。

其三,当进程通过睡眠函数sleep这样的方法将自己主动挂起时,自然也会重新调度。其四,当有优先级更高的进程运行时,为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行。

最后一个,发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序。

总结起来就这几种情况:进程CPU时间片到期、进程优先级较高、进程自己进入睡眠状态、发生中断服务
《===================================================================================》
线程上下文切换:
进程、线程概念:
线程是调度的基本单位,而进程则是资源拥有的基本单位。说白了,所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。

线程的上下文切换分为两种情况:
第一种, 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。
第二种,前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。到这里你应该也发现了,虽然同为上下文切换,但同进程内的线程切换,要比多进程间的切换消耗更少的资源,而这,也正是多线程代替多进程的一个优势。

《===================================================================================》
中断上下文切换:
概念:
中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行。

中断上下文切换并不涉及到进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等。

对同一个CPU来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。同样道理,由于中断会打断正常进程的调度和执行,所以大部分中断处理程序都短小精悍,以便尽可能快的执行结束。

另外,跟进程上下文切换一样,中断上下文切换也需要消耗CPU,切换次数过多也会耗费大量的CPU,甚至严重降低系统的整体性能。所以,当你发现中断次数过多时,就需要注意去排查它是否会给你的系统带来严重的性能问题。


《===================================================================================》
CPU上下文切换的分析:
vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU上下文切换和中断的次数。
pidstat命令可以给出每个进程详细的上下文情况,pidstat -w 5 每五秒输出一组数据,里面的字段涉及到两个新的内容,一个是cswch,表示每秒自愿上下文切换,另一个则是nvcswch,表示每秒非自愿上下文切换。

自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换。比如说,I/O、内存等系统资源不足时,就会发生自愿上下文切换

非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换。比如说,大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换。

《==================================================================================》
实战模拟:
使用sysbench来模拟系统多线调度切换的情况
1.查看空闲系统的上下文切换次数
vmstat 1 1 #每隔一秒后输出一组数据
当前系统正常
2.模拟系统多线程调度的瓶颈
sysbench --threads=10 --max-time=300 threads run #以10个线程运行五分钟基准测试,模拟多线程切换问题
3.执行vmstat查看上下文切换情况
vmstat 1
中断次数和上下文切换次数明显升高,系统用户态也明显升高
4.具体查看进程上下文切换情况
pidstat -w -u 1 # -w 参数表示输出进程切换指标,而 -u 参数则表示输出 CPU 使用指标
此时看到的内核线程kworker、rcu_sched明显上下文切换增多。但是总的切换次数少于上面的vmstat看到的,这是因为pidstat显示的是进程指标的上下文切换,所以切换次数少于vmstat命令看到的切换次数
pidstat -wt 1 #-t 可以线程的指标
可以看出sysbench产生了大量的自愿、非自愿上下文切换
5.在上面测试时,会看到中断次数也上升了
watch -d cat /proc/interrupts #可以查看中断的情况
变化速度最快的是重调度中断(RES),这个中断类型表示,唤醒空闲状态的CPU来调度新的任务运行。这是多处理器系统(SMP)中,调度器用来分散任务到不同 CPU 的机制,通常也被称为处理器间中断

总结:
自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题;
非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU的确成了瓶颈;
中断次数变多了,说明 CPU 被中断处理程序占用,还需要通过查看 /proc/interrupts 文件来分析具体的中断类型。

《================================================================================》
CPU使用率:
CPU频率(jiffies来记录节拍数),可以通过系统来设置
grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=1000 #我的CPU节拍率为1000

说明:
正因为节拍率HZ是内核选项,所以用户空间程序并不能直接访问。为了方便用户空间程序,内核还提供了一个用户空间节拍率USER_HZ,它总是固定为 100,也就是 1/100秒。这样,用户空间程序并不需要关心内核中 HZ 被设置成了多少,因为它看到的总是固定值 USER_HZ。

Linux通过/proc虚拟文件系统,向用户空间提供了系统内部状态的信息,而/proc/stat提供的就是系统的CPU和任务统计信息。
例:查看CPU信息
cat /proc/stat | grep ^cpu

cpu各字段占用率:
user(通常缩写为 us),代表用户态 CPU 时间。注意,它不包括下面的 nice 时间,但包括了 guest 时间。
nice(通常缩写为ni),代表低优先级用户态CPU时间,也就是进程的nice值被调整为1-19之间时的CPU时间。这里注意,nice 可取值范围是 -20 到 19,数值越大,优先级反而越低。
system(通常缩写为 sys),代表内核态 CPU 时间。
idle(通常缩写为 id),代表空闲时间。注意,它不包括等待 I/O 的时间(iowait)。
iowait(通常缩写为 wa),代表等待 I/O 的 CPU 时间。
irq(通常缩写为 hi),代表处理硬中断的 CPU 时间。
softirq(通常缩写为 si),代表处理软中断的 CPU 时间。
steal(通常缩写为 st),代表当系统运行在虚拟机中的时候,被其他虚拟机占用的 CPU时间。
guest(通常缩写为 guest),代表通过虚拟化运行其他操作系统的时间,也就是运行虚拟机的 CPU 时间。
guest_nice(通常缩写为 gnice),代表以低优先级运行虚拟机的时间。

注:top和ps这两个工具报告的CPU使用率,默认的结果很可能不一样,因为top默认使用3秒时间间隔,而ps使用的却是进程的整个生命周期。

perf top 可以查看具体哪一个函数CPU占用率
perf record 保存数据
说明:加上 -g 参数,开启调用关系的采样,方便我们根据调用链来分析性能问题。


案例说明:
1.运行nginx容器作为实验对象
docker run --name nginx -p 10000:80 -itd feisky/nginx
docker run --name phpfpm -itd --network container:nginx feisky/php-fpm
2.另外一台机器进行访问测试
curl http://192.168.0.10:10000/
It works!
3.ab命令进行压测
ab -c 10 -n 100 http://192.168.0.10:10000/
可以看出每秒承受的平均请求数和每请求一次耗费的时间
4.top命令查看CPU使用率
top
5.查看具体哪一个函数导致的CPU使用率上升
perf top -g -p 25151 #-g开启调用关系,-p指定进程号
查看php进程的调用关系,就可以看到具体的函数CPU使用情况
6.找到源码文件,进行处理

总结:
用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题。
系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题。
I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储是不是出现了 I/O 问题。
软中断和硬中断高,说明软中断或硬中断的处理程序占用了较多的 CPU,所以应该着重排查内核中的中断服务程序。

《=============================================================================》
特殊情况分析:
当一个程序运行起来又崩溃,而且不停的运行停止,其中代码可能有问题,导致CPU使用率很高,但是top查看,vmstat查看,pidstat查看,都很正常,CPU使用率都不高,这是由于不断起停这个服务造成的,而这些命令又无法准确显示。
可以使用命令execsnoop命令来查看,这个命令是专门用来分析这种短时进程的

《=============================================================================》
进程状态:
R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。

D是DiskSleep的缩写,也就是不可中断状态睡眠(UninterruptibleSleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。

Z是Zombie的缩写,如果你玩过“植物大战僵尸”这款游戏,应该知道它的意思。它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。

S是InterruptibleSleep的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。

I是Idle的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用D表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用Idle正是为了区分这种情况。要注意,D状态的进程会导致平均负载升高,I 状态的进程却不会。

T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态。

X,也就是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它。

僵尸进程分析:
概念:
进程组:表示一组相互关联的进程,比如每个子进程都是父进程所在组的成员
会话:指共享同一个控制终端的一个或多个进程组
s表示进程状态中的领导进程,+表示前台进程组
现象:负载升高、僵尸进程多、存在不可中断睡眠进程、处于等待的CPU占比较高
说明:这可能是由于程序代码问题导致程序运行结束后,父进程没有对子进程进行回收,父进程结束后,子进程变成了僵尸进程,子进程还占用着大量的CPU资源,导致负载过高。可以通过命令进行分析和异常排查。排查过程与上面相似。

重点概念:
不可中断状态,表示进程正在跟硬件交互,为了保护进程数据和硬件的一致性,系统不允许其他进程或中断打断这个进程。进程长时间处于不可中断状态,通常表示系统有 I/O性能问题。
僵尸进程表示进程已经退出,但它的父进程还没有回收子进程占用的资源。短暂的僵尸状态我们通常不必理会,但进程长时间处于僵尸状态,就应该注意了,可能有应用程序没有正常处理子进程的退出。

dstat命令:可以同时显示CPU和I/O两种资源的使用情况,可以看出磁盘此时的读写情况,再与前面的mpstat看到的iowait作比较,可以看出iowait的升高与对磁盘的读取有关。dstat 1 10 #每隔一秒输出10组数据

pidstat -d -p 4344 1 3 #-d表示展示I/O统计数据,-p表示指定进程号,每隔一秒输出3组数据。可以查看指定进程的磁盘读取情况

pidstat -d 1 20 #每秒输出20组数据,查看全部进程的磁盘读取情况,确定哪些进程使用了大量的io资源

strace -p 6082 #进程追踪工具,-p指定进程号,追踪进程的调用关系

perf top #查看进程的函数调用,确定具体问题

处理僵尸进程:
pstree #查看进程进程树情况,确定具体的父进程表是哪一个,根据父进程找到对应的代码文件,确认子进程资源调用有没有做了回收

《===================================================================》
中断:一种异步的事件处理机制,可以提高系统的并发处理能力。中断处理程序会打断其他程序的运行,所以,为了减少对正常进程运行调度的影响,中断处理程序就需要尽可能快地运行。

硬中断与软中断的引出:
为了解决中断处理程序执行过长和中断丢失的问题,Linux将中断处理分成了两个阶段,也就是上半部分和下半部分。

上半部用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。
下半部用来延迟处理上半部未完成的工作,通常以内核线程的方式运行。

上半部分直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行;
下半部分则是由内核触发,也就是我们常说的软中断,特点是延迟执行。

说明:上半部会打断 CPU 正在执行的任务,然后立即执行中断处理程序。而下半部以内核线程的方式执行,并且每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU编号”,比如说, 0 号 CPU 对应的软中断内核线程的名字就是 ksoftirqd/0。

软中断不只包括了刚刚所讲的硬件设备中断处理程序的下半部,一些内核自定义的事件也属于软中断,比如内核调度和 RCU 锁(Read-Copy Update 的缩写,RCU 是 Linux 内核中最常用的锁之一)等。

proc文件系统:它是一种内核空间和用户空间进行通信的机制,可以用来查看内核的数据结构,或者用来动态修改内核的配置。其中:
/proc/softirqs 提供了软中断的运行情况;
/proc/interrupts 提供了硬中断的运行情况。
查看文件可以获取到中断在CPU上的累计运行次数

ps -aux | grep 'softirq' #查看软中断运行状况。名字包含在中括号里面的,一般都是内核线程。

《==================================================================》
软中断分析:
三个命令工具:
sar 是一个系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据。
hping3 是一个可以构造 TCP/IP 协议数据包的工具,可以对系统进行安全审计、防火墙测试等。
tcpdump 是一个常用的网络抓包工具,常用来分析各种网络问题。

软中断分析模拟:

1.hping3命令实例:模拟大量访问-洪水攻击
hping3 -S -p 80 -i u100 ip地址段 #-S表示设置TCP协议的SYN(同步序列号),-p 表示目的端口为80 -i表示指定时间间隔为u100微妙发送一个网络帧。发动大量的get请求,模拟SYN攻击

2.top命令查看异常情况
top
si数据增大,可能由于软中断导致的,可以考虑查看更详细的软中断变化率

3.查看详细的软中断变化率
watch -d cat /proc/softirqs
可以发现, TIMER(定时中断)、NET_RX(网络接收)、SCHED(内核调度)、RCU(RCU 锁)等这几个软中断都在不停
变化

4.通过sar命令查看系统网络收发情况,不仅可以观察网络收发的吞吐量BPS,还可以观察网络收发的PPS,即每秒收发的网络帧数
sar -n DEV 1 #-n DEV表示显示网络收发的报告,间隔一秒输出一组数据
显示的字段解释:
第一列:表示报告的时间。
第二列:IFACE 表示网卡。
第三、四列:rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数,也就是 PPS。
第五、六列:rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数,也就是 BPS。
后面的其他参数基本接近 0,显然跟今天的问题没有直接关系,你可以先忽略掉。

5.通过sar命令显示内容,可以算出每个网络帧接受的数据大小
我这里数值计算为:20*1024/351=58字节,说明此时接受了很多小数据包

6.确定是什么样的数据包
通过tcpdump命令抓取包来获取网络帧
tcpdump -i eth0 -n tcp port 80 #-i指定网卡 -n指定协议 port 指定端口哦
发现大量的SYN请求,说明系统受到影响是由于网络攻击

7.解决办法
对ip地址进行拦截

总结:由于hping3命令发送了大量的SYN连接,服务器这边硬中断处理速度快,把后面任务交给了软中断处理,导致大量软中断请求堆积,最终导致si上升,软中断处理被占用,本身系统是通过ssh连接的,收到网络数据包延迟,导致卡顿。
用的ssh远程登录,在这期间hping3大量发包,导致其他网络连接延迟,ssh通过网络连接,使ssh客户端感觉卡顿现象。

《=====================================================》
补充:
新命令:glances yum -y install glances
可以显示很多系统资源占用信息

CPU 缓存的命中率。由于 CPU 发展的速度远快于内存的发展,CPU 的处理速度就比内存的访问速度快得多。这样,CPU 在访问内存的时候,免不了要等待内存的响应。为了协调这两者巨大的性能差距,CPU 缓存(通常是多级缓存)就出现了。
从 L1 到 L3,三级缓存的大小依次增大,相应的,性能依次降低(当然比内存还是好得多)。而它们的命中率,衡量的是 CPU 缓存的复用情况,命中率越高,则表示性能越好。

DPDK是一种优化网络处理速度的方法,它通过绕开内核网络协议栈的方法,提升网络的处理能力。不过它有一个很典型的要求,就是要独占一个 CPU 以及一定数量的内存大页,并且总是以100% 的 CPU 使用率运行。所以,如果你的 CPU 核数很少,就有点得不偿失了。

《=====================================================》
优化思路:
1.确认优化指标;
2.获取优化指标数据;
3.进行模拟测试时,需要注意测试工具不能和实验机在一个主机上。保证优化前后实验主机为同一个;
4.通过数据确认优化可以带来较大提升的指标进行优化;
5.对于这些指标进行优化,注意优化这些指标的双面性,带来的损失会不会比优化带来的效益更大。配合资源情况,做出合适的调整。
6.测试优化结果

《=====================================================》
优化总结起来分为两个方向:一个是应用程序优化,一个是系统资源优化

应用程序优化:
从应用程序的角度来说,降低CPU使用率的最好方法当然是,排除所有不必要的工作,只保留最核心的逻辑。比如减少循环的层次、减少递归、减少动态内存分配等等。

编译器优化:很多编译器都会提供优化选项,适当开启它们,在编译阶段你就可以获得编
译器的帮助,来提升性能。比如, gcc 就提供了优化选项 -O2,开启后会自动对应用程
序的代码进行优化。

算法优化:使用复杂度更低的算法,可以显著加快处理速度。比如,在数据比较大的情况
下,可以用 O(nlogn) 的排序算法(如快排、归并排序等),代替 O(n^2) 的排序算法
(如冒泡、插入排序等)。

异步处理:使用异步处理,可以避免程序因为等待某个资源而一直阻塞,从而提升程序的
并发处理能力。比如,把轮询替换为事件通知,就可以避免轮询耗费 CPU 的问题。

多线程代替多进程:前面讲过,相对于进程的上下文切换,线程的上下文切换并不切换进
程地址空间,因此可以降低上下文切换的成本。

善用缓存:经常访问的数据或者计算过程中的步骤,可以放到内存中缓存起来,这样在下
次用时就能直接从内存中获取,加快程序的处理速度。


系统优化:
优化 CPU 的运行,一方面要充分利用 CPU 缓存的本地性,加速缓存访问;另一方面,就是要控制进程的 CPU 使用情况,减少进程间的相互影响

CPU 绑定:把进程绑定到一个或者多个 CPU 上,可以提高 CPU 缓存的命中率,减少跨CPU 调度带来的上下文切换问题。

CPU 独占:跟 CPU 绑定类似,进一步将 CPU 分组,并通过 CPU 亲和性机制为其分配
进程。这样,这些 CPU 就由指定的进程独占,换句话说,不允许其他进程再来使用这些CPU。

优先级调整:使用 nice 调整进程的优先级,正值调低优先级,负值调高优先级。优先级
的数值含义前面我们提到过,忘了的话及时复习一下。在这里,适当降低非核心应用的优
先级,增高核心应用的优先级,可以确保核心应用得到优先处理。

为进程设置资源限制:使用 Linux cgroups 来设置进程的 CPU 使用上限,可以防止由于
某个应用自身的问题,而耗尽系统资源。

NUMA(Non-Uniform Memory Access)优化:支持 NUMA 的处理器会被划分为
多个 node,每个 node 都有自己的本地内存空间。NUMA 优化,其实就是让 CPU 尽可
能只访问本地内存。

中断负载均衡:无论是软中断还是硬中断,它们的中断处理程序都可能会耗费大量的
CPU。开启 irqbalance 服务或者配置 smp_affinity,就可以把中断处理过程自动负载均
衡到多个 CPU 上。

《====================================================================》
问题统计:
1.pidstat命令没有%wait列
由于版本原因, systat 11.5.5 版本才引入的新指标,可以ton过/proc文件中获取数据,命令的一些数据来源,也是来源于此

2.stress命令无法模拟iowait高的场景
因为案例中的stress -i 参数,它表示通过系统调用sync()来模拟io问题,这种方法实际上并不可靠,因为sync()本意是刷新内存缓冲区的数据到磁盘中,以确保同步。如果缓冲区本来就没有多少数据,那读写到磁盘的数据也就不多,也就没法产生io压力。这一点,在使用SSD磁盘的环境中尤为明显,很可能你的iowait总是0.却单纯因为大量的系统调用,导致系统CPU使用率sys升高。
推荐使用stress-ng 代替stress。
stress-ng -i 1 --hdd 1 --timeout 600 #-i的含义是调用sync,-hdd表示读写临时文件

3.不同版本的sysbench运行参数也不是完全一样
Ubuntu18.04
sysbench --threads=10 --max-time=300 threads run
Ubuntu16.04
sysbench --num-threads=10 --max-time=300 --test=threads run

4.%wait与%iowait的区别
pidstat中,%wait表示进程等待CPU的时间百分比
top中,iowait%则表示等待io的CPU时间百分比

5.关于重调度中断RES的说明
重调度中断是调度器用来分散任务到不同CPU的机制,也就是可以唤醒空闲状态的CPU,来调度新任务运行,而这通常借助处理器中断来实现。所以,这个中断在单核(只有一个逻辑CPU)的机器上当然就没有意义了,因为压根就不会发生重调度的情况。

6.docker运行环境,指定磁盘和读取速率
docker run --help #查看帮助
-d参数可以读取的磁盘 -s设置每次读取的数据量大小

7.perf命令在容器中执行有误
这是由于perf命令在容器中执行取不到待分析进程依赖库
解决方法:
1.在容器外面构建相同路径的依赖库。不推荐,会污染容器主机
2.在容器内部运行perf,但是需要更改为特权模式,不然会报错,存在风险不推荐
更改特权模式:将/proc/sys/kernel/perf_event_paranoid 文件改为-1
3.指定符号路径为容器文件系统的路径-不理解
mkdir /tmp/foo
PID=$(docker inspect --format {{.State.Pid}} phpfpm)
bindfs /proc/$PID/root /tmp/foo #bindfs 的基本功能是实现目录绑定
perf report --symfs /tmp/foo
#使用完成后解除绑定
umount /tmp/foo/
4.在容器外面吧分析记录保存下来,再去容器里查看结果这样,库和符号的路径也就都对了。目的是使用主机的路径
1.先运行 perf record -g -p < pid>。执行一会后,ctrl+c结束
2.将文件考入容器分析
docker cp perf.data phpfpm:/tmp
docker exec -i -t phpfpm bash
3.在容器的 bash 中继续运行下面的命令,安装 perf 并使用 perf report 查看报告
cd /tmp/
apt-get update && apt-get install -y linux-tools linux-perf procps
perf_4.9 report
4.注意点
perf命令在不同环境的安装是不一样的
Ubuntu上是这么安装的: apt-get install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r))
PHP-fpm容器这样安装:apt-get install -y linux-perf

swapper程序是CPU空闲时运行的程序,所以占比很高是很正常的

原文地址:https://www.cnblogs.com/hrers/p/12776111.html