用jmeter测试SpringBoot异步controller
下面的示例是在 springboot 的 controller 中整合异步service调用的示例。
我们需要完成:
- 做一个提供测试测试数据的 controller。
- 创建一个异步的 service,远程调用上面的测试数据 controller。
- 创建一个 controller,调用多个异步 service,并等待异步调用全部完成,输出结果。
示例
1. 测试数据 controller
package com.example.demoasync; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class EmployeeDataController { private static Logger log = LoggerFactory.getLogger(EmployeeDataController.class); @RequestMapping(value = "/addresses", method = RequestMethod.GET) public List<String> getAddresses() { log.info("get addresses Start"); ArrayList<String> employeeAddresses = new ArrayList<String>(); employeeAddresses.add("addr1"); employeeAddresses.add("addr2"); employeeAddresses.add("addr3"); return employeeAddresses; } @RequestMapping(value = "/phones", method = RequestMethod.GET) public List<String> getPhoneNumbers() { log.info("get phones Start"); ArrayList<String> phoneNumberList = new ArrayList<String>(); phoneNumberList.add("100000"); phoneNumberList.add("200000"); return phoneNumberList; } @RequestMapping(value = "/names", method = RequestMethod.GET) public List<String> getEmployeeName() { log.info("get names Start"); List<String> employeeList = new ArrayList<String>(); employeeList.add("Santa"); employeeList.add("Banta"); return employeeList; } }
2. 异步 service
import java.util.List; import java.util.concurrent.CompletableFuture; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; @Service public class AsyncService { private static Logger log = LoggerFactory.getLogger(AsyncService.class); @Autowired private RestTemplate restTemplate; @Bean public RestTemplate restTemplate() { return new RestTemplate(); } @Async("asyncExecutor") public CompletableFuture<List<String>> getEmployeeName() throws InterruptedException { log.info("getEmployeeName starts"); List<String> employeeNameData = restTemplate.getForObject("http://localhost:8080/names", List.class); log.info("employeeNameData, {}", employeeNameData); Thread.sleep(1000L); // Intentional delay log.info("employeeNameData completed"); return CompletableFuture.completedFuture(employeeNameData); } @Async("asyncExecutor") public CompletableFuture<List<String>> getEmployeeAddress() throws InterruptedException { log.info("getEmployeeAddress starts"); List<String> employeeAddressData = restTemplate.getForObject("http://localhost:8080/addresses", List.class); log.info("employeeAddressData, {}", employeeAddressData); Thread.sleep(1000L); // Intentional delay log.info("employeeAddressData completed"); return CompletableFuture.completedFuture(employeeAddressData); } @Async("asyncExecutor") public CompletableFuture<List<String>> getEmployeePhone() throws InterruptedException { log.info("getEmployeePhone starts"); List<String> employeePhoneData = restTemplate.getForObject("http://localhost:8080/phones", List.class); log.info("employeePhoneData, {}", employeePhoneData); Thread.sleep(1000L); // Intentional delay log.info("employeePhoneData completed"); return CompletableFuture.completedFuture(employeePhoneData); } }
或者:
@Async public CompletableFuture<List<RouteSelfCureDetailDTO>> getRouteSelfCureDetailList() { List<RouteSelfCureDetailDTO> list = routeMapper.getSelfCureDetailList(); if (CollectionUtils.isEmpty(list)) { logger.info("There is no data, please adding first."); return CompletableFuture.completedFuture(new ArrayList<>()); } list.stream().forEach(t -> { if (StringUtils.isEmpty(t.getSelfCureStatus())) { t.setSelfCureStatus(Constants.ROUTE_UP_STATUS); } }); return CompletableFuture.completedFuture(list); }
3. controller
package com.example.demoasync; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController public class AsyncController { private static Logger log = LoggerFactory.getLogger(AsyncController.class); @Autowired private AsyncService service; @RequestMapping(value = "/testAsynch", method = RequestMethod.GET) public void testAsynch() throws InterruptedException, ExecutionException { log.info("testAsynch Start"); CompletableFuture<List<String>> employeeAddress = service.getEmployeeAddress(); CompletableFuture<List<String>> employeeName = service.getEmployeeName(); CompletableFuture<List<String>> employeePhone = service.getEmployeePhone(); // 等待每个异步调用都完成 CompletableFuture.allOf(employeeAddress, employeeName, employeePhone).join(); log.info("EmployeeAddress--> " + employeeAddress.get()); log.info("EmployeeName--> " + employeeName.get()); log.info("EmployeePhone--> " + employeePhone.get()); } }
或者:
@RequestMapping(value = "/get_route_selfcure_list", method = RequestMethod.GET) public CompletableFuture<RetMsg> getRouteSelfCureDetailList() { if (logger.isDebugEnabled()) { logger.debug("getRouteSelfCureDetailList method begins"); } CompletableFuture<List<RouteSelfCureDetailDTO>> future = detailApi.getRouteSelfCureDetailList(); return future.thenApplyAsync(routeSelfCureDetailDTOS -> { if (CollectionUtils.isEmpty(routeSelfCureDetailDTOS)) { return new FailMsg(SelfCureExecuting.RetMsg.ROUTE_SELFCURE_DETAIL_ERROR_CODE, SelfCureExecuting.RetMsg.ROUTE_SELFCURE_DETAIL_ERROR_MSG); } return new SucMsg(routeSelfCureDetailDTOS); }); }
4.在启动类上添加@EnableAsync注解:
@EnableAsync public class Application { ....... }
5.在过滤器上添加异步支持:
@WebFilter(urlPatterns = "/*", filterName = "corsFilter", asyncSupported = true) public class CorsFilter implements Filter { ........ }
6.最后把内置的Tomcat替换成jetty:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency>
7.设置jetty启动参数:
server.jetty.connection-idle-timeout=60000
server.jetty.threads.max-queue-capacity=2000
server.jetty.threads.max=4500
server.jetty.threads.min=4000
使用jmeter测试,需要添加cookie
使用Jmeter性能测试遇到的问题:java.net.SocketException: Connection reset by peer: socket write error at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(Unknown Source) at java.net.SocketOutputStream.write(Unknown Source) at sun.security.ssl.OutputRecord.writeBuffer(Unknown Source) at sun.security.ssl.OutputRecord.write(Unknown Source) at
解决方法:
Make sure that your HTTP Requests "Implementation" is HTTPClient4
Add the following lines to user.properties file (located in /bin folder of your JMeter home)
httpclient4.retrycount=1
hc.parameters.file=hc.parameters
In the hc.parameters file (same location - JMeter's /bin folder) uncomment the next line:
http.connection.stalecheck$Boolean=true
链接:https://www.jianshu.com/p/be3b9cfbf495
https://blog.csdn.net/lanse_huanxiang/article/details/126558792