Post

스프링 네이티브 메모리 사용량 비교

메모리 기근

운영중인 이미지 관련 웹 서비스가 하나 있는데 서버 메모리가 1GB라 굉장히 빠듯하다.

자바 스프링 기반으로 작동하고 있는데, 메모리를 더 효과적으로 사용할 방법이 없을까 싶어서 조사하던 중 스프링 네이티브를 발견하게 되었다.

스프링 네이티브란?

GraalVM을 활용했으며, 스프링 어플리케이션을 네이티브 이미지로 컴파일하여 기존 JVM에 비해 더 작은 메모리 공간과 훨씬 더 빠른 시작 시간으로 실행할 수 있다고 한다.

주요 차이점으로는,

  • 애플리케이션의 정적 분석은 진입 main점에서 빌드 시 수행됩니다.
  • 네이티브 이미지가 생성될 때 도달할 수 없는 코드는 제거되며 실행 파일의 일부가 되지 않습니다.
  • GraalVM은 코드의 동적 요소를 직접 인식하지 않으며 리플렉션, 리소스, 직렬화 및 동적 프록시에 대해 알려야 합니다.
  • 애플리케이션 클래스 경로는 빌드 시 고정되며 변경할 수 없습니다.
  • 지연 클래스 로딩이 없으며 실행 파일에 포함된 모든 항목이 시작 시 메모리에 로드됩니다.
  • 완전히 지원되지 않는 Java 응용 프로그램의 일부 측면에는 몇 가지 제한 사항이 있습니다.

등이 있다고 한다. 그렇다면 GraalVM은 무엇일까?

GraalVM 이란

먼저 만들어진 배경에 대해 살펴보자.

기존의 C++로 만들어진 OpenJDK JIT Compiler는 굉장히 오랜 시간 작성된 코드다 보니 해당 소스코드를 능숙하게 다룰 사람을 구하기도 힘들고, 그러다보니 코드 수정 또한 굉장히 어려워서 개선하는 데 한계가 왔다고 한다.

그에 따른 대안으로 Java로 구성된 JIT 컴파일러를 만들기로 했고, 인력 충원 및 코드 개선이 훨씬 원활해질 수 있었다고 한다.

GraalVM은 기존 JVM에 비해 훨씬 향상된 속도와 리소스 활용 능력을 보여준다고 한다. 또한 Ahead-of-TIme Compilation (이하 AOT)를 도입했는데, 기존의 인터프리터 실행 환경이 아니라 OS에 맞게 실행 파일을 제작한다.

이는 OS에 자바를 미리 구성해야 하는 필요성을 없애주고 굉장히 빠른 실행을 기대할 수 있으나 기존 자바의 장점이던 런타임 최적화의 가능성은 사라진다.

메모리 테스트

일단 내 목적은 메모리 사용량을 줄이는 것이었으니, 한번 테스트를 해보자. 테스트 환경은 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
plugins {
    id 'java'
    id 'org.springframework.boot' version '3.0.3'
    id 'io.spring.dependency-management' version '1.1.0'
    id 'org.graalvm.buildtools.native' version '0.9.17'
}

group = 'com.coldrain'
version = '1' // 버전 명시 안해주면 bootBuildImage 커맨드 시 에러 발생함
sourceCompatibility = '17'


dependencies {
    // spring
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-validation'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-webflux'

    // util
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    implementation 'com.googlecode.json-simple:json-simple:1.1.1'

    // db
    implementation 'com.h2database:h2'

    // jwt
    implementation 'io.jsonwebtoken:jjwt:0.9.1'
    implementation 'javax.xml.bind:jaxb-api:2.1'

    // rest doc
    asciidoctorExt 'org.springframework.restdocs:spring-restdocs-asciidoctor'
    testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'

    // test
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

스프링 부트 3.0.3, 자바 17 버전을 사용했으며

./gradlew bootBuildImage

명령어를 통해 네이티브 이미지를 빌드해봤다. 참고로 도커를 미리 설치해 놓아야 한다.

소요된 시간은 일반적인 도커 이미지 빌드시간 보다는 훨씬 더 걸린다. 정확히 측정은 안해봤는데 체감상 3~4배는 더 걸린 듯 하다.

로컬 비교 결과

그냥 이미지

도커 데스크탑을 이용해 메모리 사용량을 확인해 봤다. 참고로 내 서비스의 힙사이즈는 300m, 도커 컨테이너의 메모리는 400m로 제한되어 있다.

위의 사진은 평소에 사용하는 이미지의 메모리 사용량이며, 대략 180MB의 메모리를 사용하는 것으로 확인되었다. 그렇다면 네이티브 이미지의 메모리 샤용량 결과는 어떻게 나올까?

네이티브

굉장히 큰 폭으로 메모리 사용량이 줄어든 것을 볼 수 있다. VisualVM으로 정확히 어느 부분이 메모리 점유율이 줄어든 것인지 확인하고 싶었지만, 2시간 동안 시도해도 결국 실패해서 일단 이 정도만 확인하고 넘어가기로 했다.

또 한 가지 큰 차이가 있다면 부팅 시간이 말도 안되게 빠르다.

기존에는 부팅 시간이 대략 3~4초 이내인데, 네이티브 이미지는 0.1 ~ 0.15초 사이로 나타났다.

그래서 한 번 운영서버에 띄워보고, 메모리 사용량을 보기로 했다.

서버 비교 결과

기존

와탭을 이용, 리눅스 서버 모니터링 결과를 가지고 비교해봤다.

기존에는 앱을 작동시키고 하루 정도 지나면 전체 서버 메모리 사용량이 85 ~ 90% 사이를 왔다갔다 했다. 네이티브는 어떨까?

와탭네이

똑같이 하루 정도 지나고 사용량을 확인해보았다. 메모리 점유율이 확연하게 낮아진 것을 확인할 수 있었다.

결론

나처럼 메모리 기근을 겪는 사람들은 한 번쯤 시도해 보면 좋을 옵션인 듯 하다.

그런데 한 가지 신경쓰이는 것은 로그백 관련 에러코드가 처음에 계속 뜨는데, 검색해보니 이건 해당 라이브러리를 관리하는 곳에서 패치를 진행해 줘야 하는 문제라고 한다. 다행인 건 로그 기록은 잘 되서 일단 넘어가기로 했다.

그리고 이건 어느 쪽 문제인지 모르겠는데, docker-compose volume 매핑이 상당히 까다롭다. 기존에는 폴더 하나만 툭 매핑해주면 알아서 잘 찾았는데, 자꾸 db랑 log 파일 접근을 못해서 난감했다. 혹시나 매핑이 안되는 사람이 있다면

서버_파일:/workspace/도커에서_접근할_파일

이렇게 워크스페이스를 한번 추가해보면 좋을 것 같다.

이와 같이 아직 알 수 없는 자잘한 에러들이 분명히 상주하고 있을 테니 하나의 에러조차 치명적인 중요한 서버라면 조금 더 지원 환경이 갖춰진 후에 사용하는 것이 좋을 듯 하다.

참고

  • Spring.io, GraalVM Native Image Support, https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html
  • NHN Cloud, GraalVM, Spring Native 맛보기, https://meetup.nhncloud.com/posts/273
This post is licensed under CC BY 4.0 by the author.

© . Some rights reserved.

Using the Jekyll theme Chirpy