Java性能权威指南-总结3

news2024/12/27 12:57:22

Java性能权威指南-总结3

  • 性能测试方法
    • 原则4:尽早频繁测试
    • 小结
  • Java性能调优工具箱
    • 操作系统的工具和分析
      • CPU使用率

性能测试方法

原则4:尽早频繁测试

这是最后的原则。性能测试应该作为开发周期不可或缺的一部分。理想情况下,在代码提交到中心源代码仓库前,性能测试就应该作为过程的一部分运行,如果代码引入了性能衰减,提交就会被阻止。

好的性能测试包含了许多代码——至少中等规模的介基准测试是这样。它需要在新老代码上重复运行多次,以便确认性能真的有差别而不是随机变动。在大型项目中,这可能需要花费好几天或者一周时间,这使得在提交代码到仓库之间运行性能测试变得不那么现实。

通常的软件开发周期也没使事情变得更容易。项目日程通常会固定特性的发布日期:所有的代码变动必须在发布周期的早些时候就提交到源代码仓库,而剩下的时间则贡献给了将新版本中的缺陷(包括性能问题)抖落干净。这导致了提早测试的两个问题。

  1. 为了赶上项目进度,开发人员会在时间压力之下提交代码,而一旦有时间修复性能问题时,又变得踯躇不前。早期提交代码所导致的1%的性能衰减,开发人员愿意承受压力,修复问题。而等到功能特性截止夜才提交的代码,如果性能衰减20%,开发人员就只能以后再处理了。
  2. 代码发生变化,性能也会随之而变。这个道理与测试全应用(以及可能有的模块测试)相同:堆内存的使用情况会改变,代码编译也会改变,等等。

开发过程中无论有多少困难,频繁的性能测试仍然很重要,即便有时候不能立刻解决问题。比如代码性能衰减了5%,随着开发的推进,开发人员或许可以采用以下措施:如果他的代码依赖有待集成的功能特性,那就等该功能可用时,再稍微调整代码,性能衰减的问题或许就解决了。这是合理的情况,即便这意味着性能测试不得不几个星期都伴随着5%的性能衰减(这是不幸的事,却又无法避免,还可能掩盖了其他问题)。

另一方面,如果性能衰减只有等架构更改才能修复的话,那就最好在其余代码开始依赖新代码实现之前,尽早捕获和解决它。这是一种平衡,需要仔细分析。

遵循以下准则,可以使得尽早频繁测试变得最有用:

自动化一切
所有的性能测试都应该脚本化(或者程序化,虽然脚本更简单)。全部环境都必须通过脚本安装和配置新代码(创建数据库连接、建立用户账号等),然后用脚本运行测试集。所谓自动化,还不止这些:脚本必须能够多次运行测试,对结果进行t检验分析,并能生成置信度报告,说明统计结果是相同,还是不同,如果不同,相差多少。

在测试运行前,必须通过自动化技术确保机器处于已知状态:必须检查是否有不希望运行的进程,操作系统配置是否正确,等等。只有每轮运行时保持相同的环境,性能测试才是可重复的。自动化过程中必须考虑这点。

测试一切
必须自动收集能想象到的每一点数据,以便进行后续分析。这些数据包括整个运行过程中采集的系统信息:CPU使用率、磁盘使用率、网络使用率和内存使用率等。数据还包括应用的日志——应用产生的日志,以及垃圾收集器的日志。理想情况下,还应该包括JFR记录的信息,或者对系统影响较小的性能分析(profiling)信息,周期性线程堆栈,以及其他堆分析数据,例如直方图或者全堆的转储信息(尤其是全堆转储,需要占用大量空间,没有必要长期保留)。

如果适用的话,监控信息还必须包括系统其他部分的数据:例如,如果程序使用数据库,就应该包括数据库机器的系统统计数据,以及所有的数据库诊断输出(包括Oracle的Automatic Workload Repository [AWR]这样的性能报告)。

这些数据可以指导所有未被覆盖的回归分析。如果CPU使用率上升,就需要参考性能分析信息,弄清楚是什么花费了这么多时间。如果GC时间变长,就该查阅堆性能分析信息,搞明白是什么消耗了这么多内存。如果CPU和GC时间都减少,某些地方的竞争可能降低了性能:栈数据可以指示特定的同步瓶颈,JFR记录可用来发现应用的延迟,数据库日志也可以发现数据库竞争加剧的线索。

当发现性能衰减源时,需要进一步巡查,找到更多可用数据,更多可以追踪的线索,发生性能衰减的未必是JVM。测量一切,从而确保分析的正确性。

在真实系统上运行
在单核笔记本上运行测试,与在256线程SPARC CPU机器上有很大的不同。从线程效应上来说,原因很清楚:机器规模越大,同时能运行的线程就越多,从而能减少应用线程对CPU的竞争。与此同时,大规模系统也会遇到小型笔记本上会被忽略的同步性能瓶颈。

还有其他重大的性能差异,即便乍一眼看上去不那么明显。许多重要的性能调优标志,它们的默认值是基于JVM运行的底层硬件系统计算出来的。平台和平台之间所编译出来的代码也不同。缓存——软件缓存以及更重要的硬件缓存——在不同系统和不同负载下也是不一样的,等等。

因此,除非在预期的负载和预期的硬件下测试,否则永远无法在测试中完全了解特定生产环境下的性能。可以在配置较低的硬件上运行规模较小的测试,以此来模拟和外推。在现实测试中,复制生产环境相当困难或昂贵。但外推只是简单的预测,即便在最好的情况下,预测也可能是错的。大规模系统远不只是将各部分加起来那么简单,没有什么测试能够代替在真实系统上的负载了。

快速小结

  1. 虽然频繁的性能测试很重要,但并非毫无代价,在日常的开发周期中需要仔细斟酌。
  2. 自动化测试系统可以收集所有机器和程序的全部统计数据,这可以为查找性能衰减问题提供必不可少的线索。

小结

性能测试包括各种权衡。面对诸多相互制约的选择,能否做出适当的决策,对于系统性能能否提升至关重要。

性能测试应该先测哪部分,与经验和直觉息息相关。微基准测试在这方面的作用最小,它的用途仅限于为某些操作设立宽泛的指导。这为其他测试留下广泛的施展空间,从小模块的测试到大规模多层的应用环境。所有这些测试都有某方面的价值,如何选择就得依靠经验和直觉了。不过最终部署到生产环境中之后,除了全应用测试,就没什么可选了。只有到那时才能理解所有与性能相关的问题以及全部影响。

与此类似,哪些代码导致或没导致性能衰减,并不总是皂白分明的。程序时不时会表现出随机行为,而一旦引入了随机性,就再也无法100%确定这些数据意味着什么了。使用统计分析有助于使结果变得更客观,但即便如此,仍然免不了主观臆断。理解这些数据背后的概率及其意义,有助于降低主观性。

Java性能调优工具箱

操作系统的工具和分析

实际上性能分析的起点与Java无关:它是一组操作系统自带的基本监控工具。在基于Unix的系统上,有sar(System Accounting Report)及其组成工具,例如vmstat、iostat、prstat等。在Windows上,有图形化资源监视器以及像typeperf这样的命令行工具。

无论何时运行性能测试,都应该收集操作系统的数据,至少需要收集CPU、内存和磁盘使用率的信息。 如果程序使用网络,还应该收集网络使用率。如果是自动化性能测试,还需要依靠命令行工具(即使是Windows系统)。不过,即便可以通过交互方式进行测试,也最好用命令行工具捕获输出,而不是一边盯着GUI,一边琢磨它的意思。在分析的时候可以再次将这些输出图形化。

CPU使用率

先看CPU的监控,以及监控所能告诉我们的关于Java程序的信息。通常CPU使用率可以分为两类:用户态时间和系统态时间(Windows上被称作privileged time)。用户态时间是CPU执行应用代码所占时间的百分比,而系统态时间则是CPU执行内核代码所占时间的百分比。系统态时间与应用相关,比如应用执行I/O操作,系统就会执行内核代码从磁盘读取文件,或者将缓冲数据发送到网络,等等。任何使用底层系统资源的操作,都会导致应用占用更多的系统态时间。

性能调优的目的是,在尽可能短的时间内让CPU使用率尽可能地高。这听起来有点不合常理,先来考虑一下,CPU使用率到底反映了什么。

首先需要注意的是,CPU使用率是一段时间内的平均数——5秒、30秒,也可能只有1秒那么短(不过永远不会比这还要短)。比如,10分钟内一个程序执行的CPU使用率为50%。如果代码调优之后,CPU使用率达到了100%,说明程序的性能翻了倍:程序只需要执行5分钟就可以了。如果性能再翻倍,CPU仍将是100%,而执行完程序只要2.5分钟。CPU使用率表示程序以多高的效率使用CPU,所以数字越大,性能越好。

如果在Linux桌面系统上运行vmstat 1,可以得到类似如下的几行信息(每隔一秒显示一行):

在这里插入图片描述

为了便于说明问题,这个运行示例程序只有一个活跃线程。不过即便有多个线程,也可以应用如下概念。

每秒内,CPU被占用450毫秒(42%的时间执行用户代码,3%的时间执行系统代码)。相应地,CPU空闲550毫秒。CPU空闲可能有以下原因。

  • 应用被同步原语阻塞,直至锁释放才能继续执行。
  • 应用在等待某些东西,例如数据库调用所返回的响应。
  • 应用的确是无所事事。

前面2种情况通常都可用来识别某些问题。如果竞争降低,或优化数据库使之发送响应更快,程序运行都能变得更快,平均CPU使用率也会上升(当然,得假定没有其他继续阻塞应用的问题)。

第3点则常常使人疑惑。如果应用有事情做(而不是因为等待锁或者其他资源而无事可干),CPU就会分配一些周期执行应用代码。这是一般性原则,并不只针对Java。比如,包含无限循环的简单脚本。这段脚本执行时,将消耗100%的CPU。以下的Windows批处理任务就是这么干的:

ECHO OFF
:BEGIN
ECHO LOOPING
GOTO BEGIN
REM We never get here…
ECHO DONE

如果这段脚本没有消耗100%CPU,意味着,操作系统还有些事可做——它可以打印一行L00PING——却选择了空闲。这种情况下,空闲并没有什么好处,如果我们正在进行一些有用(耗时)的计算,那么迫使CPU周期性空闲只会使我们得到响应的时间变得更长。

如果在单CPU机器上运行上述脚本,多数时候不会注意到它的运行。不过一旦开启新程序,或者测量其他程序的运行时间,就能看到影响了。操作系统擅长为争用CPU周期的程序分配时间片,但新程序可用的CPU变少了,它也就运行得更慢。所以基于这种经验,人们有时会认为,在其他程序可能需要CPU周期时预留一些空闲周期,没准是个好主意。

但操作系统无法猜到你接下来想做什么,所以(默认情况下)它会尽可能执行一切而不是让CPU空闲。

限制程序所用的CPU
尽可能利用CPU周期运行程序可以使程序性能最大化。不过有时并不希望如此。比如,运行`SETI@home',`
它将消耗机器所有可用的CPU周期。这在不干活的时候没事,上网冲浪或者写文档的时候也没事,否则就会降低生产率。

操作系统有许多机制可用来人为限定程序所使用的CPU,如果有程序需要使用CPU,它就会退出空闲周期。进程的优
先级也可以改变,所以那些后台任务既不会与你想运行的程序争用CPU,也不会让CPU处于空闲状态。,
`SETI@home`可以配置优先级,除非允许,否则它不会真的占用机器的所有空余周期。

Java和单CPU的使用率
Java应用——CPU周期性空闲意味着什么?这依赖于应用的类型。如果应用代码是批处理类型,工作量固定,应该永远都不会看到CPU空闲,因为这意味着没事可做。提高CPU使用率,一直都是批处理任务的目的,因为任务会很快完成。如果CPU已经达到100%,仍然可以寻找优化,使得工作完成的更快(也要尽量保持100%CPU使用率)。

如果测试接收请求的服务器应用,就可能出现因无事可做而出现的空闲:例如,Web服务器已经处理完所有未完成的HTTP请求,正在等待下一个请求的时候。这就引入了平均时间。上述vmstat的示例来自一个每秒接收一个请求的应用服务器。应用服务器花450毫秒处理请求——意思是CPU被100%占用450毫秒,550毫秒没有占用。这就是所报告的CPU被占用45%。

虽然经常因为CPU占用发生的时间粒度很小而难以可视化,但运行负载型应用时CPU的行为就是这种爆发式的。如果CPU每半秒收到一个请求而平均处理时间为225毫秒,也能从宏观层面看到同样的模式。CPU被占用225毫秒,空闲275毫秒,再占用225毫秒,空闲275毫秒:平均来看,被占用45%,空闲55%。

如果应用优化之后每个请求只需要400毫秒,整体CPU使用率就会减少(到40%)。这是仅有的降低CPU使用率有意义的情况——当系统负载量固定并且应用不受外部资源限制的时候。另一方面,优化也使系统可以承担更多负载,最终提高CPU使用率。微观来看,这种情况下的优化仍然是使CPU使用率在短时间内(执行请求花费400毫秒)变为100%——只是CPU峰值持续的时间很短,事实上,大多数工具都不会将其标记为100%。

Java和多CPU的使用率
上面的例子是假定在单个CPU上运行的单线程,但概念与一般情况下多CPU多线程相同。多线程倾向于以有趣的方式平均使用CPU。但一般来说,多CPU多线程的目的仍然是通过不阻塞线程来提高CPU使用率,或者是在线程完成工作等待更多任务时降低CPU使用率。

另外在多线程多CPU下,需要重点考虑以下CPU空闲的情形:即便有事可做,CPU仍然空闲。这在程序没有更多线程可用的时候可能会出现。典型的情况是,应用以固定尺寸的线程池运行各种任务。每个线程同时只能执行一个任务,当线程被某个任务阻塞时(例如,等待数据库的响应),它就没法捡出新任务执行了。所以此时的情况就是,有任务需要执行(有事可做),却没有线程执行它们,结果就是CPU处在空闲时间。

在这个例子中,应该增加线程池的大小。然而,不要假设所有的空闲都是因为CPU可用,从而增加线程池以完成更多工作。程序得不到CPU周期,还有可能是由于前面提到的两个原因——锁或者外部资源的瓶颈。很重要的一点就是,在决定采取行动前,需要搞清楚为什么程序得不到CPU。

检查CPU使用率是弄清楚应用性能的第一步,但它的用途不仅如此:它可以查看代码的CPU使用是否与预期的一样,或者可以指出一些同步或资源问题。

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

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

相关文章

【数据分享】1929-2022年全球站点的逐月最高气温(Shp\Excel\12000个站点)

气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、湿度等指标,其中又以气温指标最为常用!说到气温数据,最详细的气温数据是具体到气象监测站点的气温数据! 之前我们分享过1929-2022年全球气象站…

Win10搭建Nacos2.2.3集群版

Nacos是Alibaba提供的服务注册发现的管理平台,其优异的性能越来越受到广大开发者的喜爱,在构建分布式微服务项目中通常会首选Nacos作为注册/配置中心,在实际开发中为了提升服务的可用性和稳定性,通常都会搭建集群版,有…

《强风吹拂》呐!你喜欢跑步吗?

《强风吹拂》呐!你喜欢跑步吗? 三浦紫苑,1976生于东京。主要作品有《多田便利屋》《强风吹拂》《哪啊哪啊~神去村》《编舟记》等 林佩瑾、李建铨、杨正敏 译 文章目录 《强风吹拂》呐!你喜欢跑步吗?[toc]动漫摘录箱根驿…

Go Web下gin框架使用(一)

〇、前言 在前面,已经在这篇文章中详细地讨论了 gin 框架下的模板渲染问题,这篇文章主要对 gin 框架的使用进行讨论。 一、不同的路由 以下可以选择不同的路由进行渲染: r : gin.Default()type usr struct {Name string json:"name&…

八、go语言键盘输入和打印输出

键盘输入和打印输出 一、打印输出 1.1 fmt包 fmt包实现了类似C语言printf和scanf的格式化I/O。格式化verb(‘verb’)源自C语言但更简单。 详见官网fmt的API:https://golang.google.cn/pkg/fmt/ 1.2 导入包 import "fmt"1.3 常…

MyBatis——MyBatis项目搭建

但凡是框架,使用都是分三步走 1.导入jar文件,用maven导入 2.处理配置文件 3.开发业务代码 1.创建maven项目导入相关依赖 在pom文件中导入MyBatis相关依赖jar文件 安装lombok 在File->Settings Pugins 中安装lombok 要想启动lombok的话还需要在B…

GPT带你飞:Chat GPT吊打面试官,实时获取答案,分享调用OpenAI API key+完整源码脚本哦!

目录 福利:文末纯分享中文版CHAT GPT镜像,不存在魔法,纯分享免费使用 故事发生了 火爆GitHub 所以大家注意 网友看了之后调侃到,为了防止线上面试作弊,以后只好把面试都改成线下了。 如何安装 既然是调用GPT的AP…

nodejs基于vue的汽车订票客运站售票网站

使用Mysql创建数据表保存本系统产生的数据。系统可以提供信息显示和相应服务,其管理员负责审核会员充值,审核客户购票信息以及会员购票信息,管理客运班次与留言板,管理会员等级。客户查看客运班次,购买并支付车票&…

【Selenium】常用的Selenium基础使用模板和简单封装

前言 近来又用上了 Selneium ,因为反复用到,所以在这里将一些常用的方法封装起来,方便后续的使用。 在这篇文章中,我们将探讨 Selenium 的基础模板和基础封装,以便更好地理解 Selenium 的使用方法。 在Selenium的使用…

python基础----03-----if语句、while、for循环、range语句、continue和break

一 布尔类型和比较运算符 1.1 布尔类型和比较运算符 定义变量存储布尔类型数据:变量名称 布尔类型字面量。 布尔类型不仅可以自行定义同时也可以通过计算的来。也就是使用比较运算符进行比较运算得到布尔类型的结果。在C/C中,比较运算符称之为关系运算…

如何解决航空企业数字化转型中的痛点?

数字化时代,越来越多的企业开始关注数字技术,希望通过数字化改造提高企业效率和竞争力,为企业创造更多的商机和利润。今天就来同大家探讨航空领域,小程序在企业数字化转型中发挥的作用、 航空业员工端App的敏捷转型挑战 技术上的…

Java 异常机制:是Java 提供的一种识别及响应错误的一致性机制。

。 目录 友情提醒第一章、异常概述1.1)我们常说的异常是什么1.2)异常的作用1.3)Java异常体系和分类1.4)演示异常的产生 第二章、定义异常与抛出异常:throw2.1)自定义异常类:继承Exception或Run…

网络io与io多路复用select/poll/epoll

一、网络IO请求 网络I/O请求是指在计算机网络中,向其他主机或服务器发送请求或接收响应的操作。这些请求可以包括获取网页、下载文件、发送电子邮件等。网络I/O请求需要使用合适的协议和通信方式来进行数据传输,例如HTTP、FTP、SMTP等。 要完成一个完整…

字节面试过了,薪资都谈好了20K*13,结果挂在这里....

一般提到面试,肯定都会想问一下面试结果,我就大概的说一下面试结果,哈哈,其实不太想说,因为挺惨的,并没有像很多大佬一样 ”已拿字节阿里腾讯各大厂offer”,但是毕竟是自己的经历,无…

让效果图渲染做到最佳的几个小诀窍

制作出优秀的效果图需要多方面的技术支持,而渲染是其中非常关键的一步。一份精美的效果图需要经过高质量的渲染才能呈现出最佳的效果。本文将分享一些关于如何让效果图渲染做到最佳的小诀窍,包括专注的小细节、优化场景设置和灯光、纹理、图像应用最终修…

医疗电子红外线人体额温枪方案

在当前新冠疫情背景下,红外线人体额温枪成为疫情防控必备的设备之一。红外线人体额温枪采用红外线技术,无需接触人体,通过测量人体表面温度来判断人体是否发热。其测量快速、准确、不接触等特点,使其广泛应用于机场、车站、医院、…

数据结构之二叉树(Java)

在这里先说明一下,结点和节点其实一样的,无须关注这个。 一、树型结构 1. 概念:树是一种非线性的数据结构,它是由n个有限节点组成一个具有层次关系的集合。 如上图所示,把此种数据结构称作树是因为它看起来像一个倒挂…

校园高校教务选课成绩系统node.js+vue

系统主要实现了以下功能模块: 学籍信息 网上选课 网上评教,即对自己老师评分 任务查询,老师可以给学生发布任务(类似于作业,考试) 课表查询,希望有个图形化的课表,而不是表格式 教室…

Mysql InnoDB的Buffer Pool

Buffer Pool 在MySQL服务器启动的时候就向操作系统申请了⼀⽚连续的内存,他们给这⽚内存起了个名,叫做Buffer Pool(中⽂名 是缓冲池)。 默认情况下Buffer Pool只有128M⼤⼩,最⼩值为5M,通过修改配置文件设…

【Linux开发—多进程编程】

【Linux开发—多进程编程】 前言1,两种类型的服务端2,并发服务器的实现方法: 一,认识及应用1,进程认识2,CPU核的个数与进程数3,进程ID4,进程创建5, 调用fork函数后的程序运行流程: 二…