**高并发、微服务 、性能调优实战案例100讲，所有案例均源于个人工作实战，均配合代码落地**

加我微信：itsoku，所有案例均提供在线答疑。

# 手撸一个接口性能压测工具类

## 常用的好用的压测工具

1. Apache服务器安装目录的 ab.exe
2. Jmeter
3. LoadRunner

## 为什么要自己实现一个压测工具？

高并发有很多知识点，工具类（如：线程池、JUC四个常用工具类【CountDownLatch、CyclicBarrier、Semaphore、ExChange】等），但是很多同学，学了之后不知道如何使用，主要是缺少实战的场景，所以我在课程中，通过不同的场景案例，带大家去实战演练，才能深入掌握这些知识点，然后才能够灵活地去解决业务问题。

## 本文目标

带大家手写一个接口性能压测工具类，能够加深对下面3个知识点的理解，同时可以得到一个常用的压测工具类，方便自己或他人使用。

## 涉及的知识点

1. 线程池（ThreadPoolExecutor）
2. CountDownLatch
3. AtomicInteger

## 要实现的功能：写一个通用的压测工具类

### 类名

```java
LoadRunnerUtils
```

### 类中定义一个通用的压测方法

方法定义如下，提供3个参数，可以对第3个参数需要执行的业务进行压测，最终将压测的结果返回。

```java
/**
   * 对 command 执行压测
   *
   * @param requests    总请求数
   * @param concurrency 并发数量
   * @param command     需要执行的压测代码
   * @param <T>
   * @return 压测结果 {@link LoadRunnerResult}
   * @throws InterruptedException
   */
public static <T> LoadRunnerResult run(int requests, int concurrency, Runnable command) 
```

### 方法返回压测结果（LoadRunnerResult）

LoadRunnerResult 包含了压测结果，定义如下，主要有下面这些指标

```java
public static class LoadRunnerResult {
    // 请求总数
    private int requests;
    // 并发量
    private int concurrency;
    // 成功请求数
    private int successRequests;
    // 失败请求数
    private int failRequests;
    // 请求总耗时(ms)
    private int timeTakenForTests;
    // 每秒请求数（吞吐量）
    private float requestsPerSecond;
    // 每个请求平均耗时(ms)
    private float timePerRequest;
    // 最快的请求耗时(ms)
    private float fastestCostTime;
    // 最慢的请求耗时(ms)
    private float slowestCostTime;
}
```

## 压测工具类源码

```java
com.itsoku.lesson003.utils.LoadRunnerUtils
```

完整源码加我微信：itsoku，获取。



## 2个测试案例，先带大家看效果

### 案例1：总请求1000个，并发100，压测一个简单的接口

接口代码如下，test1接口，很简单，没有任何逻辑，这个接口效率很高

```java
@GetMapping("/test1")
public String test1() {
    log.info("test1");
    return "ok";
}
```

#### 对应的压测用例代码

LoadRunnerUtilsTest 中的 test1方法

```java
@Test
public void test1() throws InterruptedException {
    //需要压测的接口地址，这里我们压测test1接口
    //压测参数，总请求数量1000，并发100
    int requests = 1000;
    int concurrency = 100;
    String url = "http://localhost:8080/test1";
    System.out.println(String.format("压测接口:%s", url));
    RestTemplate restTemplate = new RestTemplate();

    //调用压测工具类开始压测
    LoadRunnerUtils.LoadRunnerResult loadRunnerResult = LoadRunnerUtils.run(requests, concurrency, () -> {
        restTemplate.getForObject(url, String.class);
    });

    //输出压测结果
    print(loadRunnerResult);
}
```

#### 运行test1用例，效果如下

```html
压测接口:http://localhost:8080/test1
11:47:56 - 压测开始......
11:47:57 - 压测结束，总耗时(ms):601

压测结果如下：
==============================
请求总数: 1000
并发量: 100
成功请求数: 1000
失败请求数: 0
请求总耗时(ms): 601
每秒请求数(吞吐量): 1663.8936
每个请求平均耗时(ms): 0.601
最快的请求耗时(ms): 0.0
最慢的请求耗时(ms): 565.0
```



### 案例2：总请求1000个，并发100，压测一个耗时的接口

接口代码如下，test2接口，内部休眠了100毫秒，用于模拟业务耗时操作

```java
@GetMapping("/test2")
public String test2() throws InterruptedException {
    //接口中休眠100毫秒，用来模拟业务操作
    TimeUnit.MILLISECONDS.sleep(100);
    return "ok";
}
```

#### 对应的压测用例代码

LoadRunnerUtilsTest 中的 test2方法

```java
@Test
public void test2() throws InterruptedException {
    //需要压测的接口地址，这里我们压测test2接口
    //压测参数，总请求数量10000，并发100
    int requests = 1000;
    int concurrency = 100;
    String url = "http://localhost:8080/test2";
    System.out.println(String.format("压测接口:%s", url));
    RestTemplate restTemplate = new RestTemplate();

    //调用压测工具类开始压测
    LoadRunnerUtils.LoadRunnerResult loadRunnerResult = LoadRunnerUtils.run(requests, concurrency, () -> {
        restTemplate.getForObject(url, String.class);
    });

    //输出压测结果
    print(loadRunnerResult);
}
```

#### 运行test2用例，效果如下

```html
压测接口:http://localhost:8080/test2
11:48:20 - 压测开始......
11:48:22 - 压测结束，总耗时(ms):1231

压测结果如下：
==============================
请求总数: 1000
并发量: 100
成功请求数: 1000
失败请求数: 0
请求总耗时(ms): 1231
每秒请求数(吞吐量): 812.34766
每个请求平均耗时(ms): 1.231
最快的请求耗时(ms): 100.0
最慢的请求耗时(ms): 281.0
==============================
```



## 压测工具类,源码解析

```java
com.itsoku.lesson003.utils.LoadRunnerUtils
```



## 源码获取

加我个人微信：<span style='color:red;font-weight:bold'>itsoku</span> 获取



## 课程部分大纲，连载中。。。。

以下课程均来源于个人多年的实战，均提供原理讲解 && 源码落地

```java
1. 分片上传实战
2. 通用并发处理工具类实战
3. 实现接口性能压测工具类
4. Semaphore实现接口限流实战
5. 并行查询，优化接口响应速度实战
6. 使用TransactionTemplate优化接口性能
7. 手写线程池管理器，管理&监控所有线程池
8. 使用SpringBoot实现动态Job管理功能
9. 通用的Excel导出功能实战
10. 通用的幂等性工具类实战
11. 通用的防并发处理工具类（解决并发修改db数据出错问题）
12. 接口返回值通用设计
13. 接口太多，各种dto、vo不计其数，如何命名？
14. 一个业务太复杂了，方法太多，如何传参？
15. 如何统计接口耗时？
16. AOP实战接口日志打印功能
17. AOP实现业务操作日志记录功能
18. AOP实现MyBatis分页功能
19. SpringBoot读写分离实战
20. MQ专题：事务消息实战（防止消息丢失）
21. MQ专题：消息幂等消费通用方案实战
22. MQ专题：延迟消息通用方案实战
23. MQ专题：顺序消息通用方案实战
24. 分布式事务：使用事务消息实现事务最终一致性
25. 分布式事务：通用的TCC分布式事务生产级代码落地实战
26. 分布式锁案例实战
27. 微服务中如何传递上下文？实战
28. 微服务链路日志追踪实战（原理&代码落地）
29. SpringBoot实现租户数据隔离
30. MyBatis进阶：封装MyBatis，实现通用的无SQL版CRUD功能，架构师必备
31. MyBatis进阶：自己实现通用分表功能，架构师必备
32. MyBatis进阶：实现多租户隔离ORM框架
33. SpringBoot中实现自动监听PO的变化，自动生成表结构
34. 分布式专题：其他实战课程等
35. 性能调优：如何排查死锁？
36. 性能调优：如何排查内存溢出？
37. 性能调优：CPU被打满，如何排查？
38. 性能调优：生产代码没生效，如何定位？
39. 性能调优：接口太慢，如何定位？
40. 性能调优：如何查看生产上接口的入参和返回值？
41. 性能调优：远程debug
42. 生产上出现了各种故障，如何定位？
43. 其他等各种实战案例。。。
。。。
```

