Java性能权威指南-总结2

news2024/11/20 3:31:53

Java性能权威指南-总结2

  • 性能测试方法
    • 原则2:理解批处理流逝时间、吞吐量和响应时间
      • 批处理流逝时间
      • 吞吐量测试
    • 原则3:用统计方法应对性能的变化

性能测试方法

原则2:理解批处理流逝时间、吞吐量和响应时间

性能测试的第2条原则是多角度审视应用性能。应该测量哪个指标取决于对应用最重要的因素。

批处理流逝时间

测量应用性能的最简单方法是,看它完成任务花了多少时间,例如接收10000只股票25年的历史价格并计算标准差,生成某公司50000名雇员的薪酬福利报表,以及执行1000000次循环的时间等。

在非Java的世界,可以很直接地测试流逝时间:应用记下时间点从而测量执行时间。但在Java世界中,由于即时编译(JIT),这种方法就会有些问题了。 其中的重点是,虚拟机会花几分钟(或更长时间)全面优化代码并以最高性能执行。由于这个(以及其他)原因,研究Java的性能优化就要密切注意代码优化的热身期:大多数时候,应该在运行代码执行足够长时间,已经编译并优化之后再测量性能。

其他影响应用热身的因素
通常认为的应用热身,指的就是等待编译器优化运行代码,不过基于代码的运行时长还有其他一些影响性能的因素。
例如,JPA通常都会缓存从数据库读取的数据,由于这些数据可以从缓存中获取而不需要到数据库,所以通常再次使
用时,操作就会变得更快。与此类似,应用程序读文件时,操作系统就会将文件载入内存。随后再次读取相同文件就
会变得更快,这是因为数据已经驻留在计算机主内存中,并不需要从磁盘实际读取。
一般来说,应用热身过程中有许多地方会缓存数据,虽然并不都那么明显


另一方面,许多情况下应用从开始到结束的整体性能更为重要。报告生成器处理10000个数据元素需要花费大量时间,但对最终用户而言,处理前5000个元素是否比后5000个慢50%并不重要。即便是像应用服务器这样的系统——其性能必定会随运行时间而改善——初始的性能依然很重要。某种配置下的应用服务器需要45分钟才能达到性能峰值。对于在这段时间访问应用的用户来说,热身期的性能就很重要。基于这些理由,许多例子都是面向批处理的(即便这看起来有些不寻常)。

吞吐量测试

吞吐量测试是基于一段时间内所能完成的工作量。虽然最常见的吞吐量测试是服务器处理客户端产生的数据,但这并非绝对的:单个独立运行的应用也可以像测量流逝时间一样测量吞吐量。

在客户端-服务器的吞吐量测试中,并不考虑客户端的思考时间。客户端向服务器发送请求,当它收到响应时,立刻发送新的请求。持续这样的过程,等到测试结束时,客户端会报告它所完成的操作总量。客户端常常有多个线程在处理,所以吞吐量就是所有客户端所完成的操作总量。通常这个数字就是每秒完成的操作量,而不是测量期间的总操作量。这个指标常常被称作每秒事务数(TPS)、每秒请求数(RPS)或每秒操作次数(OPS)。

所有的客户端-服务器测试都存在风险,即客户端不能足够快地向服务器发送数据。这可能是由于客户端机器的CPU不足以支持所需数量的客户端线程,也可能是因为客户端需要花大量时间处理响应才能发送新的请求。在这些场景中,测试衡量的其实是客户端性能而不是服务器性能,这并不是原本的目的。

其中的风险依赖于每个线程所承载的工作量(客户端机器的线程数和配置)。由于客户端线程需要执行大量工作,零思考时间(面向吞吐量)测试更可能会遇到这种情形。因此,通常吞吐量测试比响应时间测试的线程数少,线程负载也小。

通常吞吐量测试也会报告请求的平均响应时间。这是重要的信息,但它的变化并不表示性能有问题,除非报告的吞吐量相同。能够承受500 OPS、响应时间0.5秒的服务器,它的性能要好过响应时间0.3秒但只有400 OPS的服务器。
吞吐量测试总是在合适的热身期之后进行,特别是因为所测量的东西并不固定。

响应时间测试
最后一个常用的测试指标是响应时间:从客户端发送请求至收到响应之间的流逝时间。
响应时间测试和吞吐量测试(假设后者是基于客户端-服务器模式)之间的差别是,响应时间测试中的客户端线程会在操作之间休眠一段时间。这被称为思考时间。响应时间测试是尽量模拟用户行为:用户在浏览器输入URL,用一些时间阅读返回的网页,然后点击页面上的链接,花一些时间阅读返回的网页,等等。
当测试中引入思考时间时,吞吐量就固定了:指定数量的客户端,在给定思考时间下总是得到相同的TPS(少许差别)。基于这点,测量请求的响应时间就变得重要了:服务器的效率取决于它响应固定负载有多快。

思考时间和吞吐量
有两种方法可以测试客户端包括思考时间时的吞吐量。最简单的方法就是客户端在请求之间休眠一段时间。

	while(!done){
		time = executeOperation();
		Thread.currentThread().sleep(30 * 1000);
	}
	
这种情况下,吞吐量一定程度上依赖响应时间。如果响应时间是1秒,就意味着客户端每31秒发送一个请求,产生的吞吐量就是0.032 OPS。如果响应时间是2秒,客户端就是每32秒发送一个请求,吞吐量就是0.031OPS。
另外一种方法是周期时间(Cycle Time)。周期时间设置请求之间的总时间为30秒,所以客户端休眠的时间依赖于响应时间:

	while(!done){
		time = executeoperation();
		Thread.currentThread().sleep(30 * 1000 - time);
	}

无论响应时间是多少,这种方法都会产生固定的吞吐量,每个客户端0.033 OPS(假设本例中的响应时间都少于30秒)。
测试工具中的思考时间时常有变,平均值为特定值,但会加入随机变化以更好地模拟用户行为。另外,线程调度从来不会严格实时,所以客户端请求之间的时间也会略有不同。
因此,即便工具提供周期时间而不是思考时间,测试所报告的吞吐量也相差无几。但是,如果吞吐量远超预期,说明测试中一定有什么出错了。

衡量响应时间有两种方法。响应时间可以报告为平均值:请求时间的总和除以请求数。响应时间也可以报告为百分位请求,例如第90百分位响应时间。如果90%的请求响应小于1.5秒,且10%的请求响应不小于1.5秒,则1.5秒就是第90百分位响应时间。

两种方法的一个区别在于,平均值会受离群值影响。这是因为计算平均值时包括了离群值。离群值越大,对平均响应时间的影响就会越大。

下图展示了20个请求,它们响应时间的范围比较典型。响应时间是从1到5秒。平均响应时间(平行且靠近x轴的粗线)为2.35秒,且90%的请求发生在4秒或4秒以内(平行且远离x轴的粗线)。
在这里插入图片描述对于行为正常的测试来说,这是常见的场景。如果是下图所示的数据,离群值会影响分析的准确性。
在这里插入图片描述

这组数据中包括一个很大的离群值:有个请求花费了100秒。结果第90百分位响应时间和平均响应时间的粗线就调换了位置。平均响应时间蹿到了5.95秒,而第90百分位响应时间为1.0秒。对于这样的案例,应该考虑减少离群值带来的影响(从而降低平均响应时间)。

一般来说,像这样的离群值很少见,不过由于GC(垃圾收集)引入的停顿,Java应用更容易发生这种情况。(并不是因为GC引入了100秒的延迟,而是尤其是对于有较小的平均响应时间的测试来说,GC停顿会引入较大的离群值。) 性能测试中通常关注的是第90百分位响应时间(有时是第95百分位或第99百分位响应时间,这里说第90百分位并没有什么神奇之处)。如果只能盯住一个数字,那最好选择基于百分位数的响应时间,因为它的减少会让大多数用户受益。最好一并考虑平均响应时间和至少一种百分位响应时间,这样就不会错过有很大离群值的场景了。

快速小结

  1. Java性能测试中很少使用面向批处理的测试(或者任何没有热身期的测试),但这种测试可以产生很有价值的结果。
  2. 其他可以测量吞吐量或响应时间的测试,则依赖负载是否以固定的速率加载(也就是说,基于模拟的客户端思考时间)。

原则3:用统计方法应对性能的变化

第3条原则是性能测试的结果会随时间而变。即便程序每次处理的数据集都相同,产生的结果也仍然会有差别。因为有很多因素会影响程序的运行,如机器上的后台进程,网络时不时的拥堵等。好的基准测试不会每次都处理相同的数据集,而是会在测试中制造一些随机行为以模拟真实的世界。这就会带来一个问题:运行结果之间的差别,到底是因为性能有变化,还是因为测试的随机性。

可用以下方法来解决这个问题,即多次运行测试,然后对结果求平均。当被测代码发生变化时,就再多次运行测试,对结果求平均,然后比较两个平均值。但事情并没有想象中那么简单。要想弄清楚测试间的差别是真实的性能变化还是随机变化并不容易——这就是性能调优的关键所在。

比较基准测试的结果时,不可能知道平均值的差异是真的性能有差还是随机涨落。最好的办法是先假设“平均值是一样的”,然后确定该命题为真时的几率。如果命题很大几率为假,就有信心认为平均值是真的有差别(虽然永远无法100%肯定)。

像这种因代码更改而进行的测试称为回归测试。在回归测试中,原先的代码称为基线(baseline),而新的代码称为试样(specimen)。考虑一个批处理程序的案例,基线和试样都执行3次,下表给出了所用的时间。
在这里插入图片描述

试样的平均值表明代码性能改善了25%。这个测试所反映出来的25%的改善,可以相信多少?试样中3个有2个的值小于基线平均值,看起来改进的步子很大——但是分析这些结果就会得出结论,试样和基线性能相同的概率有43%。观察到的这些数字说明,两组测试的基本性能在43%的时间内是相同的,因此性能不相同的时间只占57%。57%的时间内性能不相同和性能改善25%也完全不是一回事,稍后。

上述概率看起来和预期有差别,其原因是测试的结果变化很大。一般来说,结果数据差别越大,就越难判断平均值之间的差异是真实的差别还是随机变动。此处的数字43%,是学生t检验(Student’s t-test,以下称t检验)得出的结果,这是一种针对一组数据及其变化的统计分析。“学生”是首次发表该检验的科学家⁵的笔名。t检验计算出的p值,是指原假设(null hypothesis)成立时的概率。

回归测试中的原假设是指假设两组测试的性能一样。这个例子中的p值大约为43%,意思是相信这两组測试平均值相同的概率为43%。相反,相信平均值不同的概率为57%。57%意味着什么,两组測试的平均值不相同?严格来讲,这并不意味着我们相信性能改善25%的概率有57%——它只是意味着,相信结果不同的概率为57%。性能可能改善了25%,也可能125%,甚至试样的实际性能也许比基线还糟糕。最大的可能则是测量出来的差别就是接近于真实的差异(特别是隨着p值下降越是如此),只是永远无法肯定这点。

统计学及其语义
正确表述`t`检验结果的语句应該像这样:试样与基线有差别的可能性为57%,差别预计最大有25%。

t检验通常与α值一起使用,α值是一个点,如果结果达到这个点那就是统计显著性(statistical significance)。通常α值设置为0.1——意思是说,如果试样和基线只在10%(0.1)的时间里相同(或反过来讲,90%的时间里试样和基线有差异),那结果就被认为是统计显著。其他常用的α值还有0.05(置信度为95%)或0.01(置信度为99%)。如果測试的p值小于1-α值,则被认为是统计显著。

因此,查找代码性能变化的正确方法是先决定一个显著性水平—比如0.1—然后用t检验判定在这个显著性水平上试样是否与基线有差别。在这个例子中,p值为0.43,在置信度为90%的情况下不能说有显著性差异,而结果表示平均值不相同。事实上,测试没有显著性差异并不意味着结果无关緊要,它仅仅表示这个測试没法形成定论。

从统计学上说,测试不能得出定论通常是因为样本数据不足。迄今为止,示例所考虑的基线和试样各是3次迭代。再加3次迭代,结果会变成这样:基线的迭代结果分别是1、1.2和0.8秒,试样的迭代结果分别是0.5、1.25和0.5秒?随着数据的增加,p值就从0.43跌落到了0.19,这意味着结果有差异的概率从57%上升到了81%。运行更多测试迭代,再加3个数据点后,概率则增加到了91%——超过了常规的统计显著性水平。

运行更多测试迭代从而达到某个统计显著性水平的方法并不总是可行。严格来说,这么做也没有必要。实际上,用以判定统计显著性的α值可以任意选择,虽然通常选的都是普遍认可的值。置信度为90%时,p值0.11不是统计显著,但置信度为89%时,它就是统计显著了。

这里得到结论:回归测试并不是非黑即白的科学。对于一组数据,不经过统计分析就没法弄清楚数字的含义,也就没法进行比较和判断。此外,由于概率的不确定性,即便用统计分析也不能给出完全可靠的结果。性能调优工程师的工作就是:考虑一堆数据(或者他们的均值)、弄清各种概率、决定往哪使力。

快速小结

  1. 正确判定测试结果间的差异需要统计分析,通过统计分析才能确定这些差异是不是归因于随机因素。
  2. 可以用严谨的t检验来比较测试结果,实现上述目的。
  3. t检验可以告知变动存在的概率,却无法告诉哪种变动该忽略,而哪种该追查。如何在两者之间找到平衡,是性能调优工程的艺术魅力所在。

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

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

相关文章

chatgpt赋能python:Python中的与非

Python中的与非 在Python编程中,我们经常会用到与非运算符,用来判断条件语句中的真假性。在本文中,我们将介绍Python中的与非运算符,并探讨其用法和实际应用场景。 什么是与非运算符? 与非运算符是一个布尔操作符&a…

NeRF-SLAM代码记录

前言 没运行成功,尤其是编译gtsam部分,每一步都有错,又是讨厌c++第一天。 这一行编译到92% 就会报错 python/CMakeFiles/gtsam_py.dir/build.make:250: recipe for target python/CMakeFiles/gtsam_py.dir/linear.cpp.o failed make[2

.NET 8 Preview 4 发布

作者:Jon Douglas - Principal Program Manager, NuGet 翻译:Alan Wang 排版:Alan Wang 我们很高兴与大家分享在 .NET 8 预览版 4 中的所有新功能和改进!这次发布是继预览版 3之后的更新。您将在这些月度发布中看到更多功能逐渐亮…

【无标题】win11打开VMware虚拟机蓝屏解决

win11打开VMware虚拟机蓝屏解决 win11打开虚拟机蓝屏!!!解决方案:win11支持16.2以上版本,其他版本不兼容,可用文末的卸载工具卸载之前已安装版本(深度卸载),然后下载16.2…

chatgpt赋能python:Python中的乘号:一个重要的数学运算符

Python中的乘号:一个重要的数学运算符 在 Python 编程语言中,乘号通常是使用“*”表示的数学运算符。这个运算符非常常用,它可以在各种情况下使用。本文将探讨 Python 中乘号的基本用法,以及更高级的用法。 基本用法 在 Python…

python+django高校人事管理系统vue

本高校人事管理系统以Django作为框架,Python语言,B/S模式以及MySql作为后台运行的数据库。本系统主要包括以下功能模块:用户、院长、职称申报、工资信息、绩效信息、奖惩信息、招聘、科系分类等模块。 本文着重阐述了高校人事管理系统的分析、…

easyX实践上手操作小项目

easyX实践上手操作小项目 效果展示主菜单的装饰玩法介绍界面开始游戏界面制作团队界面排行榜界面注:main()函数拓展数据库小结 这里我们学习过easyX的基础知识后,看看是否能实践操作一下,制作一个属于自己的游戏界面呢? 基础知识…

基于深度学习的高精度野生目标检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要:基于深度学习的高精度野生目标检测识别系统可用于日常生活中检测与定位野生目标目标,利用深度学习算法可实现图片、视频、摄像头等方式的野生目标目标检测识别,另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测…

开源SCRM营销平台MarketGo-账号管理

一、概述 企业在经营的过程中,因为业务、税收等各种因素的需要在各地成立分公司,这样针对公司来说管理成本,运营成本,营销成本都会提高,并且沟通的效率也会变低。 在用户营销的场景中,MarketGo在SCRM做了…

C++ stack容器介绍

🤔stack容器介绍: 📖 stack是一种数据结构,也可以被称为堆栈。它是一个容器,只允许在最顶层进行插入和删除,并且只能访问最后一个插入的元素。这个元素称为栈顶。所有新插入的元素都被放置在栈顶上面&#…

【C++入门】什么是引用

目录 一、引用概念 二、引用特性 三、常引用 四、使用场景 1. 做参数 2. 做返回值 五、传值,传引用效率比较 六、引用和指针的区别 一、引用概念 引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间…

【C/C++】之内存管理(超详细练气篇)

个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C之路】💌 本专栏旨在记录C的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长&…

AI绘画能力的起源:通俗理解VAE、扩散模型DDPM、DETR、ViT/Swin transformer

前言 2018年我写过一篇博客,叫:《一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD》,该文相当于梳理了2019年之前CV领域的典型视觉模型,比如 2014 R-CNN2015 Fast R-CNN、Faster R-CNN2016 YOLO、SSD2…

Seata 分布式事务-应用实例

Seata 分布式事务-应用实例 需求分析/图解 需求:完成下订单功能,由三个微服务模块协同完成, 涉及到多数据库, 多张表 分析 黑色线是执行顺序线 红色线是想Seata Server注册 最后紫色线是决定是否提交和回滚 项目目录 主题包结构都是一样的但是类名字…

eventfd 和 epoll 的结合使用

一.eventfd介绍 eventfd 是 Linux 的一个系统调用&#xff0c;创建一个文件描述符用于事件通知&#xff0c;自 Linux 2.6.22 以后开始支持。 接口及参数介绍 #include <sys/eventfd.h> int eventfd(unsigned int initval, int flags);eventfd() 创建一个 eventfd 对象&…

spring cloud Alibaba之Nacos Discovery--服务治理 (二)

接着上一篇文章 搭建的微服务环境, 实现nacos 注册中心实战操作案例 一. 服务治理介绍 先来思考一个问题 通过上一章的操作&#xff0c;我们已经可以实现微服务之间的调用。但是我们把服务提供者的网络地址 &#xff08;ip&#xff0c;端口&#xff09;等硬编码到了代码中&a…

【SpringCloud】SpringAMQP

文章目录 1、AMQP2、基本消息模型队列3、WorkQueue模型4、发布订阅模型5、发布订阅-Fanout Exchange6、发布订阅-DirectExchange7、发布订阅-TopicExchange 1、AMQP Advanced Message Queuing Protocol&#xff0c;高级消息队列协议。是用于在应用程序之间传递业务消息的开放标…

ElasticSearch安装部署——超详细

ElasticSearch安装部署 简介 全文搜索属于最常见的需求&#xff0c;开源的 Elasticsearch &#xff08;以下简称 es&#xff09;是目前全文搜索引擎的首选。 它可以快速地储存、搜索和分析海量数据。维基百科、Stack Overflow、Github 都采用它。 Elasticsearch简称es&…

JS中手撕防抖函数和节流函数

1.防抖函数 1.1定义 说明&#xff1a;在一定时间内&#xff0c;频繁执行事件&#xff0c;只执行最后一次函数。(英雄联盟回城) 1.2步骤&#xff1a; 声明定时器函数判断是否有定时器函数&#xff0c;如果有定时器函数的话就清除定时器。。如果没有定时器函数的话&#xff0…

chatgpt赋能python:Python中的三角函数介绍

Python中的三角函数介绍 Python作为一种高级编程语言&#xff0c;可以处理基础算术运算、三角函数等高等数学的操作。其中&#xff0c;三角函数是常用的数学函数之一&#xff0c;Pyhon中的三角函数包括正弦函数、余弦函数、正切函数等。 正弦函数 正弦函数在三角学中是最基本…