우선 자바의 동작 과정을 다시 살펴보자
우선 소스코드가 컴파일을 통해 바이트코드로 변하고 이걸 jvm이 인터프리터를 통해 기계어(머신 코드)를 만들어서 사용한다. 이렇게 되면 아무튼 자바만 올라갈 수 있는 환경이면 다 돌아갈 수 있다.(WORA)
컴파일에서 바로 기계어를 만드는 c++, go, rust등에 비해 성능이 뒤쳐지게 된다. 컴파일 언어는 런타임 환경에서 준비된 기계어를 즉시 수행이 가능한데 코드 최적화도 진행해서 인터프리터 언어보단 빠르다. 문제는 빌드 환경이 c++ arch에 종속적임.
컴파일언어가 성능면에서 더 이득이라고 했는데 이 성능차이를 해결하기 위해 JVM에서는 JIT Compiler를 도입함.
JIT Compiler는 바이트코드를 캐싱하고 있다가 런타임 환경에 맞춰 수행하고 반복된 작업에 대해 더욱 성능이 올라간다.
JIT Complier가 자바 성능 향상에 도움이 되지만 어플리케이션이 시작하는 단계에서는 캐싱된 내역이 없기 때문에 자연스레 성능 이슈 발생한다.
그래서 의도적으로 캐싱하여 수행하는 JVM Warmup 절차가 필요하다.
왜 이걸 고려했냐면 latency이슈가 좀 크게 있었다.
병목을 찾기 위한 고려 항목
- cpu
- mem
- network bandwith
- tps
- apm으로 살펴봐도 외부 데이터베이스에서 지연이 거의 없더라..
- Thread개수에 대해 살펴봤는데 8192까지 늘어나게 설정이 되어있었음
- RDB와 connection pool이 20~50이더라
이제 남은건 계정 API에 jvm warmup이 잘 되어있나 봐야한다.
application ready가 발생하고 3초 지연을 주게 된다. 그후 liveness ready이벤트에 신호를 준다.
warmup동작을 살펴보면 liveness 이벤트 발생 시 계정 API에서 데이터베이스에 정해진 정보를 질의하게 되어있다.
분석 요약
우선 각 팟의 tomcat thread를 200여개로 수행할 수 있게
jvm warmup과정은 실제 사용하는 api를 로컬호스트로 호출하되 리얼 트래픽처럼..
warmup의 개선 로직
application ready(400 bad request) -> jvm warmup ->(200ok) traffic in
Ideation
- Graal JIT (소득 x)
- AOT(Ahead of time)compiler : 아직 스프링에서는 테스트 단계
- Redis Connection pool : 이걸로도 해결 x
- Warm up count : 상당수 늘려보니 응답 지연문제가 좀 해결되더라.
JIT Internals
- Method 전체단위로 컴파일을 한다.
- 이후 후속 최적화를 위해 Profiling 정보 수집 진행
- Tiered compilation이라는 단계별 컴파일을 통해 코드 컴파일 진행
-- c1 : optimization 간략한 최적화
-- c2 : fully optimization 최대 최적화 : 코드 캐시에 저장 및 수행속도 up
-- interpreter를 통해 기계어로 번역되고 메서드가 임계치 만큼 호출되면 c1 호출을 통한 최적화하고 그후 c2의 임계치만큼 더 호출되면 c2호출로 최적화 진행
Compilation level
- level 0 : interpreted code
- level 1 : simple c1 compiled code 더이상 최적화 불필요하다고 느끼는 곳, profile 수집도 안함
- level 2 : limited c2 compiled code 제한된 최적화 진행
- level 3 : full c1 compiled code profile수집 후 최적화 진행
- level 4 : c2 compiled code 성능 최적화
이 단계에서 c1과 c2는 별도 thread가 있음
jvm option으로 초기 코드 캐시와 최대 사이즈 조절 가능
만약 코드 캐시 풀이 다 차서 CodeHeap [NAME] is full. Compiler has been disabled 같은 메시지를 받는다면 캐시 사이즈를 올려야한다.
-XX:ReservedCodeCacheSize
설정된 임계치 획득법
$java -XX:+PrintFlagsFinal -version | grep Threshold | grep Tier
Tier3 : c1의 level3
Tier4 : c2의 level4
invocationThreshold : 메서드 호출 수
BackEdgeThreshold : 하나의 메서드 내 반복문 횟수
CompileThreshold : 메서드의 호출 수와 메서드 내 반복문 횟수를 더한 것에 대한 기준이 된다.
실행 시 진단 모드 수행
VM Options
- XX:+UnlockDiagnosticVMOptions -XX:+LogCompilation
-- JIT 로그 확인 가능
-- 실행과 동시에 hotspot_pid[PID Number].log 파일에 기록됨
그렇다고 무턱 warmup 횟수를 늘려버리면 오히려 느려져서 적당한 값 찾는게 중요
'뭔가를 봤거나 했다면 올리는 카테고리' 카테고리의 다른 글
티스토리 오류를 보고 왜 문제가 발생했는지 추측해보기 (0) | 2023.07.01 |
---|---|
if kakao 2022 : 카카오톡 메시징 시스템 재건축 이야기 끄적끄적 (0) | 2022.12.18 |
이게 돼요? 도커 없이 컨테이너 만들기 정리 (0) | 2022.12.10 |
FastAPI와 안드로이드에서 CORS를 허용하는 방법 (0) | 2022.07.31 |
220721 ~ 220722 정리 (0) | 2022.07.24 |