一、性能測试的概念

        性能測试是通过自己主动化的測试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行測试。负载測试和压力測试都属于性能測试,两者能够结合进行。

通过负载測试,确定在各种工作负载下系统的性能,目标是当负载逐渐添加时,測试系统各项性能指标的变化情况。压力測试时通过确定一个系统的瓶颈或者不能接受的

性能点,来获取系统能提供的最大服务级别的測试。

性能測试主要包括负载測试、强度測试、容量測试。

二、性能測试的指标

        webserver:
            Avg Rps: 平均每秒的响应次数 = 总请求数 /秒数;

            Avg time to last byte per terstion(mstes): 平均每秒业务脚本的迭代次数;

            Successful Rounds: 成功的请求;

            Failed Rounds: 失败的请求;

            Successful Hits: 成功的点击次数;

            Failed Hits: 失败的点击次数;

            Hits Per Second: 每秒点击次数;

            Successful Hits Per Second:每秒成功的点击次数;

            Failed Hits Per Second: 每秒失败的点击次数;

            Attempted Connections: 尝试连接数;

            Throughput: 吞吐率;

        数据库server:
            User Connections: 用户连接数,也就是数据库的连接数量;

            Number of Deadlocks: 数据库死锁;

            Butter Cache Hit: 数据库Cache 的命中情况;


三、性能測试的流程

        1.明白性能測试需求;

        2.制定性能測试方案;

           2.1.測试范围

           2.2.入口标准

           2.3.出口标准

           2.4.測试策略(測试环境指标、存量数据、业务场景、測试通过标准等)

           2.5.測试风险

           2.6.測试资源         

        3.设计性能測试用例;

        4.运行性能測试用例;

        5.分析性能測试结果;

        6.生成性能測试报告;


四、性能測试的工具--JMeter

        为什么是JMeter而不是LoadRunner呢  1.更少的投入,针对有限的測试成本;  2.开源工具的可定制性无可比拟;  3.通过社区得到最大程度的支持。

        JMeter是Apache组织开发的基于Java的压力測试工具。最初被设计用于web应用的測试,后来扩展到其它測试领域。

可用于測试静态和动态资源,如文件、Java服务

程序、Java对象、数据库等。JMeter能够相应用程序做功能/回归測试,通过创建带有断言的脚本来验证被測程序返回了期望的结果。并且为了保证最大限度的灵活性。

JMeter同意使用正則表達式创建断言。

        

五、JMeter的特性

        1.支持对多种服务类型进行測试;

        2.支持通过录制/回訪方式获取測试脚本;

        3.具备高可移植性,是纯Java 程序;

        4.採用多线程框架。同意通过多个线程并发取样及通过独立的线程组对不同的功能同一时候取样;

        5.精心设计的GUI支持快速用户操作和精确计时;

        6.支持缓存和离线的方式分析/回放測试结果;

        7.高扩展性;

六、JMeter经常使用測试元件

1.线程组

    用来管理运行性能測试所需的JMeter线程。

    a.能够设置线程数量

    b.设置线程启动周期

    c.设置运行測试脚本的循环次数

2.控制器

    JMeter有两种类型的控制器:採样器和逻辑控制器。

    採样器被用来向server发送请求。

JMeter採样器包括:FTP Request、HTTP Request、JDBC Request等。

    逻辑控制器用来控制JMeter的測试逻辑,特别是何时发送请求。

3.监听器

    监听器提供了对JMeter在測试期间收集到的信息的訪问方法。

4.定时器

    JMeter线程在发送请求之间没有间歇,通过加入定时器,设定请求之间应该间隔的时间。

5.断言

    能够使用断言来检查从server获得的响应内容。

6.配置元件

    配置元件与採样器紧密关联。尽管配置元件并不发送请求,但可加入或改动请求。

7.前置处理器

    会在採样器发出请求之前做一些操作。

8.后置处理器

    会在採样器发出请求之后做一些操作。

JMeter运行顺序:配置元件=》前置处理器=》定时器=》採样器=》后置处理器=》断言=》监听器

七、辅助測试工具开发

        以下的代码(工具:sqlexec)是一个用来向数据库(眼下支持Oracle、Mysql)插入測试数据的工具。支持多线程,可插入千万级别測试数据。

在兴许压測中会用到该

工具,工具开发尽量简单,一个工具仅仅完毕一个任务。同一时候不要反复制造轮子。

package d706;

/*
* sql处理
*/
public class Test_DB_Insert extends Thread{ public static String SQLTEXT = null; // 待处理的sql语句 private InputStream ins = null; // 用于读取配置文件
private Properties property = new Properties(); // 读取数据库配置文件 private String databaseType = null; // 数据库连接类型
private String driver = null; // 数据库驱动
private String url = null; // 数据库连接
private String uName = null; // 数据库登录username
private String pwd = null; // 数据库登录用户password private int numOfTestRecords; // 插入数据条数
private Connection con = null; // 连接数据库
private PreparedStatement statement = null; // 获取数据库操作对象 public Test_DB_Insert(String sql){
SQLTEXT = sql; // sql语句以參数的形式,在构造实例的时候传入
} private void init(){ // 初始化配置文件
try{
ins = new FileInputStream("./d706/dbconf.properties");
}catch(FileNotFoundException ffe){
ffe.printStackTrace();
}
try{
property.load(ins); //
}catch(IOException ie){
ie.printStackTrace();
}finally{ try{ if(ins != null) ins.close(); }catch(IOException ie){ ie.printStackTrace(); } } databaseType = property.getProperty("databasetype"); // 获取配置文件里设置的连接数据库类型 if("MYSQL".equals( databaseType.toUpperCase() )){ // 推断连接数据库类型
driver = property.getProperty("driver_mysql");
url = property.getProperty("url_mysql");
uName = property.getProperty("db_userName_mysql"); // 连接数据库的用户信息;
pwd = property.getProperty("db_pwd_mysql");
}else if("ORACLE".equals( databaseType.toUpperCase() )){
driver = property.getProperty("driver_oracle");
url = property.getProperty("url_oracle");
uName = property.getProperty("db_userName_oracle");
pwd = property.getProperty("db_pwd_oracle");
} } private synchronized void Insert_DB(){ try { try {
Class.forName( driver ); // 注冊驱动;
}catch(ClassNotFoundException cf){
cf.printStackTrace();
} con = DriverManager.getConnection(url,uName, pwd); // 获取数据库连接 con.setAutoCommit(false); // 关闭事务自己主动提交 SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:SS"); // 记录运行时间
TimeZone t = sdf.getTimeZone();
t.setRawOffset(0);
sdf.setTimeZone(t);
Long startTime = System.currentTimeMillis();
System.out.println("插入数据操作開始..."); statement = con.prepareStatement(SQLTEXT); //创建数据库操作对象 /*
* "INSERT INTO TEST_DB(name,sex,nickname,test1,test2,test3,test4," +
"test5,test6,test7,test8,test9,test10,test11,test12,test13,test14," +
"test15,test16,test17,test18,test19,test20,test21,test22,test23," +
"test24,test25,test26,test27,test28,test29,test30,test31,test32," +
"test33,test34,test35,test36,test37,test38,test39,test40,test41," +
"test42) VALUES(?,? ,? ,?,?,?,?,?,? ,?,?,?,?,?,?,? ,?,? ,?,? ,?,?,?,?,? ," +
"? ,? ,?,? ,?,?,?,?,?,? ,?,?,?,?,?,?,?,?,? ,? )"
*/ numOfTestRecords = 1000; //插入的測试数据量; for(int i = 0; i<numOfTestRecords; i++) { //循环
statement.setString(i + 1, "DBTest-" + i);
//statement.setString(2, "" + i%2); //0表示男 1表示女
statement.addBatch(); // 把一个SQL命令加入命令列表
//statement.executeUpdate(); //运行SQL;
}
statement.executeBatch(); //运行批量更新
con.commit();//语句运行完毕,提交事务
//int[] ref = statement.executeBatch();
//if(ref[numOfTestRecords-1] == 0){System.out.println("插入数据操作完毕");} // System.out.println("插入数据操作完毕");
Long endTime = System.currentTimeMillis();
System.out.println("插入"+numOfTestRecords+"条数据,"+"用时(时:分:秒:毫秒)" +
sdf.format(new Date(endTime - startTime))); // }catch(Exception e) {
System.out.println("异常: " + e.toString());
e.printStackTrace();
}finally{ if(statement != null){ // 关闭数据库操作对象
try{
statement.close();
}catch(SQLException se){
se.printStackTrace();
}
} if(con != null){ // 关闭数据库连接
try{
if(con.isClosed()){con.close();}
}catch(SQLException se){
se.printStackTrace();
}
}
}
} @Override
public void run() { // 类外调用 Test_DB_Insert ti = new Test_DB_Insert(SQLTEXT); // 构造实例
ti.init(); // 初始化
ti.Insert_DB(); // 运行插入数据
} // public static void main(String[] args){
//
// Test_DB_Insert ti = new Test_DB_Insert(SQLTEXT);
// ti.init(); //初始化
// ti.Insert_DB(); //运行插入数据
// } }

// 针对增删查改,可放到一个SQL处理类(Test_DB_crud)中,推断传入的SQL字符串,然后交给相应的方法去运行并在控制台输出结果。

在Test_DB_Control类

中仅仅是new一个Test_DB_crud类,形成了Test_DB_crud对Test_DB_Control的依赖关系。

package d706;
/*
*程序界面
*button事件
*/
public class Test_DB_gui extends JFrame implements ActionListener{ private static final long serialVersionUID = 1L; public static String SQLTEXT = null; // 界面输入的sql文本 private JScrollPane js = null; private JPanel jp1 = null; private JTextArea ta = null; private JButton jb = new JButton(); public Test_DB_gui(){ this.setTitle("sqlExecV1.0"); ta = new JTextArea();
ta.setText(""); js = new JScrollPane(ta);
jp1 = new JPanel();
jp1.setLayout(new BorderLayout());
jp1.add(js,BorderLayout.CENTER); jb = new JButton();
jb.setText("运行");
jb.addActionListener(this); // 加入监听 jp1.add(jb,BorderLayout.SOUTH); this.getContentPane().add(jp1); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setBounds(400,200,700,500);
this.setVisible(true); jb.addActionListener(new ActionListener(){ // button事件 public void actionPerformed(ActionEvent e) { // 匿名内部类的形式实现button事件 SQLTEXT = ta.getText(); // 将要运行的SQL设置成静态的 Multi_process mp = new Multi_process(SQLTEXT); // 在构造实例时,传入sql mp.run(); // 运行程序 //System.out.println( mp.SQLTEXT +"***"); // 控制台输出
}
});
} public void actionPerformed(ActionEvent e) {
// 实现 ActionListener 接口,须要实现的方法
} public void run() { // 运行方法 Test_DB_gui np = new Test_DB_gui();
System.out.println( np.getTitle() );
}
}
public class Multi_process {
/*
*多线程
*/
public static String SQLTEXT = null; // 待处理的sql语句 public Multi_process(String sql){
SQLTEXT = sql; // sql语句以參数的形式,在构造实例的时候传入
} public void run(){ Test_DB_Insert td1 = new Test_DB_Insert(SQLTEXT); // 创建实例
Test_DB_Insert td2 = new Test_DB_Insert(SQLTEXT);
Test_DB_Insert td3 = new Test_DB_Insert(SQLTEXT);
Test_DB_Insert td4 = new Test_DB_Insert(SQLTEXT); Thread t1 = td1; // 创建线程
Thread t2 = td2;
Thread t3 = td3;
Thread t4 = td4; t1.start(); // 启动线程
t2.start();
t3.start();
t4.start(); }
}
public class Test_Exec {
/*
* 程序入口
*/
public static void main(String[] args){
Test_DB_gui np = new Test_DB_gui();
np.run();
}
}

在Linux下运行,需打成jar包。通过shell脚本运行。以下是sqlexec的startup.sh运行脚本.

#!/bin/sh

#
#Author: bruce
#Version: sqlExecv1.0
#Date:2013-11-20
#
read -p "please input jar file path:" jarpath
java -jar "$jarpath" echo "running sqlExec."

注:

        今天突然想到測试数据的一个问题。即造出来的数据应该更接近真实。而不是都一样。所以想利用配置文件的方式,在配置文件里写好SQL,程序读取运行配置文件

并动态生成SQL。完毕插入測试数据。

这样就攻克了測试数据不够真实。可能影响測试结果的问题。---------2014年11月27日 

学习使用Jmeter做压力測试(一)--压力測试基本概念的更多相关文章

  1. 学习使用Jmeter做压力测试(一)--压力测试基本概念

    学习使用Jmeter做压力测试(一)--压力测试基本概念 一.性能测试的概念 性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试.负载测试和压力测试都属于性能测 ...

  2. 学习总结——JMeter做http接口功能测试

    JMeter对各种类型接口的测试 默认做接口测试前,已经给出明确的接口文档(如,http://test.nnzhp.cn/wiki/index.php?doc-view-59):本地配好了JMeter ...

  3. 学习总结——JMeter做http接口压力测试

    JMeter做http接口压力测试 测前准备 用JMeter做接口的压测非常方便,在压测之前我们需要考虑这几个方面: 场景设定 场景分单场景和混合场景.针对一个接口做压力测试就是单场景,针对一个流程做 ...

  4. (转)学习使用Jmeter做压力测试(三)--数据库测试

    数据库测试 JMeter可以做为Web服务器与浏览器之间的代理网关,以捕获浏览器的请求和Web服务器的响应,这样就可很容易的生成性能测试脚本. 根据脚本,JMeter可通过线程组来模拟真实用户对Web ...

  5. (转)学习使用Jmeter做压力测试(一)--压力测试基本概念

    一.性能测试的概念 性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试.负载测试和压力测试都属于性能测试,两者可以结合进行. 通过负载测试,确定在各种工作负载下 ...

  6. 【转】学习使用Jmeter做压力测试(三)--数据库测试

    JMeter可以做为Web服务器与浏览器之间的代理网关,以捕获浏览器的请求和Web服务器的响应,这样就可很容易的生成性能测试脚本.根据脚本,JMeter可通过线程组来模拟真实用户对Web服务器做压力测 ...

  7. 【转】学习使用Jmeter做压力测试(二)--压力测试的实施

    JMeter测试步骤: 1.建立测试计划 2.添加线程组 3.添加HTTP请求 4.增加监听器 5.执行测试计划 6.根据JMeter提供的报告分析结果 一.目标 测试访问目标服务器网站首页的每秒查询 ...

  8. 【转】学习使用Jmeter做压力测试(一)--压力测试基本概念

    一.性能测试的概念 性能测试是通过自动化的测试工具模拟多种正常峰值及异常负载条件来对系统的各项性能指标进行测试.负载测试和压力测试都属于性能测试,两者可以结合进行. 通过负载测试,确定在各种工作负载下 ...

  9. 学习总结——JMeter做WebService接口功能测试

    用JMeter作WebService接口功能测试(可以借助SoapUI来完成) SoapUI里面的操作: Wsdl文件或链接导入或添加到SoapUI打开待测请求:运行请求:取URL  SOAPActi ...

随机推荐

  1. python3-开发进阶Flask的基础(5)

    内容概要: SQLAlchemy flsak-sqlalchemy flask-script flask-migrate Flask的目录结构 一.SQLAlchemy 1.概述 SQLAlchemy ...

  2. 温故而知新---Java(一)

    学习不仅要学习新的东西,而且还要时不时的回过头捡漏... 本文参考老马说编程系列等文,在此推荐大家关注老马说编程系列文章 正文 基础知识 数据类型主要是为了对数据进行分类,方便理解和操作,在Java中 ...

  3. [转]Eclipse 项目转移到Android Studio遇到的问题

    1.Android Studio直接导入项目是copy原项目的,无法纳入代码管控 解决方案: 英文地址:http://developer.android.com/sdk/installing/migr ...

  4. [转]android中listview点击事件失效

    首先说明一下我想实现的功能: 点击某个item之后,让其颜色发生变化.如果变化网上有很多例子,我就不班门弄斧了.Listview之所以点击没有反应是因为上图中绿色部分(自己定义的一个继承BaseAda ...

  5. 使用Spring配置shiro时,自定义Realm中属性无法使用注解注入解决办法

    先来看问题    纠结了几个小时终于找到了问题所在,因为shiro的realm属于Filter,简单说就是初始化realm时,spring还未加载相关业务Bean,那么解决办法就是将springmvc ...

  6. mvc-单例多线程模式

    以spring mvc 为例子 spring mvc 的Controller类默认Scope是单例(singleton) 测试结果发现spring3中的controller默认是单例的,若是某个con ...

  7. Wide-range regulator delivers 12V, 3A output from 16 to 100V source

    Synchronous buck regulators offer high efficiency and are popular in applications in which available ...

  8. jdk1.8 foreach

    lambda 表达式效率非常低,测试代码可以看到大概3~5倍的差距 遍历Map的方式有很多,通常场景下我们需要的是遍历Map中的Key和Value,那么推荐使用的: public static voi ...

  9. 传输层TCPUDP 具体解释

    1.传输层存在的必要性 因为网络层的分组传输是不可靠的,无法了解数据到达终点的时间,无法了解数据未达终点的状态.因此有必要增强网络层提供服务的服务质量. 2.引入传输层的原因 面向连接的传输服务与面向 ...

  10. java 中文与unicode互转

    public class FontUtil { public static void main(String[] args) { System.out.println(chinaToUnicode(& ...