์๊ฐ
XNUMX์ XNUMX์ผ RedHat(๊ณง IBM)
๋ชฉํ๋ Java๋ฅผ Kubernetes ๋ฐฐํฌ ๋ฐ ์๋ฒ๋ฆฌ์ค ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ์ํ ์ต๊ณ ์ ํ๋ซํผ์ผ๋ก ๋ง๋ค์ด ๊ฐ๋ฐ์์๊ฒ ๋ฐ์ํ ๋ฐ ๋ช ๋ นํ ๊ฐ๋ฐ์ ๋ํ ํตํฉ ์ ๊ทผ ๋ฐฉ์์ ์ ๊ณตํ๋ ๊ฒ์ ๋๋ค.
๋น์ ์ด ๋ณด๋ฉด
๋งค์ฐ ๋น ๋ฅธ ์ ํ๋ฆฌ์ผ์ด์ ์คํ ์๋์ ๋ฎ์ ๋ฉ๋ชจ๋ฆฌ ์๋น๊ฐ ์ฝ์๋ฉ๋๋ค. ๊ฐ๋ฐ์ ์น์ฌ์ดํธ์ ๋ฐ์ดํฐ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์์๋ถํฐ ์ฒซ ๋ฒ์งธ ์๋ต๊น์ง์ ์๊ฐ:
๊ตฌ์ฑ
REST
REST+JPA
Quarkus+GraalVM
0.014
0.055
Quarkus+OpenJDK
0.75
2.5
๊ธฐ์กด ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์คํ*
4.3
9.5
๋ฉ๋ชจ๋ฆฌ ์๋น(Mb):
๊ตฌ์ฑ
REST
REST+JPA
Quarkus+GraalVM
13
35
Quarkus+OpenJDK
74
130
๊ธฐ์กด ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์คํ*
140
218
์ธ์์ ์ด์ง ์๋์?
*์ด ๊ธฐ์ ์คํ์ ๋ํ ์ ๋ณด๋ฅผ ์ฐพ์ง ๋ชปํ์ต๋๋ค. ์ด๊ฒ์ด ์ถ๊ฐ ๋ฐ๋ ํคํธ๊ฐ ํฌํจ๋ ์ผ์ข ์ Spring Boot๋ผ๊ณ ๊ฐ์ ํ ์ ์์ต๋๋ค..
์๋ ํ์ธ์!
Quarkus๋ก ์์ฑ๋ ๊ฐ์ฅ ๊ฐ๋จํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
}
๋ง ๊ทธ๋๋ก ํ๋์ ์์ ์ด๋ฉด ์ถฉ๋ถํฉ๋๋ค! ๊ฐ๋ฐ ๋ชจ๋์์ Maven์ ์ฌ์ฉํ์ฌ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ ์ ์์ต๋๋ค.
mvn compile quarkus:dev
โฆ
$ curl http://localhost:8080/hello
hello
์ผ๋ฐ ์ดํ๋ฆฌ์ผ์ด์ ๊ณผ์ ์ฐจ์ด์ ์ Application ํด๋์ค๊ฐ ์๋ค๋ ์ ์ ๋๋ค! Quarkus๋ ํซ ๋ฆฌ๋ก๋๋ฅผ ์ง์ํ๋ฏ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ค์ ์์ํ์ง ์๊ณ ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณ๊ฒฝํ ์ ์์ด ๊ฐ๋ฐ ์๋๊ฐ ๋์ฑ ๋นจ๋ผ์ง๋๋ค.
๋ฌด์ ํฅํ ๊ณํ? ์ฃผ์์ ์ฌ์ฉํ์ฌ ์ปจํธ๋กค๋ฌ์ ์๋น์ค๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
@ApplicationScoped
public class GreetingService {
public String greeting(String name) {
return "Hello " + name + "!";
}
}
์ ์ด ์ฅ์น:
@Path("/hello")
public class GreetingResource {
@Inject
GreetingService service;
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/{name}")
public String greeting(@PathParam("name") String name) {
return service.greeting(name);
}
}
$ curl http://localhost:8080/hello/developer
Hello developer!
Quarkus๋ ์ต์ํ ํ๋ ์์ํฌ(CDI ๋ฐ JAX-RS)์ ํ์ค ์ฃผ์์ ์ฌ์ฉํฉ๋๋ค. ๋ฌผ๋ก ์ด์ ์ CDI ๋ฐ JAX-RS๋ฅผ ์ฌ์ฉํด ๋ณธ ์ ์ด ์๋ค๋ฉด ์๋ก์ด ๊ฒ์ ๋ฐฐ์ธ ํ์๊ฐ ์์ต๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ์์
์ํฐํฐ์ ๋ํ Hibernate ๋ฐ ํ์ค JPA ์ฃผ์์ด ์ฌ์ฉ๋ฉ๋๋ค. REST ์ปจํธ๋กค๋ฌ์ ๋ง์ฐฌ๊ฐ์ง๋ก ์ต์ํ์ ์ฝ๋๋ฅผ ์์ฑํด์ผ ํฉ๋๋ค. ์ด์
๋ธ๋ฆฌ ํ์ผ์ ์ข
์์ฑ์ ํ์ํ๊ณ ์ฃผ์์ ์ถ๊ฐํ๋ ๊ฒ์ผ๋ก ์ถฉ๋ถํฉ๋๋ค. @Entity
application.properties์์ ๋ฐ์ดํฐ ์์ค๋ฅผ ๊ตฌ์ฑํฉ๋๋ค.
๋ชจ๋. sessionFactory, persistence.xml ๋๋ ๊ธฐํ ์๋น์ค ํ์ผ์ด ์์ต๋๋ค. ํ์ํ ์ฝ๋๋ง ์์ฑํฉ๋๋ค. ๊ทธ๋ฌ๋ ํ์ํ ๊ฒฝ์ฐ persistence.xml ํ์ผ์ ์์ฑํ๊ณ ORM ๊ณ์ธต์ ๋ณด๋ค ์ธ๋ฐํ๊ฒ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
Quarkus๋ ์ํฐํฐ ์บ์ฑ, ์ผ๋๋ค ๊ด๊ณ์ฉ ์ปฌ๋ ์ , ์ฟผ๋ฆฌ๋ฅผ ์ง์ํฉ๋๋ค. ์ธ๋ป ๋ณด๊ธฐ์ ๊ด์ฐฎ์ ๋ณด์ด์ง๋ง, ์ง๋ฐฉ์ ํ๋์ Kubernetes ๋ ธ๋์ ๋ํ ์บ์ฑ. ์ ๊ฒ๋ค. ์๋ก ๋ค๋ฅธ ๋ ธ๋์ ์บ์๋ ์๋ก ๋๊ธฐํ๋์ง ์์ต๋๋ค. ์ด๊ฒ์ด ์ผ์์ ์ด๊ธฐ๋ฅผ ๋ฐ๋๋๋ค.
๋น๋๊ธฐ ์ฝ๋ ์คํ
์์์ ์ธ๊ธํ๋ฏ์ด Quarkus๋ ๋ฐ์ํ ํ๋ก๊ทธ๋๋ฐ ์คํ์ผ๋ ์ง์ํฉ๋๋ค. ์ด์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฝ๋๋ฅผ ๋ค๋ฅธ ํํ๋ก ์์ฑํ ์ ์์ต๋๋ค.
@Path("/hello")
public class GreetingResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/{name}")
public CompletionStage<String> greeting(@PathParam("name") String name) {
return CompletableFuture.supplyAsync(() -> {
return "Hello " + name + "!";
});
}
}
๋น๋๊ธฐ ์ฝ๋๋ฅผ ์๋น์ค๋ก ์ ์กํ ์๋ ์์ผ๋ฉฐ ๊ฒฐ๊ณผ๋ ๋์ผํฉ๋๋ค.
ํ ์คํธ
Quarkus ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ํ ํ ์คํธ๋ JUnit4 ๋๋ JUnit5๋ก ์์ฑํ ์ ์์ต๋๋ค. ๋ค์์ ์๋ํฌ์ธํธ์ ๋ํ ํ ์คํธ ์์์ ๋๋ค. ์ด๋ RestAssured๋ฅผ ์ฌ์ฉํ์ฌ ์์ฑ๋์์ง๋ง ๋ค๋ฅธ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
@QuarkusTest
public class GreetingResourceTest {
@Test
public void testGreetingEndpoint() {
String uuid = UUID.randomUUID().toString();
given()
.pathParam("name", uuid)
.when().get("/hello/{name}")
.then()
.statusCode(200)
.body(is("Hello " + uuid + "!"));
}
}
@QuarkusTest ์ฃผ์์ ํ ์คํธ๋ฅผ ์คํํ๊ธฐ ์ ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋๋ก ์ง์ํฉ๋๋ค. ๋๋จธ์ง๋ ๋ชจ๋ ๊ฐ๋ฐ์์๊ฒ ์น์ํ ์ฝ๋์ ๋๋ค.
ํ๋ซํผ๋ณ ์ ํ๋ฆฌ์ผ์ด์
Quarkus๋ GraalVM๊ณผ ๊ธด๋ฐํ๊ฒ ํตํฉ๋์ด ์์ผ๋ฏ๋ก ํ๋ซํผ๋ณ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ๋ ๋ฌผ๋ก ๊ฐ๋ฅํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ ค๋ฉด GraalVM์ ์ค์นํ๊ณ GRAALVM_HOME ํ๊ฒฝ ๋ณ์๋ฅผ ์ง์ ํด์ผ ํฉ๋๋ค. ๋ ๋์๊ฐ
mvn package -Pnative
ํฅ๋ฏธ๋กญ๊ฒ๋ ์์ฑ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ ์ ์์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ ๋ค์ดํฐ๋ธ ์ฝ๋์ ์คํ์ด JVM์์์ ์คํ๊ณผ ๋ค๋ฅผ ์ ์๊ธฐ ๋๋ฌธ์ ์ค์ํฉ๋๋ค. @SubstrateTest ์ฃผ์์ ํ๋ซํผ๋ณ ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋๋ฅผ ์คํํฉ๋๋ค. ๊ธฐ์กด ํ ์คํธ ์ฝ๋๋ฅผ ์ฌ์ฌ์ฉํ๋ ๊ฒ์ ์์์ ํตํด ์ํํ ์ ์์ต๋๋ค. ๊ฒฐ๊ณผ์ ์ผ๋ก ํ๋ซํผ ์ข ์ ์ ํ๋ฆฌ์ผ์ด์ ์ ํ ์คํธํ๊ธฐ ์ํ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@SubstrateTest
public class GreetingResourceIT extends GreetingResourceTest {
}
์์ฑ๋ ์ด๋ฏธ์ง๋ Docker์ ํจํค์ง๋์ด Kubernetes ๋๋ OpenShift์์ ์คํ๋ ์ ์์ต๋๋ค.
ํดํท
Quarkus ํ๋ ์์ํฌ๋ Maven ๋ฐ Gradle๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค. Maven์ Gradle๊ณผ ๋ฌ๋ฆฌ ์๋ฒฝํ๊ฒ ์ง์๋ฉ๋๋ค. ์ํ๊น๊ฒ๋ ํ์ฌ Gradle์ ๋น ํ๋ก์ ํธ ์์ฑ์ ์ง์ํ์ง ์์ต๋๋ค. ์น์ฌ์ดํธ์ ์์ธํ ์ ๋ณด๊ฐ ์์ต๋๋ค.
ํ์ฅ ํ๋ก๊ทธ๋จ
Quarkus๋ ํ์ฅ ๊ฐ๋ฅํ ํ๋ ์์ํฌ์
๋๋ค. ํ์ฌ ์ฃผ๋ฌธ์ด ์์ต๋๋ค
๊ฒฐ๋ก
๋ด ์๊ฐ์๋ Quarkus๊ฐ ์๋์ ํ๋ฆ์ ์๋นํ ๋ถํฉํ๋ ๊ฒ ๊ฐ๋ค. ๋ฐฑ์๋ ์ฝ๋ ๊ฐ๋ฐ์ด ์ ์ ๋ ์ฌ์์ง๊ณ ์์ผ๋ฉฐ, ์ด ํ๋ ์์ํฌ๋ Docker ๋ฐ Kubernetes์ ๋ํ ๊ธฐ๋ณธ ์ง์์ ์ถ๊ฐํ์ฌ ์๋น์ค ๊ฐ๋ฐ์ ๋์ฑ ๋จ์ํํ๊ณ ์๋๋ฅผ ๋์ ๋๋ค. ํฐ ์ฅ์ ์ GraalVM์ ๋ํ ๊ธฐ๋ณธ ์ง์๊ณผ ํ๋ซํผ ์ข ์ ์ด๋ฏธ์ง ์์ฑ์ ํตํด ์๋น์ค๊ฐ ๋งค์ฐ ๋น ๋ฅด๊ฒ ์์๋๊ณ ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ๊ฑฐ์ ์ฐจ์งํ์ง ์๋๋ค๋ ์ ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์ด๋ ๋ง์ดํฌ๋ก์๋น์ค์ ์๋ฒ๋ฆฌ์ค ์ํคํ ์ฒ์ ๋ํ ๋์ค์ ์ด์ ์ด ๋์น๋ ์๋์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
๊ณต์ ์ฌ์ดํธ-
์ถ์ฒ : habr.com