个人感悟
这两周主要围绕CPU性能优化相关基础知识进行学习。对于CPU性能问题的处理,首先我们要了解CPU相关性能指标。
CPU性能指标
平均负载,上下文切换,CPU使用率,CPU缓存命中率等.
平均负载是指系统处于可运行状态和不可中断状态的平均进程数(一般平均负载高于CPU数量70%的时候需要注意排查)。 平均负载升高可能是CPU密集进程导致,也可能是I/O或进程过多超负载导致. 可以用mpstat和pidstat辅助分析.
uptime #查看最近1/5/15分钟平均负载
watch -d uptime #实时查看变化情况
mpstat -P ALL 5 #查看CPU使用率,间隔5秒输出
pidstat -u 5 1 #查看进程CPU使用率/IOwait
上下文切换,主要分为进程上下文切换,线程上下文切换以及中断上下文切换(可以利用多线程替代多进程来提升性能)。可以通过vmstat查看系统总体上下文切换和中断次数. pidstat -w 查看每个进程上下文切换次数, -wt输出线程指标.
watch -d cat /proc/interrupts #查看中断变化具体来源
- 系统调用涉及内核态和用户态的切换因此实际发生两次CPU上下文切换,不过不涉及虚拟内存等资源也不切换进程.
- 进程的切换都在内核态,保存内核状态和CPU寄存器之前,先保存进程的虚拟内存,栈等
- 同一进程内的线程切换只需要保存线程的私有数据,寄存器等.
- 中断上下文切换并不涉及进程的用户态,比进程优先级高
CPU使用率过高时一般都是结合top/pidstat/perf来进行分析定位. 如果定位不到CPU使用率高的进程,可以跟踪top查看是否存在短时进程. 调用pstree分析父进程.
perf record -g
perf report #查看性能报告找到瓶颈
execsnoop #监控短时进程
iowait升高时,可以用dstat观察CPU和I/O的使用情况.
pidstat -d -p XXX n m #-d输出I/O情况,指定线程号间隔n秒输出m组数据
strace -p XXX #跟踪系统调用
如果定位进程状态为Z,通过perf report查看调用栈
僵尸进程, 通过pstree查看父进程,在父进程中进行解决(子进程创建和清理的地方)
pstree -aps XXX
中断处理
/proc/softirqs #查看软中断
/proc/interrupts #查看硬中断
网络监测工具
sar -n DEV 1 #网络收发报告, 间隔1秒输出一组数据
tcpdump -i eth0 -n tcp port 80 #指定网卡eth0,tcp协议,端口号80
CPU性能分析套路
通过几组实验分析我们发现对于CPU性能,常用的瓶颈问题有一些套路可以定位问题所在。虽然CPU性能指标很多,但是都不是孤立存在的,很多指标间都存在一定的关联。 再遇到CPU性能问题时我们可以先运行几个支持指标较多的工具(top/vmstat/pidstat)来缩小排查范围,查看是否是因为某个进程导致,找出导致性能问题的进程之后,再用进程分析工具来分析进程的行为。比如strace分析系统调用情况,或者perf分析调用链中各级函数的执行情况。
CPU性能优化方案
定位到问题所在之后并不是要立即着手进行优化。在需要优化之前,要先考虑优化到底能提升多少性能(应用程序和系统资源多维度评估),选取哪些性能问题进行优化以及优化方案的取舍. 优化往往会带来复杂度的提升,所以要做好性能和复杂度的平衡.
CPU优化的一些常用方法
- 应用程序优化
- 编译器优化
- 算法优化
- 异步处理
- 多线程代替多进程
- 善用缓存
- 系统优化
- CPU绑定
- CPU独占
- 优先级调整
- 为进程设置资源限制
- NUMA优化
- 中断负载均衡
接下来是本周读书笔记
Lesson 9 怎么理解Linux软中断
本周继续学习CPU性能相关知识点,Linux 性能优化实战第一周第8课提到不可中断状态一般都是短时进程,主要是系统的一种保护机制,保证硬件的交互过程不被意外打断. 但是如果进程长时间处于不可中断状态就需要注意是否存在磁盘I/O问题.
除了iowait,软中断softirq导致CPU使用率增加的场景也比较常见.
为了解决中断处理程序执行时间过长和中断丢失的问题,Linux将中断过程分为两阶段:
- 快速处理中断 (硬中断, 会打断CPU正在执行的任务)
- 延迟处理上半部未完成的工作, 通常以内核线程的方式运行 (软中断,内核线程执行)
以网卡接收数据包为例: 网卡接收到数据包之后,先通过硬中断通知内核新数据到达.此时内核调用中断处理程序来响应. 第一步快速处理中断,将网卡数据读到内存中,然后更新硬件寄存器的状态(表示数据已经读完); 第二步发送软中断信号,内核线程从内存中找到网络数据,按照网络协议栈对数据逐层解析和处理,直到将其发送给应用程序.
软中断不仅包括上述硬件设备中断处理程序的第二阶段,还包含一些内核自定义的事件. 如内核调度,RCU锁等.
~ cat /proc/softirqs #查看软中断的运行情况 10种不同软中断类型
CPU0 CPU1 CPU2 CPU3
HI: 940848 8695970 929219 958387
TIMER: 6032528 8523080 6185804 7882723
NET_TX: 13 18 10 21655
NET_RX: 81303 81483 74123 5497701
BLOCK: 112 109 1961852 73
IRQ_POLL: 0 0 0 0
TASKLET: 40 152 69233 41556
SCHED: 5262219 6279886 5054733 5849054
HRTIMER: 0 0 0 0
RCU: 4615615 5897520 4693046 5749548
➜ ~ ps -aux | grep softirq #一个CPU对应一个软中断内核线程
root 7 0.0 0.0 0 0 ? S Jun01 0:00 [ksoftirqd/0]
root 16 0.0 0.0 0 0 ? S Jun01 0:01 [ksoftirqd/1]
root 22 0.0 0.0 0 0 ? S Jun01 0:01 [ksoftirqd/2]
root 28 0.0 0.0 0 0 ? S Jun01 0:02 [ksoftirqd/3]
Lesson 10 系统的软中断CPU使用率高,怎么解决
所需工具
工具 | 用途 |
---|---|
sar | 系统报告工具,实时查看当前系统活动,配置保存和报告历史统计 |
hping3 | 构造TCP/IP包, 对系统进行安全审计,防火墙测试等 |
tcpdump | 网络抓包工具, 用来分析各种网络问题 |
实验与分析
sudo docker run -itd --name=nginx -p 81:80 nginx #启动nginx服务
curl http://localhost:81 #检查nginx服务是否正常运行
hping3 -S -p 81 -i u100 localhost #每100微秒发送一个网络帧
本机测试中并没有监测到系统响应变慢,改为1微秒时数据包全丢, 10微秒时丢包率为80%.
top查看ksoftirqd软中断进程CPU使用率也不高.
继续执行后续指令
watch -d cat /proc/softirqs #观察高亮变化
此时发现TIMER/NET_RX/SCHED/RCU都在不停变化,且NET_RX变化速率较快,几K级别的在增加. 其它几种类型的软中断是保证linux调度,时钟,临界区保护等正常工作必须,有变化是正常的.
因此我们着手分析网络接收的软中断,选取sar工具查看网络收发情况
sar -n DEV 1 #每隔1秒输出网络收发报告
07:01:11 PM IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s %ifutil
07:01:12 PM veth3a2b4de 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:01:12 PM lo 20895.00 20895.00 843.42 843.42 0.00 0.00 0.00 0.00
07:01:12 PM docker0 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:01:12 PM enp0s31f6 6.00 0.00 0.85 0.00 0.00 0.00 0.00 0.00
07:01:12 PM vethedb691a 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
07:01:12 PM br-1665f3682889 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
- rxpck/s txpck/s 表示每秒接收/发送的网络帧数 PPS
- rxkB/s txkB/s 表示每秒接收/发送的千字节数 BPS
看到网卡lo每秒接收的数据明显较多, 843*1024/20895 =41 说明每个网络帧只有41字节,小包问题.
进一步通过tcpdump分析这是什么样的网络帧
tcpdump -i lo -n tcp port 81
18:20:43.273056 IP 127.0.0.1.12537 > 127.0.0.1.81: Flags [R], seq 393134060, win 0, length 0
18:20:43.273184 IP 127.0.0.1.12538 > 127.0.0.1.81: Flags [S], seq 1240632262, win 512, length 0
18:20:43.273193 IP 127.0.0.1.81 > 127.0.0.1.12538: Flags [S.], seq 3698133257, ack 1240632263, win 65495, options [mss 65495], length 0
18:20:43.273198 IP 127.0.0.1.12538 > 127.0.0.1.81: Flags [R], seq 1240632263, win 0, length 0
可以看出网络帧是发送到nginx端口,Flags [S]表示这是一个SYN包, 可以锁定是SYN FLOOD问题,最简单的解决方法就是防火墙中封锁该来源IP.
总结
如果碰到软中断线程CPU使用率高的情况下, 可以借助sar和tcpdump等工具进一步分析来源.
Lesson 11 [套路] 如何迅速分析出系统CPU的瓶颈在哪里?
要想分析处理CPU性能问题, 首先我们需要了解CPU性能指标.
CPU性能指标
- CPU使用率
- 用户CPU使用率, 包括用户态(user)和低优先级用户态(nice). 该指标过高说明应用程序比较繁忙.
- 系统CPU使用率, CPU在内核态运行的时间百分比(不含中断). 该指标高说明内核比较繁忙.
- 等待I/O的CPU使用率, iowait, 该指标高说明系统与硬件设备I/O交互时间比较长.
- 软/硬中断CPU使用率, 该指标高说明系统中发生大量中断.
- steal CPU / guest CPU, 表示虚拟机占用的CPU百分比.
平均负载
理想情况下平均负载等于逻辑CPU个数,表示每个CPU都被充分利用. 若大于则说明系统负载较重.
进程上下文切换
包括无法获取资源的自愿切换和系统强制调度时的非自愿切换. 上下文切换本身是保证Linux正常运行的一项核心功能. 过多的切换则会将原本运行进程的CPU时间消耗在寄存器,内核占及虚拟内存等数据保存和恢复上.
CPU缓存命中率
CPU缓存的复用情况,命中率越高性能越好. 其中L1/L2常用在单核,L3则用在多核中.
性能工具
回顾之前的几个CPU性能测试场景:
- 平均负载案例
- 先用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发现短时进程导致 (execsnoop工具)
- 不可中断和僵尸进程案例
- 先用top观察iowait升高,发现大量不可中断和僵尸进程
- strace无法跟踪进程系统调用
- perf分析调用链发现根源来自磁盘直接I/O
- 软中断案例
- top观察系统软中断CPU使用率高
- 查看/proc/softirqs找到变化速率较快的几种软中断
- sar命令发现是网络小包问题
- tcpdump找出网络帧的类型和来源, 确定SYN FLOOD攻击导致
根据不同的性能指标来找合适的工具:
在生产环境中往往开发者没有权限安装新的工具包,只能最大化利用好系统中已经安装好的工具. 因此要了解一些主流工具能够提供哪些指标分析.
作者给了一个直观的套路, 先运行几个支持指标较多的工具, 如top/vmstat/pidstat,根据它们的输出可以得出是哪种类型的性能问题. 定位到进程后再用strace/perf分析调用情况进一步分析. 如果是软中断导致用/proc/softirqs
Lesson 12 CPU性能优化的几个思考
性能优化方法论
遇到性能问题,优化前首先思考三个问题:
- 首先判断优化是否有效,能提升多少性能?
- 多种性能问题同时存在情况下,先优化哪一个?
- 提升性能的方法往往不唯一,如何选取? 是否总选最大程度提升的那一种?
怎样评估性能优化效果
- 确定性能的量化指标
- 不要局限在单一维度,至少从应用程序和系统资源两个维度,分别选择不同的指标
- 应用程序: 吞吐量和请求延迟
- 系统资源: CPU使用率
- 好的应用程序是性能优化的最终目的和结果,系统资源的使用情况是影响应用程序性能的根源.
- 例如, web程序可以用ab等工具测试并发请求数和响应延迟,同时可以用vmstat/pidstat观察系统和进程的CPU使用率
- 不要局限在单一维度,至少从应用程序和系统资源两个维度,分别选择不同的指标
- 测试优化前的性能指标
- 测试优化后的性能指标
- 要避免性能测试工具的干扰
- 避免外部环境的变化
多个性能问题同时存在,如何选择?
并不是所有性能问题都值得优化,性能测试也存在二八法则
- 如果是系统资源达到的瓶颈,首先优化系统资源的使用问题.
- 针对不同类型的指标,首先优化那些由瓶颈导致,性能指标变化幅度较大的问题.
多个优化方法, 如何选择?
在提升性能的同时也要考虑优化成本.性能优化通常会带来复杂度的提升,降低程序的可维护性. (balance)
例如DPDK(Data Plane Development Kit)是一种优化网络处理速度的方法,通过绕开内核网络协议栈的方法,提升网络的处理能力. 但是它要求独占一个CPU以及一定数量的内存大页,并且以100%CPU使用率运行. 在CPU核数较少的情况下不适合.
CPU 优化
- 应用程序优化
- 编译器优化: 编译阶段开启优化选项, 如gcc -O2
- 算法优化
- 异步处理: 避免程序因为等待某个资源而一直阻塞,提升程序的并发处理能力. (将轮询替换为事件通知)
- 多线程代替多进程: 减少上下文切换成本
- 善用缓存: 加快程序处理速度
- 系统优化
- CPU绑定: 将进程绑定要1个/多个CPU上,提高CPU缓存命中率,减少CPU调度带来的上下文切换
- CPU独占: CPU亲和性机制来分配进程
- 优先级调整:使用nice适当降低非核心应用的优先级
- 为进程设置资源显示: cgroups设置使用上限,防止由某个应用自身问题耗尽系统资源
- NUMA优化: CPU尽可能访问本地内存
- 中断负载均衡: irpbalance,将中断处理过程自动负载均衡到各个CPU上
避免过早优化
优化可能会带来复杂性的提升,降低可维护性.针对当前情况进行的优化可能不适应快递迭代的新需求.
因此性能优化最好逐步完善,根据性能评估的结果选择最重要的性能问题进行优化.
Lesson 13/14 答疑 (略)
读书群内分享
-
- QPS (Queries Per Second)每秒查询率,一台服务器每秒能够响应的查询次数.
TPS (Transactions Per Second)每秒事务数,软件测试的结果.
- 用户请求服务器
- 服务器内部处理
服务器返回给客户
QPS类似TPS,但是对于一个页面的访问形成一个TPS,但是一次页面请求可能包含多次对服务器的请求,可能计入多次QPS
系统吞吐量, 包括几个重要参数:
- QPS(TPS)
- 并发数
响应时间
QPS(TPS)=并发数/平均相应时间
- 深入理解Linux系统下proc文件系统内容