在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的时候会遇到下面这些需求: 在现有页面上添加浮…

make: *** /lib/modules/3.10.0-957.el7.x86_64/build: No such file or directory.

内核版本是3.10.0-957.el7,出错之后发现: yum list|grep kernel-devel kernel-devel.x86_64 3.10.0-1160.92.1.el7 update 并且发现 yum install kernel-devel-$(uname -r) 不行,没有安装包。 按照某个博…

代码随想录算法训练营第十九天 | 动态规划系列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),将一个接口转换成客户喜…

为什么使用线程池?解释下线程池参数?

使用线程池的原因 (1)降低资源消耗:提高线程利用率,降低创建和销毁线程的消耗。 (2)提高响应速度:任务来了,直接有线程可用可执行,而不是线创建线程再执行。 &#xff0…

LLMs和GPT的相关概念

1.prompt、instruction、input和response在LLMs中的作用和区别 在LLMs中,prompt、instruction、input和response是四个重要的概念,它们各自有不同的作用和区别。 (1). Prompt(提示):Prompt是L…

idea-控制台输出乱码问题

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

Scala集合常用函数 - 高级计算函数

水善利万物而不争,处众人之所恶,故几于道💦 目录 1. 过滤 - filter 2. 转换/映射 - map 3. 扁平化 - flatten 4. 扁平化映射 - flatMap 5. 分组 - groupBy 6. 简化(规约) - reduce 7. 折叠 - fold 8. 函数小练习 1. 过…

APACHE KAFKA本机Hello World教程

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

【MySQL】 如何在MySQL中获取表中的某个字段为最大值和倒数第二条的整条数据?

文章目录 前言一、查询倒数第二个记录1.1、使用排名1.2、子查询1.3、嵌套查询 二、下面为大家提供一个测试案例三、查询某个字段为最大值的整条数据3.1、使用max3.2、使用连接3.3、前n个最大(最小)值 四、使用组合查询,先查询到最小的价格是多…

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

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

软件基础问答题

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

校园跑腿小程序怎么样?

随着社会的发展和人们生活水平的提高,高等教育越来越受到重视。大学校园不仅是学习的地方,也是学生们日常生活的场所。然而,在繁忙的学业和生活压力下,学生可能经常面临诸如代购、快递、取餐等各种琐碎但繁琐的任务。基于这个需求…

PHP中的支持向量机算法实现原理

PHP中的支持向量机算法实现原理 支持向量机(Support Vector Machine,简称SVM)是一种常用的机器学习算法,用于进行分类和回归分析。它基于统计学习理论和结构风险最小化原则,通过构造最优分类超平面来实现模型训练和预…

【技能实训】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多线程…

SQL 训练题目

title: SQL 训练题目 date: 2023-7-15 01:45:50 tags:- SQL 训练 查询 "01" 课程比 "02" 课程成绩高的学生的信息及课程分数 解题思路:要查询的是两个课程的成绩,而且还要显示学生的信息。所以需要用到两张表,SC&#xf…

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

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

2.5 vim的使用

2.5 Vim的使用 介绍 Vim是一款强大的文本编辑器,常用于在终端环境下编辑文本文件。本文将介绍Vim的基本概念、常用操作和一些实用技巧,帮助您更高效地使用Vim进行文本编辑。 Vim的基本模式 Vim具有多种模式,其中最常用的三种模式是&#…