Java 性能优化实战理论分析:性能优化,有哪些衡量指标?需要注意什么?

发布于:2022-12-26 ⋅ 阅读:(499) ⋅ 点赞:(0)

你好,我是李国。作为《Java 性能优化与面试 21 讲》这个课程的作者,我先来简单介绍下自己。

我曾任京东金融、陌陌科技高级架构师,工作期间,我接触的都是比较底层的中间件和操作系统,涉及大量高并发场景下的调优工作,比如缓存优化、多线程优化、JVM 调优等。因此,我在高并发下的性能优化方面积累了丰富的实践经验,同时积累了一套自己独有的优化思路和优化技巧。我曾经优化过一个运行缓慢的复杂业务,单机 QPS 由原来的 2k/s 提升到了 2w/s,整个集群 QPS 达到近 100w/s。

随着互联网的发展,高可靠、高并发以及降本增效,已成为各大公司面临的现实挑战,性能优化需求愈发迫切,大到分布式系统,小到代码块的算法优化,都已经成为你日常工作中必须要面对的事情。对于开发者而言,性能优化也从加分项变为一个热门技能,缺乏相关知识将很难在面试或工作中脱颖而出。

性能优化有哪些困扰

但是作为过来人,我发现很多学习者和实践者在 Java 性能优化上面临着很多的困扰,比如:

  • 工作场景中遇到“性能优化”难题,往往只能靠盲猜和感觉,用临时性的补救措施去掩盖,看似解决了问题,但下次同样的问题又会发作,原因则是缺乏方法论、思路的指引,以及工具支持

  • 能力修炼中,由于常年接触 CRUD,缺乏高并发这一实践环境,对“性能优化”只能通过理论知识进行想象,无法认识其在工作实战中的真实面目和实操过程

  • 职场晋升中,只管功能开发,不了解组件设计原理,缺少深入地思考与总结,无法完成高并发、高性能系统设计这类高阶工作,难以在工作中大展拳脚,而有挑战的工作往往留给有准备的人。

总之,一旦遇到“性能优化”问题,很少人能够由点及面逆向分析,最终找到瓶颈点和优化方法,而性能优化是软件工程的深水区,也是衡量一个程序员能力高低的标准。

进行 Java 性能优化的关键

俗话说,知己知彼百战百胜,想要克服“性能优化”这一难题,先要了解性能优化的特点,并抓住其关键和本质。

作为面试必考内容,很多应聘者反映说面试官的一些问题会让其陷入模棱两可的境地,不知如何作答,比如很多人就搞不懂缓冲与缓存的区别。这种问题的答案,只能靠体系化的整理,依靠零零散散的知识是行不通的。你需要具备触类旁通的能力,才能对面试的散点知识既有深度又有广度地做进一步升华,才会让面试官眼前一亮。

性能优化是个系统性工程,对工程师的技术广度和深度都有要求。它不仅需要你精通编程语言,还需要深刻理解操作系统、JVM 以及框架原理的相互作用关系,需要你多维度、全方面地去分析排查。

此外,很多人能够遇到问题解决问题,但救火式治理只能临时补救表面问题,无法真正找出病灶,这次的解决只是为下次发作埋下了伏笔。事实上,很多性能问题往往隐藏的很深,比如,spring-aop 所引起的性能问题就比较难以排查。

再比如,有人细致到会关注 switch 语句速度快还是 if 语句快,但并不能真正解决性能问题。原因是什么呢?他虽然做了“性能优化”这个动作,但思路方向却错了。这种极细微级别的优化对性能提升的影响面是很小的;而且,细节上极度地追求性能,反而会把代码写得晦涩难懂,难以维护,导致最后舍本逐末。其实,性能优化更多要求我们关注整体效果,兼顾可靠性、扩展性,以及极端的异常场景,这样才能体现性能优化的价值

实践比理论重要。性能优化并不是对固定、单一场景的优化,场景不同,方法也会不同。比如,如果你的业务是串行的,耗时很长,就不能简单地通过增加 CPU 资源进行性能提升;如果你的业务是并行的,也不能钻牛角尖地优化每一行代码,要照顾各个资源的协调,对短板着重进行优化,以便达到最优效果。

在过去你面临以上情况时,可能会仅凭感觉入手,或者先动手才思考,无法发现抓住本质,但在本课程中,我会向你讲解正确的思路,让你进行性能优化时有理可依。

课程设计

在这个课程中,我汇总了 Java 性能优化的经典案例,结合大量代码示例,尽力为你还原真实的业务场景。

课程分为 5 个模块,共 21 篇,我将从理论分析、工具支持、案例与面试点,以及 JVM 优化四大方面展开系统讲解:

  • 模块一:理论分析,针对平常对性能优化的盲猜问题,我们会首先讲解大量的衡量指标,然后以此为依据,盘点一下常用的优化方法,包括业务优化、复用优化、计算优化、结果集优化、资源冲突优化、算法优化、高效实现等方面。学完后,你将会了解如何描述性能,并对性能优化有个整体的印象。

  • 模块二:工具支持,工欲善其事,必先利其器。此部分将介绍一些评估操作系统设备性能的工具,包含大量实用的命令行解析;还会介绍 Java 中最有效的基准测试工具 JMH,以及一些监测 JVM 性能的应用。本模块的目的,是为大家提供一些测量性能的工具,为实践环节做准备。

  • 模块三:实战案例与高频面试点,该模块为课程的主要内容,结合之前模块的理论分析和工具支持,通过海量实战案例,深入专项性能场景,并将每个场景下的高频面试点逐一击破,点拨调优思路,目标是能够做到举一反三,在遇到相似的性能问题时,能够快速想到合适的切入点进行优化。

  • 模块四:JVM 优化,该模块对系统的性能提升是巨大的。本部分主要介绍垃圾回收的一些基本知识,看一下 JIT 在性能提升上所做的文章;最后列举了一些常见的优化参数,以及对编码方面的要求。学完本模块,你将掌握和 JVM 相关的常见优化措施。

  • 模块五:特别放送,最后,针对工作中最常用的服务和框架,我想和你介绍一个 SpringBoot 服务的优化案例,涵盖 Tomcat、Undertow、JVM、网络等场景,同时再进行优化方法和求职面经总结,希望以一个全局的案例,帮助你掌握从系统层到应用层的整个优化技巧。

你将收获

建立完整的性能优化知识体系。你可以系统地学习相关知识,而不是碎片化获取,基础理论实用性强,直入主题,让你在工作实战时有理可依,有据可循

能够对线上应用输出优化思路。掌握各种实战排查工具,并灵活应用,定位至应用中的症结瓶颈点,并输出优化思路方案。正确的方法比努力更重要,有了正确的思路方法,才能在实际工作中避免跑偏,避免把大力气花在一些细枝末节上。我还会分享大量的操作系统方面的知识,让你对应用性能有更好的评测。

收获海量实战经验分享。作为这门课最硬核内容,我将从流行的中间件介绍到常用的工具类,再到 JDK 中的知识点,用实战分析和经验分享高度还原真实的业务场景,带你了解性能优化的全过程。

获得面试 Offer 收割利器。本课程的大多数案例,都是 Java 面试题的重灾区,我将直接指出高频考点,让你既能在整体上对性能优化提供建议,也能深入细节进行针对性优化。

讲师寄语

最后,性能优化既是工程师们进阶的“拦路虎”,也可以是你能力的炼金石。希望这个专栏可以让 这个非常难啃的老大难问题,变得“平易近人”“通俗易懂”“一点就通”,希望可以让你体会到“哦,原来如此简单!”的感觉,体会到久违的学习的快乐,并能学有所用。

另外,我去年就与拉勾教育平台合作了《深入浅出 Java 虚拟机》(已完结)课程,用户口碑还不错,Java 虚拟机这门课可作为 Java 性能优化课程的一个补充,我也推荐你去学习了解。

Java 性能优化对知识广度和知识深度都有比较高的要求,让我们掌握性能调优的思路,多多实践,使自己的编码水平更上层楼。


本课时主要从理论分析入手来介绍性能优化的衡量指标,及其理论方法和注意点。

指标是我们衡量很多事物,以及做出行为决策的重要参考。例如在生活中,当你打算买汽车时,会关注很多指标,比如动力性、燃油经济性、制动性、操纵稳定性、平顺性、通过性、排放与噪声等,而这些指标也都有相关的测试和参数,同时也会对这些指标进行一一参考。

这个道理大家都懂,但一旦到了性能优化上,却往往因为缺乏理论依据而选择了错误的优化方向,陷入了盲猜的窘境。在衡量一项优化是否能达到目的之时,不能仅靠感觉,它同样有一系列的指标来衡量你的改进。如果在改动之后,性能不升反降,那就不能叫性能优化了。

所谓性能,就是使用有限的资源有限的时间内完成工作。最主要的衡量因素就是时间,所以很多衡量指标,都可以把时间作为横轴。

加载缓慢的网站,会受到搜索排名算法的惩罚,从而导致网站排名下降。 因此加载的快慢是性能优化是否合理的一个非常直观的判断因素,但性能指标不仅仅包括单次请求的速度,它还包含更多因素。

接下来看一下,都有哪些衡量指标能够帮我们进行决策。

衡量指标有哪些?

image (12).png

1. 吞吐量和响应速度

分布式的高并发应用并不能把单次请求作为判断依据,它往往是一个统计结果。其中最常用的衡量指标就是吞吐量和响应速度,而这两者也是考虑性能时非常重要的概念。要理解这两个指标的意义,我们可以类比为交通环境中的十字路口。

在交通非常繁忙的情况下,十字路口是典型的瓶颈点,当红绿灯放行时间非常长时,后面往往会排起长队。

从我们开车开始排队,到车经过红绿灯,这个过程所花费的时间,就是响应时间。

当然,我们可以适当地调低红绿灯的间隔时间,这样对于某些车辆来说,通过时间可能会短一些。但是,如果信号灯频繁切换,反而会导致单位时间内通过的车辆减少,换一个角度,我们也可以认为这个十字路口的车辆吞吐量减少了。

image (13).png

像我们平常开发中经常提到的,QPS 代表每秒查询的数量,TPS 代表每秒事务的数量,HPS 代表每秒的 HTTP 请求数量等,这都是常用的与吞吐量相关的量化指标。

在性能优化的时候,我们要搞清楚优化的目标,到底是吞吐量还是响应速度。 有些时候,虽然响应速度比较慢,但整个吞吐量却非常高,比如一些数据库的批量操作、一些缓冲区的合并等。虽然信息的延迟增加了,但如果我们的目标就是吞吐量,那么这显然也可以算是比较大的性能提升。

一般情况下,我们认为:

  • 响应速度是串行执行的优化,通过优化执行步骤解决问题;

  • 吞吐量是并行执行的优化,通过合理利用计算资源达到目标。

我们平常的优化主要侧重于响应速度,因为一旦响应速度提升了,那么整个吞吐量自然也会跟着提升。

但对于高并发的互联网应用来说,响应速度和吞吐量两者都需要。这些应用都会标榜为高吞吐、高并发的场景,用户对系统的延迟忍耐度很差,我们需要使用有限的硬件资源,从中找到一个平衡点。

2. 响应时间衡量

既然响应时间这么重要,我们就着重看一下响应时间的衡量方法。

(1)平均响应时间

我们最常用的指标,即平均响应时间(AVG),该指标能够体现服务接口的平均处理能力。它的本质是把所有的请求耗时加起来,然后除以请求的次数。举个最简单的例子,有 10 个请求,其中有 2 个 1ms、3 个 5ms、5 个 10ms,那么它的平均耗时就是(2*1+3*5+5*10)/10=6.7ms。

除非服务在一段时间内出现了严重的问题,否则平均响应时间都会比较平缓。因为高并发应用请求量都特别大,所以长尾请求的影响会被很快平均,导致很多用户的请求变慢,但这不能体现在平均耗时指标中。

为了解决这个问题,另外一个比较常用的指标,就是百分位数(Percentile)

(2)百分位数

image (14).png

这个也比较好理解。我们圈定一个时间范围,把每次请求的耗时加入一个列表中,然后按照从小到大的顺序将这些时间进行排序。这样,我们取出特定百分位的耗时,这个数字就是 TP 值。可以看到,TP 值(Top Percentile)和中位数、平均数等是类似的,都是一个统计学里的术语。

它的意义是,超过 N% 的请求都在 X 时间内返回。比如 TP90 = 50ms,意思是超过 90th 的请求,都在 50ms 内返回。

这个指标也是非常重要的,它能够反映出应用接口的整体响应情况。比如,某段时间若发生了长时间的 GC,那它的某个时间段之上的指标就会产生严重的抖动,但一些低百分位的数值却很少有变化。

我们一般分为 TP50、TP90、TP95、TP99、TP99.9 等多个段,对高百分位的值要求越高,对系统响应能力的稳定性要求越高。

在这些高稳定性系统中,目标就是要干掉严重影响系统的长尾请求。这部分接口性能数据的收集,我们会采用更加详细的日志记录方式,而不仅仅靠指标。比如,我们将某个接口,耗时超过 1s 的入参及执行步骤,详细地输出在日志系统中。

3. 并发量

并发量是指系统同时能处理的请求数量,这个指标反映了系统的负载能力

在高并发应用中,仅仅高吞吐是不够的,它还必须同时能为多个用户提供服务。并发高时,会导致很严重的共享资源争用问题,我们需要减少资源冲突,以及长时间占用资源的行为。

针对响应时间进行设计,一般来说是万能的。因为响应时间减少,同一时间能够处理的请求必然会增加。值得注意的是,即使是一个秒杀系统,经过层层过滤处理,最终到达某个节点的并发数,大概也就五六十左右。我们在平常的设计中,除非并发量特别低,否则都不需要太过度关注这个指标。

4. 秒开率

在移动互联网时代,尤其对于 App 中的页面,秒开是一种极佳的用户体验。如果能在 1 秒内加载完成页面,那用户可以获得流畅的体验,并且不会产生更多的焦虑感。

通常而言,可以根据业务情况设定不同的页面打开标准,比如低于 1 秒内的数据占比是秒开率。业界优秀的公司,比如手淘,其页面的秒开率基本可达到 80% 以上。

5. 正确性

说一个比较有意思的事情。我们有个技术团队,在进行测试的时候,发现接口响应非常流畅,把并发数增加到 20 以后,应用接口响应依旧非常迅速。

但等应用真正上线时,却发生了重大事故,这是因为接口返回的都是无法使用的数据。

其问题原因也比较好定位,就是项目中使用了熔断。在压测的时候,接口直接超出服务能力,触发熔断了,但是压测并没有对接口响应的正确性做判断,造成了非常低级的错误。

所以在进行性能评估的时候,不要忘记正确性这一关键要素。

有哪些理论方法?

性能优化有很多理论方法,比如木桶理论、基础测试、Amdahl 定律等。下面我们简单地讲解一下最常用的两个理论。

1. 木桶理论

一只木桶若想要装最多的水,则需要每块木板都一样长而且没有破损才行。如果有一块木板不满足条件,那么这只桶就无法装最多的水。

能够装多少水,取决于最短的那块木板,而不是最长的那一块。

木桶效应在解释系统性能上,也非常适合。组成系统的组件,在速度上是良莠不齐的。系统的整体性能,就取决于系统中最慢的组件。

比如,在数据库应用中,制约性能最严重的是落盘的 I/O 问题,也就是说,硬盘是这个场景下的短板,我们首要的任务就是补齐这个短板。

2. 基准测试、预热

基准测试(Benchmark)并不是简单的性能测试,是用来测试某个程序的最佳性能。

应用接口往往在刚启动后都有短暂的超时。在测试之前,我们需要对应用进行预热,消除 JIT 编译器等因素的影响。而在 Java 里就有一个组件,即 JMH,就可以消除这些差异。

注意点

1.jpeg

1. 依据数字而不是猜想

有些同学对编程有很好的感觉,能够靠猜测列出系统的瓶颈点,这种情况固然存在,但却非常不可取。复杂的系统往往有多个影响因素,我们应将性能分析放在第一位,把性能优化放在次要位置,直觉只是我们的辅助,但不能作为下结论的工具。

进行性能优化时,我们一般会把分析后的结果排一个优先级(根据难度和影响程度),从大处着手,首先击破影响最大的点,然后将其他影响因素逐一击破。

有些优化会引入新的性能问题,有时候这些新问题会引起更严重的性能下降,你需要评估这个连锁反应,确保这种优化确实需要,同时需要使用数字去衡量这个过程,而不是靠感觉猜想。

2. 个体数据不足信

你是否有这样的经历:某个知名网站的访问速度真慢,光加载就花费了 x 秒。其实,仅凭一个人的一次请求,就下了“慢”这个结论,是不合适的,而在我们进行性能评估的时候,也往往会陷入这样的误区。

这是因为个体请求的小批量数据,可参考价值并不是非常大。响应时间可能因用户的数据而异,也可能取决于设备和网络条件。

合理的做法,是从统计数据中找到一些规律,比如上面所提到的平均响应时间、TP 值等,甚至是响应时间分布的直方图,这些都能够帮我们评估性能质量。

3. 不要过早优化和过度优化

虽然性能优化有这么多好处,但并不代表我们要把每个地方都做到极致,性能优化也是要有限度的。程序要运行地正确,要比程序运行得更快还要困难。

计算机科学的鼻祖"Donald Knuth" 曾说:“过早的优化是万恶之源”,就是这个道理。

如果一项改进并不能产生明显的价值,那我们为什么还要花大力气耗在上面呢?比如,某个应用已经满足了用户的吞吐量需求和响应需求,但有的同学热衷于 JVM 的调优,依然花很大力气在参数测试上,这种优化就属于过度优化。

时间要花在刀刃上,我们需要找到最迫切需要解决的性能点,然后将其击破。比如,一个系统主要是慢在了数据库查询上,结果你却花了很大的精力去优化 Java 编码规范,这就是偏离目标的典型情况。

一般地,性能优化后的代码,由于太过于追求执行速度,读起来都比较晦涩,在结构上也会有很多让步。很显然,过早优化会让这种难以维护的特性过早介入到你的项目中,等代码重构的时候,就会花更大的力气去解决它。

正确的做法是,项目开发和性能优化,应该作为两个独立的步骤进行,要做性能优化,要等到整个项目的架构和功能大体进入稳定状态时再进行。

4. 保持良好的编码习惯

我们上面提到,不要过早地优化和过度优化,但并不代表大家在编码时就不考虑这些问题。

比如,保持好的编码规范,就可以非常方便地进行代码重构;使用合适的设计模式,合理的划分模块,就可以针对性能问题和结构问题进行聚焦、优化。

在追求高性能、高质量编码的过程中,一些好的习惯都会积累下来,形成人生道路上优秀的修养和品质,这对我们是大有裨益的。

小结

在本课时,我们简单地了解了衡量性能的一些指标,比如常见的吞吐量和响应速度,还探讨了一些其他的影响因素,比如并发量、秒开率、容错率等。

同时,我们也谈到了木桶理论和基准测试等两种过程方法,并对性能测试中的一些误区和注意点进行了介绍,现在你应该对如何描述性能有了更好的理解。像一些专业的性能测试软件,如 JMeter、LoadRunner 等,就是在这些基础性能指标上进行的扩展。我们在平常的工作中,也应该尽量使用专业术语,这样才能对系统性能进行正确评估。

了解了优化指标后,有了行动导向,那接下来该从哪些方面入手呢? Java 性能优化是否有可以遵循的规律呢?

下一课时,我们将从整体上,来介绍一下性能优化都有哪些考量点。


精选评论

*众:

老师讲的很不错

**霖:

很少看到这么系统讲解性能优化的,老师的独到见解真是的实在的东西。收获满满

**也:

期待

**千:

目前来看,这个课不错

*浩:

希望后边老师能结合一些实战案例进行讲解😁

    编辑回复:

    之后的课程中会有很多案例哦,并且还对讲解对应的高频考点

Rexza:

老师很厉害,课程很棒

**丰:

希望跟着大佬,慢慢让自己上一个台阶,🙏

**鑫:

结合实践例子多讲一些😀😀

    编辑回复:

    后面的课时会有很多实战案例哦,并且还会讲解对应的考点

**文:

讲的挺好

**哈:

言简意赅。看过很多文章,这是把响应时间 ,吞吐量,并发量解释最通俗易懂的,给老师点赞,给拉勾点赞。

**达:

性能优化光看书效果不大,跟对老师了

**强:

课程会会过期吗?

    编辑回复:

    不会,是永久的哦~

Rexza:

加油加油,一起学习进步努力

Rexza:

讲的很深入很全面,希望自己可以在性能优化方面进步多多😊

**0107:

额嗯~咱们这个课程多久更新一讲呢,喜欢

    编辑回复:

    每周一、周三更新,每次更新一讲~O(∩_∩)O

*洋:

学习了,期待后面能更深入、易懂的细节。

**1463:

很期待老师的教学

    编辑回复:

    O(∩_∩)O


网站公告

今日签到

点亮在社区的每一天
去签到