ContiPerf接口性能测试

1. 简介

ContiPerf是一个轻量级的测试工具,基于JUnit4开发,可用于接口级的性能测试,可以设置线程数和执行次数,通过限制最大时间和平均执行时间来进行效率测试。

2. 使用方法

  1. 添加依赖

    1
    2
    3
    4
    5
    6
    <dependency>
    <groupId>org.databene</groupId>
    <artifactId>contiperf</artifactId>
    <version>2.3.4</version>
    <scope>test</scope>
    </dependency>
  2. 创建Domain

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Entity
    @Table(name = "g_data_sources")
    @org.hibernate.annotations.Table(appliesTo = "g_data_sources", comment = "数据源信息表")
    public class DataSources extends BasePO {

    @Column(name = "name", columnDefinition = "varchar(30) NOT NULL comment '数据库名'")
    private String name;

    @Column(name = "url", columnDefinition = "varchar(100) NOT NULL comment '数据库ip'")
    private String url;

    @Column(name = "username", columnDefinition = "varchar(30) NOT NULL comment '数据库连接用户名'")
    private String username;

    @Column(name = "pwd", columnDefinition = "varchar(30) default '' comment '数据库连接密码'")
    private String pwd;
    //-----------------省略getter/setter方法 ---------------
    }
  3. 创建查询代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    @Repository("dataSourcesDaoImpl")
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public class DataSourcesDaoImpl {

    @PersistenceContext
    private EntityManager entityManager;

    public DataSources findById(Integer id) {
    List<DataSources> result = entityManager.createQuery("from DataSources e where e.id = " + id).getResultList();
    if (result != null && !result.isEmpty()) {
    return result.get(0);
    }
    return null;
    }
    }
  4. 创建测试类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Slf4j
    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class MybatisGeneratorApplicationTest {

    @Autowired
    private DataSourcesDaoImpl dataSourcesDao;

    @Rule
    public ContiPerfRule rule = new ContiPerfRule(); //重点

    @Test
    //10个线程 执行100次
    @PerfTest(invocations = 100, threads = 10) //重点
    //指定每次执行的最长时间/平均时间/总时间
    // @Required(max = 1200, average = 250, totalTime = 60000)
    public void test() {
    int id = (int) (Math.random() * 60);
    dataSourcesDao.findById(id);
    }
    }
  5. JUnit执行完毕,会在target/contiperf-report中有相关的执行结果

  1. 可以使用浏览器打开查看结果

    • Measured invocations: 请求次数
    • Thread Count: 线程数
    • Execution time:总执行时间
    • Throughput: 吞吐量,每秒效率 TPS
    • Min. latency: 最短响应时间
    • Average latency: 平均响应时间
    • Median: TP50响应时间
    • 90%: TP90响应时间,指在一个时间段内(如5分钟),统计该方法每次调用所消耗的时间,并将这些时间按从小到大的顺序进行排序,取第90%的那个值作为TP90 值;配置此监控指标对应的报警阀值后,需要保证在这个时间段内该方法所有调用的消耗时间至少有90%的值要小于此阀值,否则系统将会报警
    • Max latency: 最长响应时间

报告图片显示不出来,是源码中使用了google图表,需要在线!!并且源码中写死了cht=lxy,可以参考ContiPerf html报告

3. @PerfTest参数说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PerfTest {
//常用的就是这个参数 执行次数 与线程无关
int invocations() default 1;
/**
* 间隔时间 可以暂时不用 因为性能测试主要是测试并发
* @PerfTest(invocations = 300, threads = 2, duration = 100),如果执行方法300次的时候执行时间还没到100ms,则继续执行到满足执行时间等于100ms,如果执行到50次的时候已经100ms了,则会继续执行之100次。
* The number of milliseconds to run and repeat the test with the full number of configured threads -
* use this alternatively to {@link #invocations()}. When using a {@link #rampUp()}, the ramp-up times
* add to the duration.
* @see #duration()
*/
int duration() default -1;
/**
* 线程数
* The number of threads which concurrently invoke the test. The default value is 1.
*/
int threads() default 1;
/**
* The number of milliseconds to wait before each thread is added to the currently active threads.
* On {@link #duration()}-based tests, the total ramp-up time of rampUp * (threads - 1) is added to the
* configured duration.
*/
int rampUp() default 0;

/**
* The number of milliseconds to wait before the actual measurement and requirements monitoring is activated.
* Use this to exclude ramp-up times from measurement or wait some minutes before dynamic optimizations are
* applied (like code optimization or cache population).
*/
int warmUp() default 0;
/**
* Set this to true, if execution should stop with a failure message as soon as a configured {@link Required#max()}
* value is violated. Set it to false, if you are interested in performing a full measurement to get percentiles,
* throughput and more. The default value is false.
*/
boolean cancelOnViolation() default false;

/**
* The class of a {@link WaitTimer} implementation by which a wait time can be incurred between test invocations
*/
Class<? extends WaitTimer> timer() default None.class;
/**
* The parameters to initialize the {@link WaitTimer}.
* The meaning of the values is individual for the WaitTimer implementation.
*/
double[] timerParams() default {};
/**
* One ore more {@link Clock} classes to use for time measurement.
* The first one specified is the one relevant for requirements verification.
*/
Class<? extends Clock>[] clocks() default {};
}

4. @Required参数说明

参数 说明
@Required(throughput = 20) 要求每秒至少执行20个测试
@Required(average = 50) 要求平均执行时间不超过50ms
@Required(median = 45) 要求所有执行的50%不超过45ms
@Required(max = 2000) 要求没有测试超过2s
@Required(totalTime = 5000) 要求总的执行时间不超过5s
@Required(percentile90 = 3000) 要求90%的测试不超过3s
@Required(percentile95 = 5000) 要求95%的测试不超过5s
@Required(percentile99 = 10000) 要求99%的测试不超过10s