• 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空闲时运行的程序,所以占比很高是很正常的

  • 相关阅读:
    java占位符应用
    【QuickHit项目实例】
    【那些年关于java多态应用】
    【那些年关于MyEclipse的快捷键大全】
    那些年【深入.NET平台和C#编程】
    关于《网络电视精灵》项目
    VS2013常用快捷键
    关于C#的继承结论
    关于【项目经理评分】项目的代码分析
    序列化和发序列化
  • 原文地址:https://www.cnblogs.com/hrers/p/12776111.html
Copyright © 2020-2023  润新知