到底应该怎么理解“平均负载”?

  • 平均负载定义

    • 单位时间内,系统处于可运行状态不可中断状态的平均进程数,也就是平均活跃进程数。

      • 可运行状态:指正在使用 CPU 或者正在等待 CPU 的进程
      • 不可中断状态:指正处于内核态关键流程中的进程,并且这些流程是不可打断的
  • 当平均负载高于 CPU 数量 70% 的时候,你就应该分析排查负载高的问题
  • 平均负载与 CPU 使用率区别

    • 平均负载:不仅包括了正在使用 CPU 的进程,还包括等待 CPU 等待 I/O 的进程
    • CPU使用率:是单位时间内 CPU 繁忙情况的统计

      • CPU 密集型进程,使用大量 CPU 会导致平均负载升高,此时这两者是一致的
      • I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高
      • 大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高
  • 测试工具

    • stress:Linux 系统压力测试工具
    • sysstat:包含了常用的 Linux 性能工具,用来监控和分析系统的性能

      • mpstat 是一个常用的多核 CPU 性能分析工具,用来实时查看每个 CPU 的性能指标,以及所有 CPU 的平均指标
      • pidstat 是一个常用的进程性能分析工具,用来实时查看进程的 CPU、内存、I/O 以及上下文切换等性能指标

经常说的 CPU 上下文切换是什么意思

  • 【CPU上下文】定义:CPU在运行任何任务前,必须的依赖环境。包括:CPU寄存器、程序计数器
  • 【CPU上下文切换】定义:就是先把前一个任务的 CPU 上下文保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
  • CPU上下文切换的几种场景

    • 进程上下文切换

      • 进程的运行空间分为:内核空间、用户空间

        • 内核空间(Ring 0)具有最高权限,可以直接访问所有资源;
        • 用户空间(Ring 3)只能访问受限资源,不能直接访问内存等硬件设备,必须通过系统调用陷入到内核中,才能访问这些特权资源。
      • 系统调用

        • 当我们查看文件内容时,就需要多次系统调用来完成:首先调用 open() 打开文件,然后调用 read() 读取文件内容,并调用 write() 将内容写到标准输出,最后再调用 close() 关闭文件
        • 一次系统调用的过程,会发生了两次 CPU 上下文切换
        • 系统调用过程通常称为特权模式切换,而不是上下文切换
      • 进程上下文包括:内核空间的堆栈、寄存器信息;用户空间的虚拟内存、栈、全局变量等。
      • 切换流程:进程A执行->进程A上下文保存->加载进程B上下文->进程B执行
      • 切换时机:只有在进程调度的时候,才需要切换上下文

        • 进程执行完。则它之前使用的CPU会释放出来,这个时候再从就绪队列里,拿一个新的进程运行
        • CPU按时间片轮转。当某个进程的时间片耗尽了,就会被系统挂起,切换到其它正在等待 CPU 的进程运行
        • 进程在系统资源不足(比如内存不足)时。此时要等到资源满足后才可以运行,这个时候进程也会被挂起,并由系统调度其他进程运行
        • 进程调用sleep睡眠函数。此时进程会将自己主动挂起,自然也会重新调度
        • 有优先级更高的进程运行时。为了保证高优先级进程的运行,当前进程会被挂起,由高优先级进程来运行
        • 发生硬件中断时。此时CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序
    • 线程上下文切换

      • 线程是调度的基本单位,而进程则是资源拥有的基本单位。
      • 线程上下文切换分为两种情况

        • 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上下文切换是一样。
        • 前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。
    • 中断上下文切换

      • 为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件。
      • 跟进程上下文不同,中断上下文切换并不涉及到进程的用户态。所以,即便中断过程打断了一个正处在用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源。中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等。
      • 对同一个 CPU 来说,中断处理比进程拥有更高的优先级,所以中断上下文切换并不会与进程上下文切换同时发生。
  • 排查工具介绍

    • vmstat

      • vmstat 是一个常用的系统性能分析工具,主要用来分析系统的内存使用情况,也常用来分析 CPU 上下文切换和中断的次数。
      • 例子(每隔5秒输出1组数据):vmstat 5
      • 关键字段

        • cs(context switch)是每秒上下文切换的次数
        • in(interrupt)则是每秒中断的次数
        • r(Running or Runnable)是就绪队列的长度,也就是正在运行和等待 CPU 的进程数
        • b(Blocked)则是处于不可中断睡眠状态的进程数
    • pidstat

      • 查看每个进程/线程的上下文切换情况
      • 例子(每隔5秒输出1组数据,-w参数表示输出上下文切换指标,而-u参数则表示输出CPU使用指标,-t 表示输出线程维度的指标信息):pidstat -w -u -t 5
      • 关键字段

        • cswch ,表示每秒自愿上下文切换(voluntary context switches)的次数
        • nvcswch ,表示每秒非自愿上下文切换(non voluntary context switches)的次数
      • 关键字段概念

        • 自愿上下文切换,是指进程无法获取所需资源,导致的上下文切换
        • 非自愿上下文切换,则是指进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换
    • sysbench

      • 多线程基准测试工具,一般用来评估不同系统参数下的数据库负载情况。
      • 例子(以10个线程运行5分钟的基准测试,模拟多线程切换):sysbench --threads=10 --max-time=300 threads run
    • 查看中断信息

      • 命令:watch -d cat /proc/interrupts
  • 排查总结

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

某个应用的CPU使用率居然达到100%,我该怎么办?

  • CPU使用率

    • 节拍率:单位HZ,表示每秒CPU时间轮转的次数

      • 查看系统节拍率:grep 'CONFIG_HZ=' /boot/config-$(uname -r)
      • 用户空间节拍率:USER_HZ,它总是固定为 100,也就是 1/100 秒
    • 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):代表以低优先级运行虚拟机的时间。
    • CPU使用率公式

      • CPU 使用率,就是除了空闲时间外的其他时间占总 CPU 时间的百分比。
      • 性能分析工具给出的都是间隔一段时间的平均 CPU 使用率,所以要注意间隔时间的设置。
  • 常用排查工具

    • top

      • top 显示了系统总体的 CPU 和内存使用情况,以及各个进程的资源使用情况。
    • pidstat
    • perf

      • 性能分析工具。它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题。
      • perf top

        • 支持参数:-g开启调用关系分析,-p指定特定进程PID
        • 显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数。
        • 采样数(Samples)、事件类型(event)和事件总数量(Event count)。
        • 第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
        • 第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
        • 第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
        • 最后一列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。
      • perf record

        • 持续采集数据,直至你强制终止。
      • perf report

        • 打开上面用record采集的离线数据并分析。
  • 经验总结

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

【案例】系统的 CPU 使用率很高,但为啥却找不到高 CPU 的应用?

  • 排查经过

    • 通过top、pidstat发现整体CPU使用率高,但每个进程则使用率均很低
    • 发现某些进程虽一直存在,但PID实际在不断变化,说明有两种可能:

      • 第一个原因,进程在不停地崩溃重启,比如因为段错误、配置错误等等,这时,进程在退出后可能又被监控系统自动重启了。
      • 第二个原因,这些进程都是短时进程,也就是在其他应用内部通过 exec 调用的外面命令。这些命令一般都只运行很短的时间就会结束,你很难用 top 这种间隔时间比较长的工具发现。
    • 通过pstree命令,树状查看进程之间关系

【案例】系统中出现大量不可中断进程和僵尸进程怎么办?

  • 进程状态

    • R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行。
    • D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠(Uninterruptible Sleep),一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断。
    • Z 是 Zombie 的缩写,它表示僵尸进程,也就是进程实际上已经结束了,但是父进程还没有回收它的资源(比如进程的描述符、PID 等)。
    • S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态。
    • I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。前面说了,硬件交互导致的不可中断进程用 D 表示,但对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况。要注意,D 状态的进程会导致平均负载升高, I 状态的进程却不会。
    • s 表示这个进程是一个会话的领导进程,而 + 表示前台进程组
  • 进程状态相关概念

    • 进程组,表示一组相互关联的进程,比如每个子进程都是父进程所在组的成员;

      • 后台运行的命令,构成后台进程组;在前台运行的命令,构成前台进程组
    • 会话,是指共享同一个控制终端的一个或多个进程组。
  • 排查工具

    • dstat,用于实时查看系统所有资源情况,包括CPU、mem、IO、network等。
    • strace,常用的跟踪进程的系统调用的工具。命令范例:strace -p

      • 若遇到返回Operation not permitted,可能是进程已经是僵尸进程导致无法访问。
  • 排查经过

    • iowait分析

      • 症状:整体iowait很高
      • 先top命令,查看处于D状态的进程有哪些
      • pidstat -d 3 10,查看各个进程的磁盘读写情况
      • strace -p ,查看嫌疑进程的系统调用情况
      • perf record -g,perf report。查看CPU调用栈情况。
    • 僵尸进程

      • 解决整理思路:找到它们的根儿,也就是找出父进程,然后在父进程里解决。
      • 使用pstree查看进程之间依赖关系,来找可疑父进程。

怎么理解Linux软中断?

  • 中断概念

    • 中断是系统用来响应硬件设备请求的一种机制,它会打断进程的正常调度和执行,然后调用内核中的中断处理程序来响应设备的请求。
    • 中断其实是一种异步的事件处理机制,可以提高系统的并发处理能力。
    • 中断处理程序在响应中断时,会临时关闭中断。这就会导致上一次中断处理完成之前,其他中断都不能响应,也就是说中断有可能会丢失。
  • 硬件中断&软中断概念

    • 为解决中断处理程序执行过长和中断丢失的问题,Linux 将中断处理过程分成了两个阶段,也就是上半部(硬件中断)和下半部(软中断)
    • 上半部(硬件中断),用来快速处理中断,它在中断禁止模式下运行,主要处理跟硬件紧密相关的或时间敏感的工作。
    • 下半部(软中断),用来延迟处理上半部未完成的工作,通常以内核线程的方式运行。

      • 每个 CPU 都对应一个软中断内核线程,名字为 “ksoftirqd/CPU 编号”。
  • 查看软中断&内核线程

    • /proc/softirqs,提供了软中断的运行情况
    • /proc/interrupts,提供了硬中断的运行情况

【案例】系统的软中断CPU使用率升高,我该怎么办?

  • 使用工具

    • sar,系统活动报告工具,既可以实时查看系统的当前活动,又可以配置保存和报告历史统计数据。

      • 怀疑CPU问题,使用:sar -usar -q

        • sar -u 查看CPU使用率情况
        • sar -q 查看运行队列进程数、平均负载等信息
      • 怀疑内存存在瓶颈,使用:sar -Bsar -rsar -W

        • sar -B 查看内存分页和缓存的使用情况
        • sar -r 查看内存和交换空间的统计信息
        • sar -W 查看系统SWAP交换的统计信息
      • 怀疑I/O存在瓶颈,使用:sar -bsar -usar -d

        • sar -b 查看I/O和传送速率的统计信息
        • sar -d 查看每一个块设备的活动信息
    • tcpdump ,常用的网络抓包工具,常用来分析各种网络问题。
  • 排查经过

    • 使用top查看CPU使用情况。发现其中si(软中断)比例相对较高,且软中断核心线程ksoftirqd/0的CPU使用率相对也较高。
    • 查看所有软中断的次数变化速率情况,所用命令:watch -d cat /proc/softirqs

      • 发现NET_RX(网络数据包接收)变化速率最快
    • 使用sar查看系统的网络收发情况,所用命令:sar -n DEV 1(-n DEV 表示显示网络收发的报告,间隔1秒输出一组数据)

      • 第一列:表示报告的时间
      • 第二列:IFACE 表示网卡
      • 第三、四列:rxpck/s 和 txpck/s 分别表示每秒接收、发送的网络帧数,也就是 PPS
      • 第五、六列:rxkB/s 和 txkB/s 分别表示每秒接收、发送的千字节数,也就是 BPS
      • 排查发现PPS大,而BPS小,说明接收到的都是小包。
    • 使用tcpdump抓包排查,所用命令:tcpdump -i eth0 -n tcp port 80(-i eth0 只抓取eth0网卡,-n不解析协议名和主机名,tcp port 80表示只抓取tcp协议并且端口号为80的网络帧)

【总结】如何迅速分析出系统CPU的瓶颈在哪里?

111.png
112.png
113.png
114.png

  • 工具汇总

    • 系统整体维度

      • top,展示系统整体以及各个进程的资源使用情况。
      • vmstat,查看系统内存、交换区、io、中断、上下文切换、CPU使用情况

        • vmstat 2 10(每2秒输出一次,输出10次)
      • dstat,查看CPU使用、io、网络、交换区(分页)、中断、上下文切换
      • sar,系统所有指标都能看。CPU、IO、内存等等。
    • CPU维度

      • mpstat,查看每个CPU或者整体的使用情况。

        • mpstat -P 0 2 10(查看CPU0的使用情况,每2秒输出一次,输出10次)
      • /proc/softirqs,查看软中断类型和每个CPU上的中断次数

        • watch -d cat /proc/softirqs
      • /proc/interrupts,查看硬件中断类型和每个CPU上的中断次数

        • watch -d cat /proc/interrupts
    • 进程/线程维度

      • pidstat,查看进程的 CPU、内存、I/O 以及上下文切换等性能指标。

        • pidstat -u -r -d -w -t 2 10(-u查看CPU、-r查看内存、-d查看IO、-w查看上下文、-t看线程维度,-p指定进程号,最后每2秒输出一次,输出10次)
      • ps,查看进程状态情况

        • ps -ef,ps -aux
      • pstree,查看进程之间的数状关系

        • pstree -p -a(加-p表示展示进程pid,-a表示展示进程完整指令参数。两者都可不加)
      • strace,查看进程的系统调用。

        • strace -p
      • perf,性能分析工具

        • perf top -g -p (加-g开启调用关系分析,-p则指定分析某个进程)
        • perf record,持续采集数据。
        • perf report,分析所采集的数据。

【总结】CPU 性能优化的几个思路

  • 性能优化方法论

    • 怎么评估性能优化的效果

      • 确定性能的量化指标

        • 不要局限在单一维度的指标上(至少要从应用程序系统资源这两个维度选择指标)
      • 测试优化前的性能指标
      • 测试优化后的性能指标

        • 避免性能测试工具干扰应用程序的性能
        • 避免外部环境的变化影响性能指标的评估
    • 多个性能问题同时存在,要怎么选择

      • 并不是所有的性能问题都值得优化(二八法则,20%代码造成80%的性能问题)
      • 第一,如果发现是系统资源达到了瓶颈,比如 CPU 使用率达到了 100%,那么首先优化的一定是系统资源使用问题。完成系统资源瓶颈的优化后,我们才要考虑其他问题。
      • 第二,针对不同类型的指标,首先去优化那些由瓶颈导致的,性能指标变化幅度最大的问题。比如产生瓶颈后,用户 CPU 使用率升高了 10%,而系统 CPU 使用率却升高了 50%,这个时候就应该首先优化系统 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 上
  • 千万避免过早优化