平均负载
平均负载是指单位时间内,系统处于可运行状态和不可中断的平均进程数,也就是平均活跃进程数:
- 可运行状态的进程:指正在使用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)
- 用户cpu和nice高,说明用户态进程占用较多的cpu,所以应该排查进程的性能问题
- 系统cpu高,说明内核态占用了较多cpu,所以应该排查内核线程或系统调用的性能问题
- io等待cpu高,说明等待i/ode事件较多,说明应该着重排查系统存储是不是出现了io问题
- 软中断和硬中断高,说明软中断和硬中断的处理程序占用了较多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)下部分用来处理上半部分未完成的工作,通常以内核线程的方式运行
软中断内核线程的名字: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的并行能力
- 应用程序优化
- 编译器优化
- 算法优化
- 异步处理
- 多线程代替多进程
- 善用缓存
- 系统优化
- CPU绑定
- CPU独占
- 优先级调整(nice)
- 为进程设置资源限制(cgroup)
- NUMA优化
- 中断负载均衡(irqbalance,smp_affinity)
切记:因业务变而变,过早优化是万恶之源