1.CPU
1.1 CPU 相关的术语
平均负载 :单位时间内,系统处于可运行状态和不可中断状态的平均进程数,平均活跃进程数;和CPU 使用率 没直接关系。
CPU 密集型进程,大量 CPU 使用会导致平均负载升高,此时 CPU 使用率也升高;
IO 密集型进程,等待 I / O 会导致平均负载升高,此时 CPU 使用率不一定高;
大量等待 CPU 调度,会导致平均负载升高,此时 CPU 使用率也高;
可以用 mpstat/pidstat 工具辅助分析;
CPU 上下文切换,按任务类型分为:
- 进程上下文切换;
- 线程上下文切换;
- 中断上下文切换;
切换的时机有:
- CPU 时间片运行完,
- 系统资源不足导致进程挂起,
- 进程通过 sleep 主动挂起,
- 高优先级进程抢占时间片
- 硬件中断时 cpu 上的进程被挂起,转而执行内核的中断服务;
线程上下文切换:
1. 前后线程属于同一个进程,切换时虚拟内存资源不变,只需要切换线程私有数据,寄存器等;
2. 前后线程属于不同进程,与进程上下文切换相同
同进程的线程切换消耗资源较少。
中断上下文切换;
不涉及进程的切换,因此只需要包含内核态中断服务程序执行所必须的寄存器,内核堆栈,硬件中断参数等;
中断优先级比进程高,所以中断上下文切换和进程上下文切换不会同时发生。
vmstat可查看上下文切换;
- cs: 每秒上下文切换次数;
- in:每秒中断次数;
- r: 就绪队列长度,正在运行和等待 cpu 的进程数;
- b:blocked,处于不可中断睡眠状态的进程数;
查看单独某个进程情况:pidstat
pidstat -w 3
- cswch 每秒自愿上下文切换次数;(进程无法获取所需资源导致上下文切换)
- nvcswch:每秒非自愿上下文切换次数;(时间片轮流等系统强制调度)
vmstat 1 1
- r 列:远超系统 cpu 个数,说明存爱大量 cpu 竞争;
- us 和 sy 列:sy 列占比 80%, 说明 cpu 主要被内核栈用;
- in 列:中断次数明显上升,说明中断处理也是潜在问题;
CPU 使用率:除了空闲时间以为,其他进程占总 CPU 时间的百分比。
cat /proc/stat // 计算 cpu 使用率;
也可以用 tp/ps 来查看一段时间内的平均值;
进程状态:
- R Running/Runnable, 表示进程在 CPU 的就绪队列中,正在运行或等待运行;
- D Disk Sleep,不可中断状态睡眠,一般表示进程正在跟硬件交互,并且交互进程中不允许被其他进程中断;
- Z Zombie, 僵尸进程
- S InterruptibleSleep 可中断睡眠状态,表示进程因为等待某个时间而被挂起,当等待事件发生则会被唤醒进入 R 状态;
- I Idle, 空闲状态,用在不可中断睡眠的内核线程上。该状态不会导致平均负载升高;
- T Stop/Traced, 表示进程处于暂停或跟踪状态;
- X Dead,进程死亡,不会在 top/ps 看到;
案例:
top 查看,发现:
1)平均负载逐渐增加,且一分钟内平均负载达到 cpu 个数,说明系统可能已经有了性能瓶颈;
2)僵死进程较多且不断增加;
3)us/sys CPU 使用率都不高,iowait 比较高;
4)每个进程 CPU 使用率也不高,但又有两个进程处于 D 状态,可能在等待 io;
分析数据可知,iowait 过高导致系统平均负载升高,僵尸进程不断增长说明有程序没能正确清理子进程资源;
用 pidstat 分析,
pidstat -d -p xxx
展示进程的 I / o 统计数据;
最终定位是 app 内部进行了磁盘的直接 I /O,定位到具体代码,进行优化即可。
碰到 iowait 升高时,先用 dstat pidstat 等工具确认是否存在磁盘 I / O 问题,再找是哪些进程导致 I /O,不能用 strace 直接分析进程调用时可以通过 perf 工具分析;
对于僵尸问题,用 pstree 找到父进程,然后看源码检查子进程结束的梳理逻辑即可。
1.2 CPU 性能指标:
CPU 使用率:用户 CPU 使用率,系统 CPU 使用率,等待 I / O 的 CPU 使用率;软 / 硬件中断 CPU 使用率;
steal CPU/guest CPU,表示虚拟机占用的 CPU 百分比;
平均负载: 理想情况下平均负载等于逻辑 CPU 个数,表示每个 CPU 充分利用,若大于说明系统负载较重;
进程上下文切换:
过多的切换,CPU 时间消耗在上下文保护切换上;
CPU 缓存命中率: 命中率越高,性能越好。L1/L2 常用在单核,L3 则用在多核;
1.3 性能分析工具:
平均负载案例:
先用 uptime 查看系统平均负载
判断负载在升高再用 mpstat,pidstat 分别查看每个 CPu 和每个进程 CPU 使用情况,找出导致平均负载过高的进程;
上下文切换:
先用 vmstat 查看系统上下文切换和中断次数;
再用 pidstat 观察进程的资源和非自愿上下文切换情况;
最后,通过 pidstat 观察线程的上下文切换情况;
进程 CPU 使用率高案例:
先用 top 查看系统和进程的 CPU 使用情况,定位到进程;
再用 perf top 观察进程调用链,定位到具体函数;
系统 CPU 使用率高案例
先用 top 查看系统和进程 CPU 使用情况,top/pidstat 都无法找到 CPU 使用率高的进程;
重新审视 top 输出;
从 CPu 使用率不高,但是出于 Running 状态的进程入手;
perf record/report 发现短时进程导致;
不可中断和僵尸进程案例
先用 top 观察 iowait 升高,发现大量不可中断和僵尸进程;
strace 无法跟踪系统调用;
perf 分析调用链发现根源来自磁盘直接 i /o
软中断案例:
top 观察系统软中断 CPu 使用率高;
查看 /proc/softirqs 找到变化率较快的几种软中断
sar 命令发现是网络小包问题;
在生产环境中,往往没有权限安装新的工具包,只能最大化利用好系统中已经安装好的工具。
1.4 CPU 优化
1.4.1 应用程序优化
- 编译器优化:编译阶段开启优化选项,比如 gcc -O2;
- 算法优化;
- 异步处理:避免程序因为等待某个资源而一直阻塞,提升程序的并发处理能力,比如讲轮询改为时间通知;
- 多线程代替多进程:减少上下文切换成本;
- 善用缓存:提高 cache 命中率;
1.4.2 系统优化
- CPU 绑定:将进程绑定到 1 个或多个 CPu 上,提高 CPU 缓存命中率,减少 CPU 调度带来的上下文切换;
- CPu 独占:CPU 亲和性机制来分配进程;
- 优先级调整:使用 nice 适当降低非核心应用的优先级;
- 为进程设置资源显示:cgroups 设置使用上限,防止由某个应用自身问题耗尽系统资源;
- NUMA 优化:CPu 尽可能访问本地内存;
- 中断负载均衡:irqbalance,将中断处理过程自动负载均衡到各个 CPU 上
2. 内存
安装 bcc 包可以通过 cachestat 和 cachetop 来检测缓存的读写命中情况;
Linux 如何衡量内存资源是否紧张?
(1)直接内存回收:新的大块内存分配请求,但剩余内存不足,此时系统回收一部分内存;
(2)kswapd:内核线程定期回收内存,内核定义三个水位
pages_min,pages_low,pages_high;
(3)NUMA 和 SWAP: 有时候系统剩余内存较多,但 SWAP 依旧升高,是由于处理器的 NUMA 架构;
swappiness
实际回收过程,根据 /proc/sys/vm/swapiness 选项来调整使用 swap 的积极度,从 0 -100,值越大,越积极使用 swap,更倾向回收匿名页。否则倾向于回收文件页;
这里 swapiness 只是一个权重,即使设置为 0,内存不够时,还是会发生 swap;
2.2 内存性能指标
(1)系统内存指标
已用内存 / 剩余内存;
共享内存(tmpfs 实现)
可用内存:包括剩余内存和可回收内存;
缓存:磁盘读取文件的页缓存,slab 分配器中的可回收部分;
缓冲区:原始磁盘块的临时存储,缓存将要写入磁盘的数据;
(2)进程内存指标;
虚拟内存:
常驻内存:
共享内存:
swap 内存:
(3)缺页异常
可以直接从物理内存中分配,次缺页异常;
需要磁盘 IO 介入(比如 swap),主缺页异常,此时内存访问会慢很多;
2.3 内存性能工具
如何迅速分析内存的性能瓶颈?
通常先运行几个覆盖面较大的性能工具,比如 free,top,vmstat,pidstat等;
- 先用 free 和 top 查看系统整体内存使用情况;
- 再用 vmstat 和 pidstat 查看一段时间的趋势,判断内存问题类型;
- 最后进行详细分析,比如内存分配分析,缓存 / 缓冲区分析,具体内存使用分析等;
常见优化思路:
(1)最好禁止 swap,若必须开启,则尽量降低 swappiness 的值;
(2)减少内存的动态分配,可以使用内存池,HugePage 等;
(3)尽量使用缓存和缓冲区来访问数据。
(4)cgroups 等方式限制进程的内存使用情况,确保系统内存不被异常内存耗尽;
(5)/proc/pid/oom_adj 调整核心程序的 oom_score,保证即使内存紧张,核心应用也不会被 oom 杀死;
vmstat 使用详解:
https://www.cnblogs.com/ggjucheng/archive/2012/01/05/2312625.html
pidstat 使用详解: