初衷:随着互联网的发展,高可靠、高并发、降本增效成为各大公司面临的现实挑战。性能优化的需求越来越迫切,从大型分布式系统到小型代码块。算法优化已经成为你日常工作中必须面对的事情。对于开发者来说,性能优化也从加分项变成了热门技能。没有相关知识,很难在面试或工作中脱颖而出。本文主要从理论分析入手,介绍性能优化的衡量指标、理论方法和注意点。指标是我们衡量很多事物和做出行为决策的重要参考。比如在生活中,当你打算买车的时候,你会关注很多指标,比如动力、燃油经济性、刹车、操纵稳定性、乘坐舒适性、通过性、排放和噪音等等,而这些指标也有相关的测试和参数,也可以一一参考这些指标。这个道理大家都懂,但是一旦涉及到性能优化,往往会因为缺乏理论基础而选择错误的优化方向,陷入盲目猜测的困境。衡量一个优化能否达到目的,不能光靠感觉,它还有一系列的指标来衡量你的进步。如果修改后,性能不升反降,那就不能称为性能优化。所谓绩效,就是用有限的资源,在有限的时间内完成工作。最重要的衡量因素是时间,所以很多衡量指标都可以用时间作为横轴。加载缓慢的网站会受到搜索排名算法的惩罚,导致网站排名下降。因此,加载速度是判断性能优化是否合理的一个非常直观的因素,但是性能指标不仅仅包括单个请求的速度,还包括更多的因素。接下来,让我们看看哪些指标可以帮助我们做出决策。指标是什么?1.吞吐量和响应速度分布式高并发应用不能以单个请求作为判断依据,它往往是一个统计结果。最常用的指标是吞吐量和响应能力,这两个指标在考虑性能时都是非常重要的概念。要理解这两个指标的意义,我们可以将其比作交通环境中的十字路口。在车流量非常大的情况下,路口是典型的瓶颈点。当红绿灯放行时间很长的时候,后面往往会排起长龙。从我们开车开始排队到车子通过红绿灯的时间就是响应时间。当然,我们可以适当减少红绿灯的间隔,这样对于一些车辆来说,通过的时间可能会更短一些。但是,如果信号灯频繁切换,单位时间内通过的车辆数量就会减少。从另一个角度,我们也可以认为这个路口的车辆通过量有所下降。我们平时开发中经常会提到,QPS代表每秒查询数,TPS代表每秒事务数,HPS代表每秒HTTP请求数等,这些都是常用的与吞吐量相关的量化指标。在优化性能的时候,我们需要弄清楚优化的目标是吞吐量还是响应速度。有的时候,虽然响应速度比较慢,但是整体的吞吐量很高,比如一些数据库的批量操作,一些buffer的合并等,虽然信息的延迟增加了,但是如果我们的目标是吞吐量,那么这个显然可以算是比较大的性能提升。总的来说,我们认为:响应速度是串行执行的优化,通过优化执行步骤来解决问题;吞吐量是并行执行的优化,通过合理使用计算资源来达到目标??。我们平时的优化主要集中在响应速度上,因为一旦响应速度提高了,整体的吞吐量自然也会随之增加。但是对于高并发的互联网应用,响应速度和吞吐量都是有要求的。这些应用标榜为高吞吐、高并发场景,用户对系统延迟的容忍度很差。我们需要在有限的硬件资源上找到一个平衡点。2.响应时间的测量既然响应时间如此重要,那么我们就着重介绍一下响应时间的测量方法。(1)平均响应时间我们最常用的指标是平均响应时间(AVG),它可以反映服务接口的平均处理能力。其实质就是把所有的请求时间加起来除以请求次数。举个最简单的例子,有10个请求,其中1ms有2个,5ms有3个,10ms有5个,那么它的平均耗时是(21+35+5*10)/10=6.7ms。除非服务在一段时间内出现严重问题,否则平均响应时间将持平。因为高并发应用的请求量特别大,长尾请求的影响会很快被平均,导致很多用户的请求变慢,但这在平均耗时指标上无法体现。为了解决这个问题,另一个常用的指标就是百分位数。(2)百分位数也更容易理解。我们划定一个时间范围,把每个请求的耗时加到一个列表中,然后把这些时间从小到大排序。这样我们就把特定百分位的时间消耗拿出来,这个数字就是TP值。可见TP值(TopPercentile)类似于中位数、平均值等,是统计学中的一个名词。这意味着超过N%的请求在X时间内返回。例如TP90=50ms,表示超过90th的请求会在50ms内返回。这个指标也很重要,它可以反映应用界面的整体响应情况。比如某段时间发生长时间的GC,某段时间以上的指标会出现严重的抖动,但一些低百分位数的值变化不大。我们一般将其分为TP50、TP90、TP95、TP99、TP99.9等多个段,百分位值越高,对系统响应能力的稳定性要求越高。在这些高稳定性系统中,目标是杀死严重影响系统的长尾请求。对于这部分接口性能数据的采集,我们将采用更详细的日志记录方式,而不是单纯依赖指标。比如我们在日志系统中详细输出一个接口的输入和执行步骤,耗时超过1秒。3.并发并发是指系统可以同时处理的请求数。该指标反映了系统的负载能力。在高并发应用中,光有高吞吐量是不够的,还必须能够同时为多个用户服务。当并发度很高时,会导致严重的共享资源争用。我们需要减少资源冲突和长期占用资源的行为。设计响应时间通常是灵丹妙药。因为响应时间减少,同时可以处理的请求数必然会增加。值得注意的是,即使是秒杀系统,经过层层筛选和处理,最终达到某个节点的并发数也只有五十、六十左右。在我们平时的设计中,除非并发极低,否则不需要过多关注这个指标。4、秒开率在移动互联网时代,尤其是APP中的页面,瞬间打开是一种极好的用户体验。如果页面可以在1秒以内加载,用户可以有一个流畅的体验,不会感到更加焦虑。一般来说,可以根据业务情况设置不同的页面打开标准。比如1秒内的数据占比就是秒开率。行业内优秀的公司,如手机淘宝,页面打开率在80%以上。5.正确性说了一件比较有意思的事。我们有一个技术团队。在测试过程中,我们发现界面响应非常流畅。将并发数增加到20后,应用界面响应还是很快的。但是当应用真正启动的时候,因为接口返回了无法使用的数据,所以发生了重大事故。问题的原因也比较容易定位,就是项目中使用了熔断器。压测的时候接口直接超过了服务能力,触发了熔断,但是压测没有判断接口响应的正确性,导致了很低级的错误。所以在做性能评估的时候,不要忘了正确性这个关键要素。有哪些理论方法?性能优化的理论方法有很多,比如木桶理论、基础测试、阿姆达尔定律等,下面我们简单介绍一下最常用的两种理论。1.木桶理论木桶要想装最多的水,需要每块木板的长度一样,不能破损。如果有一块板不满足条件,那么这个桶装不了最多的水。能装多少水取决于最短的木头,而不是最长的木头。木桶效应也很适合用来解释系统性能。组成系统的组件的速度各不相同。系统的整体性能由系统中最慢的组件决定。例如,在数据库应用中,最严重的性能约束就是磁盘I/O问题。也就是说,硬盘在这个场景下是一个短板,我们的首要任务就是弥补这个短板。2.基准测试,热身基准测试(Benchmark)不是简单的性能测试,它是用来测试某个程序的最佳性能。API通常在启动后会有短暂的超时。在测试之前,我们需要对应用程序进行预热,以消除JIT编译器等因素的影响。在Java中,有一个组件,即JMH,可以消除这些差异。Note1.基于数字而不是猜测有些同学对编程有很好的感觉,可以通过猜测列出系统的瓶颈点。这种情况是存在的,但是非常不可取。复杂的系统往往有多个影响因素。我们应该把性能分析放在第一位,性能优化放在第二位。直觉只是我们的辅助,但不能作为得出结论的工具。在进行性能优化时,我们一般会将分析结果进行优先级排序(根据难度和影响程度),从大局着手,先分解影响最大的点,然后再逐一分解其他影响因素。一些优化会引入新的性能问题,有时这些新问题会导致更严重的性能下降。您需要评估此连锁反应以确保确实需要此优化。同时,你需要用数字来衡量这个过程,而不是凭感觉去猜测。2、个人数据不够可信。你有没有这样的经历:某个知名网站的访问速度真的很慢,加载需要x秒。事实上,仅仅根据一个人的一个请求就得出“慢”的结论是不合适的,而我们在进行绩效评估时,往往会陷入这样的误区。这是因为个人要求的小批量数据,参考价值不大。响应时间可能因用户数据而异,也可能取决于设备和网络状况。一个合理的做法是从统计数据中找出一些规律,比如上面提到的平均响应时间、TP值等,甚至是响应时间分布的直方图,可以帮助我们评价性能好坏。3.不要过早优化和过度优化。性能优化虽然好处多多,但并不代表我们要把每件事都做到极致。性能优化也有一个限度。一个程序正确运行比一个程序运行得更快更难。计算机科学之父“DonaldKnuth”曾说过:“过早的优化是万恶之源”,正因如此。如果改进没有产生明显的价值,我们为什么要费心呢?比如一个应用已经满足了用户的吞吐量和响应要求,但是有些同学热衷于JVM调优,还在参数测试上花了不少功夫,这种优化就是过度优化。时间紧迫,我们需要找到最紧迫的需要解决的性能点,然后对其进行攻击。比如一个系统,主要是数据库查询速度慢,而你却花了很大的力气去优化Java编码标准,这是典型的偏离目标的情况。一般来说,性能优化后的代码由于过分追求执行速度,读起来晦涩难懂,而且在结构上会有很多让步。显然,过早的优化会让这个难以维护的特性过早地介入到你的项目中,而当代码重构时,需要付出更多的努力来解决。正确的做法是项目开发和性能优化应该作为两个独立的步骤进行。做性能优化,应该等到整个项目的结构和功能已经大体进入稳定状态。4.保持良好的编码习惯上面我们提到,不要过早地优化和过度优化,但这并不意味着你在编码时不考虑这些问题。例如,如果你保持良好的编码标准,你就可以很容易地重构你的代码;如果使用合适的设计模式,合理划分模块,就可以集中优化性能和结构问题。在追求高性能和高质量编码的过程中,会积累一些好的习惯,在人生的道路上形成优秀的修养和品质,这对我们是大有裨益的。总结我们简单了解了一些衡量性能的指标,比如常见的吞吐量和响应速度,也讨论了一些其他的影响因素,比如并发量、二次打开率、容错率等。同时,我们也谈到了两个介绍了木桶理论、基准测试等工艺方法,并介绍了性能测试中的一些误区和注意点。现在您应该对如何描述性能有了更好的理解。一些专业的性能测试软件,如JMeter、LoadRunner等,就是在这些基本性能指标的基础上进行的扩展。在平时的工作中,我们应该尽量使用专业术语,这样才能正确评价系统的性能。了解了优化指标,有了行动导向之后,接下来应该从哪些方面入手呢?Java性能优化有规律可循吗?
