why my spring webflux vs spring mvc load test throughput is same? - spring-boot

We are comparing the throughput of the spring webflux vs spring mvc for one of our project.
We have service1 and service2. Service1 prepares content and posts it to service2 using webclient. The code below is from service1 which posts content to service2.
Note: Service 2 takes 500ms to process a single request.
Spring Webflux
#PutMapping(path = "/")
public Mono<String> create() throws Exception {
ClassPathResource classpathResource = new ClassPathResource("/file.zip");
MultipartBodyBuilder multipartBodyBuilder = new MultipartBodyBuilder();
multipartBodyBuilder.part("key", "value");
multipartBodyBuilder.part("file", classpathResource, MediaType.APPLICATION_OCTET_STREAM);
MultiValueMap<String, HttpEntity<?>> multiValueMap = multipartBodyBuilder.build();
return WebClient.create()
.post()
.uri(uri)
.contentType(MediaType.MULTIPART_FORM_DATA)
.headers(httpHeaders -> httpHeaders.setBearerAuth(token))
.body(BodyInserters.fromMultipartData(multiValueMap))
.retrieve()
.bodyToMono(String.class);
}
Spring MVC
#PutMapping(path = "/")
public ResponseEntity<String> create() throws Exception {
String response = null;
ClassPathResource classpathResource = new ClassPathResource("/file.zip");
try (InputStream zipInputStream = new BufferedInputStream(classpathResource.getInputStream())) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
headers.setBearerAuth(token);
LinkedMultiValueMap<String, String> fileMap = new LinkedMultiValueMap<>();
ContentDisposition contentDisposition = ContentDisposition.builder("form-data").name("file").filename("file")
.build();
fileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
fileMap.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
HttpEntity<InputStreamResource> sipEntity = new HttpEntity<InputStreamResource>(
new InputStreamResource(zipInputStream), fileMap);
LinkedMultiValueMap<String, String> formatfileMap = new LinkedMultiValueMap<>();
contentDisposition = ContentDisposition.builder("form-data").name("key")
.build();
formatfileMap.add(HttpHeaders.CONTENT_DISPOSITION, contentDisposition.toString());
HttpEntity<String> formatEntity = new HttpEntity<String>("value", formatfileMap);
LinkedMultiValueMap<String, Object> linkedMultiValueMap = new LinkedMultiValueMap<String, Object>();
linkedMultiValueMap.add("file", sipEntity);
linkedMultiValueMap.add("key", formatEntity);
HttpEntity<LinkedMultiValueMap<String, Object>> request = new HttpEntity<LinkedMultiValueMap<String, Object>>(
linkedMultiValueMap, headers);
response = restTemplate.postForObject(ingestUrl, request, String.class);
}
return new ResponseEntity<String>(response, HttpStatus.OK);
}
We did a load test with 200, 300, 500, 1000 concurrent users using jmeter. In all the cases we have received same throughput for both frameworks. Are we doing something wrong here?
I have captured load test stats using Gatling for 1000 users for both mvc and reactive.
Webflux - 1000 users
Spring webflux with 1000 concurrent users
MVC - 1000 users
Spring MVC with 1000 concurrent users

I wouldn't say you did something wrong, rather this specific use case is not suitable for a hard comparison. Both endpoints rely on first loading something from a disk and then making an HTTP call.
The limiting factor here (I guess) is for both the network call, which takes the same time to finish nonetheless you use WebFlux or the MVC.
The benefit you get from WebFlux is the non-blocking behaviour, which scales better with fewer resources under load.
Something similar was already answered quite well on Quora: https://www.quora.com/Does-Spring-WebFlux-perform-better-than-Spring-MVC

Related

Socket timeout not working in Rest template third party API call - Spring boot

I am trying to test response-time out by configuring socket time out when third party rest service call. I am calling external web service by Spring Rest Template in my service.
For response timeout testing purpose, the external web service is taking more time which I configured.
I have configured 1600 milliseconds for timeout, but unfortunately I am getting response in more then configured time, around 2500 - 3000 milliseconds.
As per the configuration I should get time out exception.
public ClientHttpRequestFactory getClientHttpRequestFactory(String timeout) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(Integer.parseInt(timeout))
.setConnectionRequestTimeout(Integer.parseInt(timeout))
.setSocketTimeout(Integer.parseInt(timeout))
.build();
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.build();
return new HttpComponentsClientHttpRequestFactory(closeableHttpClient);
}
public String milisecTimeout = "1600";
RestTemplate restTemplate = new RestTemplate(appConfig.getClientHttpRequestFactory(milisecTimeout));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Content-Type", "application/json");
httpHeaders.set("Accept", "application/json");
httpHeaders.set("Accept-Charset", "UTF-8");
HttpEntity<String> httpEntity = new HttpEntity<>(request, httpHeaders);
String responseBody = "";
try {
ResponseEntity<String> response = restTemplate.exchange(hostUrl, HttpMethod.POST, httpEntity, String.class);
String statusCode = response.getStatusCodeValue();
String responseBody = response.getBody();
SearchRS searchSdnRS = objectMapper.readValue(responseBody, SearchRS.class);
} catch (Exception ex){
log.error("Error:", ex.getCause());
}
Please correct me if any misunderstanding.
Socket timeout is defined as maximum time of inactivity between two data packets. It's not about total request duration. So in the case you're describing it could well be that the data transfer from server to client started after 1500 milliseconds and lasted 1000–1500 milliseconds.

Sending a multipart request using RestTemplate

I want to make a multipart request to some external API (created using Spring Boot) but all I get is Required request part 'file' is not present.
I know the source code of the external API but I can't modify it. It looks like this:
#PostMapping("/upload")
public ResponseEntity handleFileUpload(#RequestParam("file") MultipartFile file){
return ResponseEntity.ok().build();
}
And from my application I create and send requests exactly like on the following snippet:
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body
= new LinkedMultiValueMap<>();
body.add("file", "dupa".getBytes());
HttpEntity<MultiValueMap<String, Object>> requestEntity
= new HttpEntity<>(body, headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate
.postForEntity("http://api:8080/upload", requestEntity, String.class);
return response.getBody();
What's the reason it doesn't work? The above code rewritten using Apache HttpClient works like charm.
You basically have two options, the solution with byte array:
map.add("file", new ByteArrayResource(byteArrayContent) {
#Override
public String getFilename() {
return "yourFilename";
}
});
I remember having a problem with just adding a byte array, so you need to have a filename too and use ByteArrayResource.
Or adding a File:
map.add("file", new FileSystemResource(file));

413 request entity too large issue in HTTP Get method call

Please don't mistake it as already asked question. The main difference here is, this issue is coming in Get method call. All the solutions discussed here or other places talks about either POST method or multipart form data.
Configuration I have provided is as below:
String url = env.getProperty(ApplicationConstants.PMCC_MANAGER_REGION_QUERY_URL);
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(url).queryParam("inTIS_PMA_NUMBER","ALL");
URI uri = builder.build().toUri();
RestTemplate restTemplate = getRestTemplateBuilder().build();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.GET, entity, String.class);
private RestTemplateBuilder getRestTemplateBuilder() {
Integer connectionTimeOut = 2000;
Integer readTimeOut = 3000;
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
restTemplateBuilder.setConnectTimeout(connectionTimeOut);
restTemplateBuilder.setReadTimeout(readTimeOut);
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setBufferRequestBody(false);
restTemplateBuilder.requestFactory(factory);
return restTemplateBuilder;
}
This code is part of Spring Boot application and deployed in WebLogic server.

spring boot application periodic post request via resttemplate in json

Below is my spring boot code snippet to post json data to server url every few min to tell that I am alive and running(which loads my json input data to db). purpose of this post request is to update the status on application monitoring tool.
What could be the right approach to implment this behaviour in my spring boot app? Is their any decorator api to do such post request to url, every few miuntes through out the application.? how can I know the time of successful post request to do next post request ? Please help me. Thanks in advance.
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"I am alive\":\"App name?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);
Why don't you use the #Scheduled annotation? This will seutes.nd your REST request every 3 minutes...
#Component
public class Heartbeater {
#Scheduled(fixedDelay = 180000)
public void heartbeat() {
// Your code is below...
RestTemplate restTemplate = new RestTemplate();
String url = "endpoint url";
String requestJson = "{\"I am alive\":\"App name?\"}";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
String answer = restTemplate.postForObject(url, entity, String.class);
System.out.println(answer);
}

send multipart response in spring boot

I am working on apis which is developed in spring boot. Now I have one API in which I have to send response which contains one binary file and and xml.
Both will be seperated by multipart boundary.
So is there any way to do this?
In spring boot try following the way to send a response in multipart.
#RequestMapping(method = { RequestMethod.GET },value = "/multipartdata",produces=MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<MultiValueMap<String, Object>> gerMultipartData()
throws Exception {
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<String, Object>();
formData.add("first_name", "ganesh");
formData.add("last_name", "patil");
formData.add("file-data_1", new FileSystemResource("C:\Users\ganesh\img\logo.png"));
formData.add("file-data_2", new FileSystemResource("C:\Users\ganeshg\Desktop\download.jpg"));
formData.add("file-data_3", new FileSystemResource("C:\Users\ganeshg\Desktop\odstext.txt"));
formData.add("file-data_4", new FileSystemResource("D:\Agent\152845.docx"));
formData.add("file-data_5", new FileSystemResource("D:\testxls.xlsx"));
return new ResponseEntity<MultiValueMap<String, Object>>(formData, HttpStatus.OK);
}

Resources