目录
1.性能统计信息
1.1.平均负载率
1.2.上下文切换
1.3.CPU使用率
1.3.1.CPU使用率过高怎么办
2.linux性能工具
2.1.CPU性能指标
2.2.根据工具查指标
3.性能调优策略
3.1.应用程序优化
3.2.系统优化
每一种系统级Linux性能工具都提供了不同的方式来提取相似的统计结果。虽然没有工具能显示全部的信息,但是有些工具显示的是相同的统计信息。
平均负载是指单位时间内,系统处于 可运行状态 和 不可中断状态 的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。
可运行状态的进程
是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。
不可中断状态的进程
是正处于内核态关键流程中的进程,并且这些流程是不可打断的, 比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 D 状态 (Uninterruptible Sleep,也为 Disk Sleep)的进程。
(比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到磁盘回复前,它是不能被其他进程或者中断打断的,这个时候的进程就处于不可中断状态。如果此时的进程被打断了,就容易出现磁盘数据与进程数据不一致的问题。 所以,不可中断状态实际上是系统对进程和硬件设备的一种保护机制。 )
uptime命令
uptime查看系统负载是执行uptime来了解系统的负载情况。
[root@centos7-1 ~]# uptime
16:01:25 up 15 min, 1 user, load average: 0.00, 0.02, 0.05
[root@centos7-1 ~]#
16:01:25 // 当前时间
up 15 min // 系统运行时间
1 user // 正在登录用户数
load average: 0.00, 0.02, 0.05 //三个数字呢,依次则是过去 1 分钟、5 分钟、15 分钟的平均负载
平均负载为多少时合理
平均负载最理想的情况是等于 CPU 个数。所以在评判平均负载时,首先要知道系统有几个 CPU,这可以通过 top 命令或者从文件 /proc/cpuinfo 中读取:
# 关于 grep 和 wc 的用法请查询它们的手册或者网络搜索
[root@centos7-1 ~]# grep 'model name' /proc/cpuinfo | wc -l
1
当平均负载比 CPU 个数还大的时候,系统已经出现了过载。在观察负载数据时,有三个时间点的数据,因此都要看。三个不同时间间隔的平均值,其实给我们提供了,分析系统负载趋势的数据来源,让我们能更全面、更立体地理解目前的负载状况。
举个例子
假设我们在一个单 CPU 系统上看到平均负载为 1.88,0.70,6.76, 那么说明在过去 1 分钟内,系统有 188% 的超载,而在 15 分钟内,有 676% 的超载,从整体趋势来看,系统的负载在降低
当平均负载高于 CPU 数量 70% 的时候,你就应该分析排查负载高的问题了(70% 这个数字并不是绝对的,最推荐的方法)。
平均负载和cpu使用率关系
我们经常容易把平均负载和 CPU 使用率混淆,来区分一下。然平均负载代表的是活跃进程数,那平均负载高了,不就意味着 CPU 使用率高吗?
我们还是要回到平均负载的含义上来,平均负载是指单位时间内,处于可运行状态和不可中断状态的进程数。所以,平均负载不仅包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程。
而CPU使用率,是单位时间内CPU繁忙情况的统计,跟平均负载并不一定完全对应。比如
如何理解上下文切换
Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行,这是通过频繁的上下文切换、将CPU轮流分配给不同任务从而实现的。
每个进程运行时,CPU都需要知道进程已经运行到了哪里以及当前的各种状态,因此系统事先设置好 CPU 寄存器和程序计数器。
CPU 上下文切换,就是先把前一个任务的 CPU 上下文(CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务,而保存下来的上下文, 会存储在系统内核中,并在任务重新调度执行时再次加载进来 。
根据 Tsuna 的测试报告,每次上下文切换都需要几十纳秒到到微秒的CPU时间,因此如果进程上下文切换次数过多,就会导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间,实际上有效的CPU运行时间大大减少(可以认为上下文切换对用户来说是在做无用功)。
上下文切换的时机
上下文切换分类
所以,根据任务的不同,CPU 的上下文切换可以分为不同的场景
系统调用
Linux 按照特权等级划分进程的运行空间
进程既可以在用户空间运行,又可以在内核空间中运行。进程在用户空间运行时,被称为进程的用户态,而陷入内核空间的时候,被称为进程的内核态。 从用户态到内核态的转变,需要通过系统调用来完成。
系统调用举例:
当我们查看文件内容时, 需要多次系统调用来完成:
系统调用的过程如何进行 CPU 上下文的切换?
系统调用和进程上下文切换的不同
进程上下文切换
在 Linux 中,进程是由内核来管理和调度进程的,切换只能发生在内核态,进程的上下文不仅包括了 虚拟内存 、 栈 、 全局变量 等用户空间的资源,还包括了 内核堆栈 、 寄存器 等内核空间的资源。
进程上下文切换:
什么时候会切换进程上下文
CPU 如何挑选进程来运行?
进程上下文切换如何影响系统性能
每次上下文切换都需要几十纳秒到数微秒的 CPU 时间。这个时间还是相当可观的,特别是在进程上下文切换次数较多的情况下,很容易导致 CPU 将大量时间耗费在寄存器、内核栈以及虚拟内存等资源的保存和恢复上,进而大大缩短了真正运行进程的时间。
线程上下文切换
线程是调度的基本单位,而进程则是资源拥有的基本单位。 所谓内核中的任务调度,实际上的调度对象是线程;而进程只是给线程提供了虚拟内存、全局变量等资源。
线程的上下文切换其实就可以分为两种情况:
1). 前后两个线程属于不同进程。此时,因为资源不共享,所以切换过程就跟进程上 下文切换是一样。
2). 前后两个线程属于同一个进程。此时,因为虚拟内存是共享的,所以在切换时, 虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据。
中断上下文切换
硬件通过触发信号,向CPU发送中断信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核, 内核通过这些参数进行中断处理。 中断处理会打断进程的正常调度和执行,而在打断其他进程时,就需要将进程当前的状态保存下来,这样在中断结束后,进程仍然可以从原来的状态恢复运行
例如,A进程启动写磁盘操作,A进程睡眠后B进程在运行,当磁盘写完后磁盘中断信号打断的是B进程,在中断处理时会唤醒A进程。
进程上下文 VS 中断上下文
耗资源程度
CPU使用率
用什么指标来描述系统的 CPU 性能呢 ? 不是平均负载,也不是CPU上下文切换,而是另一个更直观的指标CPU使用率 ,CPU 使用率是单位时间内 CPU 使用情况的统计,以百分比的方式展示。
节拍率的概念
为了维护 CPU 时间,Linux 通过事先定义的节拍率(内核中表示为 HZ),触发时间中断,并使用全局变量 Jiw ies 记录了开机以来的节拍数。每发生一次时间中断,Jiw ies 的值就加 1。
1)查看系统节拍率
不同的系统可能设置不同数值,你可以通过查询 /boot/config 内核选项来查看它的配置值。
[root@centos7-2 ~]# grep 'CONFIG_HZ=' /boot/config-$(uname -r)
CONFIG_HZ=1000
2)用户节拍率
正因为节拍率 HZ 是内核选项,所以用户空间程序并不能直接访问。为了方便用户空间程序,内核还提供了一个用户空间节拍率 USER_HZ,它总是固定为 100,也就是 1/100 秒。这样,用户空间程序并不需要关心内核中 HZ 被设置成了多少,因为它看到的总是固定值 USER_HZ。
USER_HZ=100
CPU使用率公式
CPU使用率,就是除了空闲时间外的其他时间占总CPU时间的百分比,用公式来表示就是
根据这个公式,我们就可以从 /proc/stat 中的数据,很容易地计算出 CPU 使用率。当然,也可以用每一个场景的 CPU 时间,除以总的 CPU 时间,计算出每个场景的 CPU 使用率。
性能工具是如何计算CPU使用率的
事实上,为了计算机CPU使用率,性能能工具一般都会间隔一段时间(比如 3 秒)的两次值,做差后,再计算出这段时间的平均CPU使用率
性能分析工具给出的都是间隔一段时间的平均CPU使用率,所以要注意间隔时间的设置,特别是用多个工具对比分析时,你一定要保证他们用的是相同的间隔时间
怎么查看CPU使用率
查看 CPU 使用率 top 、ps 和pidstat是最常用的性能分析工具 :
分析思路
1、找到CPU使用率过高的进程
通过top、ps 、pidstat等工具
2、判断占用CPU高的到底是代码里的那个函数
perf 和 GDB
GDB(The GNU Project Debugger), 这个功能强大的程序调试利器 ,GDB 调试程序的过程会中断程序运行,这在线上环境往往是不允许的;
perf 是 Linux 2.6.31 以后内置的性能分析工具。它以性能事件采样为基础,不仅可以分析系统的各种事件和内核性能,还可以用来分析指定应用程序的性能问题 ,使用 perf 分析 CPU 性能问题,perf两种用法
第一种常见用法是 perf top,类似于 top,它能够实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数,使用界面如下所示:
[root@centos7-2 ~]# perf top Samples: 724 of event 'cpu-clock', Event count (approx.): 125711088 Overhead Shared Object Symbol 45.11% [kernel] [k] generic_exec_single ...
输出结果中,第一行包含三个数据,分别是采样数(Samples)、事件类型(event)和事件总数量(Event count)。比如这个例子中,perf 总共采集了1000个 CPU 时钟事件,而总事件数则为 271937500。 采样数需要特别注意,如果采样数过少(比如只有十几个),那下面的排序和百分比就没什么实际参考价值了。
- 第一列 Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示。
- 第二列 Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object),如内核、进程名、动态链接库名、内核模块名等。
- 第三列 Object ,是动态共享对象的类型。比如 [.] 表示用户空间的可执行程序、或者动态链接库,而 [k] 则表示内核空间。
- 第四列 Symbol 是符号名,也就是函数名。当函数名未知时,用十六进制的地址来表示。
第二种常见用法,也就是 perf record 和 perf report。 perf top 虽然实时展示了系统的性能信息,但它的缺点是并不保存数据,也就无法用于离线或者后续的分析。而 perf record 则提供了保存数据的功能,保存后的数据,需要用 perf report 解析展示
perf record # 按 Ctrl+C 终止采样 [root@centos7-2 ~]# perf report Samples: 5K of event 'cpu-clock', Event count (approx.): 1332500000 Overhead Command Shared Object Symbol 97.15% swapper [kernel.kallsyms] [k] native_safe_halt 0.49% swapper [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 0.36% vmtoolsd libvmtools.so.0.0.0 [.] Backdoor_InOut 0.34% swapper [kernel.kallsyms] [k] __do_softirq 0.17% swapper [kernel.kallsyms] [k] tick_nohz_idle_exit 0.13% swapper [kernel.kallsyms] [k] tick_nohz_idle_enter 0.13% vmtoolsd [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 0.11% kworker/0:1 [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 0.11% vmtoolsd libvmtools.so.0.0.0 [.] BackdoorHbOut 0.08% dockerd [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 0.08% vmtoolsd [kernel.kallsyms] [k] __do_softirq 0.06% kworker/1:2 [kernel.kallsyms] [k] queue_delayed_work_on 0.06% vmtoolsd [kernel.kallsyms] [k] format_decode 0.04% irqbalance [kernel.kallsyms] [k] cap_mmap_file 0.04% kworker/0:0 [kernel.kallsyms] [k] ata_sff_pio_task 0.04% kworker/1:2 [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 0.04% mysqld mysqld [.] fts_optimize_words 0.04% swapper [kernel.kallsyms] [k] rcu_idle_exit 0.04% vmtoolsd libvmtools.so.0.0.0 [.] BackdoorHbIn 0.02% dockerd [kernel.kallsyms] [k] __do_softirq 0.02% in:imjournal rsyslogd [.] 0x0000000000016f90 0.02% irqbalance [kernel.kallsyms] [k] __fsnotify_parent 0.02% irqbalance [kernel.kallsyms] [k] _raw_spin_unlock_irqrestore 0.02% irqbalance [kernel.kallsyms] [k] copy_user_generic_unrolled 0.02% irqbalance [kernel.kallsyms] [k] native_flush_tlb_single 0.02% irqbalance [kernel.kallsyms] [k] unmap_page_range Tip: For tracepoint events, try: perf report -s trace_fields
从 CPU 的性能指标出发。也就是说,当要查看某个性能指标时,要清楚知道哪些工具可以做到。
根据不同的性能指标,对提供指标的性能工具进行分类和理解。这样,在实际排查性能问题时,你就可以清楚知道,什么工具可以提供你想要的指标。
性能指标
|
工具
|
说明 |
---|---|---|
平均负载
|
uptime
top
|
uptime 使用最简单 ;
top 提供了更安全的指标
|
系统整体 CPU 使
用率
|
vmstat
mpstat
top
sar
/proc/stat
|
top 、 vmstat 、 mpstat 只可以动态查看,
而 sar 还可以记录历史数据
/proc/stat 是其他性能工具数据来源
|
进程 CPU 使用率
|
top
pidstat
ps
htop
atop
|
top 和 ps 可以按 CPU 使用率给进程排序 ,
而 pidstat 只显示实际用了 CPU 的进程
htop 和 atop 以不同颜色显示更直观
|
系统上下文切换
|
vmstat
|
除了上下文切换次数还提供运行状态和不可中断状态进程的
数量
|
进程上下文切换
|
pidstat
|
使用时注意加上 -w 选项
|
软中断
|
top
/proc/soxirqs
mpstat
|
top 提供软中断 CPU 使用率
而 /proc/soxirqs 和 mpstat 提供了各种软中断在每个 CPU 上的
运行次数
|
硬中断
|
vmstat
/proc/interrupts
|
vmstat 提供了总的中断次数
而 /proc/interrupts 提供了各种中断在每个 CPU 上的积累次数
|
CPU 个数
|
/proc/cpuinfo
lscpu
|
lscpu 更直观查看
|
事件剖析
|
pref
execsnoop
|
perf 可以用来分析 CPU 的缓存及内核调用链
execsnoop 用来监控短时进程
|
第二个维度,从工具出发。也就是当你已经安装了某个工具后,要知道这个工具能提供哪些指标。
具体到每个工具的使用方法,一般都支持丰富的配置选项。这些配置选项并不用背下来。你只要知道有哪些工具、以及这些工具的基本功能是什么就够了。真正要用到的时候, 通过 man 命令,查它们的使用手册就可以了 。
性能工具
|
CPU 性能指标
|
---|---|
uptime
|
平均负载
|
top |
平均负载、运行队列、整体的 CPU 使用率及每个进程的状态和 CPU 使用率
|
htop |
top 增强版、可以以不同的颜色区分不同类型的进程
|
atop |
CPU 、内存、磁盘和网络等各种资源的全面监控
|
vmstat |
系统整体的 CPU 使用率、上下文切换次数、中断次数、还包括处于运行 和不可中断状态的进程数
|
mpstat |
每个 CPU 使用率和软中断次数
|
pidstat |
进程和线程的 CPU 使用率、中断上下文切换次数
|
/proc/sofirqs |
软中断类型和每个 CPU 上的累计中断次数
|
/proc/interrupts
|
硬中断类型和每个 CPU 上的累计中断次数
|
ps |
每个进程的状态和 CPU 使用率
|
pstree |
进程的父子关系
|
dstat |
系统整体的 CPU 使用率
|
sar |
系统整体的 CPU 使用率 , 包括可配置的历史数据
|
starces |
进程的系统调用
|
perf |
CPU 性能事件剖析 , 如调用链分析 ,CPU 缓存 ,CPU 调度
|
execsnoop |
监控进程
|
CPU 优从 应用程序 和 系统 的角度,分别来看看如何才能降低 CPU 使用率,提高 CPU 的并行处理能力。
首先,从应用程序的角度来说,降低 CPU 使用率的最好方法当然是,排除所有不必要的工作,只保留最核心的逻辑。比如减少循环的层次、减少递归、减少动态内存分配等等。
编译器优化:很多编译器都会提供优化选项,适当开启它们,在编译阶段你就可以获得 编译器的帮助,来提升性能。
算法优化:使用复杂度更低的算法,可以显著加快处理速度
异步处理:使用异步处理,可以避免程序因为等待某个资源而一直阻塞,从而提升程序 的并发处理能力。比如,把轮询替换为事件通知,就可以避免轮询耗费 CPU 的问题。
多线程代替多进程:相对于进程的上下文切换,线程的上下文切换并不切换进程地址空间,因此可以降低上下文切换的成本。
善用缓存:经常访问的数据或者计算过程中的步骤,可以放到内存中缓存起来,这样在 下次用时就能直接从内存中获取,加快程序的处理速度。
从系统的角度来说,优化 CPU 的运行,一方面要充分利用 CPU 缓存的本地性,加速缓存访问;另一方面,就是要控制进程的 CPU 使用情况,减少进程间的相互影响。
CPU 绑定:把进程绑定到一个或者多个 CPU 上,可以提高 CPU 缓存的命中率,减少跨 CPU 调度带来的上下文切换问题。
CPU 独占:跟 CPU 绑定类似,进一步将 CPU 分组,并通过 CPU 亲和性机制为其分配进程。这样,这些 CPU 就由指定的进程独占,换句话说,不允许其他进程再来使用这些 CPU。
优先级调整:使用 nice 调整进程的优先级,正值调低优先级,负值调高优先级。为进程设置资源限制:使用 Linux cgroups 来设置进程的 CPU 使用上限,可以防止由于某个应用自身的问题,而耗尽系统资源。
中断负载均衡:无论是软中断还是硬中断,它们的中断处理程序都可能会耗费大量的 CPU。开启 irqbalance 服务或者配置 smp_aw inity,就可以把中断处理过程自动负载均衡到多个 CPU 上。