1. 들어가며
이전 장들에서 JVM 메모리 문제를 다루는 데 필요한 지식과 도구를 알아보았다면 이제 실전 사례를 보면서 익혀보자.
2. 사례 분석
JDK 버전을 올리거나, 하드웨어를 업그레이드하거나, 설계 및 개발 단계에서 미리 피할 수 있는 문제도 많지만 여기서는 배포 수준에서의 문제 해결에 집중해보자. 하드웨어와 소프트웨어를 유지한채로 배포와 설정 전략을 조율하여 문제를 풀거나 완화하는 방법을 중점적으로 알아보자.
2.1 대용량 메모리 기기 대상 배포 전략
현상
16GB 짜리 메모리를 가진 하드웨어에 12GB 힙을 주고 애플리케이션 서버 하나를 띄운뒤 운영했더니 웹사이트가 장시간 응답하지 않은 일이 자주 발생했다.
원인
- GC로 패러렐 컬렉터를 사용하고 있었고, 이는 STW 시간보다 처리량에 중점을 둔 GC라서 full GC 타이밍에 항상 STW가 길게 생긴 것이 원인이다.
해결
- 애플리케이션의 힙 사이즈를 1.5~2GB 로 줄이니 해결되었다.
- 혹은 한 하드웨어에 가상 머신 여러개를 띄워 논리적인 클러스터를 구성하면 된다.(하나 크게 말고 작은 pod 여러개)
- G1GC, ZGC 등 지연을 줄이는 GC를 선택했다.
번외
단일 가상 머신으로 거대 메모리를 관리할 계획이라면 다음 잠재 문제를 고려해야한다.
- 힙 메모리의 거대 블록들을 수거하느라 긴 STW 가 생기는 문제는 G1GC 이후 많이 줄어들었다.
- 단일 가상 머신이 거대메모리를 쓰면 힙덤프 파일도 엄청 커서 분석하기 어렵다.
- 가능하다면 단일 가상머신보다는 같은 물리 머신에 여러개의 서버 프로세스를 띄우고 다른 포트를 할당한 뒤 LB를 도입해서 요청을 분배하자. (스케일아웃하자)
- 스케일 아웃 방식으로 하더라도 단점은 있다.
- 노드들이 전역 자원을 놓고 경합한다. (e.g. Disk)
- 노드별로 노는 노드, 바쁜 노드가 나뉠 수 있다. → 이건 LB 설정 잘하면 되지 않을까?
- 로컬 캐싱하는게 까다로워진다. (멀티 인스턴스 환경이니까)