基准测试这个单词在工作中相信大家都经常会遇到,在我刚开始工作的时候,看一些文档的时候老是会碰见基准测试,当初以为基准测试就是简单的性能测试。但是随着后面的一些经验,发现基准测试并不是这么的简单,最近也在看一本书叫做《JAVA性能权威指南》,其中也介绍了基准测试相关的一些东西,大家有兴趣的下来也可以去看下,于是我在这这里简单的聊一下基准测试相关的一些东西。
基准测试的英语名字叫做benchmark,基准测试是一种性能测试,在网络上我发现了很多对基准测试的定义都是用来测试某个程序的最佳性能,我觉得这个定义的比较笼统,在这篇文章中(https://www.cnblogs.com/imyalost/p/9630843.html),定义基准测试为:
通过设计合理的测试方法,选用合适的测试工具和被测系统,实现对某个特定目标场景的某项性能指标进行定量的和可对比的测试。
从上可以提取出基准测试的几个关键点:
测试方法:到底使用微基准测试,介基准测试,还是使用宏基准测试,需要根据我们的需要选择一个合适的。
测试工具:选择合适的测试工具,能更好的精确的测量出我们的数据。
某个目标场景:性能测试时,往往需要选择一些场景。比如到底只是达到某个比较低的标准即可,还是想直接把系统压死等等
某项性能指标:需要知道这一次到底追求的是哪个性能指标,到底是QPS还是吞吐量,还是TP99等等。
可对比:用不同的方法或者工具进行多次测试进行数据对比。
微基准测试(Micro-benchmarks)是基准测试中的一种方法,用来测试微小代码单元的性能,通常这个微小代码单元可以是一段算法,一个方法,一个数据结构。微基准测试的代码比较难以编写
上面是一段测试斐波拉契数列性能的代码,很多人以为用上面的方式就可以测试出fibImpl这个函数的性能,但是结果往往是错误的,通常会有下面一些问题:
没有使用函数测试结果,通常如果没有使用结果的话Java可能会将这个代码优化成不会执行fibImpl这个函数。
没有预热,在JAVA中被预热编译执行的代码比解释执行的代码性能更好。
容易发生OSR(栈上替换),这里我们模拟循环来测试多次fibImpl性能,但是如果发生OSR,那么OSR之后的性能会比之前的更好。
当然还有其他更多的问题这里就不一一介绍了,只是想突出微基准测试有很多容易影响测试结果的地方,同样的微基准测试在做业务开发的时候使用场景也很局限,我们很多时候瓶颈不会是某个算法,某个数据结构,而往往是数据库,网络等等。
宏基准测试(macro-benchmark),顾名思义和上面的测试相反,往往会测试一个应用的整体性能,比如模拟大量的真实用户使用这个应用,从而测试出性能。很多时候我们的全链路压测基本就会对应宏基准测试,测试所需要的的流程以及环境都和真实场景一样,这样才能真正的测试出整个应用性能的问题。在真正的全链路压测的情况下,往往会把真实的请求数据先复制下来,然后收集足够多的数据之后,利用这些真实的数据来进行压测。
宏基准测试对于很多场景比较重,这个时候就出现了介基准测试,介基准测试没有要求请求的真实,在整个链路上一些不是很重要的地方在介基准测试中都可以进行忽略,比如登录验证,安全验证等等,将测试的目标聚焦在我们的业务核心上,通过介基准测试能让我们更简便的测试出系统的性能。
我们在第三章介绍了微基准测试编写代码很困难,但是在Java里有一个组件叫做JMH,也就是Java的微基准测试套件,他能帮助你做到下面这些事:
能自动帮助预热
时间精确到纳秒
能更加详细的知道测试数据,平均时间,最大值,TP99等
不需要额外代码编写多线程
使用JMH很简单,如下面代码,直接加注解即可,具体的一些配置也可以通过注解来进行调试。
Apache JMeter是Apache组织开发的基于Java的压力测试工具。它可以用于测试静态和动态资源,例如静态文件、Java 小服务程序、CGI 脚本、Java 对象、数据库、FTP 服务器等等。另外,JMeter能够对应用程序做功能/回归测试,通过创建带有断言的脚本来验证你的程序返回了你期望的结果。为了最大限度的灵活性,JMeter允许使用正则表达式创建断言。同时JMeter支持对性能压测结果做图形分析。
JMeter通常是一个模拟用户就是一个线程,当模拟并发数变多的时候性能会下降,通常会搭建一个JMeter集群去模拟并发数较多的情况。
Gatling是一款基于Scala 开发的高性能服务器性能测试工具,它主要用于对服务器进行负载等测试,并分析和测量服务器的各种性能指标。Gatling主要用于测量基于HTTP的服务器,比如Web应用程序,RESTful服务等。
Gatling对Java选手来说有一定的学习成本,并且Gatling国内好像使用得较少,但是Gatling使用得Akka Actors异步模型,他可以使用少量的线程就能支持高并发,不需要像JMeter一样搭建多个集群去使用。Gatling在我们公司使用得较多,目前只能测试Http相关的,如果要测试rpc相关的需要先将rpc协议转换成Http协议。
上面介绍的都不能用来做全链路压测,都缺少很多核心功能,比如请求录制,定时压测,实时监控,报告分析等等,这个时候我们可以直接使用阿里云的PTS进行全链路压测,或者自研一套基于自己业务系统的全链路压测系统。
我们通常进行基准测试的时候,在结果中会有很多需要值得关注的目标,下面列举一些比较重要的。
QPS是我们的每秒查询数量,TPS是每秒的事务数量。通常我们进行基准测试往往会定一个目标,比如支撑1000QPS的请求量来完成我们的目标,或者测试出我们这个系统极限的QPS是多少,同样的QPS也不是越大越好,也需要结合我们的响应时间,如果我们一味的追求QPS忽略了响应时间那么用户的体验也是极差的。
有很多认为响应时间应该看平均时间,如果写要求比较低的系统的确是可以看平均时间,这样就会导致很多用户响应的速度很慢,但是我们在监控指标上体现不出来,所以就有了百分位指标这样的概念,TP99的意思就是,取排名排到第99百分位的响应时间,即排除了一些异常的情况(剩余的那1%),又保证了大多数用户的响应时间。
当我们有很多CPU密集型应用的时候,可以多多关注CPU的情况,从而进行针对性的调优
如果是Java的应用,GC问题绝对不会缺席,尤其是在我们基准测试中,往往如果在测试中出现了大量的GC,说不定是代码写得有问题,有时候可以通过代码进行优化,或者说也可以更换GC收集器。
当我们传输的数据比较多的时候,比如传输文件,或者一些大的数据结构,这个时候就需要关注I/O相关的问题,来进行针对的调优。
可对比同样是基准测试的重要点,通常有下面的几个点:
使用不同的测试工具做对比
使用不同的测试数据做对比
使用不同的测试环境做对比
建立长期的基准测试,进行不同时间的基准测试对比。
通常基准测试就是要随时进行测试因子变量的变更,我们才能真正的得到最优的测试结果。
要做好一个基准测试并不是想象中的那么简单,我们需要选对合适的方法,合适的工具以及做好数据的观察统计等等,才能做好我们的基准测试
如果大家觉得这篇文章对你有帮助,你的关注和转发是对我最大的支持,O(∩_∩)O: