在工作中遇到同时向多个服务请求的场景,在此将自己的研究过程记录一下
模拟三个请求requestA、requestB、requestC:
@Servicepublic classParallelService {publicString requestA() {try{
TimeUnit.MILLISECONDS.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}return "A";
}publicString requestB() {try{
TimeUnit.MILLISECONDS.sleep(2000);
}catch(InterruptedException e) {
e.printStackTrace();
}return "B";
}publicString requestC() {try{
TimeUnit.MILLISECONDS.sleep(2500);
}catch(InterruptedException e) {
e.printStackTrace();
}return "C";
}
}
建立一个测试类ParallelController,request方法用来模拟请求不同服务:
@Slf4j
@RestController
@RequestMapping("parallel")public classParallelController {
@AutowiredprivateParallelService parallelService;private String request(intindex) {if (index == 0) {returnparallelService.requestA();
}if (index == 1) {returnparallelService.requestB();
}if (index == 2) {returnparallelService.requestC();
}return null;
}
}
接下来,就开始尝试不同的请求方式:
串行(传统方式)
/**
* 串行(传统请求)*/@GetMapping("/test1")public voidtest1() {long start =System.currentTimeMillis();
List list = new ArrayList<>();
IntStream.range(0, 3).forEach(index ->{
list.add(request(index));
});
log.info("串行,响应结果:{},响应时长:{}", Arrays.toString(list.toArray()), System.currentTimeMillis() -start);
}
使用JMeter进行压测,压测参数如下:

创建30个线程,在20秒之内循环请求,结果:


从控制台结果可以看到:请求是顺序执行,所以结果都是[A, B, C],响应时长也很稳定
从JMeter结果可以看到:平均响应时长:5805ms,最小响应时长:5507ms,最大响应时长:6497ms,TPS:5.0/sec
并行
并行采用的是java8的语法流,利用多核处理器同时去请求,当获取所有请求结果后才终止
/**
* 并行请求*/@GetMapping("/test2")public voidtest2() {long start =System.currentTimeMillis();
List list = new ArrayList<>();
IntStream.range(0, 3).parallel().forEach(index ->{
list.add(request(index));
});
log.info("java8并行,响应结果:{},响应时长:{}", Arrays.toString(list.toArray()), System.currentTimeMillis() -start);
}
使用jmeter同样的参数压测,结果:


从控制台结果可以看到:请求是独立执行没有顺序,所以结果是不确定的,响应时长很不稳定
从JMeter结果可以看到:平均响应时长:16648ms,最小响应时长:2513ms,最大响应时长:36052ms,TPS:1.3/sec
多线程
多线程的处理方式是,创建多个线程,分别去请求,当获取所有请求结果后才终止
/**
* 多线程请求*/@GetMapping("/test3")public voidtest3() {long start =System.currentTimeMillis();
List list = new ArrayList<>();
List> futureList = new ArrayList<>();
ExecutorService executor= Executors.newFixedThreadPool(3); //开启3个线程
IntStream.range(0, 3).forEach(index ->{
Future task = executor.submit(() ->request(index));
futureList.add(task);
});for (Futurefuture : futureList) {try{//如果任务执行完成,future.get()方法会返回Callable任务的执行结果。//future.get()方法会产生阻塞,所有线程都阻塞在这里,当获取到一个结果后,才执行下一个
list.add(future.get());
}catch(Exception e) {
log.error(e.getMessage(), e);
}
}//停止接收新任务,原来的任务继续执行
executor.shutdown();
log.info("多线程,响应结果:{},响应时长:{}", Arrays.toString(list.toArray()), System.currentTimeMillis() -start);
}


从控制台结果可以看到:请求是顺序执行的,结果都是[A, B, C],响应时长比较稳定
从JMeter结果可以看到:平均响应时长:2505ms,最小响应时长:2503ms,最大响应时长:2519,TPS:11.4/sec
结论:
1、串行处理多请求,代码很简单,响应时长是每个请求时长的总和,很稳定但是效率不高
2、使用java8并行处理,代码很简单,响应时长很不稳定,效率也不高,不建议使用
3、使用多线程处理时,代码复杂,响应时长为单个请求中时长最长的那个,效率很高,推荐使用