1.自我介绍和介绍
这一般是面试的第一个问题,记住每个人的简历都不一样,但是jd只有一份。所以要研究这个岗位的jd,再来定制自我介绍,去掉无关的,强调相关的,着重突出能给你加分的。所以一般都有这个套路:
- 先介绍自己的学校和公司,现在一般看本科和上一家公司,如果都不好,可能简历关都过不了。
a. 如果你学校让你骄傲的话,先介绍下你的学校和专业
b. 如果学校不行的话,直接介绍你工作过的公司,挑有名和相关的说 - 简单说说你在公司负责的项目和你的职责,不用细说,因为后面面试肯定会详细问。
- 说下对这个职位的了解和兴趣
注意一定要简单,到位,达意,一切都是为了这个岗位做的自我介绍。
2、介绍下你负责的公司项目
- 首先你要给人家介绍清楚,你这个项目的产品是什么?话不要多,比如我们的产品是直播应用,市场上竞品是什么,这里说个top 1的,然后说下特色是什么,如果知道用户数据也可以说下。
- 接着,讲下项目产品有几个端,服务端,客户端,安卓,ios。简单说下,如果面试者还有兴趣,你可以把技术架构说一下,这个挺难的。得好好看看自己产品。
- 一般到这里,面试官会问,你在项目中干嘛了。那你就要说你在项目中承担的角色,是测试总控,还是某个模块负责人。如果是总控就要说说你的测试计划和测试策略,如果负责测试模块的,就要说说是哪些模块。这些模块的作用是什么?4. 最后,说说你取得的成绩。
3、如果项目周期很短,测试人力匮乏,你是怎么协调的?
- 测试有压力,开发必然有压力,和开发一起砍需求
- 系分和测分增加投入,做更精准的测试
- 测试提前进入
- 加强开发自测,拉取开发交付用例
- 加班
4、描述下你团队的测试分工
- 业务压力大的时候,业务为主,技术为辅
- 业务少的时候,技术为主,业务也不丢
- 老人带新人,新人帮老人,选出业务领头人和技术领头人,形成团队梯队
5、使用什么测试框架做的上一个项目的自动化测试
testng
6、自己最熟悉哪个库,如何使用这些库的,是否做了基于复用的封装,怎么考虑的这些封装
分别封装了基础类例如:等待某元素出现的方法,更方便查找操作元素的方法,和被测试业务相关的类和方法
7.如何使用xpath定位一个兄弟元素,就是和该元素同属于一个父亲节点的元素
答: 先找到父亲元素,再找到自己的兄弟元素
8、自动化遇到用例fail掉如何排查故障
答:手工查应用是否真的有bug, 确认不是bug,是不是新版本引入了新的变更,调试脚本看看自己的脚本是不是因为没有等待元素出现后就操作了,是不是元素上面有其他元素出现这样操作是不是操作了其他的元素上了
9、等待元素出现的这个方法如何实现的
等待方式有三种:
1)显示等待:显示等待,就是明确的要等到某个元素的出现,等不到就一直等,除非在规定的时间之内都没找到,那么就跳出Exception,代码,element = WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement"))
2)隐式等待:就是在创建driver时,为浏览器对象创建一个等待时间,这个方法是得不到某个元素就等待一段时间,直到拿到某个元素位置3)线程暂停:Thread.sleep();这种等待属于死等,很容易让线程挂掉,使程序抛异常
用一个循环间隔时间去检查这个元素是否可见
自己封装的软等待类软waitElementIsEnabledBy
使用 WebDriverWait.until,20秒等待到了元素直接执行,没有就循环等待,20秒等待不到就抛出异常
public static Boolean waitElementIsEnabledBy(By by) {
try {
WebDriver waitDriver = driver;
long waitTime = 20;
waitDriver.manage().timeouts().implicitlyWait(waitTime, TimeUnit.SECONDS);
(new WebDriverWait(waitDriver, waitTime)).until(ExpectedConditions.elementToBeClickable(by));
return true;
} catch (Exception e) {
return false;
}
}
10、在selenium自动化测试中,你一般完成什么类型的测试?
用于回归测试。每次迭代都会执行一次回归
11、你什么时候不自动化测试?
① 人们不应该在以下情况下自动化
② 当受测试的应用程序频繁更改时
③ 一次测试案例
④ 临时 - 随机测试
12、你如何从Selenium连接到数据库?
Selenium是一个Web UI自动化工具。它不提供任何API来建立数据库连接。
我们需要jdbcjar包,然后使用Connection对象来连接数据库并执行sql
13、XPath中使用单斜杠和双斜杠有什么区别?
1)如果XPath是从文档节点开始,它将允许创建“绝对”路径表达式。
例如 “/ html / body / p”匹配所有的段落元素。
2)如果XPath在文档中的任意位置开始进行选择匹配,那么它将允许创建“相对”路径表达式。
例如 “// p”匹配所有的段落元素。
Selenium中可以用哪些验证点?
Selenium最主要有三种验证点 -
检查页面标题
检查某些文字
检查某些元素(文本框,下拉菜单,表、 元素是否出现 、是否可点击 、是否消失等)
14、在selenium中处理多个弹出窗口的机制是什么?
可以使用命令getWindowHandles()
来处理多个弹出窗口。
然后将所有窗口名称存储到Set变量中并将其转换为数组。
接下来,通过使用数组索引,导航到特定的窗口。
driver.switchTo().window(ArrayIndex);
15、你如何处理使用Selenium的Ajax控件?
处理这样的控件,需要在文本框中输入值之后,捕获字符串中的所有建议值;然后,分割字符串,取值就好了。
16、你将如何处理Selenium WebDriver中的警报/弹出窗口?
有两种类型的警报通常被引用。
基于Windows的警报弹出窗口
基于Web的警报弹出窗口
- 基于Web的警报弹出窗口。
WebDriver为用户提供了一种使用Alert界面处理这些弹出窗口的非常有效的方法。
1)void dismiss() - 一旦出现弹出窗口,dismiss()方法就会点击“Cancel”按钮。
2)void accept() - 只要弹出窗口出现,accept()方法就会点击“Ok”按钮。
3)String getText() - getText()方法返回警告框中显示的文本。
4)void sendKeys(String stringToSend) - sendKeys()方法将指定的字符串模式输入到警告框中。 - 基于Windows的警报弹出窗口。
处理基于windows的弹出窗口总是有点棘手,因为我们知道Selenium是一个自动化测试工具,它只支持Web应用程序测试,也就是说,它不支持基于Windows的应用程序,窗口警报就是其中之一。
Robot class是基于Java的实用程序,它模拟键盘和鼠标操作,并可以有效地用于处理基于windows的弹出与键盘事件的帮助。
KeyPress和KkeyRelease方法可以分别模拟用户按下和释放键盘上某个键的操作。
17、Selenium WebDriver中的可用定位器是什么?
1)ID,
2)Name,名称
3)CSS,
4)XPath,
5)Class name,
6)TagName,
7)LinkText, 链接文本
8)Partial Link Text.部分链接文本
18、解释使用TestNG而不是JUnit框架的好处?
TestNG相较于Junit的优势:
1)在JUnit中,我们必须声明@BeforeClass和@AfterClass,这是JUnit中的一个约束,而在TestNG中没有像这样的约束。
2)TestNG提供了更多的setUp / tearDown级别。1.@ Before/AfterSuite 2.@Before/AfterTest 3.@Before/AfterGroup
3)TestNG中不需要扩展任何类。
4)TestNG中没有方法名称约束,就像JUnit一样。
5)在TestNG中,我们可以告诉测试一个方法依赖于另一个方法,而在JUnit中这是不可能的。
6)测试用例的分组在TestNG中可用,而JUnit中则不可用。执行可以基于组完成。例如,如果你已经定义了许多案例,并通过将2个组分别定义为“离职“与”回归”隔离。如果你只是想执行“理智”的情况,那就告诉TestNG执行“理智”。TestNG将自动执行属于“离职”组的案例。
7)另外,TestNG支持并行测试用例执行。
19、可以使用TestNG运行一组测试用例吗?
是的,TestNG框架支持在测试组的帮助下执行多个测试用例。
它提供了以下选项来运行特定组中的测试用例。
如果想基于回归测试或冒烟测试等其中一个组来执行测试用例,那么:
@Test(groups = {“regression-tests”, “smoke-tests”})
20、常见控件使用
1) link/button:
element.click()
注:ajax不能使用clickAndWait()函数,因为cickAndWait函数会在click之后等待页面重新加载完成,而ajax是部分刷新,所以这个页面不能重新加载完成。
2) Textbox:
element.send_keys(‘test’)
3) Upload
Driver.find_element_by_id(‘id’).send_keys(‘D\test.txt’)
4) Mouse Event:
e1=driver.find_element_by_id(‘kw’)
ActionChains(driver).double_click()/.context_click()/.drag_and_drop()/.move_to_element()/.perform()
# 双击/右击/拖动/悬停/执行actionChains中的行为
5) Dropdown:
·<Select>标签的下拉菜单
from selenium.webdriver.support.ui import Select
Select(driver.find_element_by_id(‘gender’)).select_by_index(1)
Select(driver.find_element_by_id(‘gender’)).select_by_value(“2”)
Select(driver.find_element_by_id(‘gender’)).select_by_visible_text(“Male”)
·非<Select>标签的下拉菜单
Dropdown1 = driver.find_element_by_id(‘id’) #先定位到dropdown
Dropdown1.find_element_by_id(“li2_input_2”) #再定位到dropdown中的值
6) Alert:
driver.switch_to.alert.accept()//接受
driver.switch_to.alert.dismiss() //取消
Message=driver.switch_to.alert.text //获取弹窗的文本消息
driver.switch_to.alert.send_keys(‘hello’) //输入值,这个在alert和confirm中不可用
7) Window
Driver.refresh() 刷新
Driver.back() 后退
Driver.forward() 前进
Driver.maximize_window() 最大化
Driver.set_window_size(100,200) 设置窗口大小
Driver.switch_to.window(searchwindow)
8) Frame
Driver.switch_to.frame(ReferenceFrame)
Driver.switch_to.parent_frame() # frame需要一级一级切
Driver.switch_to.default_content()
21、关于自动化测试报告生成?
TestNG原生就可以生成测试报告,也有第三方叫reportNG的插件
22、怎么提高用例执行速度
TestNG配置并行执行
parallel="methods" thread-count="3"
parallel:指定并行执行方式(是否多线程并发运行测试;可选值(false | methods | tests | classes | instances),默认 "false")
thread-count:并行的值(并发执行时的线程池数量,默认为"5)
23、web自动化测试报告怎么输出的
用TestNG生成报告,由于Testng生成的测试报告不够直观,可以使用reportng来生成
方法:
1)配置reportng依赖和监听
2)在Window-->Preferences中设置
(1)禁用默认监听器
(2)设置监听器:org.uncommons.reportng.HTMLReporter
3)xml文件配置使用的reportng方法
<listeners>
//testng的XML配置文件中添加这些内容
<listener class-name="org.uncommons.reportng.HTMLReporter" />
<listener class-name="org.uncommons.reportng.JUnitXMLReporter" />
</listeners>
4)Html下的index.html 就是reportNg 生成的报告,另外TestNG-xslt也可以,但是没有用过
- TestNG xml参数文件详解
testng.xml文件节点属性说明:
suite属性说明:
@name: suite的名称,必须参数
@junit:是否以Junit模式运行,可选值(true | false),默认"false"
@verbose:命令行信息打印等级,不会影响测试报告输出内容;可选值(1|2|3|4|5)
@parallel:是否多线程并发运行测试;可选值(false | methods | tests | classes | instances),默认 "false"
@thread-count:当为并发执行时的线程池数量,默认为"5"
@configfailurepolicy:一旦Before/After Class/Methods这些方法失败后,是继续执行测试还是跳过测试;可选值 (skip | continue),默认"skip"
@annotations:获取注解的位置,如果为"javadoc", 则使用javadoc注解,否则使用jdk注解
@time-out:为具体执行单元设定一个超时时间,具体参照parallel的执行单元设置;单位为毫秒
@skipfailedinvocationcounts:是否跳过失败的调用,可选值(true | false),默认"false"
@data-provider-thread-count:并发执行时data-provider的线程池数量,默认为"10"
@object-factory:一个实现IObjectFactory接口的类,用来实例测试对象
@allow-return-values:是否允许返回函数值,可选值(true | false),默认"false"
@preserve-order:顺序执行开关,可选值(true | false) "true"
@group-by-instances:是否按实例分组,可选值(true | false) "false"
test属性说明:
@name:test的名字,必选参数;测试报告中会有体现
@junit:是否以Junit模式运行,可选值(true | false),默认"false"
@verbose:命令行信息打印等级,不会影响测试报告输出内容;可选值(1|2|3|4|5)
@parallel:是否多线程并发运行测试;可选值(false | methods | tests | classes | instances),默认 "false"
@thread-count:当为并发执行时的线程池数量,默认为"5"
@annotations:获取注解的位置,如果为"javadoc", 则使用javadoc注解,否则使用jdk5注解
@time-out:为具体执行单元设定一个超时时间,具体参照parallel的执行单元设置;单位为毫秒
@enabled:设置当前test是否生效,可选值(true | false),默认"true"
@skipfailedinvocationcounts:是否跳过失败的调用,可选值(true | false),默认"false"
@preserve-order:顺序执行开关,可选值(true | false) "true"
@group-by-instances:是否按实例分组,可选值(true | false) "false"
@allow-return-values:是否允许返回函数值,可选值(true | false),默认"false"
性能测试类
1、 性能测试包含了哪些软件测试(至少举出3种)?
负载测试(Load Testing):负载测试是一种主要为了测试软件系统是否达到需求文档设计的目标,譬如软件在一定时期内,最大支持多少并发用户数,软件请求出错率等,测试的主要是软件系统的性能。
压力测试(Stress Testing):强度测试也就是压力测试,压力测试主要是为了测试硬件系统是否达到需求文档设计的性能目标,譬如在一定时期内,系统的cpu利用率,内存使用率,磁盘I/O吞吐率,网络吞吐量等,压力测试和负载测试最大的差别在于测试目的不同。
容量测试(Volume Testing):确定系统最大承受量,譬如系统最大用户数,最大存储量,最多处理的数据流量等。
或者在下面选择几项:
并发测试 - 测试多用户并发访问同一个应用、模块、数据时是否产生隐藏的并发问题
基准测试 - 比较新的或未知测试对象与已知参照标准(如现有软件或评测标准)的性能。
争用测试:- 核实测试对象对于多个主角对相同资源(数据记录、内存等)的请求的处理是否可以接受。
性能配置 - 核实在操作条件保持不变的情况下,测试对象在使用不同配置时其性能行为的可接受性。
负载测试- 核实在保持配置不变的情况下,测试对象在不同操作条件(如不同用户数、事务数等)下性能行为的可接受性。
强度测试- 核实测试对象性能行为在异常或极端条件(如资源减少或用户数过多)之下的可接受性。
容量测试- 核实测试用户同时使用软件程序的最大数量
2、请问什么是性能测试、负载测试、压力测试?
1)性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。
2)负载测试、压力测试参考答案如上题
3、什么时候可以开始执行性能测试?
在产品相对比较稳定,功能测试结束后。
3、简述性能测试的步骤。
熟悉应用
了解应用的架构、功能逻辑
测试需求
1、需要将开发给定的需求转为吞吐量和响应时间。
2、根据测试目的,细化需求
测试准备
测试准备包括测试客户端机器准备、测试数据准备、测试脚本准备。
测试执行
测试的执行中,需要监控测试客户端和服务器性能,监控服务器端应用情况:
客户端的系统资源(cpu、io、memory)情况
服务端的系统资源(cpu、io、memory)情况
服务器的jvm运行情况
服务端的应用情况,看是否有异常
响应时间、吞吐量等指标
系统资源监控,linux下可以采用的工具有:vmstat、top、meminfo等。
JVM的监控,可以用jprofiler工具,linux下面的jmap、jhat等。
响应时间、吞吐量等,由grinder提供。
上述这些信息,一般在测试结束后,均需要归档整理,已备后续详细分析
我们自己开发一套脚本,用于以固定的频率获取测试客户端和服务器的vmstat和top输出、grinder的log,并从中截取有用信息保存,用于事后分析。
每次测试运行完以后,肯定会增加很多数据,需要考虑本次执行对数据量的影响,如果数据量的变化对后续测试会有影响,则需要清理数据。
测试分析
4、lr和jmeter有什么区别
1).安装:Jmeter安装方便快捷,占据空间小,无需破解,无需费用;
LR安装繁琐,耗时长,对环境要求严格,占据空间大,安装包为1G多,需 要破解,正版价格昂贵, LR11仅支持IE8~9,LR12无法破解,支持IE11及以上;
2).IP欺骗功能:IP欺骗是指在一台PC机上可以模拟多个IP地址分配给并发用户,能够更加真实的模拟实际的应用环境;
Jmeter没有IP欺骗功能,LR有IP欺骗功能
3).录制脚本:Jmeter支持代理录制脚本,但并不好用,需要装IE代理,也可用badboy录制; LR支持录制脚本,方便使用;
4).压力机资源情况:LR体积大,消耗的资源比Jmeter高,高并发情况下,LR可能出现压力机资源瓶颈;
5).静态资源下载:LR默认下载静态资源,若不下载静载资源需要手动配置;
Jmeter默认不下载静态资源,若二者均使用默认设置,性能测试结果差异会较大;
6).协议:Jmeter只支持WEB、FTP和数据库方面的性能测试;
LR支持协议多,能覆盖绝大多数应用,功能强大;
7).网速模拟:Jmeter不支持网速模拟,LR支持网速模拟;
8).扩展性:Jmeter是开源的,可根据需要更改源代码,LR可附加函数库;
9).报告:Jmeter报表分析数据较少,LR报告监控的性能指标丰富,界面美观;
5、Nginx和Tomcat是进程模式还是线程模式
Nginx:多进程. 一个主进程管理多个worker子进程
Tomcat:单进程多线程
Tomcat的运行模式有几种?简单讲一下模式之间的区别
Tomcat的运行模式有3种, BIO、NIO和APR。我们公司用的NIO
BIO
一个线程处理一个请求。缺点:并发量高时,线程数较多,浪费资源。Tomcat7或以下,在Linux系统中默认使用这种方式。
NIO
利用Java的异步IO处理,可以通过少量的线程处理大量的请求。Tomcat8在Linux系统中默认使用这种方式。
Tomcat7必须server.xml里的Connector节点配置来启动:
<Connector port="8080" protocol="org.apache.coyote.http11.Http11NioProtocol" connectionTimeout="20000" redirectPort="8443"/>
APR
即Apache Portable Runtime,从操作系统层面解决io阻塞问题。Tomcat7或Tomcat8在Win7或以上的系统中启动默认使用这种方式。
6、简单说一下你们公司的系统架构(明日补充)
1)静态文件、css样式、文件模板放在了cdn上
2)Nginx负载均衡
3)
7、Nginx怎么获取请求的真实ip
location 中配置 proxy_set_header X-Forwarded-For 然后服务端代码 request.getHeader就可以获得真实ip
server {
listen 80;
server_name www.wenki.info; #要访问的域名
charset utf8;
location / {
proxy_pass http://server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
8、全链路压测做过吗?怎么做的?
做过,全链路我们在正式环境做的
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跟进核心的接口和依赖,每周大家碰一下同步下总体的进度
什么情况下回出现Full GC,什么情况下会出现Young GC
- 对象优先在新生代Eden区中分配,如果Eden区没有足够的空间时,就会触发一次young gc
- Full gc的触发条件有多个,FULL GC的时候会STOP THE WORD。
① 在执行Young gc之前,JVM会进行空间分配担保——如果老年代的连续空间小于新生代对象的总大小(或历次晋升的平均大小),则触发一次full gc。
② 显式调用System.gc()方法时;
③ 方法去空间不足
④ 大对象直接进入老年代,从年轻代晋升上来的老对象,尝试在老年代分配内存时,但是老年代内存空间不够;
9、你们公司的jvm垃圾回收用的那种方法
答: copying ( 一般存活区使用这个算法)
问:为什么用copying?
答:第一个好处:没有内存碎片的好处;第二:大小相等,位置互换,降低存活对象到老年区的评率,降低fullGC的频率;
问:老年区你们用什么算法?
答:标记-整理,Mark-Compact
问:原理说一下,结合了标记-清楚和copying两个的特点,优点有两个,第一:可以使用全部的内存,第二:对内存做了压缩、排序,减少了内存碎片
10、jvm内存分配比例是多少
整个堆大小=年轻代大小 + 年老代大小 + 持丽代大小。持丽代
一般固定大小为 64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置年轻代大小为整个堆癿 3/8。现在一般都是年轻代3/1,老年代2/3,持久带分别占用年轻代的1/10
11、如果现在让你做10000并发,你怎么做的?
1)熟悉应用
了解了应用架构,我们才能知道,我们需要模拟的是:一般的html静态文件请求、一般的servlet和jsp请求、AJAX请求、还是远程调用请求等。
我们必须了解:应用的功能逻辑
2)明确测试需求
一般我们得到的任务类似:100万uv(每天使用应用的人数)
但是,我们了解的是吞吐量、响应时间等指标,所以我们要根据自己的经验转换成一系列的指标。
100万uv的活动时间分布,然后根据28原则算出tps,当然最后的结果还是要和整个team讨论一下
3)测试准备
客户端机器准备、测试数据准备、测试脚本准备、服务器端环境准备
客户端机器:执行压测脚本机器,首先客户机资源要足够,如果瓶颈在客户机,无法评估服务端
测试数据:例如订单商品扫描,那么首先我们需要造订单数据和商品数据
测试脚本准备:脚本准备好,并先调试成功
服务端准备:最优:软、硬件与线上一致,如果条件不允许,可以先压单机,测出指标,然后增加一台应用服务器做集群,测出指标,按照增加时的损耗,换算出线上环境支持的并发指标
4)测试执行
客户端的系统资源(cpu、io、memory)情况
服务端的系统资源(cpu、io、memory)情况
服务器的jvm运行情况
服务端的应用情况,看是否有异常
响应时间、吞吐量等指标
5)测试分析
根据测试保存的数据和运行中的监控数据发现问题
常见的问题有:内存问题、有限资源竞争问题、软件配置
内存可以使用:jmap,jhat,jstat,可以得到内存快照,得到堆内存的详细信息,或者使用met
共享资源竞争问题:一个共享资源在一个时间点上,只能被一个线程获得,其他线程必须等待,这就容易造成很多线程的timedwait状态。通过jprofiler工具,能够得到线程快照,并分析改进方法,也可以使用jstack打印栈信息进行分析
6)总结,输出测试报告
12、设计性能测试方案需要考虑哪些问题?
时间成本、人力成本、环境&脚本可复用性、实现难度
13、压测中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、系统架构
比如是否有缓存服务,缓存服务器配置,缓存命中率、缓存穿透以及缓存过期等,都会影响到测试结果。
14、测试环境和生产环境服务器配比肯定不一样?怎么保证性能测试的数据正确性?
-版本一致性
包括操作系统、数据库、中间件的版本,jdk、被测系统的版本。
-配置一致性
系统(操作系统/数据库/中间件/被测试系统)参数的配置一致,这些系统参数的配置有可能对系统造成巨大的影响。所以,除了保证测试环境与真实环境所使用的软件版本一致,也要关注其参数的配置是否一致。
然后在单台服务器上获得具体的性能指标,每台服务器能够承受500用户并发,平均TPS为60,响应时间为2秒,接着,添加负载均衡策略,再次测试负载策略下的数据损耗。得出数据后添加1台负载均衡服务器,测试在两台服务器下每台服务器的性能指标,以此类推
15、如何准备测试数据?如何防止数据污染?
生产数据备份、数据隔离、测试数据落入影子库、挡板、mock都可以
16、线程和进程的区别?
进程和线程都是一个时间段的描述,是CPU工作时间段的描述,不过是颗粒大小不同;
(1)进程是资源的分配和调度的一个独立单元,而线程是CPU调度的基本单元
(2)同一个进程中可以包括多个线程,并且线程共享整个进程的资源(寄存器、堆栈、上下文),一个进行至少包括一个线程。
(3)进程的创建调用fork或者vfork,而线程的创建调用pthread_create,进程结束后它拥有的所有线程都将销毁,而线程的结束不会影响同个进程中的其他线程的结束
(4)线程是轻两级的进程,它的创建和销毁所需要的时间比进程小很多,所有操作系统中的执行功能都是创建线程去完成的
(5)线程中执行时一般都要进行同步和互斥,因为他们共享同一进程的所有资源
(6)线程有自己的私有属性TCB,线程id,寄存器、硬件上下文,而进程也有自己的私有属性进程控制块PCB,这些私有属性是不被共享的,用来标示一个进程或一个线程的标志
17、如果发现瓶颈,你怎么分析?
查找瓶颈时按以下顺序,由易到难:服务器硬件瓶颈-〉网络瓶颈(对局域网,可以不考虑)-〉服务器操作系统瓶颈(参数配置)-〉中间件瓶颈(参数配置,数据库,web服务器等)-〉应用瓶颈(SQL语句、数据库设计、业务逻辑、算法等)
19、简单说几个Nginx、Tomcat中的配置参数,参数是干什么的?
Nginx--配置文件名 nginx.conf
server_name:配置主机域名
Nginx:upstream,设置web服务器的ip、端口和权重
worker_connections:定义每个进程的最大连接数
keepalive_timeout :设置客户端连接保存活动的超时时间
woker_precess :设置Nginx 启动多少个工作进程的数量
Tomcat--配置文件名 server.xml
Connector port :配置端口
URIEncoding:解决中文乱码
connectionTimeout: 连接超时时间(毫秒)
acceptCoumt="300" :指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理
maxThreads="300" :允许最大的线程数
maxProcessors="1000" :同时最大的处理线程数,如果系统中已经有这个数字的线程,那么,更多的连接请求将进入排队(ACCEPT COUNT)
minProcessors="5" :最小的处理线程数,即使没有任何HTTP请求,TOMCAT也保持至少这么多线程以等待处理
JAVA_OPTS --Xms--Xxs :配置启动时初始内存、最大内存,一般配置一样
session-timeout:session超时时间
20、Redis支持哪些数据类型?
String字符串、Hash(哈希)、List(列表)、Set(集合) zset(sorted set:有序集合)
21、说几个你工作中调优过的几个实例
22、如果现在在压测的时候cpu高,你怎么分析
23、你做性能测试一般遇到哪些类型的性能问题
A. OOM内存不足:1\. 不断地申请对象,后面对象申请不到内存资源(调整对象大小或扩容);2\. 持续地启线程,申请栈资源,造成内存不足(调整每个线程的堆栈大小Xss=256或者扩容)3\. 频繁地触发FULL GC,造成OOM(调整新生代GC大小或降低GC的执行次数)
B. 内存泄露:对象和线程等一直不释放资源,导致内存泄露(释放不必要的引用、使用对象缓存池、采用合理的缓存失效算法、合理使用SoftReference和WeekReference:SoftReference的对象会在内存不够用的时候回收,WeekReference的对象会在Full GC的时候回收)
C. 线程死锁:两个线程占用不同的资源不释放,造成线程死锁(规定资源执行顺序,但是也会造成锁饥饿,解决办法是减短锁释放时间)
D. 锁争用:很多线程竞争互斥资源,但资源有限, 造成其他线程都处于等待状态(使用非阻塞队列算法、拆分锁,去除读写操作的互斥,尽可能少用锁)
E. 堆栈资源不足:线程嵌套式地申请堆栈资源,导致堆栈资源不足(调整堆栈大小)
F. Java进程消耗CPU过高:1\. us高:执行线程不需要任何挂起动作,且一直执行,导致CPU 没有机会去调度执行其他的线程。(增加Thread.sleep,以释放CPU 的执行权,降低CPU 的消耗);2\. sy高:线程的运行状态要经常切换(降低线程数)
G. 文件IO消耗严重:多个线程在写进行大量的数据到同一文件,导致文件很快变得很大,从而写入速度越来越慢,并造成各线程激烈争抢文件锁。(异步写文件、批量读写、限流、限制文件大小)
H. 网络IO消耗严重: 同时需要发送或接收的包太多。(限流,限流通常是限制发送packet的频率,从而在网络IO消耗可接受的情况下来发送packget。)
24、线程的状态有几种?
在Java当中,线程通常都有五种状态,创建、就绪、运行、阻塞和死亡。
1)第一是创建状态。在生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态;
2)第二是就绪状态。当调用了线程对象的start方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。在线程运行之后,从等待或者睡眠中回来之后,也会处于就绪状态
3)第三是运行状态。线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码。
4)第四是阻塞状态。线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend等方法都可以导致线程阻塞。
5)第五是死亡状态。如果一个线程的run方法执行结束,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪状态。
java基础
1、equals与==的区别
使用==比较原生类型如:boolean、int、char等等,使用equals()比较对象。
1)==是判断两个变量或实例是不是指向同一个内存空间。 equals是判断两个变量或实例所指向的内存空间的值是不是相同。
2)==是指对内存地址进行比较。 equals()是对字符串的内容进行比较。
3)==指引用是否相同。 equals()指的是值是否相同
2、成员变量与局部变量的区别有那些?
① 成员变量是输入类的,局部变量是在方法中定义的变量或是方法的参数
② 成员变量可以被public等修饰,局部变量不行
③ 成员变量是属于对象的一部分,对象存在于堆内存中;局部变量存在于栈内存中
④ 成员变量值声明不赋值的话,会自动以类型的默认值赋值;局部变量不会自动赋值;
⑤ 成员变量随着对象的创建而存在;局部变量随着方法的调用也消失
3、.讲讲对static的理解?J
静态变量:
① 一个类只有一份被类的所有实例共享
② 能在没有生成任何类的实例时就被访问到
③ 直接使用类名来访问
静态方法:
① 可以在没有任何实例时调用
② 不能在static方法内部访问非static成员
③ 不能被重写
4、 重写和重载的区别?
重载规则:必须具有不同的参数列表; 可以有不同的返回类型;可以有不同的访问修饰符;可以抛出不同的异常。
重写规则:参数列表必须完全与被重写的方法相同,否则不能称其为重写而是重载;返回类型必须一直与被重写的方法相同,否则不能称其为重写而是重载;
访问修饰符的限制一定要大于等于被重写方法的访问修饰符;
重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常,譬如父类方法声明了一个检查异常 IOException,在重写这个方法时就不能抛出 Exception,只能抛出 IOException 的子类异常,可以抛出非检查异常。
15、Reader和InputStream区别?
都是抽象类,Reader用于读取字符流(char或String),InputStream用于读取字节流(byte数组)
5、抽象类和interface的区别
① 抽象类可以有构造方法,接口中不能有构造方法
② 抽象类中可以有普通成员变量,接口中没有普通成员变量
③ 抽象类中可以包含非抽象普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的方法。
④ 一个类可以实现多个接口,用逗号隔开,但只能继承一个抽象类,接口不可以实现接口,但可以继承接口,并且可以继承多个接口,用逗号隔开。
⑤ 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问权限可以是任意的,但接口中定义的变量只能是 public static final 类型的,并且默认即为 public static final 类型
6、Java支持多继承么?如果不支持,如何实现?
不支持,Java不支持多继承。每个类都只能继承一个类,实现多继承有两种方式,一是接口,而是内部类
7、构造器(constructor)是否可被重写(override)?
构造方法是不能被子类重写的,但是构造方法可以重载
简单的讲,就是说一个类可以有多个构造方法。
8、Array和ArrayList有什么区别?
可以将 ArrayList想象成一种“会自动扩增容量的Array”。
① Array类型的变量在声明的同时必须进行实例化(至少得初始化数组的大小),而ArrayList可以只是先声明
② Array对象的初始化必须只定指定大小,且创建后的数组大小是固定的,ArrayList的大小可以动态指定,其大小可以在初始化时指定,也可以不指定,也就是说该对象的空间可以任意增加
9、简述Java中实现多态的机制是什么?
答:重载(overloading)、重写(overriding)
1.重载(overloading):是一个类中多态的表现,比如一个类中定义多个同名的方法,但它们具有不同的参数或不同参数类型都称之为重载。
2.重写(overriding):子类定义一个方法和父类的方法名称参数都相同,那么父类的方法被重写。
10、.简述java中super()和this()、super和this的区别?
答:①.super()和this()区别:
super():调用父类无形参的构造方法;
super(形参):调用父类中某个带形参的构造方法;
this(形参):调用本类中另一种形式的构造方法
注意:放在方法的首行;
② .super和this的区别:
super.父类的成员变量;
super.父类的方法;
super:当子类中的成员变量、方法和父类的相同时,实现调用父类的成员变量和方法;
this:代表当前的对象;
使用的地方:若函数的形参和成员变量同名时,需要用this.成员变量名
11、Java中有哪些基本数据类型?String是基本数据类型吗?String类是否能够继承?
答:
①.java定义了4中类8种基本类型:
整型:byte、short、int、long
浮点型:float、double
布尔型: boolean
字符型: char
②.String不是基本数据类型,String属于引用类型。
③.String类是一个final类,因此不能被继承。
12、.Integer和int的区别?
答:Integer是一个封装int类型的封装类,默认值为null,int是Java中8中数据类型之一,默认值为0.
13、String s=new String(“xyz”)创建了几个对象?
答:创建2个String对象,一个是=null的s,一个是=“xyz”的string。
14、Java中堆和栈有什么不同?
每个线程都有自己的栈内存,用于存储本地变量,方法参数和栈调用,一个线程中存储的变量对其它线程是不可见的。而堆是所有线程共享的一片公用内存区域。
数据库
1、数据库的乐观锁和悲观锁是什么?
确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性,乐观锁和悲观锁是并发控制主要采用的技术手段。
- 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
在查询完数据的时候就把事务锁起来,直到提交事务
实现方式:使用数据库中的锁机制 - 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
在修改数据的时候把事务锁起来,通过version的方式来进行锁定
实现方式:使用version版本或者时间戳
2、varchar和char的区别
Char是一种固定长度的类型,varchar是一种可变长度的类型