作为一个半吊子的全栈工匠,在20多年的职业生涯中遇到了太多关于软件性能的问题。演示或证明性能的问题通常很关键。性能问题能否通过一次小的、合乎逻辑的、可证明的和可审计的步骤来解决?已经有人尝试创建一种公理化方法来优化计算机软件性能,但这种能力令我感到惭愧。其次最好的事情是能够清楚和系统地思考如何优化计算机软件的性能。1、什么是性能?厘清表演的概念——表演,概念外延太多,生活中几乎随时可见。比如专业的人的绩效就是中文的绩效,绩效考核就是每个人都会面临的绩效考核。但是,如果您在Internet上进行谷歌搜索,大多数关于性能的热门文章都是关于:计算机软件执行您指定的任何任务需要多长时间。如果从面向对象开始,什么是任务?任务基本上是一个面向业务的工作单元,任务可以嵌套。对于计算机用户来说,性能通常意味着系统执行某项任务所花费的时间。响应时间是任务执行的持续时间,以每个任务的时间为单位。例如,在百度上搜索“性能”的响应时间约为0.2秒。有一种方法可以在浏览器中查看此测量结果,即APerformanceEvidenceforWebSearch。因为软件性能的主体是人,不同的人对同一个软件会有不同的主观感受,不同的人对软件性能的看法也不同。有些人将性能视为吞吐量,即在指定时间间隔内完成的任务执行次数,例如“每秒点击次数”。一般来说,负责团队绩效的人更关心吞吐量,因为他们关心的是系统能否处理所有用户需要处理的所有数据。那么什么是性能呢?时间和空间可能是连续的。从时间和空间的角度来看,绩效是完成某项任务时所表现出的时效性和空间资源效能。对于用户来说,他们更注重时效性,而对于服务或产品提供者来说,他们更注重时间和空间,这是各种因素的权衡。2Performanceindex——时空纠缠性能指标,指的是性能的度量。从时间的角度,包括响应时间、延迟时间等;从空间的角度,包括吞吐量、并发用户数、资源利用率。由于时间和空间的内在联系,以两个重要指标为例,吞吐量和响应时间通常相互关联,但又不完全相同。真正的关系是微妙而复杂的。通信中的吞吐量和响应时间假设一个基准测量每秒1000个任务的吞吐量。那么,平均用户响应时间是多少?人们很容易认为每个任务的平均响应时间是0.001秒,但事实并非如此。如果处理这个吞吐量的系统要有1000个并行、独立、同质的服务通道,在这种情况下每个请求可能会消耗恰好1秒。现在,已知每个任务的平均响应时间在0到1秒之间。然而,响应时间不能单独从吞吐量测量中推断出来,它必须单独测量。当然,有数学模型可以计算给定吞吐量的响应时间,但这些模型需要的输入不仅仅是吞吐量。计算中的吞吐量和响应时间朝另一个方向发展,揭示了微妙之处。如果你需要对一台单CPU计算机进行编程以提供每秒100个新任务的吞吐量,假设你编写的新任务在计算机系统上执行只需0.001秒,它是否能够产生所需的吞吐量?如果可以,如果任务在一秒内运行一次,那么它必须能够在一整秒内至少运行100次。例如,任务请求被很好地序列化,因此所有100个任务都可以在一个循环中处理,一个接一个地顺序执行。但是,如果系统上每秒随机出现100个任务,来自100个不同的用户登录到一台单CPU机器上怎么办?CPU调度程序和序列化资源可能会将吞吐量限制在远低于每秒任务数100,因此无法从响应时间测量中完全推导出吞吐量,需要单独测量。响应时间和吞吐量不一定是对立的。要了解两者,您需要同时测量它们。哪个更重要?对于给定的情况,可以从两个方向合理地寻求答案。在许多情况下,答案是两者都是需要管理的重要指标。例如,一个系统可能有一个业务需求,不仅要求给定任务的响应时间在超过99%的系统响应中小于1秒,而且系统必须支持在1秒内连续执行1,000个任务的吞吐量。第二个间隔。3.描述性能:所有结果都是“99%以上系统响应”的概率,这是响应时间的一个预期极限。有些人更习惯用“平均响应时间必须是x秒”来形容。然而,陈述目标的百分比方法更好地反映在人类经验中。想象一下,对于每天在计算机上执行的特定任务,响应时间容差可能为1秒。假设,a系统90%的平均响应时间为1秒,b系统60%的平均响应时间为1秒,则a系统有10%的用户不满意,b系统有40%的用户不满意不满意?若a在系统b中,90%响应时间为0.91秒;在系统b中,90%的响应时间是1.07秒,所以这个描述比仅仅说平均响应时间1.00秒更能提供信息。我们试图用两个可能的数字来描述世界,一个是均值,另一个是方差。客户感知的可能是方差,而不是均值。将响应时间表示为百分比会产生符合最终用户期望且令人信服的性能描述,例如“动态库加载”任务必须在至少99.99%的执行中在0.5秒内完成。我们还使用概率来描述性能。或许,所有的抽象都可以归于数学,所有的结果都可以归于概率。4问题诊断——以终为始以往遇到的性能问题大多与响应时间有关:“以前做一件事不到一秒,现在有时需要10秒以上。”当然,更谦虚的说法是,“整个系统太慢了,用不上”。关于性能问题的诊断,最重要的是把问题说清楚。以终为始,系统想要达到的目标状态是什么?找到一些可以用来表达目标状态的详细数据:例如,“在很多情况下,系统的响应时间小于2秒。如果至少95%的关键任务响应时间在一秒以下,这就是我们想要的。”这个描述看起来不错,但是——如果用户没有这样的量化目标怎么办?这个具体目标有两个数量(1s和95%),如果你不知道其中一个怎么办?更糟糕的是,如果用户确实有某些想法,但这些期望无法实现怎么办?你怎么知道什么是“可能”或“不可能”?...性能问题诊断从问题的描述开始,从最后开始,倒序进行,然后使用工具来处理这些问题。TimeSharpTool-SequenceDiagram时序图是UML中规定的一种图形,用来按照交互发生的先后顺序展示对象之间的交互,时序图是一个非常有用的可视化响应时间的工具。考虑到绘制顺序图的比例,每个传入的“请求”箭头和相应的“响应”箭头之间的距离与服务请求所需的时间成正比,说明图中表示的组件如何花费时间,可以“感觉到”响应时间的相对贡献。序列图可以帮助人们概念化给定系统中的响应时间是如何消耗的,还可以显示同步处理线程是如何并行工作的。除了分析业务,它也是性能分析的好工具。但是要系统地考虑性能,还需要其他东西。假设要修复的任务的响应时间为2048秒,在此期间运行该任务将导致应用程序服务器执行320,000次数据库调用。图3显示了此任务的时序图。应用程序层和数据库层之间有太多的请求和响应箭头,很难看到任何细节。也就是说,在很长的滚动条上打印时序图并不是一个有用的解决方案。时序图是概念化控制流和对应的时间流的好工具,可以作为时间上的锐利边缘,那么空间上有没有边缘呢?空间分析-组件描述直方图为了处理需要大量调用的任务,一个方便的时间序列集合可以理解时间花费的重要模式。摘要描述是响应时间的表格细分,通常按组件响应时间贡献的降序排列。直方图通常会准确显示慢速任务花费时间的位置。例如,您可以导出配置文件描述中标识的每个函数以及函数调用的响应时间百分比,还可以导出任务期间每种类型的函数调用的平均响应时间。如果您可以深入到汇总到单个调用中的持续时间,您可以知道这些调用中有多少对应于对某个函数的其他调用,并且您可以知道每个调用消耗了多少响应时间。“这个任务要运行多长时间?”使用组件来描述直方图,可以构造问题的答案。老coder认为这是问题诊断的第一个重要问题,是解决性能问题的开始。5条优化原则-要事第一?性能改进与程序使用正在改进的内容的程度成正比。如果你试图改进的事情只占任务总响应时间的5%,那么你能产生的最大影响恰好是总响应时间的5%。这意味着我们越关注直方图的顶部(假设组件直方图按响应时间降序排列),对整体响应时间的潜在好处就越大。然而,这并不意味着组件响应始终按自上而下的顺序进行处理,还需要考虑执行补救措施的成本。考虑组件的响应时间直方图,添加最佳补救方法可以节省多少时间,您可以看到每种补救方法的实施成本。确立优化的起点那么,首先应该采取哪些补救措施呢?成本核算,寻找更好的净收益,这才是真正的优化点。包含改进成本的组件响应时间直方图为更好地决定首先实施哪些补救措施打开了大门,为预测改进的性能指标提供了一个尺度。此外,可以找到比预期更有效的方法,以低于预期的成本减少响应时间。首先采取哪种补救措施取决于对成本估算的信任程度。“非常便宜”是否真的考虑了提议的改进可能给系统带来的风险?例如,更改此参数或删除该索引看起来非常经济,但这种更改是否具有潜在的破坏性?改变一些现在甚至意想不到的组件的良好性能呢?可靠的成本估算是技术能力发挥作用的另一个领域。进步中的可信度另一个值得考虑的因素是通过取得小胜利可以获得的可信度。也许低成本、低风险的改进不会导致整体响应时间的改进,但建立小改进的跟踪记录很有价值,这些小改进完全符合预测为慢速响应时间节省了多少任务。在软件性能方面,预测和最终实施的跟踪记录带来了必要的可信度来影响我们的同事甚至经理、客户等,他们将支持你采取越来越昂贵的补救措施,带来更大的回报。在提出和获得对更大、昂贵、高风险的补救建议的支持时,应谨慎行事。声誉是脆弱的,建立起来很困难,但推倒它只需要一瞬间。降低连贯性风险在实践中,固定一项任务的性能经常会损害另一项任务的性能。那么,我们在优化性能的时候应该注意什么呢?这里,我们可以类比这样一个问题:“为了凉爽,我应该开窗还是脱掉厚衣服?”这就是性能优化中最小化风险的原则。确保您本地的东西是有序的,并尝试缩小故障域的范围。如果除了一两个程序之外的所有程序都处理得很好,那么最安全的解决方案是将修改范围限制在这一个或两个程序上。6性能时空因素在具体的性能优化过程中,会遇到各种各样的情况,常见的因素有数据倾斜、执行效率、负载和延迟等。数据倾斜在处理组件响应时间直方图时,您可能会反复遇到x次数据库调用占用y秒响应时间的问题。如果我们可以消除一半的呼叫,可以消除多少不必要的响应时间?答案往往出乎意料,而且几乎从来没有“一半的响应时间”,这取决于我们可以消除的单个调用的响应时间。不能假设每次调用的时长是y/x秒的平均值,声明并没有告诉我们调用时长是一致的。数据倾斜是特定调用中的不一致,其中倾斜的可能性使得无法提供有关组件响应时间的准确答案。在对数据偏差一无所知的情况下,可以提供的答案是“介于0到y秒之间。但是,假设有特定的附加信息。可以制定更精确的最佳情况和最坏情况估计。在数据库应用程序中,读写分离只是大粒度分离数据倾斜的一种方式。运行效率即使整个系统每个人都很痛苦,你仍然应该把注意力放在业务首先需要修复的流程上。出发点是确保程序尽可能高效地工作。效率与在不增加容量和不牺牲业务功能的情况下可以消除多少任务执行的总服务时间成反比。换句话说,效率与浪费成反比。下面是一个数据库应用程序中经常出现的浪费的两个例子:中层程序为每一行数据创建一个单独的SQL语句碱基插入。它执行1000次数据库准备调用,即1000次网络IO调用,并且可以通过一次调用传递。减少999次网络IO调用以完成作业。一条SQL语句需要数据库缓冲数万次才能返回数百行的结果集。而一个额外的过滤语句可以返回最终用户真正希望看到的6个OK,只需要几十个数据库缓冲区访问。当然,如果一个系统存在一些全局性的问题,比如索引考虑不周、参数设置不当、硬件配置不当等,就会导致整个系统在大量任务时效率低下,那么就应该修复。但是,不要调整系统以适应低效程序,也不要将权宜之计用作永久解决方案。解决低效率问题通常会解决程序本身的低效率问题即使某些程序是现成的商业应用程序,与软件供应商合作以使程序从长远来看更高效,而不是尝试优化系统以有效地处理固有的低效率问题尽可能。一个更高效的程序可以为系统中的每个人带来巨大的好处,而且很容易看出减少浪费如何有助于修复任务的响应时间。工作负载许多人还不了解的是,使程序更高效会为系统中与正在修复的程序没有明显关系的其他程序带来性能改进。这是由于负载对系统的影响。负载是并发任务执行引起的资源竞争。这就是为什么我们的性能测试没有发现生产后期出现的所有性能问题。负载的一种度量是利用率,它是指定时间间隔内的资源使用量除以资源容量。随着资源利用率的增加,用户从该资源请求服务的响应时间也会增加。凡是在北京高峰时段开车的人,都经历过在交通非常拥堵的情况下,在红绿灯处要等更长时间的现象。软件减速与汽车在繁忙交通中以30英里/小时的速度行驶与在开阔道路上以60英里/小时的速度行驶不同。由于CPU每个时钟周期的指令数是固定的,所以计算机软件总是以同样的速度运行,但响应时间肯定会随着系统资源使用的增加而减少。还是时空纠缠,随着负载的增加,系统变慢的原因有两个:排队延迟和一致性延迟。排队延迟负载和响应时间之间的数学关系是众所周知的。称为M/M/m的排队模型将响应时间与一组特定需求的系统负载相关联。M/M/m有一个假设,即系统具有“理论上完美的可扩展性”,虽然有一些过剩,但M/M/m模型在性能方面仍然有很多需要学习的地方。下图显示了当m=8时该模型的响应时间与负载之间的关系。【本文来自专栏作家“老曹”原创文章,作者微信公众号:哦家ArchiSelf,id:wrieless-com】点此阅读更多本作者好文
