TIL: Java SpringBoot 대 Asp.Net REST API 성능
TIL: Java Spring 부트와 Asp.Net REST API 성능 비교
오늘 저는 Java SpringBoot 및 Asp.Net 성능에 대해 배웠습니다(#til).
곧 출시될 .Net 7 릴리스와 Minimal API를 테스트하고 있었는데 그 속도에 놀랐습니다. 그래서 Java 18 SpringBoot 프로젝트와 비교하기로 했습니다.
결과는 Asp.Net 7 솔루션이 Java 18의 SpringBoot 애플리케이션보다 거의 2배 빠르다는 것입니다!
결과는 다음과 같습니다.
Asp.Net 7 최소 API는 SpringBoot Java 18 애플리케이션의 경우 30초당 2,152,070 요청에 비해 30초에 4,084,163 요청을 제공합니다!
자바 18 스프링부트
$ k6 run --vus 16 --duration 30s config.json
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: config.json
output: -
scenarios: (100.00%) 1 scenario, 16 max VUs, 1m0s max duration (incl. graceful stop):
* default: 16 looping VUs for 30s (gracefulStop: 30s)
running (0m30.0s), 00/16 VUs, 2152070 complete and 0 interrupted iterations
default ✓ [======================================] 16 VUs 30s
data_received..................: 373 MB 12 MB/s
data_sent......................: 392 MB 13 MB/s
http_req_blocked...............: avg=1.61µs min=441ns med=942ns max=2.39ms p(90)=1.53µs p(95)=1.75µs
http_req_connecting............: avg=308ns min=0s med=0s max=1.55ms p(90)=0s p(95)=0s
http_req_duration..............: avg=180.65µs min=114.4µs med=170.42µs max=4.11ms p(90)=202.21µs p(95)=216.99µs
{ expected_response:true }...: avg=180.65µs min=114.4µs med=170.42µs max=4.11ms p(90)=202.21µs p(95)=216.99µs
http_req_failed................: 0.00% ✓ 0 ✗ 2152070
http_req_receiving.............: avg=22.51µs min=4.59µs med=20.95µs max=3.95ms p(90)=32.44µs p(95)=39.5µs
http_req_sending...............: avg=6.3µs min=2.63µs med=5.61µs max=3.03ms p(90)=8.87µs p(95)=9.59µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=151.83µs min=92.24µs med=142.39µs max=3.43ms p(90)=172.73µs p(95)=187.11µs
http_reqs......................: 2152070 71733.676043/s
iteration_duration.............: avg=218.91µs min=138.9µs med=207.65µs max=4.54ms p(90)=244.87µs p(95)=263.15µs
iterations.....................: 2152070 71733.676043/s
vus............................: 16 min=16 max=16
vus_max........................: 16 min=16 max=16
Asp.Net 7
$ k6 run --vus 16 --duration 30s config.json
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: config.json
output: -
scenarios: (100.00%) 1 scenario, 16 max VUs, 1m0s max duration (incl. graceful stop):
* default: 16 looping VUs for 30s (gracefulStop: 30s)
running (0m30.0s), 00/16 VUs, 4084163 complete and 0 interrupted iterations
default ✓ [======================================] 16 VUs 30s
data_received..................: 845 MB 28 MB/s
data_sent......................: 743 MB 25 MB/s
http_req_blocked...............: avg=1.06µs min=431ns med=972ns max=2.48ms p(90)=1.41µs p(95)=1.62µs
http_req_connecting............: avg=0ns min=0s med=0s max=66.6µs p(90)=0s p(95)=0s
http_req_duration..............: avg=74.37µs min=30.59µs med=67.84µs max=7.33ms p(90)=91.37µs p(95)=106.97µs
{ expected_response:true }...: avg=74.37µs min=30.59µs med=67.84µs max=7.33ms p(90)=91.37µs p(95)=106.97µs
http_req_failed................: 0.00% ✓ 0 ✗ 4084163
http_req_receiving.............: avg=13.64µs min=4.43µs med=12.72µs max=7.05ms p(90)=17.75µs p(95)=19.44µs
http_req_sending...............: avg=6.36µs min=2.77µs med=5.96µs max=5.83ms p(90)=8.24µs p(95)=8.96µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=54.35µs min=19.55µs med=48.45µs max=5.34ms p(90)=70.1µs p(95)=83.96µs
http_reqs......................: 4084163 136135.973692/s
iteration_duration.............: avg=113.11µs min=56.58µs med=105.71µs max=7.9ms p(90)=133.41µs p(95)=153.52µs
iterations.....................: 4084163 136135.973692/s
vus............................: 16 min=16 max=16
vus_max........................: 16 min=16 max=16
세부
목표는 JSON 본문을 가져오고 역직렬화하고 값을 수정하고 직렬화된 JSON 응답을 다시 반환하는 간단한 HTTP POST API를 테스트하는 것이었습니다.
요청 및 응답 개체는 동일하지만 다른 클래스로 표시됩니다. 데이터 수정은 단순히 문자열을 연결하고 정수 값을 추가하는 것입니다.
Asp.Net 프로젝트의 경우 .Net 7의 미리 보기7이 사용되었으며 Java 대응 항목의 경우 Oracle OpenJDK 18.0.2.1과 결합된 종속성으로 spring-boot-starter-web
및 lombok
가 포함된 새로운 SpringBoot 프로젝트가 사용되었습니다.
코드는 다음과 같습니다.
자바 18 스프링부트
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>RestApiDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>RestApiDemo</name>
<description>RestApiDemo</description>
<properties>
<java.version>18</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
RestApiDemoApplication.java
package com.example.restapidemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestApiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestApiDemoApplication.class, args);
}
}
입력모델.자바
package com.example.restapidemo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public final class InputModel {
String FirstName;
String LastName;
Integer Age;
}
OutputModel.java
package com.example.restapidemo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
public final class OutputModel {
String FirstName;
String LastName;
Integer Age;
}
DemoController.java
package com.example.restapidemo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@PostMapping("/get")
@ResponseBody
public OutputModel GetData(@RequestBody InputModel input) {
return new OutputModel(input.FirstName + "x", input.LastName + "x", input.Age + 10);
}
}
Asp.Net 7
Program.cs
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/get", ([FromBody] InputModel input) => new OutputModel
{
FirstName = input.FirstName + "x",
LastName = input.LastName + "x",
Age = input.Age + 10
}
);
app.Run();
internal sealed class InputModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
internal sealed class OutputModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
K6.io 구성.json
import http from 'k6/http';
export default function () {
const url = 'http://localhost:8080/get';
const payload = JSON.stringify({
FirstName: 'John',
LastName: 'Doe',
Age: 33
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};
http.post(url, payload, params);
}
응답 유효성을 위해 CURL로 먼저 테스트:
자바 18 스프링부트
$ curl -X POST http://localhost:8080/get -H "content-type: application/json" -d "{\"FirstName\":\"John\",\"LastName\":\"Doe\",\"Age\":33}"
{"firstName":"Johnx","lastName":"Doex","age":43}%
Asp.Net 7
$ curl -X POST http://localhost:8080/get -H "content-type: application/json" -d "{\"FirstName\":\"John\",\"LastName\":\"Doe\",\"Age\":33}"
{"firstName":"Johnx","lastName":"Doex","age":43}%
.Net 7이 포함된 Kestrel 서버는 Java 18 기반 SpringBoot 애플리케이션이 포함된 기본 Tomcat 서버와 비교하여 간단한 API를 처리하는 꽤 괜찮은 작업을 수행하는 것 같습니다.
일부 ORM 프레임워크 또는 로깅을 사용하기로 결정할 때까지 기본 언어가 매우 유사하기 때문에 간단한 REST API를 구현하기로 결정할 때 누군가 이것을 사용하는 것을 고려할 수 있습니다.
Reference
이 문제에 관하여(TIL: Java SpringBoot 대 Asp.Net REST API 성능), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/slavius/til-java-springboot-vs-aspnet-rest-api-performance-jm2
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
$ k6 run --vus 16 --duration 30s config.json
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: config.json
output: -
scenarios: (100.00%) 1 scenario, 16 max VUs, 1m0s max duration (incl. graceful stop):
* default: 16 looping VUs for 30s (gracefulStop: 30s)
running (0m30.0s), 00/16 VUs, 2152070 complete and 0 interrupted iterations
default ✓ [======================================] 16 VUs 30s
data_received..................: 373 MB 12 MB/s
data_sent......................: 392 MB 13 MB/s
http_req_blocked...............: avg=1.61µs min=441ns med=942ns max=2.39ms p(90)=1.53µs p(95)=1.75µs
http_req_connecting............: avg=308ns min=0s med=0s max=1.55ms p(90)=0s p(95)=0s
http_req_duration..............: avg=180.65µs min=114.4µs med=170.42µs max=4.11ms p(90)=202.21µs p(95)=216.99µs
{ expected_response:true }...: avg=180.65µs min=114.4µs med=170.42µs max=4.11ms p(90)=202.21µs p(95)=216.99µs
http_req_failed................: 0.00% ✓ 0 ✗ 2152070
http_req_receiving.............: avg=22.51µs min=4.59µs med=20.95µs max=3.95ms p(90)=32.44µs p(95)=39.5µs
http_req_sending...............: avg=6.3µs min=2.63µs med=5.61µs max=3.03ms p(90)=8.87µs p(95)=9.59µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=151.83µs min=92.24µs med=142.39µs max=3.43ms p(90)=172.73µs p(95)=187.11µs
http_reqs......................: 2152070 71733.676043/s
iteration_duration.............: avg=218.91µs min=138.9µs med=207.65µs max=4.54ms p(90)=244.87µs p(95)=263.15µs
iterations.....................: 2152070 71733.676043/s
vus............................: 16 min=16 max=16
vus_max........................: 16 min=16 max=16
$ k6 run --vus 16 --duration 30s config.json
/\ |‾‾| /‾‾/ /‾‾/
/\ / \ | |/ / / /
/ \/ \ | ( / ‾‾\
/ \ | |\ \ | (‾) |
/ __________ \ |__| \__\ \_____/ .io
execution: local
script: config.json
output: -
scenarios: (100.00%) 1 scenario, 16 max VUs, 1m0s max duration (incl. graceful stop):
* default: 16 looping VUs for 30s (gracefulStop: 30s)
running (0m30.0s), 00/16 VUs, 4084163 complete and 0 interrupted iterations
default ✓ [======================================] 16 VUs 30s
data_received..................: 845 MB 28 MB/s
data_sent......................: 743 MB 25 MB/s
http_req_blocked...............: avg=1.06µs min=431ns med=972ns max=2.48ms p(90)=1.41µs p(95)=1.62µs
http_req_connecting............: avg=0ns min=0s med=0s max=66.6µs p(90)=0s p(95)=0s
http_req_duration..............: avg=74.37µs min=30.59µs med=67.84µs max=7.33ms p(90)=91.37µs p(95)=106.97µs
{ expected_response:true }...: avg=74.37µs min=30.59µs med=67.84µs max=7.33ms p(90)=91.37µs p(95)=106.97µs
http_req_failed................: 0.00% ✓ 0 ✗ 4084163
http_req_receiving.............: avg=13.64µs min=4.43µs med=12.72µs max=7.05ms p(90)=17.75µs p(95)=19.44µs
http_req_sending...............: avg=6.36µs min=2.77µs med=5.96µs max=5.83ms p(90)=8.24µs p(95)=8.96µs
http_req_tls_handshaking.......: avg=0s min=0s med=0s max=0s p(90)=0s p(95)=0s
http_req_waiting...............: avg=54.35µs min=19.55µs med=48.45µs max=5.34ms p(90)=70.1µs p(95)=83.96µs
http_reqs......................: 4084163 136135.973692/s
iteration_duration.............: avg=113.11µs min=56.58µs med=105.71µs max=7.9ms p(90)=133.41µs p(95)=153.52µs
iterations.....................: 4084163 136135.973692/s
vus............................: 16 min=16 max=16
vus_max........................: 16 min=16 max=16
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>RestApiDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>RestApiDemo</name>
<description>RestApiDemo</description>
<properties>
<java.version>18</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
package com.example.restapidemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestApiDemoApplication {
public static void main(String[] args) {
SpringApplication.run(RestApiDemoApplication.class, args);
}
}
package com.example.restapidemo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public final class InputModel {
String FirstName;
String LastName;
Integer Age;
}
package com.example.restapidemo;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@AllArgsConstructor
public final class OutputModel {
String FirstName;
String LastName;
Integer Age;
}
package com.example.restapidemo;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@PostMapping("/get")
@ResponseBody
public OutputModel GetData(@RequestBody InputModel input) {
return new OutputModel(input.FirstName + "x", input.LastName + "x", input.Age + 10);
}
}
using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapPost("/get", ([FromBody] InputModel input) => new OutputModel
{
FirstName = input.FirstName + "x",
LastName = input.LastName + "x",
Age = input.Age + 10
}
);
app.Run();
internal sealed class InputModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
internal sealed class OutputModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
import http from 'k6/http';
export default function () {
const url = 'http://localhost:8080/get';
const payload = JSON.stringify({
FirstName: 'John',
LastName: 'Doe',
Age: 33
});
const params = {
headers: {
'Content-Type': 'application/json',
},
};
http.post(url, payload, params);
}
$ curl -X POST http://localhost:8080/get -H "content-type: application/json" -d "{\"FirstName\":\"John\",\"LastName\":\"Doe\",\"Age\":33}"
{"firstName":"Johnx","lastName":"Doex","age":43}%
$ curl -X POST http://localhost:8080/get -H "content-type: application/json" -d "{\"FirstName\":\"John\",\"LastName\":\"Doe\",\"Age\":33}"
{"firstName":"Johnx","lastName":"Doex","age":43}%
Reference
이 문제에 관하여(TIL: Java SpringBoot 대 Asp.Net REST API 성능), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/slavius/til-java-springboot-vs-aspnet-rest-api-performance-jm2텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)