2022년 진행된 if(kakao)에서 발표하신 카카오모빌리티 이형구님의 JVM Warm Up 세션을 보고 정리한 내용입니다.
계정 서버 배포 직후 발생하는 초기 API 응답 Latency 지연문제를 JVM에서 원인을 찾고 해결한 내용입니다.
제가 작성한 모든 글의 내용과 사진은 if(kakao)2022에서 발표한 내용을 인용 및 사용하였습니다.
계정 서비스
계정 서비스는 높은 TPS를 특징으로 가지고 있으며, 빠른 응답 속도를 보장하는 것이 중요한 서비스이다.
Java, Spring 기반으로 서비스가 작성되어 있으며, 오늘의 내용을 살펴보기 앞서 Java에 대해 잠깐 알아볼 필요가 있다.
작성된 Java Code를 중간언어인 Byte Code로 변환되며 War, Jar로 Archive되어 사용된다.
빌드된 파일을 실행하면 JVM(Interprete)에서는 Byte Code를 번역하여 기계어를 만들고 기계어를 CPU에서 처리하는 절차를 가진다.
이렇게 빌드된 Byte Code는 별도의 추가 빌드 없이 Java가 실행 가능한 CPU 아키텍처 혹은 OS에 상관없이 실행이 가능하다.
이렇듯 Java는 컴파일과 인터프리트 두가지 과정을 거쳐서 실행되게 된다.
그렇기에 컴파일 과정에서 기계어를 바로 만드는 C, C++, golang과 비교하면 성능이 떨어지게 된다.
또한 해당 언어들은 이 과정에서 코드 최적화또한 진행하기에 Interprete 언어와 비교하여 좋은 성능을 가지게 된다.
다만 이런 언어들은 컴파일 시점에 CPU에 종속적이 되어버리기때문에 다른 CPU 환경에서는 다시 빌드를 해야하는 단점이 있다.
JIT(Just In Time) Compiler
Java는 이런 성능 문제를 해결하기 위해 JIT(Just In Time) Compiler를 도입하였다. (JDK1.3버전 부터 반영)
JIT 컴파일러는 Byte Code를 기계어로 변환하는 과정에서 기계어를 캐시에 저장하고 사용하게 된다.
이를 통해 반복되는 기계어 변환 과정을 줄이고 성능을 향상시킨다. 더불어 런타임 시점에 코드를 최적화함으로 추가적인 성능을 향상시킨다. 그래서 애플리케이션 시작후 의도적으로 로직을 실행시켜 기계어가 캐시에 저장될 수 있도록하는 Warm Up 절차가 필요하다.
대응
기존 계정 서비스에도 Warm Up 절차가 존재했지만 실제 동작하는 API 로직이 아닌 database query를 호출하는 형태로 되어 있었기에 localhost api call 과정을 통해서 코드 캐싱이 될 수 있도록 조치를 진행하였다. 추가적으로 서버 실행후 tomcat thread 갯수가 200개 까지 증가하였기때문에 초기 tomcat thread 갯수를 10개에서 200개로 늘려주었다.
Warm Up 과정을 살펴보면 기존과 동일하게 쿠버네티스의 Liveness/Readiness Probes 과정에서 처리하게된다.
쿠버네티스 readiness 요청에 대해 400 응답을 Application에 응답함으로 트래픽을 중단시키고 Warm Up 절차가 완료 되면 Readiness Probe 요청에 200 응답을 반환함으로 트래픽을 인입시킨다.
이전에는 지정된 시간 만큼만 지연시키고 트래픽을 인입시켰다면 Warm Up이 완료된 후 트래픽이 인입되도록 수정하였다.
Warm Up은 각 Pod마다 localhost로 API를 호출하도록 처리함.
대부분의 GET API가 대상으로 포함되었다.
특히 서비스에서 자주 사용되거나 APM에서 지연대상으로 포함된 API를 Warm Up대상으로 추가하였다.
이후 문제가 되었던 초기 응답 지연은 해소 되었다.
'Java' 카테고리의 다른 글
[Java] Java 원격 디버깅(Java Remote Debugging) (0) | 2025.01.08 |
---|---|
[Java] JVM의 한계와 GraalVM 살펴보기 (1) | 2024.12.16 |
[JAVA] 회원 시스템 분산 트랜잭션(JTA) 처리와 성능 이슈 해결 (1) | 2024.10.31 |