엄지월드

[2차시] 애플리케이션 구동 시간 단축하기 : 빠른 스타트업을 위한 전략과 기법 본문

기타

[2차시] 애플리케이션 구동 시간 단축하기 : 빠른 스타트업을 위한 전략과 기법

킨글 2025. 3. 17. 22:18

어플리케이션 구동 개요

  • 1 - JVM 시작
    • 클래스 로딩 : 어플리케이션 클래스와 라이브러리 로드
    • 메모리 할당 : 힙(Heap) 메모리와 스택(Stack) 메모리 초기화
    • JVM 옵션 설정 : 성능 최적화를 위한 옵션 설정 (예 : -Xmx, -Xms)
  • 2 - Spring Application 클래스 실행 단계
    • 어플리케이션의 시작점을 정의
    • 구성 설정과 리스너 등록
    • 배너 출력 및 로깅 설정
  • 3 - 환경 설정 단계
    • 메서드 호출 시 지역 변수 저장
    • 메서드 호출 및 반환 시 스택 프레임 추가 및 제거
    • Stack 메모리의 한계 (고정 크기)
  • 4 - 어플리케이션 컨텍스트 생성 단계
    • Application Context 생성
    • 스프링의 DI(Dependency Injection)를 통한 Bean 주입
    • Bean 라이프사이클 관리
  • 5 - Bean 등록 및 초기화
    • Bean 등록 및 의존성 주입
    • Bean의 초기화 메서드 실행
    • Bean 순환 참조 나 지연 초기화 최적화
  • 6 - 어플리케이션 서버(WAS) 시작
    • 내장 톰캣, Jetty, Undertow 등의 웹 서버 실행
    • HTTP 포트 및 SSL 설정 적용
    • Servlet 컨테이너 초기화 및 요청 처리 준비
  • 7 - 어플리케이션 컨텍스트 완료 및 준비 상태
    • 모든 Bean 초기화 및 의존성 주입 완료
    • Application Ready Event 발생
    • 어플리케이션은 요청을 처리할 준비가 완료됨

라이브러리 의존성 관리를 통한 최적화

  • 의존성 트리 분석 및 버전 관리
    • 의존성 트리를 분석해 상호 의존 관계 최적화
    • 중복 의존성 제거
    • 최신 버전의 라이브러리를 사용해 성능 최적화
      • ./gradlew dependencies # 의존성 트리 확인

Lazy Initialization을 통한 최적화

  • 스프링 부트의 기본 Bean 초기화
    • 기본적으로 즉시 초기화로 동작
    • 어플리케이션 시작 시 모든 빈을 미리 로딩
    • 빈의 수가 많아질수록 구동 시간이 증가
  • Lazy Initialization 설정 방법
    • 어플리케이션 전체에 적용
      • spring.main.lazy-initialization=true
    • 개별 빈에만 적용
      • @Lazy 어노테이션 추가
  • Lazy Initialization의 장단점
    • 장점
      • 어플리케이션 시작 시간 단축
      • 사용되지 않는 빈의 초기화를 방지해 리소스 절약
    • 단점
      • 빈을 사용할 때 지연 로딩 시간 발생
      • 특정 시점에서 성능 오버헤드가 생길 수 있음
  • Lazy Initialization 최적화 전략
    • 자주 사용되지 않는 Bean에 적용
    • 대규모 모듈이나 외부 서비스 연동 Bean에 적용
    • 테스트 환경에서 사용 시 유용
  • Lazy Initialization과 빈 순환 참조 문제
    • 두 빈이 서로 순환 참조를 갖는 경우
    • Lazy Initialization으로 인해 순환 참조 발생 시 예외 가능성
    • 순환 참조 문제 해결을 위한 설계 개선 필요
  • Lazy Initialization의 대안 : Application Context 초기화
    • 프로파일을 통해 환경별로 빈 초기화 제어
    • Application ContextInitializer를 통한 컨텍스트 초기화 최적화
    • Bean 로딩 조건을 세분화해 필요 없는 빈의 초기화 방지

Fat JAR, AOT, CDS

  • Fat JAR란? 
    • 모든 종속성을 포함한 단일 JAR 파일
    • 스프링 부트에서 기본적으로 제공
    • 독립 실행 가능한 어플리케이션 배포에 적합
    • 배포와 실행이 간편하지만, JAR 크기와 구동 시간에 영향을 미침
  • Fat JAR 장점
    • 종속성이 모두 포함되어 있어 일관된 실행 환경 제공
    • 배포가 간편하고 단일 파일로 배포 가능
    • 서버 설정이나 라이브러리 설치 없이 실행 가능
  • Fat JAR 단점
    • JAR 크기 증가 : 모든 종속성을 포함하여 파일 크기 증가
    • 불필요한 라이브러리 포함 가능성
    • JAR 크기에 따라 어플리케이션 시작 시간 증가
  • Layered JAR를 통한 Fat JAR 최적화
    • Layered JAR : JAR 파일을 여러 계층으로 분리
    • 어플리케이션 코드와 종속성을 별도 레이어로 관리
    • 캐시 가능 : 종속성이 변경되지 않으면 캐싱을 통해 빌드 속도 향상
    • 특히, Docker 이미지 빌드에서 유용
  • Docker에서의 Fat JAR 최적화
    • Layered JAR와 Docker의 이미지 레이어 분리
    • Docker 이미지에서 종속성과 어플리케이션 레이어를 독립적으로 관리
    • 종속성 캐싱을 통해 Docker 이미지 빌드 속도 최적화
FROM open jdk:11-jre-slim
COPY build/libs/app.jar /app/app.jar
WORKDIR/app
ENTRYPOINT ["java", "-jar", "app.jar"]

 

  • AOT 컴파일 개요
    • JIT 컴파일 
      • 런타임에 코드가 실행될 때 동적으로 컴파일
      • 실행 시점에서 최적화를 수행
      • 초기 구동 시간은 느리지만, 장기적으로 성능이 좋아질 수 있음 
      • 장점
        • 빠른 시작 시간 : 초기 로딩 과정에서 컴파일 시간을 절약
        • 메모리 사용량 감소 : 미리 컴파일된 코드를 사용해 런타임 메모리 절감
        • 네이티브 이미지 : Spring Native로 경량화된 어플리케이션 생성
        • 클라우드 및 서버리스 환경에서 유리
    • AOT 컴파일
      • 실행 전에 코드를 미리 컴파일하여 성능 최적화
        • 스프링 부트에서 Spring Native를 사용해 AOT 컴파일 적용 가능
      • 구동 시점에서 빠르게 실행 가능
      • 메모리 사용량 감소 및 빠른 시작 시간 제공
  • Spring Native로 AOT 컴파일 적용
    • Spring Native : 스프링 어플리케이션을 네이티브 이미지로 변환
    • GraalVM : Spring Native가 GraalVM을 사용해 AOT 컴파일
    • 네이티브 이미지로 변환된 어플리케이션은 JVM 없이 실행 가능
dependencies {
	implementation("org.springframework.experimental:spring-native")
}

task.withType<JavaCompile> {
	options.compilerArgs.add("-parameters")
}

 

  • CDS 개념 및 기본 원리
    • JVM의 클래스 메타데이터를 공유 아카이브에 저장
    • 여러 JVM 프로세스가 동일한 클래스를 공유
    • 클래스 로딩 시간을 줄여 어플리케이션 구동 시간을 단축
    • 메모리 절약 : 클래스 데이터를 공유하여 중복 로딩 방지
    • 장점
      • 빠른 JVM 시작 시간 : 자주 사용하는 클래스의 로딩 시간을 단축
      • 메모리 절약 : 여러 JVM 인스턴스에서 클래스 데이터를 공유하여 중복 로딩 방지
      • 자바 기반의 마이크로서비스 환경에서 특히 유용
      • 대규모 서버 어플리케이션에서 메모리와 성능 최적화 
  • CDS 적용 방법
    • Shared Archive 생성
    • JVM에 아카이브 파일을 지정하여 CDS 활성화
    • 스프링 부트 어플리케이션에서의 적용 예시
    • 쉽게 말해서 자주 사용하는 클래스 정보를 미리 저장해두고 JVM이 이를 바로 활용하도록 만드는 방식
java -Xshare:dump-XX:SharedArchiveFile=app-cds.jsa -jar app.jar
java -Xshare:on -XX:SharedArchiveFile=app-cds.jsa -jar app.jar
  • 스프링 부트에서의 CDS 적용
    • 스프링 부트 어플리케이션의 빈 로딩 최적화
    • 빈 정의 및 초기화에 대한 메타데이터 공유
    • Spring Native와 함께 CDS를 사용해 더 빠른 시작 시간 구현
  • Dynamic CDS와 CDS의 차이
    • CDS : 고정된 클래스를 미리 아카이브에 저장하여 공유
    • Dynamic CDS : 동적으로 로드되는 클래스를 아카이브에 추가 가능
    • 어플리케이션 실행 중에도 아카이브 갱신 가능
Comments