性能测试相关概念
并发用户数(VU): 系统同时处理的request/事务数
QPS(TPS)(transaction per second):每秒钟处理request/事务 数量
响应时间rt: 一般取平均响应时间
这三个参数是一组,理论上,并发数=QPS*rt,当QPS*rt<并发数 时,这时的压力就接近系统所能承受的最大压力了,也就是接近了系统瓶颈。
cpu使用率:cpu被占用的情况,一般要保证在75%以下
load:系统平均负载,被定义为在特定时间间隔(1m,5m,15m)内运行队列中的平均进程数。
前后优化耗时:
1. 慎用try-catch,尤其是在循环之中,可以的话将其移到循环之外。循环内110ms,循环外62ms
2. 多用局部变量。由于局部变量在栈中,其它如静态变量的多在堆中,相比之下变量在栈中会更优秀一些。使用static变量266ms,使用局部变量78ms。
3.位运算代替乘、除法。原219ms,位运算后31ms。
4.switch在循环中可以用数组代替(书中理论)。比较有意思的是我的本机上跑循环中switch耗时8ms,用map/array替代耗时32ms。
5.提取公共表达式。提取前156ms,提取后78ms。
6.展开循环,拉开迭代器增长步长。有必要说一下,这会导致可读性变差,也是没有办法的办法才这么搞。优化前94ms,优化后31ms。
7.静态static方法代替实例方法。
并发过程的优化,这里也是有优化策略的。首先由于数据同步,并发结构需要更改如下:
List : Collections.synchronizedList(List)
Set : Collections.synchronizedList(Set)
HashMap : concurrentHashMap
Queue : concurrentLinkedQueue
volatile : 变量其它线程可见
synchronized : 锁方法,内部锁
ReadWriteLock : 重入锁
ThreadLocal : 局部变量,每个变量一个副本
semaphore :信号量,指定多个线程同时访问某一资源
关于锁,有以下几种方法:
1. 减小锁的范围,举个例子,如果某条记录操作数据库,如果可以将这条记录锁住,那就千万不要用锁整个数据库的方式,而使用将这条记录锁住。
2.减小锁粒度。如concurrentHaspMap结构,其内部是分为16段的,减少Hash时冲突问题。当然这也存在一个问题,就是concurrentHaspMap作为全局使用时,需要获取全部的16个锁。
3.锁分离。LinkedBlockingQueue,基于链表前端、尾端同时操作;此外读写分离锁(针对读多写少的情况)也是这个思想。
4.锁粗化:循环内频繁使用锁时,放在循环之外。
nGrinder
http://blog.csdn.net/neven7/article/details/50740018
Android 性能测试总结
启动时间
启动时间一般我们会测试三种情况。
首次启动
非首次启动
activity 切换所消耗的时间
测试方法一般使用两种:
1、程序内部打点到logcat,手动操作后获取log日志,来获取相应的时间。
2、使用adb 命令来操作,在操作的前后分别记录消耗的时间。(由于adb 操作可能会有延时等可能,此方法并不是很准确)
ps. 还有一种方式是采用告诉摄像机的方式来做,由于本人没有接触过,不过多说明。
1、获取cpu数据
adb shell dumpsys cpuinfo |grep$package_name
输出格式为;
45% TOTAL:18%user+ 20% kernel +6.2% iowait +0.2% softirq
可取total得值作为整体cpu利用率。
2、获取内存数据
adb shell dumpsys meminfo |grep$package_name
或者
adbshell dumpsys meminfo$package_name
直接dumpsys meminfo $package_name 可以看到比较完整的堆,线程,java等级别的内存数据,pss 可以作为内存的参考。
2、使用top 同时获取cpu和内存,-d 参数指定采样数据的间隔时间。
adb shell top-d2
输出:
PIDPR CPU% S#THR VSS RSS PCY UID Name
名词解释:
VSS- Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS- Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS- Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS- Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
一般来说内存占用大小有如下规律:VSS >= RSS >= PSS >= USS
可以看到,top 命令取出的内存对应是vss 和 rss,其中rss会比pss稍大,如果没有特别严格的要求,只是对比内存是否泄漏上涨等问题,rss也可以作为参考。
1、通过tcpdump抓包,然后wireshark 解包信息,来获取流量数据。
2、通过adb 命令来获取,先获取应用的pid,然后通过/proc/uid_stat/uid/下的文件来读取流量值。此方式会有rom兼容性问题,并不是所有的文件都可以找到这两个文件。
adbshelldumpsys$package_nameadbshellcat/proc/uid_stat/uid/tcp_rcv -- 下载流量adbshellcat/proc/uid_stat/uid/tcp_snd -- 上传流量
由于tcp_rcv, tcp_snd 的值是一个累加的值,想要获取两次操作间消耗的流量,可以在操作前和操作后分别获取,差值即为期间消耗的流量。也可以每个一段时间做采样,来获取整个过程中的使用情况。
帧率一定程度上反应的是app在使用中的流畅程度,理想情况是每秒60帧。
1、在开发者选项中有个“ GPU呈现模式分析(Profile GPU rendering,计算adb shell dumpsys gfxinfo中的呈现时间)”功能,在开启这个功能后,系统就会记录保留每个界面最后128帧图像绘制的相关时间信息。在开启这个功能后,重新启动APP,滑动页面然后执行adb命令。
adbshell dumpsys gfxinfo$package_name
输出结果中包含这部分数据
DrawProcessExecute1.301.250.530.630.621.640.240.510.440.251.760.400.251.550.430.250.530.370.491.512.12
Draw: 表示在Java中创建显示列表部分中,OnDraw()方法占用的时间。
Process:表示渲染引擎执行显示列表所花的时间,view越多,时间就越长。
Execute:表示把一帧数据发送到屏幕上排版显示实际花费的时间。其实是实际显示帧数据的后台缓存区与前台缓冲区交换后并将前台缓冲区的内容显示到屏幕上的时间。
Draw + Process + Execute = 完整显示一帧 ,这个时间要小于16ms才能保存每秒60帧。
2、通过SurfaceFlinger, 这种方式还没有研究过,过段时间再来补充
adb shell dumpsys SurfaceFlinger
1、对于电量的测试没有什么特别好的方式,可以选择使用物理设备来测试电池的电量情况。
2、对于android 5.0 以上的系统,adb命令可以支持获取电量信息。
adbshelldumpsysbattery
输出内容如下:
ACpowered:falseUSBpowered:trueWirelesspowered:falsestatus:1#电池状态:2:充电状态 ,其他数字为非充电状态health:2present:truelevel:55#电量: 百分比scale:100voltage:3977currentnow:-335232temperature:335#电池状态technology:Li-poly
jvm的调优
查看堆空间大小分配(年轻代、年老代、持久代分配)
垃圾回收监控(长时间监控回收情况)
线程信息监控:系统线程数量
线程状态监控:各个线程都处在什么样的状态下
线程详细信息:查看线程内部运行情况,死锁检查
CPU热点:检查系统哪些方法占用了大量CPU时间
内存热点:检查哪些对象在系统中数量最大
服务器性能瓶颈如何定位
https://www.cnblogs.com/mumulog/p/11455018.html
CPU定位分析
CPU利用率大于50%,需要注意;大于75%,需要密切关注;高于90%-95%,情况比较严重;
监控命令:vmstat、sar、dstat、mpstat、top、ps
类型度量方法衡量标准
利用率
1、vmstat统计1-%idle
2、sar -u统计1-%idle
3、dstat统计1-%idl
4、mpstat -P ALL统计1-%idle
注意>=50%
告警>=70%
严重>=90%
满载
1、vmstat的r值> cpu逻辑颗数
2、sar -q ,“runq-sz”>cpu逻辑颗数
运行队列大于1时,证明已经有一定的负载
内存定位分析
当物理内存不够时,会使用swap分区,所以性能测试过程中需要关注swap和mem的使用情况。
物理内存不够,大量的内存置换到swap空间,可能导致CPU和I/O的瓶颈。
监控命令:vmstat、sar、dstat、free、top、ps等
类型度量方法衡量标注
占用率
1、free 查看使用情况
2、vmstat
3、sar -r
4、ps
注意>=50%
告警>=70%
严重>=80%
满载
1、vmstat的si/so比例,swapd占比
2、sar -W 查看次缺页数
3、dmesg | grep killed
1、so数值大,且swapd已经占比很高,内存已经饱和
2、sar命令次缺页多意味内存已经饱和
3、内存不够用会触发内核的OOM机制
网络定位分析
监控命令:sar、ifconfig、netstat,以及查看net的dev速率。
通过查看发现收发包的吞吐率达到网卡的最大上限,网络数据报文有因为这类原因而引起的丢包、阻塞等现象都证明当前网络可能存在瓶颈。
为了减小网络对性能测试的影响,一般我们都在局域网中进行测试执行。
类型度量方法衡量标准
使用情况
1、sar -n DEV 的收发计数大于网卡上限
2、ifconfig RX/TX宽带超过网卡上限
3、cat /proc/net/dev的速率超过上限
4、nicstat的util基本满负荷
1、收发包的吞吐率达到网卡上限
2、有延迟
3、有丢包
4、有阻塞
满载1、ifconfig dropped 有计数
2、netstat -s "segments retransmited"有计数
3、sar -n EDEV,rxdrop/s txdrop/s有计数
有丢包统计
错误
1、ifconfig,“errors”
2、netstat -i,RX-ERR TX-ERR
3、sar -n EDEV,rxerr/s txerr/s
4、ip -s link, “errors”
错误有计数
IO定位分析
I/O读写频繁的时候,如果I/O得不到满足会导致应用的阻塞。
需要考虑I/O的TPS、平均I/O数据、平均队列长度、平均服务时间、平均等待时间、IO利用率(磁盘Busy Time%)等指标
监控命令:sar、iostat、iotop
类型度量方法衡量标准
使用情况
1、iostat -xz,“%util”
2、sar -d,“%util”
3、cat /proc/pid/sched | grep iowait
注意>=40%
告警>=60%
严重>=80%
满载
1、iostat -xnz,“avgqu-sz ”>1
2、iostat await>70
IO疑似满载
错误
1、dmseg 查看io错误
2、smartctl /dev/sda
有错误信息
Jmeter知识
一台台式机能支持的最大并发量 This is based on my experience If we follow the best practices as follow then we can achieve 350 ~ 500 concurrent users (web based application) and 900~1100 concurrent users (backend API) provided 8 GB RAM with 64-bit OS.
1、如何配置多个用户--放在csv文件里面,进行调用
2、前面一个接口的返回值,比如登录的token值,如何作为下一个接口的参数,进行传输--后置处理器中的正则表达式去提取,或者json提取器
3、加密参数如何传输--调用一个函数--https://www.cnblogs.com/kikihuang/p/11475669.html
4、如何处理异步通信
https://blog.csdn.net/weixin_42484338/article/details/102851774?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.baidujs&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4.baidujs
5、压力测试在测试环境还是线上环境做?如果是测试环境做,如何保证和线上环境一样?因为测试环境配置的服务器啥的大多和线上不一样
6、分布式压测了解一下
https://www.cnblogs.com/gcgc/p/11727761.html
https://www.cnblogs.com/dcszhangsir/p/13463299.html
7、根据测试报告的数据,如何分析测试结果,并给出开发一些修改意见
8、压力测试主要分析哪些测试指标
9、遇到过得测试出来的什么问题,是什么原因,给出了什么建议,大概讲一下
gatling
全链路压测
1)首先要梳理核心链路的流程,明确链路的边界,核心链路是一个业务的核心,这一块应该可以很快梳理清楚,但是,难点在于梳理清楚链路的边界,分支业务
每个业务owner反复确认,哪些是核心业务,哪些是分支业务,哪些参与压测,哪些不参与压测,把这些形成文档,逐个跟进。
2)提供全链路压测的底层支持
我的理解:
流量、数据隔离 ,可以在head中打标
新建影子表,写入和读取都走影子表
日志-影子目录:将压测流量产生的日志落入到影子目录
全链路透传压测标志:必须有一种在全链路透传压测标志的能力,并且必须基于一次请求,也就是同一个traceId,现在,大部分分布式业务都会接入trace系统,例如,google的dapper,阿里的鹰眼等,对trace系统进行改造,使其能够透传压测标志,需要透传的路径大概有:
HTTP,RPC(DUBBO),MQ,线程池等
影子表:参与压测的业务,要逐个排查自己依赖的数据库,然后创建影子表,影子表必须跟正常表的schema保持一致,可以在每次压测时候手动创建,也可以推动DBA自动创建。创建好影子表后,如果当前流量是压测流量,那么写入和读取都走影子表。如果有自己的数据库中间件最好,没有的话可以借助于Mybatis的Interceptor机制。
日志-影子目录:为了防止压测流程的日志对正常日志造成干扰,需要改造日志组件,将压测流量产生的日志落入到影子目录。影子目录可以有日志组件自动创建。
MQ支持是否消费压测流量:有的时候,全链路会通过MQ进行传递,所以,必须在消费MQ的时候进行选择:是否选择消费压测流量的MQ消息。这就需要对MQ系统进行改造,一方面使其可以透传压测流量,另一方面,需要支持配置是否消费压测的MQ消息
缓存,大数据隔离:还有一些场景,比如,缓存层,大数据层对压测流量的处理也要考虑隔离。缓存可以使用不同的集群;大数据可以直接不收集压测的数据
3)思考全链路压测的数据怎么mock
在使用影子表之后,可以比较轻松的实现跟正常数据隔离,那剩下的就是好构造好mock数据,有几点需要考虑:
① 用户数据要提前做好认证等准备工作
② Mock数据要尽可能跟真实数据保持一致,比如,价格水平,图片数量,地址信息等等
③ Mock数据有些限制需要放开,比如,库存,一些运营性质的活动可以取消等
④ 千万不要污染正常数据:认真梳理数据处理的每一个环节,确保mock数据的处理结果不会写入到正常库里面
4)梳理监控体系
① 核心接口和核心依赖的流量和耗时监控
② 中间件组件,缓存,数据库的监控报警
③ 机器的指标报警
5)线下做好预演
真实的压测之前,肯定要进行预演,预演主要确认:
① 压测流程是否写入到了正确的目的地,例如,写入到影子表,影子目录,压测cache等等
② 压测流量的降级是否完备和有效
③ 进一步确保监控都已到位
6)尽量模拟现实,用户的行为,例如
① 购买的行为:不是下单后立即购买,而是要等一下子
② 骑车子的行为:开锁后并不是里面换车,而是骑一会
7)逐步平滑加压
压测的时候,逐步加压,并且要保持平滑加压,不要把一秒的流量都在前面几毫秒内都压出去。
难点: 推进
全链路压测的技术难点不多,除了要花时间梳理流程和思考如何处理数据之外,最难的就是整个链路跨多个业务,甚至部门,需要跟进每个业务线的进度,确保大家能够在给定的时间点进行联调以及进行压测。在推进的时候,按照核心链路所在的模块进行跟进,每个模块出一个owner,各个owner跟进核心的接口和依赖,每周大家碰一下同步下总体的进度
压测中TPS上不去,那么你怎么分析这个问题?
1、网络带宽
在压力测试中,有时候要模拟大量的用户请求,如果单位时间内传递的数据包过大,超过了带宽的传输能力,那么就会造成网络资源竞争,间接导致服务端接收到的请求数达不到服务端的处理能力上限。
2、连接池
可用的连接数太少,造成请求等待。连接池一般分为服务器连接池(比如Tomcat)和数据库连接池(或者理解为最大允许连接数也行)。
3、垃圾回收机制
从常见的应用服务器来说,比如Tomcat,因为java的的堆栈内存是动态分配,具体的回收机制是基于算法,如果新生代的Eden和Survivor区频繁的进行Minor GC,老年代的full GC也回收较频繁,那么对TPS也是有一定影响的,因为垃圾回收其本身就会占用一定的资源。
4、数据库配置
高并发情况下,如果请求数据需要写入数据库,且需要写入多个表的时候,如果数据库的最大连接数不够,或者写入数据的SQL没有索引没有绑定变量,抑或没有主从分离、读写分离等,就会导致数据库事务处理过慢,影响到TPS。
5、通信连接机制
串行、并行、长连接、管道连接等,不同的连接情况,也间接的会对TPS造成影响。
6、硬件资源
包括CPU(配置、使用率等)、内存(占用率等)、磁盘(I/O、页交换等)。
7、压力机
比如jmeter,单机负载能力有限,如果需要模拟的用户请求数超过其负载极限,也会间接影响TPS(这个时候就需要进行分布式压测来解决其单机负载的问题)。
8、压测脚本
还是以jemter举个例子,之前工作中同事遇到的,进行阶梯式加压测试,最大的模拟请求数超过了设置的线程数,导致线程不足。提到这个原因,想表达意思是:有时候测试脚本参数配置等原因,也会影响测试结果。
9、业务逻辑
业务解耦度较低,较为复杂,整个事务处理线被拉长导致的问题。
10、系统架构
比如是否有缓存服务,缓存服务器配置,缓存命中率、缓存穿透以及缓存过期等,都会影响到测试结果。
性能测试CPU占有率高如何定位问题?
通过Top命令查看具体的进程,然后使用相关的命令具体到线程,最后通过相关的工具查看栈的问题,以至于最后定位到代码。
总结:
1. 查找进程
top查看进程占用资源情况
明显看出java的那个进程占用过高cpu.
2.查找线程
使用top -H -p <pid>查看线程占用情况
3.查找java的堆栈信息
将线程id转换成十六进制
#printf %x 15664
#3d30
然后再使用jstack查询线程的堆栈信息
语法:jstack | grep -a 线程id(十六进制)
jstack <pid> | grep -a 3d30
这样就找出了有问题的代码了。
pid :进程id tid :线程 id
https://blog.csdn.net/lord_is_layuping/article/details/90238816
Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好的优化语句。
Explain语法:explain select … from … [where ...]
https://blog.csdn.net/jwq101666/article/details/78561022