Ver3.0 ๐ ์คํ๋ง ๋ถํธ GraalVM Native Image๋ก ๋น๋ํ๊ธฐ: ์ด๊ณ ์ ์คํ์ ์ธ๊ณ๋ก!

๐ ์คํ๋ง ๋ถํธ GraalVM Native Image๋ก ๋น๋ํ๊ธฐ: ์ด๊ณ ์ ์คํ์ ์ธ๊ณ๋ก!
์๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋ก์ด ํจ๋ฌ๋ค์, Native Image ์๋ฒฝ ๊ฐ์ด๋
์๋
, ์น๊ตฌ! ๐ ์ค๋์ ์ ๋ง ํฅ๋ฏธ์ง์งํ ์ฃผ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ด. ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์
์ GraalVM Native Image๋ก ๋น๋ํ๋ ๋ฐฉ๋ฒ์ ๋ํด ์ด์ผ๊ธฐํด๋ณผ ๊ฑฐ์ผ.
ํน์ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ด ์์ํ ๋ ๋๋ฌด ๋๋ ค์ ๋ต๋ตํ๋ ์ ์์ง? ๐ ๋๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋๋ฌด ๋ง์ด ๋จน์ด์ ๊ณ ๋ฏผํ๋ ๊ฒฝํ? ๊ทธ๋ฐ ๋ฌธ์ ๋ค์ ํด๊ฒฐํ ์ ์๋ ๋ง๋ฒ ๊ฐ์ ๊ธฐ์ ์ด ๋ฐ๋ก GraalVM Native Image์ผ!
์ด ๊ธ์ ๋ค ์ฝ๊ณ ๋๋ฉด, ๋๋ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง ๋น๋ ์ ๋ฌธ๊ฐ๊ฐ ๋ ์ ์์ ๊ฑฐ์ผ. ์, ๊ทธ๋ผ ์์ํด๋ณผ๊น? ๐ฏ
๐ค GraalVM Native Image๊ฐ ๋ญ๊ธธ๋?
๋จผ์ ๊ธฐ๋ณธ๋ถํฐ ์์๋ณด์. GraalVM Native Image๋ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ค์ดํฐ๋ธ ์คํ ํ์ผ๋ก ์ปดํ์ผํ๋ ๊ธฐ์ ์ด์ผ.
์ผ๋ฐ์ ์ธ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ JVM(Java Virtual Machine) ์์์ ์คํ๋์ง? ๊ทธ๋ฐ๋ฐ Native Image๋ JVM ์์ด๋ ์ง์ ์ด์์ฒด์ ์์ ์คํ๋ ์ ์๋ ๋
๋ฆฝ์ ์ธ ์คํ ํ์ผ์ ๋ง๋ค์ด์ค. ๐ฎ
โจ Native Image์ ๋๋ผ์ด ์ฅ์ ๋ค
1. ์ด๊ณ ์ ์์ ์๊ฐ โก
์ผ๋ฐ ์คํ๋ง ๋ถํธ ์ฑ์ด 10-20์ด ๊ฑธ๋ฆฐ๋ค๋ฉด, Native Image๋ 0.1์ด ์ดํ๋ก ์์๋ผ. ์ ๋ง ๋ ๊น์งํ ์ฌ์ด์ผ!
2. ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ฑ ๐พ
JVM ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์
๋ณด๋ค ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์ฌ ์ ๊ฒ ์ฌ์ฉํด. ๋ณดํต 1/5 ์์ค์ผ๋ก ์ค์ด๋ค์ด.
3. ์ปจํ
์ด๋ ํ๊ฒฝ์ ์ต์ ํ ๐ณ
Docker๋ Kubernetes ๊ฐ์ ์ปจํ
์ด๋ ํ๊ฒฝ์์ ๋น ๋ฅธ ์ค์ผ์ผ๋ง์ด ๊ฐ๋ฅํด์ ธ.
4. ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ์ ๊ตฌ์ธ์ฃผ โ๏ธ
AWS Lambda ๊ฐ์ ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ์์ ์ฝ๋ ์คํํธ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ด.
๐ ๏ธ ์์ํ๊ธฐ ์ ์ค๋น๋ฌผ
Native Image ๋น๋๋ฅผ ์์ํ๊ธฐ ์ ์ ํ์ํ ๊ฒ๋ค์ ์ฑ๊ฒจ๋ณด์. ๋ง์น ์๋ฆฌํ๊ธฐ ์ ์ ์ฌ๋ฃ๋ฅผ ์ค๋นํ๋ ๊ฒ์ฒ๋ผ ๋ง์ด์ผ! ๐จโ๐ณ
1๏ธโฃ GraalVM ์ค์นํ๊ธฐ
๊ฐ์ฅ ๋จผ์ GraalVM์ ์ค์นํด์ผ ํด. GraalVM์ Oracle์์ ๊ฐ๋ฐํ ๊ณ ์ฑ๋ฅ JDK์ผ.
GraalVM Community Edition์ ๋ค์ด๋ก๋ํ๋ฉด ๋ฌด๋ฃ๋ก ์ฌ์ฉํ ์ ์์ด. ๊ณต์ ์น์ฌ์ดํธ(graalvm.org)์์ ์ด์์ฒด์ ์ ๋ง๋ ๋ฒ์ ์ ๋ค์ด๋ฐ์ผ๋ฉด ๋ผ.
2๏ธโฃ Native Image ์ปดํฌ๋ํธ ์ค์น
GraalVM์ ์ค์นํ๋ค๋ฉด, Native Image ์ปดํฌ๋ํธ๋ฅผ ์ถ๊ฐ๋ก ์ค์นํด์ผ ํด. ํฐ๋ฏธ๋์์ ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ๋ฉด ๋ผ:
gu install native-image
3๏ธโฃ ๋น๋ ๋๊ตฌ ์ค๋น
Native Image ๋น๋๋ฅผ ์ํด์๋ C ์ปดํ์ผ๋ฌ๊ฐ ํ์ํด. ์ด์์ฒด์ ๋ณ๋ก ๋ค์๊ณผ ๊ฐ์ด ์ค๋นํ๋ฉด ๋ผ:
Windows: Visual Studio Build Tools ์ค์น
macOS: Xcode Command Line Tools ์ค์น
Linux: gcc์ glibc-devel ํจํค์ง ์ค์น
4๏ธโฃ ์คํ๋ง ๋ถํธ ๋ฒ์ ํ์ธ
์คํ๋ง ๋ถํธ 3.0 ์ด์์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ฐ๋ ฅํ ์ถ์ฒํด! ๐ฏ
์คํ๋ง ๋ถํธ 3.0๋ถํฐ Native Image ์ง์์ด ๋ํญ ๊ฐ์ ๋๊ฑฐ๋ . ํนํ AOT(Ahead-Of-Time) ์ปดํ์ผ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋์ด์ ๋น๋๊ฐ ํจ์ฌ ์์ํด์ก์ด.
๐ฆ ํ๋ก์ ํธ ์ค์ ํ๊ธฐ
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์คํ๋ง ๋ถํธ ํ๋ก์ ํธ๋ฅผ Native Image๋ก ๋น๋ํ ์ ์๋๋ก ์ค์ ํด๋ณด์! ๐จ
Maven ํ๋ก์ ํธ ์ค์
Maven์ ์ฌ์ฉํ๋ค๋ฉด pom.xml ํ์ผ์ ๋ค์ ์ค์ ์ ์ถ๊ฐํด์ผ ํด:
<project>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.0</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.graalvm.buildtools</groupId>
<artifactId>native-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Gradle ํ๋ก์ ํธ ์ค์
Gradle์ ์ ํธํ๋ค๋ฉด? ๊ฑฑ์ ๋ง! build.gradle ํ์ผ์ ์ด๋ ๊ฒ ์ค์ ํ๋ฉด ๋ผ:
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.0'
id 'io.spring.dependency-management' version '1.1.4'
id 'org.graalvm.buildtools.native' version '0.9.28'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
graalvmNative {
binaries {
main {
imageName = 'my-native-app'
mainClass = 'com.example.Application'
buildArgs.add('--verbose')
}
}
}
๐ฏ Native Image ๋น๋ ์คํํ๊ธฐ
๋๋์ด ๋น๋๋ฅผ ์คํํ ์๊ฐ์ด์ผ! ๐ ์ค๋ ์ง ์์? ์ฒ์ ๋น๋ํ ๋๋ ์๊ฐ์ด ์ข ๊ฑธ๋ฆด ์ ์์ผ๋ ์ปคํผ ํ ์ ์ค๋นํ๋ ๊ฒ๋ ์ข์. โ
Maven์ผ๋ก ๋น๋ํ๊ธฐ
Maven ํ๋ก์ ํธ๋ผ๋ฉด ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํด:
./mvnw -Pnative native:compile
๋๋ ์คํ๋ง ๋ถํธ ํ๋ฌ๊ทธ์ธ์ ์ฌ์ฉํด์:
./mvnw -Pnative spring-boot:build-image
๐ ๋ช ๋ น์ด ์ต์ ์ค๋ช
-Pnative: native ํ๋กํ์ผ์ ํ์ฑํํด
native:compile: ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง๋ก ์ปดํ์ผํด
spring-boot:build-image: Docker ์ด๋ฏธ์ง๋ก๋ ๋ง๋ค ์ ์์ด
Gradle๋ก ๋น๋ํ๊ธฐ
Gradle ์ฌ์ฉ์๋ผ๋ฉด ์ด๋ ๊ฒ:
./gradlew nativeCompile
Docker ์ด๋ฏธ์ง๋ก ๋น๋ํ๋ ค๋ฉด:
./gradlew bootBuildImage
๋น๋ ๊ณผ์ ์ดํดํ๊ธฐ
Native Image ๋น๋ ๊ณผ์ ์ ์ผ๋ฐ ์๋ฐ ์ปดํ์ผ๊ณผ๋ ๋ง์ด ๋ฌ๋ผ. ์ด๋ค ์ผ์ด ์ผ์ด๋๋์ง ์์๋ณด์:
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ชจ๋ ์ฝ๋๋ฅผ ๋ถ์ํด์ ์ค์ ๋ก ์ฌ์ฉ๋๋ ํด๋์ค์ ๋ฉ์๋๋ฅผ ์ฐพ์๋ด.
์คํ๋ง ๋ถํธ 3.0์ AOT ์์ง์ด ์คํ ์์ ์ ํ์ํ ์ค์ ๋ค์ ๋ฏธ๋ฆฌ ์์ฑํด.
GraalVM์ด ๋ฐ์ดํธ์ฝ๋๋ฅผ ๋ค์ดํฐ๋ธ ๋จธ์ ์ฝ๋๋ก ๋ณํํด.
๋ชจ๋ ์ฝ๋์ ํ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํ๋์ ์คํ ํ์ผ๋ก ๋ฌถ์ด.
๐ง ๋ฆฌํ๋ ์ ๊ณผ ๋์ ๊ธฐ๋ฅ ์ฒ๋ฆฌํ๊ธฐ
Native Image์ ๊ฐ์ฅ ํฐ ๋์ ๊ณผ์ ๋ ๋ฐ๋ก ๋ฆฌํ๋ ์ ์ด์ผ. ์๋ฐ์ ๋ฆฌํ๋ ์ ์ ๋ฐํ์์ ํด๋์ค ์ ๋ณด๋ฅผ ๋์ ์ผ๋ก ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ์ธ๋ฐ, Native Image๋ ์ปดํ์ผ ํ์์ ๋ชจ๋ ๊ฑธ ๊ฒฐ์ ํด์ผ ํ๊ฑฐ๋ . ๐ค
๋ฆฌํ๋ ์ ์ค์ ํ์ผ ๋ง๋ค๊ธฐ
๋ฆฌํ๋ ์
์ ์ฌ์ฉํ๋ ํด๋์ค๋ค์ ๋ช
์์ ์ผ๋ก ์ค์ ํ์ผ์ ๋ฑ๋กํด์ผ ํด.
src/main/resources/META-INF/native-image ๋๋ ํ ๋ฆฌ์ ์ค์ ํ์ผ์ ๋ง๋ค์ด๋ณด์:
[
{
"name": "com.example.MyClass",
"allDeclaredConstructors": true,
"allDeclaredMethods": true,
"allDeclaredFields": true
},
{
"name": "com.example.AnotherClass",
"methods": [
{"name": "specificMethod", "parameterTypes": ["java.lang.String"]}
]
}
]
Tracing Agent ์ฌ์ฉํ๊ธฐ
์ ํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ฉด์ ๋ฆฌํ๋ ์ ์ฌ์ฉ์ ์ถ์ ํ๋ ๋ฐฉ๋ฒ์ด์ผ:
java -agentlib:native-image-agent=config-output-dir=src/main/resources/META-INF/native-image \
-jar target/myapp.jar
์ด๋ ๊ฒ ํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋๋ ๋์ ์ฌ์ฉ๋ ๋ชจ๋ ๋ฆฌํ๋ ์ , ํ๋ก์, ๋ฆฌ์์ค ์ ๊ทผ์ ๊ธฐ๋กํด์ ์ค์ ํ์ผ์ ์๋์ผ๋ก ๋ง๋ค์ด์ค! ์ ๋ง ํธ๋ฆฌํ์ง? ๐
์คํ๋ง ๋ถํธ์ ์๋ ํํธ
๋คํํ ์คํ๋ง ๋ถํธ 3.0๋ถํฐ๋ ๋๋ถ๋ถ์ ์คํ๋ง ์ปดํฌ๋ํธ์ ๋ํ ํํธ๊ฐ ์ด๋ฏธ ์ ๊ณต๋ผ.
ํ์ง๋ง ์๋ํํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์ถ๊ฐ ์ค์ ์ด ํ์ํ ์ ์์ด.
๐จ RuntimeHints ์ธํฐํ์ด์ค ํ์ฉ
์ฝ๋๋ก ์ง์ ํํธ๋ฅผ ์ ๊ณตํ ์๋ ์์ด:
@Configuration
public class MyRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
// ๋ฆฌํ๋ ์
ํํธ ๋ฑ๋ก
hints.reflection()
.registerType(MyClass.class,
MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INVOKE_DECLARED_METHODS);
// ๋ฆฌ์์ค ํํธ ๋ฑ๋ก
hints.resources()
.registerPattern("config/*.properties");
// ํ๋ก์ ํํธ ๋ฑ๋ก
hints.proxies()
.registerJdkProxy(MyInterface.class);
}
}
๐ณ Docker์ ํจ๊ป ์ฌ์ฉํ๊ธฐ
Native Image๋ Docker์ ํ์์ ๊ถํฉ์ด์ผ! ์ปจํ ์ด๋ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์์ฒญ๋๊ฒ ์ค์ผ ์ ์๊ฑฐ๋ . ๐
๋ฉํฐ ์คํ ์ด์ง Dockerfile
ํจ์จ์ ์ธ Docker ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค๊ธฐ ์ํ Dockerfile ์์ ์ผ:
FROM ghcr.io/graalvm/native-image:ol8-java17-22 AS builder
WORKDIR /app
COPY . .
RUN ./mvnw -Pnative native:compile
FROM oraclelinux:8-slim
WORKDIR /app
COPY --from=builder /app/target/my-native-app .
EXPOSE 8080
ENTRYPOINT ["./my-native-app"]
๐ ์ด๋ฏธ์ง ํฌ๊ธฐ ๋น๊ต
์ผ๋ฐ JVM ๊ธฐ๋ฐ ์ด๋ฏธ์ง: 200-300MB
Native Image ๊ธฐ๋ฐ: 50-80MB
๋ฌด๋ ค 70% ์ด์ ๊ฐ์! ๐ฏ
Spring Boot Buildpacks ํ์ฉ
Dockerfile ์์ด๋ Native Image Docker ์ด๋ฏธ์ง๋ฅผ ๋ง๋ค ์ ์์ด:
./mvnw spring-boot:build-image
๋๋ Gradle:
./gradlew bootBuildImage
Kubernetes ๋ฐฐํฌ
Native Image๋ Kubernetes ํ๊ฒฝ์์ ์ง๊ฐ๋ฅผ ๋ฐํํด. ๋น ๋ฅธ ์์ ์๊ฐ ๋๋ถ์ ์คํ ์ค์ผ์ผ๋ง์ด ํจ์ฌ ํจ๊ณผ์ ์ด๊ฑฐ๋ !
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-native-app
spec:
replicas: 3
selector:
matchLabels:
app: my-native-app
template:
metadata:
labels:
app: my-native-app
spec:
containers:
- name: app
image: my-native-app:latest
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 1
periodSeconds: 3
โก ์ฑ๋ฅ ์ต์ ํ ํ
Native Image์ ์ฑ๋ฅ์ ๊ทน๋ํํ๋ ๋ฐฉ๋ฒ๋ค์ ์์๋ณด์! ์ด๋ฏธ ์ถฉ๋ถํ ๋น ๋ฅด์ง๋ง, ๋ ๋น ๋ฅด๊ฒ ๋ง๋ค ์ ์์ด. ๐
1. PGO (Profile-Guided Optimization)
ํ๋กํ์ผ ๊ธฐ๋ฐ ์ต์ ํ๋ ์ค์ ์คํ ํจํด์ ๋ถ์ํด์ ๋ ํจ์จ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ธฐ๋ฒ์ด์ผ.
./mvnw -Pnative -Dagent=true native:compile
./target/my-app
./mvnw -Pnative -Dpgo=true native:compile
๐ PGO ํจ๊ณผ
์ฒ๋ฆฌ๋: 10-30% ํฅ์
๋ ์ดํด์: 5-15% ๊ฐ์
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ: ์ฝ๊ฐ ์ฆ๊ฐ (5% ๋ด์ธ)
2. ๋น๋ ์ต์ ์ต์ ํ
๋ค์ํ ๋น๋ ์ต์ ์ผ๋ก ์ฑ๋ฅ์ ํ๋ํ ์ ์์ด:
<buildArgs>
<buildArg>-O3</buildArg>
<buildArg>-march=native</buildArg>
<buildArg>--gc=G1</buildArg>
<buildArg>-H:+UnlockExperimentalVMOptions</buildArg>
<buildArg>-H:+ReportExceptionStackTraces</buildArg>
</buildArgs>
3. ๋ฉ๋ชจ๋ฆฌ ์ค์ ์กฐ์
Native Image๋ ๋ฉ๋ชจ๋ฆฌ ์ค์ ์ด ์ค์ํด:
-Xmx64m -Xms64m
JVM๋ณด๋ค ํจ์ฌ ์ ์ ๋ฉ๋ชจ๋ฆฌ๋ก๋ ์ ๋์๊ฐ! ๐
4. ๋ถํ์ํ ๊ธฐ๋ฅ ์ ๊ฑฐ
์ฌ์ฉํ์ง ์๋ ์คํ๋ง ๋ถํธ ์๋ ์ค์ ์ ์ ์ธํ๋ฉด ๋น๋ ์๊ฐ๊ณผ ์ด๋ฏธ์ง ํฌ๊ธฐ๋ฅผ ์ค์ผ ์ ์์ด:
@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
๐ ๋ฌธ์ ํด๊ฒฐ ๊ฐ์ด๋
Native Image ๋น๋ํ๋ค ๋ณด๋ฉด ์ฌ๋ฌ ๋ฌธ์ ๋ฅผ ๋ง๋ ์ ์์ด. ํํ ๋ฌธ์ ๋ค๊ณผ ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์์๋ณด์! ๐ง
๋ฌธ์ 1: ClassNotFoundException
์์ธ:
๋ฆฌํ๋ ์ ์ผ๋ก ๋ก๋๋๋ ํด๋์ค๊ฐ ์ค์ ์ ํฌํจ๋์ง ์์์ด.
ํด๊ฒฐ:
reflect-config.json์ ํด๋น ํด๋์ค๋ฅผ ์ถ๊ฐํ๊ฑฐ๋ Tracing Agent๋ฅผ ์ฌ์ฉํด.
๋ฌธ์ 2: ๋น๋ ์๊ฐ์ด ๋๋ฌด ์ค๋ ๊ฑธ๋ฆผ
์์ธ:
ํ๋ก์ ํธ๊ฐ ํฌ๊ฑฐ๋ ์์กด์ฑ์ด ๋ง์.
ํด๊ฒฐ:
- ๋น๋ ๋จธ์ ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋๋ ค (์ต์ 8GB ๊ถ์ฅ)
- ๋ณ๋ ฌ ๋น๋ ์ต์ ์ฌ์ฉ: -H:NumberOfThreads=8
- ๋ถํ์ํ ์์กด์ฑ ์ ๊ฑฐ
๋ฌธ์ 3: ๋ฆฌ์์ค ํ์ผ์ ์ฐพ์ ์ ์์
์์ธ:
๋ฆฌ์์ค๊ฐ ๋ค์ดํฐ๋ธ ์ด๋ฏธ์ง์ ํฌํจ๋์ง ์์์ด.
ํด๊ฒฐ:
resource-config.json ์ค์ :
{
"resources": {
"includes": [
{"pattern": "application.properties"},
{"pattern": "static/.*"},
{"pattern": "templates/.*"}
]
}
}
๋ฌธ์ 4: ๋์ ํ๋ก์ ์๋ฌ
์์ธ:
JDK ํ๋ก์๋ CGLIB ํ๋ก์๊ฐ ์ค์ ๋์ง ์์์ด.
ํด๊ฒฐ:
proxy-config.json ์์ฑ:
[
{
"interfaces": ["com.example.MyInterface"]
}
]
๐ ์ค์ ์์ : REST API ์ ํ๋ฆฌ์ผ์ด์
์ด๋ก ์ ์ถฉ๋ถํ ๋ฐฐ์ ์ผ๋, ์ค์ ๋ก ๋์ํ๋ ์์ ๋ฅผ ๋ง๋ค์ด๋ณด์! ๊ฐ๋จํ REST API๋ฅผ Native Image๋ก ๋น๋ํด๋ณผ ๊ฑฐ์ผ. ๐จ
ํ๋ก์ ํธ ๊ตฌ์กฐ
my-native-app/
โโโ src/
โ โโโ main/
โ โโโ java/
โ โ โโโ com/example/
โ โ โโโ Application.java
โ โ โโโ controller/
โ โ โ โโโ UserController.java
โ โ โโโ model/
โ โ โ โโโ User.java
โ โ โโโ service/
โ โ โโโ UserService.java
โ โโโ resources/
โ โโโ application.properties
โ โโโ META-INF/
โ โโโ native-image/
โ โโโ reflect-config.json
โโโ pom.xml
๋ฉ์ธ ์ ํ๋ฆฌ์ผ์ด์
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.nativex.hint.TypeHint;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
๋๋ฉ์ธ ๋ชจ๋ธ
package com.example.model;
public class User {
private Long id;
private String name;
private String email;
// ์์ฑ์
public User() {}
public User(Long id, String name, String email) {
this.id = id;
this.name = name;
this.email = email;
}
// Getter & Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
์๋น์ค ๋ ์ด์ด
package com.example.service;
import com.example.model.User;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Service
public class UserService {
private final Map<Long, User> users = new ConcurrentHashMap<>();
private final AtomicLong idCounter = new AtomicLong();
public UserService() {
// ์ด๊ธฐ ๋ฐ์ดํฐ
createUser(new User(null, "ํ๊ธธ๋", "hong@example.com"));
createUser(new User(null, "๊น์ฒ ์", "kim@example.com"));
}
public List<User> getAllUsers() {
return new ArrayList<>(users.values());
}
public Optional<User> getUserById(Long id) {
return Optional.ofNullable(users.get(id));
}
public User createUser(User user) {
Long id = idCounter.incrementAndGet();
user.setId(id);
users.put(id, user);
return user;
}
public Optional<User> updateUser(Long id, User user) {
if (users.containsKey(id)) {
user.setId(id);
users.put(id, user);
return Optional.of(user);
}
return Optional.empty();
}
public boolean deleteUser(Long id) {
return users.remove(id) != null;
}
}
์ปจํธ๋กค๋ฌ
package com.example.controller;
import com.example.model.User;
import com.example.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
private final UserService userService;
public UserController(UserService userService) {
this.userService = userService;
}
@GetMapping
public List<User> getAllUsers() {
return userService.getAllUsers();
}
@GetMapping("/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
return userService.getUserById(id)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@PostMapping
public User createUser(@RequestBody User user) {
return userService.createUser(user);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@RequestBody User user) {
return userService.updateUser(id, user)
.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
return userService.deleteUser(id)
? ResponseEntity.ok().build()
: ResponseEntity.notFound().build();
}
}
์ค์ ํ์ผ
spring.application.name=my-native-app
server.port=8080
logging.level.root=INFO
๋น๋ ๋ฐ ์คํ
์ด์ ๋น๋ํด๋ณด์:
# ๋น๋
./mvnw -Pnative native:compile
# ์คํ
./target/my-native-app
API ํ ์คํธ:
# ๋ชจ๋ ์ฌ์ฉ์ ์กฐํ
curl http://localhost:8080/api/users
# ํน์ ์ฌ์ฉ์ ์กฐํ
curl http://localhost:8080/api/users/1
# ์ฌ์ฉ์ ์์ฑ
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"์ด์ํฌ","email":"lee@example.com"}'
๐ ๊ณ ๊ธ ์ฃผ์ : AOT ์ฒ๋ฆฌ ์ปค์คํฐ๋ง์ด์ง
์คํ๋ง ๋ถํธ 3.0์ AOT(Ahead-Of-Time) ์ฒ๋ฆฌ๋ฅผ ์ง์ ์ปค์คํฐ๋ง์ด์งํ ์ ์์ด. ๋ ์ธ๋ฐํ ์ ์ด๊ฐ ํ์ํ ๋ ์ ์ฉํ์ง! ๐ฏ
BeanFactoryInitializationAotProcessor
๋น ์ด๊ธฐํ ๊ณผ์ ์ AOT ์์ ์ ์ต์ ํํ ์ ์์ด:
@Component
public class MyAotProcessor implements BeanFactoryInitializationAotProcessor {
@Override
public BeanFactoryInitializationAotContribution
processAheadOfTime(ConfigurableListableBeanFactory beanFactory) {
// ํน์ ๋น์ ๋ํ AOT ์ฒ๋ฆฌ
String[] beanNames = beanFactory.getBeanNamesForType(MyService.class);
if (beanNames.length == 0) {
return null;
}
return (generationContext, beanFactoryInitializationCode) -> {
// ์ฝ๋ ์์ฑ ๋ก์ง
GeneratedMethod method = beanFactoryInitializationCode
.getMethods()
.add("initMyService", method -> {
method.addCode("// ์ด๊ธฐํ ์ฝ๋");
});
};
}
}
RuntimeHintsRegistrar ๊ณ ๊ธ ํ์ฉ
๋ณต์กํ ํํธ ๋ฑ๋ก๋ ๊ฐ๋ฅํด:
@Configuration
public class AdvancedRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
// ํจํค์ง ์ ์ฒด ์ค์บ
hints.reflection()
.registerType(
TypeReference.of("com.example.model.*"),
hint -> hint
.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)
.withMembers(MemberCategory.DECLARED_FIELDS)
);
// ์กฐ๊ฑด๋ถ ํํธ ๋ฑ๋ก
if (isProductionProfile()) {
hints.resources()
.registerPattern("prod-config/*.yml");
}
// ์ง๋ ฌํ ํํธ
hints.serialization()
.registerType(MySerializableClass.class);
// JNI ํํธ
hints.jni()
.registerType(MyNativeClass.class,
MemberCategory.INVOKE_PUBLIC_METHODS);
}
private boolean isProductionProfile() {
// ํ๋กํ์ผ ์ฒดํฌ ๋ก์ง
return true;
}
}
๐ ํด๋ผ์ฐ๋ ํ๊ฒฝ๋ณ ๋ฐฐํฌ ์ ๋ต
Native Image๋ฅผ ๋ค์ํ ํด๋ผ์ฐ๋ ํ๊ฒฝ์ ๋ฐฐํฌํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์! โ๏ธ
AWS Lambda
Native Image๋ AWS Lambda์ ์ฝ๋ ์คํํธ ๋ฌธ์ ๋ฅผ ์๋ฒฝํ๊ฒ ํด๊ฒฐํด:
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
MyNativeFunction:
Type: AWS::Serverless::Function
Properties:
Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker
Runtime: provided.al2
CodeUri: target/function.zip
MemorySize: 512
Timeout: 30
Environment:
Variables:
SPRING_CLOUD_FUNCTION_DEFINITION: myFunction
๐ Lambda ์ฑ๋ฅ ๋น๊ต
JVM ๊ธฐ๋ฐ:
- ์ฝ๋ ์คํํธ: 5-10์ด
- ๋ฉ๋ชจ๋ฆฌ: 512MB ํ์
- ๋น์ฉ: ๋์
Native Image:
- ์ฝ๋ ์คํํธ: 100-200ms
- ๋ฉ๋ชจ๋ฆฌ: 256MB ์ถฉ๋ถ
- ๋น์ฉ: 50% ์ ๊ฐ ๊ฐ๋ฅ
Google Cloud Run
Cloud Run์์๋ Native Image๊ฐ ๋น์ ๋ฐํด:
# ๋น๋
./mvnw spring-boot:build-image
# ํ๊ทธ
docker tag my-native-app gcr.io/PROJECT_ID/my-native-app
# ํธ์
docker push gcr.io/PROJECT_ID/my-native-app
# ๋ฐฐํฌ
gcloud run deploy my-native-app \
--image gcr.io/PROJECT_ID/my-native-app \
--platform managed \
--region asia-northeast1 \
--memory 256Mi
Azure Container Instances
Azure์์๋ ๊ฐ๋จํ๊ฒ ๋ฐฐํฌํ ์ ์์ด:
az container create \
--resource-group myResourceGroup \
--name my-native-app \
--image myregistry.azurecr.io/my-native-app:latest \
--cpu 1 \
--memory 0.5 \
--ports 8080
๐ ๋ชจ๋ํฐ๋ง๊ณผ ๊ด์ฐฐ์ฑ
Native Image ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ชจ๋ํฐ๋ง์ด ์ค์ํด! ์ด๋ป๊ฒ ํ๋์ง ์์๋ณด์. ๐
Spring Boot Actuator
Actuator๋ Native Image์์๋ ์ ๋์ํด:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
์ค์ :
management.endpoints.web.exposure.include=health,info,metrics,prometheus
management.metrics.export.prometheus.enabled=true
Prometheus & Grafana
Prometheus๋ก ๋ฉํธ๋ฆญ์ ์์งํ๊ณ Grafana๋ก ์๊ฐํํ ์ ์์ด:
scrape_configs:
- job_name: 'my-native-app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['localhost:8080']
๋ถ์ฐ ์ถ์
Micrometer Tracing์ผ๋ก ๋ถ์ฐ ์ถ์ ๋ ๊ฐ๋ฅํด:
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
</dependency>
๐ CI/CD ํ์ดํ๋ผ์ธ ๊ตฌ์ถ
Native Image ๋น๋๋ฅผ CI/CD ํ์ดํ๋ผ์ธ์ ํตํฉํด๋ณด์! ๐
GitHub Actions
name: Native Image Build
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup GraalVM
uses: graalvm/setup-graalvm@v1
with:
version: 'latest'
java-version: '17'
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Cache Maven packages
uses: actions/cache@v3
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
- name: Build Native Image
run: ./mvnw -Pnative native:compile
- name: Test Native Image
run: ./target/my-native-app &
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: native-image
path: target/my-native-app
GitLab CI
stages:
- build
- test
- deploy
native-build:
stage: build
image: ghcr.io/graalvm/native-image:ol8-java17-22
script:
- ./mvnw -Pnative native:compile
artifacts:
paths:
- target/my-native-app
expire_in: 1 week
cache:
paths:
- .m2/repository
docker-build:
stage: build
image: docker:latest
services:
- docker:dind
script:
- docker build -t my-native-app:$CI_COMMIT_SHA .
- docker push my-native-app:$CI_COMMIT_SHA
Jenkins Pipeline
pipeline {
agent any
tools {
maven 'Maven 3.9'
}
environment {
GRAALVM_HOME = '/usr/lib/graalvm'
}
stages {
stage('Checkout') {
steps {
checkout scm
}
}
stage('Build Native Image') {
steps {
sh './mvnw -Pnative native:compile'
}
}
stage('Test') {
steps {
sh './target/my-native-app &'
sh 'sleep 5'
sh 'curl http://localhost:8080/actuator/health'
}
}
stage('Deploy') {
steps {
sh 'docker build -t my-native-app:latest .'
sh 'docker push my-registry/my-native-app:latest'
}
}
}
}
๐จ ์ฌ๋ฅ๋ท์์ ๋ฐฐ์ฐ๋ Native Image
Native Image ๋น๋๊ฐ ์ฒ์์๋ ์ด๋ ค์ธ ์ ์์ด. ํ์ง๋ง ๊ฑฑ์ ํ์ง ๋ง! ์ฌ๋ฅ๋ท์๋ ์คํ๋ง ๋ถํธ์ GraalVM ์ ๋ฌธ๊ฐ๋ค์ด ๋ง์ด ์์ด. ๐
์ค์ ํ๋ก์ ํธ์ Native Image๋ฅผ ์ ์ฉํ๊ณ ์ถ์๋ฐ ๋ง๋งํ๋ค๋ฉด, ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. 1:1 ์ปจ์คํ
๋ถํฐ ํ๋ก์ ํธ ์ ์ฒด ๋ง์ด๊ทธ๋ ์ด์
๊น์ง ๋ค์ํ ์๋น์ค๋ฅผ ์ฐพ์ ์ ์๊ฑฐ๋ !
ํนํ ๋ณต์กํ ๋ ๊ฑฐ์ ์์คํ
์ Native Image๋ก ์ ํํ๋ ์์
์ ๊ฒฝํ์ด ํ๋ถํ ์ ๋ฌธ๊ฐ์ ๊ฐ์ด๋๊ฐ ํฐ ๋์์ด ๋ผ. ์ฌ๋ฅ๋ท์์ ์์ ์๊ฒ ๋ง๋ ์ ๋ฌธ๊ฐ๋ฅผ ์ฐพ์๋ณด์! ๐ฏ
๐ก ๋ฒ ์คํธ ํ๋ํฐ์ค ์ด์ ๋ฆฌ
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ด์ฉ์ ๋ฐํ์ผ๋ก Native Image ๋น๋์ ๋ฒ ์คํธ ํ๋ํฐ์ค๋ฅผ ์ ๋ฆฌํด๋ณผ๊ฒ! ๐
1. ํ๋ก์ ํธ ์์ ๋จ๊ณ
โ
์คํ๋ง ๋ถํธ 3.0 ์ด์ ์ฌ์ฉ
โ
Spring Initializr์์ GraalVM Native Support ์ ํ
โ
ํ์ํ ์์กด์ฑ๋ง ์ต์ํ์ผ๋ก ์ถ๊ฐ
โ
๋ฆฌํ๋ ์
์ฌ์ฉ์ ์ต์ํํ๋ ์ค๊ณ
2. ๊ฐ๋ฐ ๋จ๊ณ
โ
์ ๊ธฐ์ ์ผ๋ก Native Image ๋น๋ ํ
์คํธ
โ
Tracing Agent๋ก ์ค์ ์๋ ์์ฑ
โ
RuntimeHints๋ก ๋ช
์์ ํํธ ์ ๊ณต
โ
๋จ์ ํ
์คํธ์ ํตํฉ ํ
์คํธ ์์ฑ
3. ๋น๋ ์ต์ ํ
โ
PGO ํ์ฉ์ผ๋ก ์ฑ๋ฅ ํฅ์
โ
๋ถํ์ํ ์๋ ์ค์ ์ ์ธ
โ
๋น๋ ์บ์ ํ์ฉ
โ
๋ฉํฐ ์คํ
์ด์ง Docker ๋น๋
4. ๋ฐฐํฌ ๋ฐ ์ด์
โ
์ปจํ
์ด๋ ํ๊ฒฝ ํ์ฉ
โ
์ ์ ํ ๋ฉ๋ชจ๋ฆฌ ์ค์
โ
๋ชจ๋ํฐ๋ง ๋ฐ ๋ก๊น
๊ตฌ์ฑ
โ
๋กค๋ฐฑ ๊ณํ ์๋ฆฝ
5. ๋ฌธ์ ํด๊ฒฐ
โ
--verbose ์ต์
์ผ๋ก ๋๋ฒ๊น
โ
์ปค๋ฎค๋ํฐ ํ์ฉ (Stack Overflow, GitHub Issues)
โ
๊ณต์ ๋ฌธ์ ์ฐธ์กฐ
โ
์ ๋ฌธ๊ฐ ๋์ ๋ฐ๊ธฐ (์ฌ๋ฅ๋ท ํ์ฉ!)
๐ ๋ฏธ๋ ์ ๋ง๊ณผ ๋ฐ์ ๋ฐฉํฅ
GraalVM Native Image๋ ๊ณ์ ๋ฐ์ ํ๊ณ ์์ด. ์์ผ๋ก ์ด๋ค ๋ณํ๊ฐ ์์์ง ์ดํด๋ณด์! ๐ฎ
1. ๋น๋ ์๊ฐ ๋จ์ถ
Oracle๊ณผ ์ปค๋ฎค๋ํฐ๋ ๋น๋ ์๊ฐ์ ์ค์ด๊ธฐ ์ํด ๋ ธ๋ ฅํ๊ณ ์์ด. ์ ์ง์ ์ปดํ์ผ, ๋ ๋์ ์บ์ฑ ๋ฉ์ปค๋์ฆ ๋ฑ์ด ๊ฐ๋ฐ ์ค์ด์ผ.
2. ๋ ๋์ ๋๋ฒ๊น ์ง์
ํ์ฌ๋ Native Image ๋๋ฒ๊น ์ด ์ ํ์ ์ด์ง๋ง, ์์ผ๋ก๋ JVM ์์ค์ ๋๋ฒ๊น ๊ฒฝํ์ ์ ๊ณตํ ๊ณํ์ด๋.
3. ๋์ ๊ธฐ๋ฅ ์ง์ ํ๋
๋ฆฌํ๋ ์ , ๋์ ํ๋ก์ ๋ฑ์ ์ ์ฝ์ด ์ ์ ์ค์ด๋ค๊ณ ์์ด. ์คํ๋ง ํ๋ ์์ํฌ๋ ์ด์ ๋ง์ถฐ ๊ณ์ ๊ฐ์ ๋๊ณ ์์ง.
4. ํด๋ผ์ฐ๋ ๋ค์ดํฐ๋ธ ์ต์ ํ
Kubernetes, ์๋ฒ๋ฆฌ์ค ํ๊ฒฝ์ ๋์ฑ ์ต์ ํ๋ ๊ธฐ๋ฅ๋ค์ด ์ถ๊ฐ๋ ์์ ์ด์ผ.
๐ ์ฃผ๋ชฉํ ๋งํ ๋ฐ์
Project Leyden: OpenJDK์ ์๋ก์ด ํ๋ก์ ํธ๋ก, JVM๊ณผ Native Image์ ์ฅ์ ์ ๊ฒฐํฉํ๋ ค๋ ์๋์ผ.
CRaC (Coordinated Restore at Checkpoint): JVM ์ํ๋ฅผ ์ค๋
์ท์ผ๋ก ์ ์ฅํ๊ณ ๋ณต์ํ๋ ๊ธฐ์ ๋ก, Native Image์ ๋์์ด ๋ ์ ์์ด.
Spring Native ํตํฉ: ์คํ๋ง ํ์ด Native Image ์ง์์ ํต์ฌ ๊ธฐ๋ฅ์ผ๋ก ๋ง๋ค๊ณ ์์ด.
๐ ์ถ๊ฐ ํ์ต ๋ฆฌ์์ค
๋ ๊น์ด ๊ณต๋ถํ๊ณ ์ถ๋ค๋ฉด ์ด๋ฐ ๋ฆฌ์์ค๋ค์ ํ์ฉํด๋ด! ๐
๊ณต์ ๋ฌธ์
โข GraalVM ๊ณต์ ๋ฌธ์: graalvm.org/docs
โข ์คํ๋ง ๋ถํธ Native Image ๊ฐ์ด๋: spring.io/guides
โข Native Build Tools ๋ฌธ์: graalvm.github.io/native-build-tools
์ปค๋ฎค๋ํฐ
โข Spring Community Forum
โข GraalVM Slack ์ฑ๋
โข Stack Overflow #graalvm ํ๊ทธ
โข GitHub Discussions
๋ธ๋ก๊ทธ & ํํ ๋ฆฌ์ผ
โข Baeldung์ Spring Native ์๋ฆฌ์ฆ
โข DZone์ GraalVM ์ํฐํด
โข Medium์ ์ค์ ๊ฒฝํ๋ด
โข ์ฌ๋ฅ๋ท์ ์ง์์ธ์ ์ฒ (๋ค์ํ ๊ฐ๋ฐ ํ!)
์์ ์๋ฃ
โข Spring I/O ์ปจํผ๋ฐ์ค ๋ฐํ
โข Devoxx ์ธ์
โข YouTube ํํ ๋ฆฌ์ผ
โข ์จ๋ผ์ธ ๊ฐ์ ํ๋ซํผ
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ฌ๊ธฐ๊น์ง ์ฝ์๋ค๋ฉด ์ ๋ง ๋๋จํด! ๐ ์ฐ๋ฆฌ๋ GraalVM Native Image์ ๊ธฐ์ด๋ถํฐ ๊ณ ๊ธ ์ฃผ์ ๊น์ง ๋ชจ๋ ์ดํด๋ดค์ด.
Native Image๋ ์๋ฐ ์ ํ๋ฆฌ์ผ์ด์
์ ํจ๋ฌ๋ค์์ ๋ฐ๊พธ๋ ํ์ ์ ์ธ ๊ธฐ์ ์ด์ผ. ๋น ๋ฅธ ์์ ์๊ฐ, ์ ์ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ, ํด๋ผ์ฐ๋ ํ๊ฒฝ ์ต์ ํ ๋ฑ ๋ง์ ์ฅ์ ์ด ์์ง. ๋ฌผ๋ก ๋น๋ ์๊ฐ์ด ๊ธธ๊ณ ์ผ๋ถ ์ ์ฝ์ฌํญ์ด ์์ง๋ง, ์คํ๋ง ๋ถํธ 3.0๊ณผ ํจ๊ป๋ผ๋ฉด ์ด๋ฐ ๋ฌธ์ ๋ค๋ ๋ง์ด ํด๊ฒฐ๋์ด. ๐
์ฒ์์๋ ์ด๋ ค์ธ ์ ์์ด. ํ์ง๋ง ์ฐจ๊ทผ์ฐจ๊ทผ ๋ฐ๋ผํ๋ค ๋ณด๋ฉด ์ด๋์ Native Image ์ ๋ฌธ๊ฐ๊ฐ ๋์ด ์์ ๊ฑฐ์ผ! ์ค์ ํ๋ก์ ํธ์ ์ ์ฉํ๋ฉด์ ๊ฒฝํ์ ์๋ ๊ฒ ๊ฐ์ฅ ์ค์ํด.
๋งํ๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ์ปค๋ฎค๋ํฐ์ ์ง๋ฌธํ๊ฑฐ๋, ์ฌ๋ฅ๋ท์์ ์ ๋ฌธ๊ฐ์ ๋์์ ๋ฐ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. ํผ์ ๊ณ ๋ฏผํ์ง ๋ง๊ณ ํจ๊ป ์ฑ์ฅํ์! ๐
์, ์ด์ ๋น์ ์ ์คํ๋ง ๋ถํธ ์ ํ๋ฆฌ์ผ์ด์
์ Native Image๋ก ๋น๋ํด๋ณผ ์๊ฐ์ด์ผ. ์ด๊ณ ์์ผ๋ก ์คํ๋๋ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง๋ค์ด๋ณด์! ํ์ดํ
! ๐ชโจ
๐ ์ถํํฉ๋๋ค! ๐
๋น์ ์ ์ด์ GraalVM Native Image ๋น๋์ ๋ชจ๋ ๊ฒ์ ์๊ฒ ๋์์ต๋๋ค!
์ด ์ง์์ ๋ฐํ์ผ๋ก ๋ฉ์ง ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง๋ค์ด๋ณด์ธ์!
๐ ๐ป โก ๐ฏ โจ
Happy Coding! ์ฆ๊ฑฐ์ด ๊ฐ๋ฐ ๋์ธ์! ๐
๋ ๋ง์ ๊ฐ๋ฐ ์ง์์ ์ฌ๋ฅ๋ท์ ์ง์์ธ์ ์ฒ์์ ๋ง๋์!
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.