最近很多B乎粉丝都在面试性能测试工程师的岗位,
🍅知乎号主:程序员面试秘籍
💬 大厂面试真题、简历模板、近40篇面试经验文章、接口、自动化测试、性能测试、安全测试学习资源、学习路线指引。关注我,都给你
🌈 感激相遇,愿你我皆有所获
同时再问我:有没有性能测试专项面试题(包含答案这种),这不爆肝一晚上给大家整出来了。
从性能测试概念、方案、工具、性能调优并结合调优案例一并给大家整全面了。
概念篇
-
吞吐量、吞吐率、点击率是什么?
-
事务、TPS、QPS是什么?
-
PV、UV 是什么?
-
负载测试、压力测试是什么?
-
性能测试包含了哪些测试(至少举出3种)。
-
简述性能测试的步骤。
-
性能测试什么时候开始?
方案篇
-
如何得到性能测试需求
-
「客户」在性能测试中关注什么?
-
「开发」在性能测试中关注什么?
-
「测试」在性能测试中关注什么?
-
需求分析应关注哪些「性能」点?
-
敏捷开发模型,如何设计「性能测试策略」?
-
对于一个缺乏性能明确需求的项目,你是如何提取性能需求 的?
工具篇
-
请描述LoadRunner性能测试过程?
-
LoadRunner由哪些部件组成?
-
LoadRunner的一些基础概念。
-
什么是集合点?设置集合点有什么意义?Loadrunner中设置集合点的函数是哪个?
-
Vuser_init 中包括什么内容?
-
Vuser_end 中包括什么内容?
-
think time是什么?think_time有什么用?
-
如何在LR中进行手动关联?
-
如何在LR中编写自定义函数?
-
解释以下函数及他们的不同之处。
调优篇
-
请描述什么是系统性能拐点?
-
如何识别性能瓶颈?
-
打开浏览器输入网址到页面渲染,响应时间通常可以细分为哪些?
-
什么是内存泄露?
-
硬件关注「性能指标」有哪些?
-
中间件关注「性能指标」有哪些?
-
数据库关注「性能指标」有哪些?
-
前端关注「性能指标」有哪些?
案例篇
-
SQL执行时间长排查
-
数据库出现死锁排查
-
线程阻塞在日志记录上排查
-
多线程并发问题排查
-
打开了太多文件排查
-
内存泄漏排查
-
JVM垃圾回收频繁排查
-
CPU高排查
-
批处理时间长、数据库逐笔插入缓慢排查
-
数据库CPU高排查
-
压测TPS曲线剧烈下降或抖动排查
概念篇
1. 吞吐量、吞吐率、点击率是什么?
-
吞吐量:1次性能测试过程中网络上传输的数据量的总和。
-
吞吐率:单位时间内网络上传输的数据量。
-
点击率:每秒钟用户向web服务器提交的HTTP请求数。
例子:
小黑向系统A发动攻击了1次攻击,
模拟多个用户在10秒钟内请求了200次HTTP请求、并且发送了100MB流量
吞吐量:100MB
吞吐率:10MB(100MB/10秒)
点击率:20次(200次/10秒)
2. 事务、TPS、QPS是什么?
-
事务:用户某一步或几步操作的集合,例:如用户对某一个页面的一次请求,用户对某系统的一次登录,淘宝用户对商品的一次确认支付过程。
-
TPS:每秒传输事物率,Transaction Per second,人为定义事物
-
QPS:每秒查询率,Queries Per Second,查询后端服务器次数
例子:
用户访问 index 页面会请求服务器 3 次,
包括:1次 html、1次 css、1次 js
结论:访问 index 页面产生1个“T”,产生3个“Q”。
3. PV、UV 是什么?
-
PV:page view 即页面浏览量
-
UV:Unique Visitor 指独立访客访问数,通常使用终端mac地址作为唯一标识
举例:
某网站首页1天内的用户累计「页面访问量」达到1000万,
其中「不重复的电脑mac」的数量有80万。
该网站首页1天内
PV:1000万
UV:80万
4. 负载测试、压力测试是什么?
负载测试:通过「不断的加大负载」来确定在满足性能指标情况下,目的:获取系统所能够承受的「最大并发数」。
压力测试:通过「高负载」的手段来使服务器资源处于极限的状态,目的:获取系统在极限状态「长时间运行是否稳定」。
举例:
背景:某系统A存在用户注册、登录、访问首页的业务,
目前需要对登录业务进行性能测试任务。
负载测试:设置并发数10、20、50、100来验证系统「最大并发数」是多少。
压力测试:假设「最大并发数」是50,那么设置10倍即500并发数,
看系统在极限情况下「长时间运行是否稳定」。
5. 性能测试包含了哪些测试(至少举出3种)?
6. 简述性能测试的步骤。
-
1)熟悉应用:了解应用的架构、功能逻辑;
-
2)需求分析:根据测试目的,细化需求;
-
3)测试准备:客户端准备、测试数据准备、测试脚本准备;
-
4)执行测试:监控测试客户端和服务器性能,监控服务器端应用情况;
-
客户端的系统资源(CPU、IO、Memory)情况;
-
服务端的系统资源(CPU、IO、Memory)情况;
-
服务器的JVM运行情况;
-
服务端的应用情况是否有异常;
-
响应时间、吞吐量等指标;
-
-
5)性能分析与调优:找出性能瓶颈,提高系统整体性能,满足用户需求;
-
6)编写测试报告:测试结束后,归档整理测试报告;
7. 性能测试什么时候开始?
-
一般在系统功能稳定没有大的缺陷之后开始执行。
-
但前期准备工作可以从系统需求分析时就开始:性能目标制定、场景获取、环境申请等。
方案篇
1. 如何得到性能测试需求
-
查看需求文档提取性能测试需求,了解客户实际使用情况;
-
结合业务信息,设计操作场景从而总结出需要测试的性能关键指标;
-
执行用例后,提取关键性能指标来分析是否满足性能需求;
2. 「客户」在性能测试中关注什么?
-
客户:重点关注打开速度及响应时间;
-
在进行操作时,每个请求之间的间隔时间;
-
大量用户在同一时刻在软件系统上操作是否有较好的体验;
-
3. 「开发」在性能测试中关注什么?
-
开发人员:重点关注响应时间和数据库交互,进行性能调优;
-
系统架构:架构设计是否合理;
-
数据库设计:数据库设计是否存在问题;
-
代码:代码是否存在性能方面的问题,系统中是否有不合理的内存使用方式;
-
业务逻辑:系统中是否存在不合理的线程同步方式,系统中是否存在不合理的资源竞争;
-
4. 「测试」在性能测试中关注什么?
-
测试人员:重点关注用户感受到的软件性能;
-
系统的响应时间;
-
系统状态的相关信息,如:CPU、内存、应用服务器状态、JVM可用内存、数据库的状态等;
-
系统的可扩展性,处理并发的能力;
-
系统可能的最大容量,可能的性能瓶颈,通过更换哪些设备或是进行哪些扩展能够提高系统性能;
-
长时间运行是否足够稳定,是否能够不间断的提供业务服务等;
-
5. 需求分析应关注哪些「性能」点?
-
明确到底要不要做性能测试,性能测试的目的是什么;
-
明确被测系统的架构、软硬件配置、网络等;
-
明确被测系统的基本业务、关键业务、用户行为;
-
明确被测系统未来的业务拓展规划以及性能需求;
-
明确工具选型,比如Jmeter、LoadRunner等;
-
明确性能测试的指标,比如并发、吞吐量、响应时间等;
6. 敏捷开发模型,如何设计「性能测试策略」?
-
每个迭代目标中包含明确的性能目标;
-
建立不同层次的性能测试;
-
完全或接近完全自动化的性能测试;
-
使用测试驱动方法保证性能与优化性能;
7. 对于一个缺乏性能明确需求的项目,你是如何提取性能需求的?
-
与客户交流,查看历史日志,跟同类产品对比,根据以往的经验。
工具篇
1. 请描述LoadRunner性能测试过程?
2. LoadRunner由哪些部件组成?
-
VuGen(Virtual User Generator):录制脚本,录制一个场景(在一个事务中),通过录制或编写脚本来模拟用户的行文;对用户名、密码参数化(使多个用户运行同一脚本,在本地修改用户名密码),到Controller;
-
Controller:设置场景、监控运行场景,收集数据到Controller;
-
Analysis:在测试完成后,对测试过程中收集到的各种性能数据进行计算、汇总和处理,生成各种图表和报告,为系统性能测试结果分析提供支持。
3. LoadRunner的一些基础概念。
-
Scenario:场景。所谓场景,是指在每一个测试过程中发生的事件。
-
Vusers:虚拟用户。LoadRunner使用多线程或多进程来模拟用户对应用程序操作时产生的压力。一个场景可能包括多个虚拟用户,甚至成千上万个虚拟用户。
-
Vuser Script:脚本。用脚本来描述Vuser在场景中执行的动作。
-
Transactions:事务。事务代表了用户的某个业务过程,需要衡量这些业务过程的性能。
-
rendezvous :集合。当我们测试多个用户并发时,每个用户执行到该事务脚本的先后顺序是不确定的,所以得到的测试结果也并不是一个完全 并发的极限测试结果。在开始事务之前 ,插入一个“集合点”,那么在多用户执行时,就可以将用户请求停下来,直到用户数量达到满足的条件(默认是100%的用户都到达集合点)。那么,所有的用户都将同时发出接下来的请求。
4. 集合点是什么?集合点意义是什么?Loadrunner中设置集合点的函数是哪个?
-
集合点是什么:在测试计划中,可能会要求系统能够承受1000 人同时提交数据,在LoadRunner 中可以通过在提交数据操作前面加入集合点,这样当虚拟用户运行到提交数据的集合点时,LoadRunner 就会检查同时有多少用户运行到集合点,如果不到1000 人,LoadRunner 就会命令已经到集合点的用户在此等待,当在集合点等待的用户达到1000 人时,LoadRunner 命令1000 人同时去提交数据,从而达到测试计划中的需求。
-
集合点意义是什么:插入集合点是为了衡量在加重负载的情况下服务器的性能情况。
-
集合点函数:rendezvous
5. Vuser_init中包括什么内容?
vuser_init:虚拟用户的初始化函数,一般将用户初始化的操作放在这里,如登录操作、分配内存等。
6. Vuser_end中包括什么内容?
-
vuser_end () :与vuser_init相对,结束函数,只运行一次,例如登出操作,内存释放等。
-
请描述什么是系统性能拐点?
-
如何识别性能瓶颈?
-
打开浏览器输入网址到页面渲染,响应时间通常可以细分为哪些?
-
什么是内存泄露?
-
硬件关注「性能指标」有哪些?
-
中间件关注「性能指标」有哪些?
-
数据库关注「性能指标」有哪些?
-
前端关注「性能指标」有哪些?
7.think time是什么?think_time有什么用?
-
think time是什么:用户在执行连续操作之间等待的时间称为“思考时间”,它是决定对服务器施压大小的因素之一。
-
think_time有什么用:设置思考时间,是为了更真实的模拟用户
8. 如何在LR中进行手动关联?
-
录制测试脚本,录制二遍
-
使用WinDiff工具找出两次脚本的不同,判断是否需要进行关联
-
确定插入关联的位置
-
在VIEW TREE中使用web_reg_save_param函数手动建立关联
-
将脚本中有用到关联的数据,用参数代替
-
验证关联的正确性
9. 如何在LR中编写自定义函数?
-
在创建用户自定义函数前我们需要和创建DLL(external libary)。把库放在VuGen bin 目录下。
- 一旦加了库,把 自定义函数分配做一个参数。该函数应该具有一下格式:__declspec (dllexport) char* (char*, char*)。
10. 解释以下函数及他们的不同之处。
- lr_debug_message 函数在指定的消息级别
-
// 处于活动状态时发送一条调试消息。如果指定的
-
// 消息级别未处于活动状态,则不发出消息。
-
-
Lr_output_message 要发送不是特定错误消息的特殊通知
-
Lr_error_message 函数将错误消息发送到// 输出窗口和 Vuser日志文件
-
Lrd_stmt lrd_exec 函数执行 lrd_stmt设置的 SQL 语句。
-
Lrd_fetch 函数从结果集中提取后续若干行
调优篇
1.请描述什么是系统性能拐点?
性能开始急剧下降的点。
2.如何识别性能瓶颈?
-
硬件上的性能瓶颈:如CPU、内存、磁盘读写等的瓶颈,为服务器硬件瓶颈;
-
应用软件上的性能瓶颈:如服务器操作系统瓶颈(参数配置)、数据库瓶颈(参数配置)、web服务器瓶颈(参数配置)、中间件瓶颈(参数配置)等;
-
应用程序上的性能瓶颈:应用程序上的性能瓶颈,如SQL语句、数据库设计、业务逻辑、算法等等;
-
操作系统上的性能瓶颈:一般指的是Windows、linux等操作系统,如出现物理内存不足时,或虚拟内存设置不合理(虚拟内存设置不合理,会导致虚拟内存的交换率大大降低,从而导致行为的响应时间大大增加,可以认为在操作系统上出现了性能瓶颈);
-
网络设备上的性能瓶颈:一般是防火墙、动态负载均衡器、交换机等设备导致;
3.打开浏览器输入网址到页面渲染,响应时间通常可以细分为哪些?
-
从客户端到服务端的请求时间(请求网络传输时间Request);
-
从服务端返回数据到客户端的时间(响应网络传输时间Response);
-
页面渲染时间(客户端浏览器加载页面的时间);
-
处理器的处理时间(应用服务器+数据库服务器处理时间);
4. 什么是内存泄露?
-
内存泄漏是指对象不再被应用程序使用,但是垃圾回收器却不能回收它们,因为它们正在被引用。
-
对于长时间运行的程序来说,内存泄漏会使程序占用的内存一直增加,最后就会出现内存耗尽而导致宕机。
-
即使不宕机也会是系统的运行越来越慢,还有就是内存有其他资源,比如数据库连接,网络连接等等
5. 硬件关注「性能指标」有哪些?
-
硬件性能指标:CPU,内存Memory,磁盘I/O(Disk I/O),网络I/O(Network I/O) ;
6. 中间件关注「性能指标」有哪些?
-
中间件:常用的中间件如web服务器Tomcat, Weblogic web服务器,JVM(java虚拟机),ThreadPool线程池,JDBC数据驱动 ;
7. 数据库关注「性能指标」有哪些?
-
数据库指标:SQL,吞吐量,缓存命中率,连接数等;
8. 前端关注「性能指标」有哪些?
-
前端指标 :首次显示时间,页面数量,页面大小,网络startRender,firstRender等。
-
前端的性能与后端的性能的不同点在于,前端是每个用户的直观的感受,如前端页面加载元素耗费的时间,
-
后端的性能关注点在于多用户使用系统时,服务器是否能够承受或者服务器的处理能力如何,能否以较好的响应时间响应;
案例篇
1. SQL执行时间长排查
-
问题现象:系统响应时间长、数据库cpu高。
-
问题原因:全表扫描、索引低效、排序溢出。
-
解决方法:
-
通过数据库快照查看执行时间长的SQL,查看该SQL执行计划,在cost比较高的SQL上增加合适索引。要求所有大表SQL执行计划的cost低于100,超过100的SQL要评审。对于排序溢出、可参考数据中心规范设置排序堆大小,规范中排序堆设置为AUTOMATIC。
-
制定数据库表清理策略。根据数据的生命周期要求,对流水类的数据定期进行清理备份,不再长期保留。定期对全库的表结构进行reorg、runstats操作,以提高索引效率。
-
-
排查方法:
-
获得数据库快照(DB2数据库为例):db2 get snapshot for all on corpdb >gswyzfzzshpl1207.log
-
从快照中提取慢SQL,Toad查看SQL执行计划
-
Db2命令方式查看SQL执行计划:db2expln -d corpdb -t -g -q “SQL语句”
-
执行计划查看方法:自上而下查看cost最大的分支,找到未走索引或索引使用不当的表
-
2. 数据库出现死锁排查
-
问题现象:数据库快照检测到存在数据库死锁,或通过db2evmon -db corpdb -evm DB2DETAILDEADLOCK>dlock.txt生成死锁监控文件,快照或监控文件中存在deadlock的情况。
-
问题原因:全表扫描、大事务、更新相同表记录的SQL执行顺序交叉等。
-
解决方法:缩短事务路径长度,避免全表扫描。如果必须存在大事务,则更新相同表的SQL执行顺序一致,并且坚决避免全表扫描。网银系统指令发送功能全表扫描+全局大事务,导致数据库死锁。
-
排查方法:根据死锁监控文件dlock.txt找到导致死锁的SQL,以及该SQL持有的锁,分析该SQL可能存在的问题。
3. 线程阻塞在日志记录上排查
-
问题现象:系统响应时间长、通过javacore查看很多线程阻塞在打印日志上。
-
问题原因:log4j1.x版本较低,性能较差;大报文日志多次输出。
-
解决方法:
-
减少无效日志、删除无用日志,减少大日志输出。
-
升级log4j组件到log4j2,参考log4j2官方文档,配置合理的日志缓冲区,采用高效的Appenders,比如RollingRandomAccessFile。但log4j2仍然采用同步日志,不采用异步日志。如果日志量少(压测产生日志的速度,低于日志写入文件的速度),则可以使用异步日志,大幅提高性能。如果日志量较大,则不建议使用异步日志。
-
-
排查方法:
-
JVM启动参数中增加-XX:+HeapDumpOnCtrlBreak,压测进行时,kill -3 pid 杀几个javacore,使用jca457.jar工具打开并分析。推荐使用该工具,因为该工具可以对所有线程状态进行统计,并生成饼状图,方便查看。
-
压测进行时,使用jvisualvm获取jvm快照,分析线程堆栈。
-
4. 多线程并发问题排查
-
问题现象:采用合理的并发数压测,系统出现逻辑错误、交易失败或异常报错。经查是由于对象中变量被异常修改导致。
-
问题原因:系统中全局对象中的类变量或全局对象,被多个线程修改。
-
解决方法:排查系统中所有持有全局对象或类变量的代码,检查其全局变量是否可能被多个线程并行修改。
-
修改方法:
-
将全局变量转成方法内的局部变量;
-
对全局变量进行同步控制比如syncronized代码块,或者java.util.concurrent锁。
-
-
排查方法:并发问题很可能是由全局变量或者对象导致,准确识别全局变量,通过阅读代码找问题。建议应用梳理所有可能存放全局对象的代码,统一管控,或者把所有全局对象放到一个类中,方便管理。
5. 打开了太多文件排查
-
问题现象:采用合理的并发数压测,交易失败,或后台日志报错:To many open files。
-
问题原因:
-
读取配置文件或者业务数据文件后,未关闭文件流;
-
/etc/security/limits.conf中最大打开文件数配置过小
-
-
解决方法:
-
使用lsof –p pid 命令查看进程打开的文件,如果大部分文件都是同一类型的文件,说明可能未关闭文件流。找到打开文件的代码,关闭文件流即可。
-
如果不存在未关闭文件流的问题,且业务本身就需要处理大量文件,则修改/etc/security/limits.conf
-
vim /etc/security/limits.conf
#在最后加入
* soft nofile 4096
* hard nofile 4096
6. 内存泄漏排查
-
问题现象:JVM内存耗尽,后台日志抛出OutOfMemeryError异常;
-
问题原因:内存溢出问题可能的原因比较多,可能是全局的List、Map等对象不断被扩大,也可能是程序不慎将大量数据读到内存里;可能是循环操作导致,也可能后台线程定时触发加载数据导致。
-
解决方法:对于jdk纯java应用,在jvm启动时设置-XX:+HeapDumpOnOutOfMemory Error参数,会在内存溢出时生成heapdump文件。使用MAT(memory analyzer tool)工具打开heapdump文件,分析大对象是如何产生的。
-
当然,在heapdump中对象类型可能只是List这种结构,看不出具体哪个业务代码创建的对象。此时要分析所有的全局对象,列出可疑的List或Map对象,排查其溢出原因。
-
全局对象、引用的初始化、修改要慎重。建议应用梳理所有可能存放全局对象的代码,统一管控。
-
7. JVM垃圾回收频繁排查
-
问题现象:top –H –p pid命令查看,GC Slave线程CPU占用排名始终为前三名,同时Jconsole查看jvm内存占用较高,垃圾回收频繁。使用JConsole分析gc日志,查看gc频率、时长。
-
问题原因:高并发下,内存对象较多,jvm堆内存不够用 。
-
解决方法:扩大堆内存大小–Xmx2048m –Xms2048m。
8. CPU高排查
-
问题现象:50并发压测,监控工具显示bp、前置CPU占用90%以上。
-
问题原因:业务处理中存在大量CPU计算操作。
-
解决方法:采用更高效的算法、数据结构替换原来消耗CPU的代码,或者采用新的设计绕过瓶颈代码,比如查找数据的逻辑,可以把List改为Map,以空间换时间;比如用Json报文替换XML报文,提高传输、解析和打印日志的效率。
-
导致Cpu计算资源高消耗的代码:报文格式转换、加解密、正则表达式、低效的循环、低效的正则表达式。
-
- 排查方法:
-
压测进行时,使用jvisualvm工具远程连接应用,点抽样器àCPU,点快照生成线程快照。采样一段时间后,抽样器会显示各个方法占用cpu时间,可以针对CPU时间占用高的方法进行优化。
-
使用tprofiler,jprofiler,OracleDeveloperStudio12.6-linux-x86工具分别分析消耗CPU时间长的方法,以上工具分析结果可能有些差别。针对CPU计算耗时最长的方法进行优化。
-
9. 批处理时间长、数据库逐笔插入缓慢排查
-
问题现象:大批量数据(10万条以上)更新或插入数据库,耗时较长。
-
问题原因:批量数据处理时,如果逐条更新数据库,则会存在大量网络io、磁盘io,耗时较长,而且对数据库资源消耗较大。
-
解决方法:
-
采用java提供的batchUpdate方法批量更新数据库,每1000条commit一次,可大幅提高数据更新效率。
-
单线程改成线程池,并行处理,充分利用多核CPU,通过数据库或者其他同步锁控制并行性;增加缓冲池,降低数据库或磁盘IO访问频次。
-
10. 数据库CPU高排查
-
问题现象:后台指令发送满负荷工作时,数据库CPU高。
-
问题原因:后台指令发送线程每次对全量查询结果排序,结果集很大,然后取一条记录;索引区分度不高,满负荷执行时;查询频率很高;压测显示,并行发送指令的后台线程越多,数据库CPU越高,效率越低。
-
解决方法:
-
去掉ORDER BY,增加索引后,效果不明显。因为结果集大和查询频繁两个问题没有解决,因此考虑使用设计新的方案。
-
新方案:设计指令发送线程池,生产者线程每台任务服务器只有一个线程,负责查询待发送指令,每次查询50条指令。每条指令包装成一个Runnable对象,放进ThreadPoolExecutor线程池,线程池大小参数设置为100或200。每当线程池满时,生产者停止生产指令,休息15秒后继续。消费者线程即线程池里的线程,参数设置为4,8或12(和不同指令类型的指令数据量成正比)。
-
改进后的方案,数据库CPU降到10%一下,发送效率单机提升6倍,且可线性扩展任务服务器。
-
11. 压测TPS曲线剧烈下降或抖动排查
-
问题现象:50并发压测,TPS曲线正常应该是平缓的,波动不大,如果突然出现剧烈下降,并且短时间内无法恢复,则可能存在问题。
-
问题原因:一般是由于前置或bp的jvm进行垃圾回收,或者日志记录磁盘满导致的。
-
解决方法:如果不是特别剧烈的波动或者TPS曲线下降后长时间不反弹,则可以忽略该问题。否则,需要分析曲线下降的时刻,系统当时正在发生的事情。可以通过top命令监控当时CPU占用比价高的线程,也可以kill -3 pid杀javacore来查看线程堆栈。
资料白嫖关注公号:程序员一凡,可自行🔍WeChat查看!