在Linux下做性能分析1:基本模型

==介绍==

本Blog开始介绍一下在Linux分析性能瓶颈的基本方法。主要围绕一个基本的分析模型,介绍perf和ftrace的使用技巧,然后东一扒子,西一扒子,逮到什么说什么,也不一定会严谨。主要是把这个领域的一些思路和技巧串起来。如果读者来讨论得多,我们就讨论深入一点,如果讨论得少,那就当作一个提纲给我做一些对外交流用吧。

==基本模型==

我们需要有一套完整的方法来发现系统的瓶颈。“瓶颈”这个概念,来自业务目标,不考虑业务目标就没有“瓶颈”这个说法。从业务目标角度,通常我们的瓶颈出现在业务的通量(Throughput)和时延(Latency)两个问题上。(手机等领域常常还会考虑功耗这个要素,但那个需要另外的模型,这里暂时忽略)

比如一个MySQL数据库,你从其他机器上对它发请求,每秒它能处理10万个请求,这个就是通量性能,每个请求的反应时间是0.5ms,这个就是时延性能。

通量和时延是相互相承的两个量,当通量达到系统上限,时延就会大幅提高。我们从下面这个例子开始来看这个模型(图1):

请求从客户端发到计算机上,花t1的时间,用t2的时间完成计算,然后用t3的时间把结果送回到客户端,这个时延是t1+t2+t3,如果我们在t3发过来后,发下一个请求,这样系统的通量就是1/(t1+t2+t3)。

当然,现实中我们不可能使用这样的方法来处理业务请求,这样处理通量肯定是很低的。因为t2和t1/t3作用在两个不同的运行部件上,完全没有必要让他们串行(在同一个会话中有必要,但整体上没有必要。其原理就是CPU流水线)。所以这个模型应该这样来实现(图2):

t2变成一个队列的处理,这样时延还是会等于t1+t2+t3,但t2的含义变了。只要调度能平衡,而且认为通讯管道的流量无限,通量可以达到1/t2(和CPU流水线中,一个节拍可以执行一条指令的原理相同)。1/t2是CPU清队列库存的速度,数据无限地供给到队列上,如果瞬时队列的长度是len,CPU处理一个包的时间是ti,t2=len*ti,如果请求无限上升,len就会越来越长,时延就会变大,所以,通常我们对队列进行流控,流控有很多方法,反压丢包都可以,但最终,当系统进入稳态的时候,队列的长度就会维持在一个稳态,这时的t2就是可以被计算的了。

对于上面这样一个简单模型,如果CPU占用率没有到100%,时延会稳定在len*ti。len其实就等于接收线程(或者中断)一次收入的请求数。但如果CPU达到100%,队列的长度就无限增加,时延也会跟着无限增加。所以我们前面说,当通量达到上限的时候,时延会无限增加,直到发生流控。

现代CPU是一个多核多部件系统,这种队列关系在整个系统中会变得非常复杂,比如,它有可能是这样的(图3):

虽然很多系统看起来不是这样一个接一个队列的模型,但其实如果你只考虑主业务流,几乎大部分情形都是这样的

对这样的系统,我们仍有如下结论:系统的时延等于路径上所有队列的len[i]*t[i]的和。其实你会发现,这个模型和前一个简单模型本质上并没有区别。只是原来的原则作用在了所有的队列上。

也就是说:如果CPU没有占满,队列也没有达到流控,则时延会稳定在len[i]*t[i]上。我们只要保证输入短可以供数据到系统中即可

这个结论为我们的性能优化提供了依据。就是说,我们可以先看CPU是否满载,满载就优化CPU,没有满载就找流控点,通过流控点调整时延和通量就可以了。

在多核的情况下,CPU无法满载还会有一个原因,就是业务线程没有办法在多个CPU上展开,这需要通过增加处理线程来实现。

==全系统的线程模型==

我们一般看系统是从“模块”的角度来看的,但看系统的性能模型,我们是从线程的角度来看的。

这里的线程是广义线程,表示所有CPU可以调度以使用自己的执行能力的实体,包括一般意义的线程,中断,signal_handler等。

好比前面的MySQL的模型,请求从网卡上发送过来。首先是中断向量收到包请求,然后是softirq收包,调用napi的接口来收包,比如napi_schedule。这时调用进入网卡框架层了,但线程上下文还是没有变,napi_schedule回过头调用网卡的polling函数,网卡收包,通过napi_skb_finish()一类的函数向IP层送包,然后顺着比如netif_receive_skb_internal->__netif_receive_skb->__netif_receive_skb_core->deliver_skb->...这样的路径一路进去到某种类型的socket buffer中,这个过程跨越多个模块,跨越多个协议栈的层,甚至在极端情况下可以跨越内核态和用户态。但我们仍认为是一个线程搬移,是softirq线程把网卡上的buffer,搬移到CPU socket buffer的一个过程。调整网卡和socket buffer之间的大小,流控时间,部署给这些队列的线程的数目和调度时间,就可以调整好整个系统的性能。

从线程模型上看性能,处理模型就会比较简单:我们如果希望提高一个队列清库存的效率,只要增加在这个队列上的搬移线程,或者提高部署在上面的线程(实际上是CPU核)的数量,就可以平衡它的流控时间。如果我们能平衡所有队列的效率和长度,我们就比较容易控制整个系统的通量和时延了。

这其中当然还会涉及很多细节的设计技巧,但大方向是这个。

在线程这个问题上,最后要补充几句:线程是为了驱动系统的运行。不少新手很容易把线程和模块的概念搞到一起,甚至给每个模块配备一个线程。这是不少系统调度性能差的原因。初学者应该要时刻提醒自己,线程和模块是两个独立的,正交的概念,是不应该绑定的。模块是为了实现上的内聚,而线程是为了:

1. 把计算压力分布到多个核上

2. 匹配不同执行流程的速率

3. 当线程的执行流程中有同步IO的时候,增加线程以便减少在同步IO上的等待时间(本质上是增加流水线层次提升执行部件的同步效率)

后面我们谈具体的优化技巧的时候我们会重新提到线程的这些效果。

==一般操作方法==

所以,当我们遭遇一个通量性能瓶颈的时候,我们通常分三步来发现瓶颈的位置:

1. CPU占用率是否已经满了,这个用top就可以看到,比如下面这个例子:

有两个CPU的idle为0,另两个基本上都是接近100%的idle,我们基于这个就可以决定我们下一步的分析方向是什么了。

如果CPU没有满,有三种可能:

1.1 某个队列提早流控了。我们通过查看每个独立队列的统计来寻找这些流控的位置,决定是否需要提升队列长度来修复这种流控。例如,我们常常用ifconfig来观察网卡是否有丢包:

wlan0     Link encap:以太网  硬件地址 7c:7a:91:xx:xx:xx  inet 地址:192.168.0.103  广播:192.168.0.255  掩码:255.255.255.0inet6 地址: fe80::7e7a:91ff:fefe:5a1a/64 Scope:LinkUP BROADCAST RUNNING MULTICAST  MTU:1500  跃点数:1接收数据包:113832 错误:0 丢弃:0 过载:0 帧数:0发送数据包:81183 错误:0 丢弃:0 过载:0 载波:0碰撞:0 发送队列长度:1000 接收字节:47850861 (47.8 MB)  发送字节:18914031 (18.9 MB)

在高速网卡场景中,我们常常要修改/proc/sys中的网络参数保证收包缓冲区足够处理一波netpolling的冲击。

我们自己写业务程序的时候,也应该对各个队列的水线,丢包数等信息进行统计,这样有助于我们快速发现队列的问题。

1.2 调度没有充分展开,比如你只有一个线程,而你其实有16个核,这样就算其他核闲着,你也不能怎么样。这是需要想办法把业务hash展开到多个核上处理。上面那个top的结果就是这种情形。

1.3 配套队列的线程有IO空洞,要通过异步设计把空洞填掉,或者通过在这个队列上使用多个线程把空洞修掉。具体的原理,后面谈分析方法的时候再深入介绍。

2. 如果CPU占用率已经占满了,观察CPU的时间是否花在业务进程上,如果不是,分析产生这种问题的原因。Linux的perf工具常常可以提供良好的分析,比如这样:

这里例子中的CPU占用率已经全部占满了。但时间中只有15.43%落在主业务流程上,下面有大量的时间花在了锁和调度上。如果我们简单修改一下队列模式,我们就可以把这个占用率提升到23.39%:

当我们发现比如schedule调度特别频繁的时候,我们可以通过ftrace观察每次切换的原因,比如下面这样:

你可以看到业务线程执行3个ns就直接切换为Idle了,我们可以在业务线程上加mark看具体是什么流程导致这个切换的(如果系统真的忙,任何线程都应该用完自己的时间片,否则就是有额外的问题引起额外的代价了)

3. 如果CPU的时间确实都已经在处理业务的,剩下的问题就是看CPU执行系统是否被充分利用(比如基于例如Top Down模型分析系统CPU的执行部件是否被充分利用) 或者软件算法是否可以优化了。这个也可以通过perf和ftrace组合功能来实现。

在后面几篇博文中,我们会逐一看看Linux的perf和ftrace功能如何对这些分析提供技术支持的。


==关于流控==

流控是个很复杂的问题,这里没有准备展开,但需要补充几个值得考量的问题。

第一,流控应该出现在队列链的最前面,而不是在队列的中间。因为即使你在中间丢包了,前面几个队列已经浪费CPU时间在这些无效的包上了,这样的流控很低效。所以,中间的队列,只要可能,一般不设置自身的流控

第二,在有流控的系统上,需要注意一种很常见的陷阱:就是队列过长,导致最新的包被排到很后才处理,等完成整个系统的处理的时候,这个包已经被请求方判断超时了。这种情况会导致大量的失效包。所以,流控的开始时间要首先于每个包的超时时间。


==总结==

性能分析应该是一个有针对性的工作,我们大部分情况都不可能通过“调整这个参数看看结果,再调整调整那个参数看一个结果,然后寄望于运气。我们首先必须从一开始就建立系统的运行模型,并有意识地通过程序本身的统计以及系统的统计,对程序进行profiling,并针对性地解决问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/3960.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter悬浮UI的设计Overlay组件

文章目录 APP开发经常要遇到的开发场景Overlay 的介绍Overlay的使用规则举例说明源码例子报错报错No Overlay widget found报错原因解决方法 修改后的源码 例子效果 APP开发经常要遇到的开发场景 有时候我们在开发APP的时候会遇到下面这些需求: 在现有页面上添加浮…

代码随想录算法训练营第十九天 | 动态规划系列5,6,7,8

动态规划系列5,6,7,8 377 组合总和 Ⅳ未看解答自己编写的青春版重点代码随想录的代码我的代码(当天晚上理解后自己编写)求排列数的题,用二维DP过不了?自己捋逻辑的话,也是可以觉得有漏洞,但是怎么修改,一下子还没思路&…

JVM之内存与垃圾回收篇2

文章目录 3 运行时区域3.1 本地方法栈3.2 程序计数器3.3 方法区3.3.1 Hotspot中方法区的演进3.3.2 设置方法区内存大小3.3.3 运行时常量池3.3.4 方法区使用举例3.3.5 方法区的演进3.3.5 方法区的垃圾回收 3.4 栈3.4.1 几个面试题 3.5 堆3.5.1 Minor GC、Major GC和Full GC3.5.2…

适配器模式-不兼容结构的协调

去英语国家旅游时,我们只会说中文,为了与当地人交流,我们需要购买个翻译器,将中文翻译成英文,而这运用了适配器模式。 1 概述 适配器模式(Adapter Pattern),将一个接口转换成客户喜…

idea-控制台输出乱码问题

idea-控制台输出乱码问题 现象描述: 今天在进行IDEA开发WEB工程调式的时候控制台日志输出了乱码,如下截图 其实开发者大多都知道乱码是 编码不一致导致的,但是有时候就是不知到哪些地方不一致,今天我碰到的情况可能和你的不相同…

APACHE KAFKA本机Hello World教程

目标 最近想要简单了解一下Apache Kafka,故需要在本机简单打个Kafka弄一弄Hello World级别的步骤。 高手Kafka大佬们,请忽略这里的内容。 步骤 Apacha Kafka要求按照Javak8以上版本的环境。从官网下载kafka并解压。 启动 # 生产kafka集群随机ID KA…

未来Mac下载站怎么打不开了

重要公告: 未来软件园因业务需要现更换域名 原域名:Mac.orsoon.com 更为新域名:未来mac下载-Mac软件-mac软件下载-mac软件大全 程序已全面转移,请访问新域名

软件基础问答题

性能: 负载压力测试是指在一定约束条件下测试系统所能承受的并发用户量、运行时间、数据量等,以确定系统所能承受的最大负载压力。 负载测试是通过逐步增加系统负载,测试系统性能的变化,并最终确定在满足性能指标的情况下&#xf…

【技能实训】DMS数据挖掘项目-Day11

文章目录 任务12【任务12.1】创建用户信息表【任务12.2】在com.qst.dms.entity下创建用户实体类User,以便封装用户数据【任务12.3】在com.qst.dms.service下创建用户业务类UserService【任务12.4】在项目根目录下创建图片文件夹images,存储dms.png【任务…

计算机毕业论文选题推荐|软件工程|信息管理|数据分析|系列一

文章目录 导文题目导文 计算机毕业论文选题推荐|软件工程|信息管理 (***语言)==使用其他任何编程语言 例如:基于(***语言)门窗账务管理系统的设计与实现 得到:基于JAVA门窗账务管理系统的设计与实现 基于vue门窗账务管理系统的设计与实现 等等 题目 基于requests多线程…

微信小程序——字符串截取

indexOf() : 判断一个字符是否在字符串 中 存在,如果存在返回该元素或字符第一次出现 的 位置 的 索引,不存在返回-1。 lastIndexOf() : 返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。…

静态数码管显示

学习芯片: EP4CE6F17C8 本次学习使用的为共阴极数码管,即用低电平点亮数码管,同样可知,共阳极数码管的阳极连在一起,即用高电平点亮数码管。 八段数码管示意图: a,b,c,d,e,f,g,dg表示八段数码管时&#…

7、sentinel使用和源码分析

一、分布式系统遇到的问题 1、服务雪崩效应 在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等待&#x…

力扣 135. 分发糖果

题目来源:https://leetcode.cn/problems/candy/description/ C题解(来源代码随想录): 先从左往右比较,右边孩子评分比左边高就多发1颗糖,否则就只发1颗;再从右往左比较,左边孩子评分…

机械臂的雅克比矩阵推导

1. 线速度和角速度的递推通式推导 p i p i − 1 R i − 1 r i − 1 , i i − 1 \mathbf{p}_{i}\mathbf{p}_{i-1}\mathbf{R}_{i-1} \mathbf{r}_{i-1, i}^{i-1} pi​pi−1​Ri−1​ri−1,ii−1​ p i − 1 \mathbf{p}_{i-1} pi−1​是 { i − 1 } \{i-1\} {i−1}坐标系的原点的…

记一次ruoyi中使用Quartz实现定时任务

一、首先了解一下Quartz Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标…

UE4/5AI制作基础AI跳跃(适合新手)

目录 制作 添加逻辑 添加导航链接代理 结果 在上一章中,我们讲解了简单的AI跟随玩家,制作了一个基础的ai。 UE4/5AI制作基础AI(适合新手入门,运用黑板,行为树,ai控制器,角色类,任…

4、深入理解ribbon

一、负载均衡的两种方式 服务器端负载均衡 传统的方式前端发送请求会到我们的的nginx上去,nginx作为反向代理,然后路由给后端的服务器,由于负载均衡算法是nginx提供的,而nginx是部署到服务器端的,所以这种方式又被称为…

linux之Ubuntu系列(-)常见指令 重定向

Ubuntu 中文 版本 注意点 通过修改语言改成英文 在终端录入:export LANGen_US 在终端录入:xdg-user-dirs-gtk-update 单用户和多用户 命令格式 command [-选项] [参数] –查看命令的帮助 命令 --help man 命令 |操作键| 功能| |空格键|-显示手册的下…

OSS对象存储后端实现+Vue实现图片上传【基于若依管理系统开发】

文章目录 基本介绍术语介绍图片上传方式介绍普通上传用户直传应用服务器签名后直传 OSS对象存储后端实现maven配置文件配置类ServiceController 图片上传前端图片上传组件api页面使用组件组件效果 基本介绍 术语介绍 Bucket(存储空间):用于…