Jusene's Blog

【读书笔记】Linux性能优化 CPU篇

字数统计: 4.1k阅读时长: 15 min
2019/12/01 Share

平均负载

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

  • 可运行状态的进程:指正在使用cpu或者正在等待cpu的进程,也就是R状态的进程
  • 不可中断进程:是指正处于内核关键流程中的进程,并且这个进程不可打断,即处于D状态的进程

复习下进程状态:

  • R 是Running或者Runnable的缩写,表示进程就绪在CPU的就绪队列,正在运行或者正在等待运行
  • D 是Disk Sleep的缩写,也就是不可中断睡眠,一般表示该进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断
  • Z 是Zombie的缩写,僵尸进程,进程已经结束,但父进程没有回收资源,过度的僵尸进程会消耗系统资源和文件数
  • S 是Interruptible Sleep缩写,也就是可中断睡眠,因某个事件被系统挂起,当进程等待的事件发生,会进入R状态
  • I 是Idle的缩写,空闲状态,用在不可中断睡眠内核线程上,与硬件交互导致不可中断进程,但对某些内核线程内核线程来说,可能并没有任何负载,用idle区分
  • T和t 是Stopped和Trace的缩写
  • X是Dead缩写

错误认知:

  • 平均负载就是cpu的使用率

从平均的负载的含义来看包括:

  • 使用cpu的进程
  • 等待cpu的进程
  • 等待io的进程

从在三个方面分析业务场景:

  • cpu密集型进程,使用大量cpu导致平均负载升高,cpu使用率和平均负载升高的主要因素
  • 大量进程等待cpu调度,导致平均负载升高,此时cpu的使用lv也是比较高的
  • io密集型,等到i/o也会导致平均负载升高,但cpu的使用lv不一定很高

性能调试工具:

  • pidstat:一个常用的进程性能分析工具,用来查看进程的cpu、内存、i/o
  • mpstat:常用的多核cpu性能分析工具,用来实时查看每个cpu的性能指标,以及所以的cpu的平均指标
  • iostat:提供cpu统计,存储i/o统计(磁盘设备,分区及网络文件系统)

需要安装这些工具:
sysstat包官网:http://sebastien.godard.pagesperso-orange.fr/download.html

总结

  • 平均负载高可能是cpu密集型进程导致的
  • 平均负载高不一定代表cpu使用率高,还有可能是i/o更繁忙
  • 平均负载高于cpu数量70%的时候,就要去排查负载高的问题

CPU上下文切换

从业务场景分析,大量进程等待cpu调度,进程在竞争cpu的时候并没有真正运行,为什么会导致系统负载升高,而cpu的上下文切换就是根本原因。

在每个任务运行前,cpu都需要知道任务从哪里加载,又从哪里开始运行,需要系统设置好cpu寄存器和程序计数器/

  • cpu寄存器:是cpu内置的容量小,但速度极快的内存
  • 程序计数器:存储cpu正在执行的指令位置,或者即将执行的下一个指令位置

在cpu运行任务之前,必须依赖的环境,因此被叫做cpu上下文切换

cpu上下文切换分:

  • 进程上下文切换
  • 线程上下文切换
  • 中断上下文切换

进程上下文切换

进程即可以在用户空间运行,也可以在内核空间运行,进程从用户态到内核态的转变,需要通过系统调用(system call)来完成。

系统调用的过程发生了cpu上下文切换

系统调用cpu寄存器里的原来的用户态的指令位置,需要保存起来,为了内核代码的执行,cpu寄存器需要更新为内核态指令代码,最后跳到内核态运行内核任务。

一次系统调用的过程,其实是发生了两次cpu上下文切换

系统调用和进程上下文切换的不同点:

  • 系统调用不需要虚拟内存等进程用户资源,也不切换进程
  • 进程上下文切换是指一个进程切换到另一个进程
  • 系统调用始终在一个一个进程内完成

系统调用过程通常称为特权模式切换,而不是上下文切换

cpu山下文切换不是免费的,在大量进程等待cpu调度的场景,很容易频繁的进程上下文切换,导致cpu将大量的时间耗费在寄存器、内核栈等资源的保存和恢复上,大大缩减运行进程的时间,这也是导致平均负载升高的原因。

进程调度场景:

  • cpu时间划分时间片,分配给各个进程,当某个进程时间片耗尽,就会被系统挂起,切换到其他正在等待cpu的进程运行
  • 进程在系统资源不足的时候,需要等到资源满足才能运行,这个时候进程也会被挂起,并由其他进程运行
  • 当进程通过睡眠函数sleep方法主动挂起
  • 当有优先级更高的进程进行时,为保证高优先级进程运行,当前进程会被挂起
  • 当发生硬件中断时,cpu也会被挂起,转而执行内核的中断服务程序

线程上下文切换

线程是调度的基本单位,而进程是资源拥有的基本单位

线程的上下文切换:

  • 前后两个线程属于不同进程,资源不共享,所以切换和进程上下文切换是一样的
  • 前后两个线程属于同一个进程,虚拟内存共享,所以切换时,只需要切换线程私有数据、寄存器等不共享的数据

中断上下文切换

为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而处理中断程序,响应硬件事件

中断处理不涉及用户态的资源,所以中断只需要保存内核态的资源

另外对同一个cpu来说,中断处理比进程拥有更高的优先级

总结

cpu上下文切换,是保证linux系统正常运行的核心功能之一,过多的cpu上下文切换,会把cpu时间消耗在寄存器、内核栈以及内存等数据保存和恢复上,从而缩进进程真正运行的时间,导致系统整体性能大幅下降

调试工具:
vmstat查看系统上下文切换:

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

pidstat -w查看每个进程的上下文切换:

  • cswch: 每秒的自愿上下文切换
  • nvcswch: 每秒的非自愿上下文切换

自愿性上下文切换:是指进程无法获取所需的资源,导致的上下文切换
非自愿性上下文切换:是指进程时间片已到,被系统强制调度

当我们查看进程无法定位上下文切换的进程,需要查看线程的上下文切换时:
pidstat -w -t 可以显示线程级上下文切换

查看中断:watch -d /proc/interrupts

  • cpu上下文切换取决cpu的性能,数量级在一万以内应该算正常。
  • 自愿性上下文切换变多,说明进程都在等待资源,可能发生i/o或内存不足等问题
  • 非资源上下文切换变多,说明进程都在被强制调度,都在抢cpu
  • 中断次数变多,说明cpu被中断处理程序占用,通过/proc/interrupt文件分析中断类型

perf分析cpu性能

1
perf top
2
Samples: 1K of event 'cpu-clock', 4000 Hz, Event count (approx.): 180292181 lost: 0/0 drop: 0/0                                                                                 
3
Overhead  Shared Object        Symbol                                                                                                                                           
4
   5.26%  perf                 [.] rb_next
5
   5.00%  [kernel]             [k] finish_task_switch
6
   4.48%  perf                 [.] __symbols__insert
7
   3.70%  [kernel]             [k] kallsyms_expand_symbol.constprop.1
8
   3.69%  [kernel]             [k] _raw_spin_unlock_irqrestore
9
   2.72%  [kernel]             [k] clear_page
10
   2.35%  libc-2.17.so         [.] __GI_____strtoull_l_internal
11
   2.06%  libc-2.17.so         [.] _IO_getdelim
12
   1.85%  [kernel]             [k] vsnprintf
13
   1.78%  [kernel]             [k] number.isra.2
14
   1.78%  [kernel]             [k] strnlen
15
   1.71%  [kernel]             [k] module_get_kallsym
16
   1.71%  perf                 [.] __dso__load_kallsyms

第一行:

  • 采样数(samples)
  • 事件类型(event)
  • 事件总数量(event count)

第二行:

  • overhead:该符号的性能事件在所有采样中的比例
  • shared:该函数或指令所在的动态共享对象,如内核、进程名
  • object:是动态共享对象的类型,比如[.]表示用户空间执行程序或者动态链接库,而[k]则表示内核空间
  • symbol:是符号名,也是函数名,当函数未知时,用16进制的地址表示

perf record保留数据的功能, perf report保留数据解析展示

perf top和perf record加上-g参数,开启调用关系的采样,方便根据调用链分析性能问题

top 中cpu事间含义:

  • 用户(us)
  • 系统(sy)
  • nice (ni)
  • 空闲(id)
  • io等待(wa)
  • 硬件中断(hi)
  • 软件中断(si)
  • 虚拟化(st)
  1. 用户cpu和nice高,说明用户态进程占用较多的cpu,所以应该排查进程的性能问题
  2. 系统cpu高,说明内核态占用了较多cpu,所以应该排查内核线程或系统调用的性能问题
  3. io等待cpu高,说明等待i/ode事件较多,说明应该着重排查系统存储是不是出现了io问题
  4. 软中断和硬中断高,说明软中断和硬中断的处理程序占用了较多cpu,所以着重排查内核的中断服务程序

短时进程

当cpu使用率很高的时候,不一定能找到相应的高cpu使用率的进程

cpu使用率很高,但是就是无法定位哪个进程引起的,这时需要从进程状态R的进程:
ps axu | awk '{if ($8 == "R") print $0}'

这时我们可以注意查看是否有频繁的进程变化,频繁的换pid,那么要定位:

  • 该进程是不是不停奔溃重启,进程不停被拉起
  • 这些进程是否短时进程,是很难通过top定位的

这个需要长时间尝试查看,并可以通过进程的进程树来定位该进程的父进程或监控器:
yum install psmisc

execsnoop是专门为短时进程设计的工具,它通过ftrace实时监控进程的exec()行为,并输出短时进程的基本信息。

github: https://github.com/brendangregg/perf-tools/blob/master/execsnoop

不可中断进程

cpu iowait高,导致平均负载升高

  • 用dstat查看cpu和磁盘读写的关联关系
  • 查看处于D状态的进程
  • pidstat来定位是否是该进程导致的cpu iowait过高
  • 可以用perf top来定位导致iowait升高的函数

iowait高不一定代表i/o有性能瓶颈,当系统中有i/o类型的进程在运行时,iowait也会很高,但实际磁盘的读写远没有达到性能瓶颈的程度

软中断

中断:系统用来响应硬件设备请求的一种机制,会打断进程的正常调度和执行,通过调用内核中的中断处理程序来响应设备的请求

  1. 中断是一种异步的事件处理机制,可以提高系统的并发处理能力
  2. 为了减少对系统进程运行调度的影响,中断处理程序就需要尽可能快地运行
  3. 中断分上下两部分:
    (1)上部分用来快速处理中断,主要处理跟硬件紧密相关的和时间敏感的工作
    (2)下部分用来处理上半部分未完成的工作,通常以内核线程的方式运行

软中断内核线程的名字:ksoftirqd/cpu编号

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

当软中断事件频发时,内核线程会因为cpu的使用率过高而导致而导致软中断处理不及时,进而引发网络收发延迟、调度缓慢等性能问题

小包问题

机器变慢,软中断cpu时间变大,软中断会导致网络延迟

1
watch -d /proc/softirqs

可以发现NET_RX是网络数据包接收软中断的变化速率最快

通过sar来查看网络问题

1
# DEV显示网络收发报告
2
sar -n DEV 1
3
Linux 3.10.0-693.el7.x86_64 (node1)     11/22/2019      _x86_64_        (2 CPU)
4
5
04:31:14 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
6
04:31:15 AM      eth0  38986.00  19494.00   2056.78   1104.30      0.00      0.00      0.00
7
04:31:15 AM        lo      3.00      3.00      0.40      0.40      0.00      0.00      0.00
8
9
04:31:15 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
10
04:31:16 AM      eth0  40204.00  20102.00   2121.02   1139.11      0.00      0.00      0.00
11
04:31:16 AM        lo      6.00      6.00      0.99      0.99      0.00      0.00      0.00
12
13
04:31:16 AM     IFACE   rxpck/s   txpck/s    rxkB/s    txkB/s   rxcmp/s   txcmp/s  rxmcst/s
14
04:31:17 AM      eth0  41120.00  20560.00   2168.91   1165.00      0.00      0.00      0.00
15
04:31:17 AM        lo      3.00      3.00      0.40      0.40      0.00      0.00      0.00
  • rxpck/s和txpck/s分别表示每秒接收、发送的网络帧数,也就是PPS
  • rxkB/s和txkB/s分别表示每秒接收、发送的字节数,也就是BPS

接收的PPS比较大,而BPS却很小,计算
BPS*1024/PPS 比如 约等于 54字节,这是一个很小网络帧

在通过tcpdump来抓去网络包,通过网络分析来封堵小包的来源IP

性能指标和性能工具联系起来

性能指标 工具 说明
平均负载 uptime top
系统整体cpu使用率 vmstat mpstat top sar /proc/stat /proc/stat是基于性能工具数据来源
进程cpu使用率 top pidstat ps htop atop
系统上下文切换 vmstat 除了上下文切换,还提供运行状态和不可中断状态的进程数
进程上下文切换 pidstat -w选项
软中断 top /proc/softirqs pidstat pidstat -w查看进程的上下切换 -t查看线程上下文切换
硬中断 top vmstat /proc/interrupts vmstat提供总中断次数
网络 dstat sar tcpdump
I/O dstat sar pidstat pidstat -d 可以查看每个磁盘io
cpu个数 /proc/cpuinfo lscpu
事件 perf execsnoop
性能工具 CPU性能指标
uptime 平均负载
top 平均负载 运行队列 整体的cpu使用率以及每个进程的状态和cpu使用率
htop top增强版
atop cpu 内存 磁盘 网络等各种资源全面监控
vmstat 系统整体cpu使用率,上下文切换、中断次数、运行和不可中断的进程数
mpstat 每颗cpu的使用率和软中断次数
pidstat 进程和线程的cpu使用率,中断上下文切换次数
/proc/softirqs 软中断类型和在每个cpu上的累计中断次数
/proc/interrupts 硬中断类型和在每个cpu上的累计中断次数
ps 每个进程的状态和cpu使用率
pstree 进程的父子关系
dstat 系统整体的cpu使用率
sar 系统整体的cpu使用率,包括可配置的历史数据
strace 进程的系统调用
perf cpu性能事件刨析,如调用链分析
execsnoop 监控短时进程

CPU优化套路

  • CPU优化

降低cpu使用率,提供cpu的并行能力

  • 应用程序优化
  1. 编译器优化
  2. 算法优化
  3. 异步处理
  4. 多线程代替多进程
  5. 善用缓存
  • 系统优化
  1. CPU绑定
  2. CPU独占
  3. 优先级调整(nice)
  4. 为进程设置资源限制(cgroup)
  5. NUMA优化
  6. 中断负载均衡(irqbalance,smp_affinity)

切记:因业务变而变,过早优化是万恶之源

CATALOG
  1. 1. 平均负载
    1. 1.1. 总结
  2. 2. CPU上下文切换
    1. 2.1. 进程上下文切换
    2. 2.2. 线程上下文切换
    3. 2.3. 中断上下文切换
    4. 2.4. 总结
  3. 3. perf分析cpu性能
  4. 4. 短时进程
  5. 5. 不可中断进程
  6. 6. 软中断
    1. 6.1. 小包问题
  7. 7. 性能指标和性能工具联系起来
  8. 8. CPU优化套路