2018년 9월 15일 토요일

[Java] Ergonomics - Hotspot VM 문서를 보며 이해하기

Ergonomics의 사전적 의미는 "인체 공학의"라는 뜻입니다만, 이걸 정확히 어떻게 번역해야할지 몰라 그냥 영어를 썼습니다. 사람에 따라 다르고 변수가 많아 이를 다루는 인체 공학의 성격과, JVM의 GC 설정 역시 machine에 따라 다르고 애플리케이션에 따라 변수가 생길 수 있는 상황이 비슷하기 때문에 Ergonomics라는 단어를 쓴 걸로 이해하면 되겠습니다.

Ergonomics는 JVM과 Garbage collection이 애플리케이션의 성능을 높이기 위해 행위 기반의 휴리스틱 조절과 같은 처리들을 일컫습니다.

JVM은 platform에 따라서 garbage collector와 heap 크기, 그리고 런타임 compiler의 기본 선택이 달라집니다. 다양한 애플리케이션 타입에 따라 다양한 설정이 있을 수 있는데 이에 따른 command line 튜닝을 더 적게 하기 위해서죠. 게다가 행위 기반의 튜닝은 애플리케이션의 동작에 따라 heap 의 크기를 동적으로 최적화하기도 합니다. 이번 포스팅에서는 기본 설정과 행위 기반의 튜닝에 대해 살펴볼 것입니다. 여기서 기본 설정이 어떤가를 이해하고, 상세한 설정에 대해서는 다른 섹션에서 다루도록 하겠습니다.

Garbage Collector, Heap, and Runtime Compiler 기본 설정

아래와 같은 물리 스펙의 서버가 기준입니다.
  • 2개 이상의 물리 프로세서
  • 2GB이상의 물리 메모리
위 경우엔 아래가 기본입니다.
  • Garbage-First (G1) collector
  • 물리 메모리의 1/64의 초기 heap 크기(16GB machine일 경우 256MB입니다)
  • 물리 메모리의 1/4의 최대 heap 크기(16GB machine일 경우 4GB입니다)
  • Tiered compiler, using both C1 and C2

행위 기반의 튜닝

HotSpot VM garbage collectors는 정지 시간 최소화 혹은 애플리케이션 throughput 향상, 두 목표 중 하나에 최적화 된 설정을 할 수 있습니다. 만약 둘 중 하나를 만족시켰다면, 나머지 하나를 최대한 만족시키려고합니다. 물론 둘을 항상 충족시킬 수 있는 건 아닙니다. 둘 중의 하나도 만족 못 할 수도 있는거죠. 애플리케이션은 최소 살아있는 모든 객체를 위한 공간이 있어야하는데, 다른 설정이 목표 달성이 불가능하도록 될 수도 있는 거죠

최대 정지시간 목표

 정지 시간은 Garbage collector가 애플리케이션을 멈추고 더이상 사용하지 않는 객체들을 정리하여 공간을 확보하는 것입니다. 최대 정지 시간의 목표는 이 정지되는 시간 중 가장 오래 정지되는 시간을 제한하는 것입니다. 평균 정지시간과 이 평균 정지시간의 분산값은 Garbage collector가 관리합니다. 평균은 Garbage collection 시작부터 걸리는 시간이지만 최근에 멈춘 횟수가 많을수록 더 무겁도록 가중될 수 있습니다. 만약 정지 시간의 분산을 더한 평균이 최대 목표 정지 시간보다 클 경우, Garbage collector는 그 목표는 충족되지 않았다고 판단하게 됩니다.
 최대 정지 시간 목표는 command-line option으로 -XXMaxGCPauseMillis=<nnn>으로 줄 수 있습니다. 이 옵션은 Garbage collector에게 <nnn>만큼보다 더 적게 정지하도록 하라는 힌트로 해석됩니다. Garbage collector는 Java Heap 크기와 <nnn> milli초 보다 더 짧도록 다른 파라미터를 조절합니다. 그러나 이렇게 조절함으로써 Garbage collection이 더 자주 일어날 수도 있고, 애플리케이션 전체 Throughput이 감소할 수 있습니다. 그럼에도 불구하고 설정된 정지 최대 정지 시간을 충족 못 시킬 수도 있습니다. 정리하면 -XXMaxGCPauseMillis 옵션은 권고일 뿐입니다. Garbage collector가 최선을 다하겠지만, 보장되는 값이 아니라는 점에 주의하셔야합니다.

Throughput 목표

이 목표는 Garbage를 수집하는데 걸린 시간이라는 측면과, Garbage collection과 별개의 애플리케이션 시간에 관련된 값으로 측정된 것입니다.
 command-line 옵션으로는 -XX:GCTimeRatio=<nnn>으로 지정할 수 있습니다. 이 비율은 Garbage collection시간과 애플리케이션이 동작하는 시간의 비율로 1/(1+nnn) 값입니다. 예를 들면 -XX:GCTimeRatio=19라면, 1/(1+19) = 5%이며 이는 전체 실행시간에서 Garbage collection 시간이 5%이하로 차지하도록 권고하는 값입니다.

Garbage collection의 소요시간은 실행 정지를 유발하는 모든 Garbage collection의 총 시간입니다. 만약 Throughput 목표가 충족되지 않는다면, Garbage collector가 가능한 행동은 수집 정지 사이 애플리케이션이 정상 동작하는 시간을 늘릴 수 있도록 heap size를 늘리는 것입니다.

만약 Garbage collector가 위 두 목표를 모두 충족시켰다면, 목표 중 하나가 충족되지 않도록 heap 크기를 줄입니다. Garbage collector가 사용할 수 있는 최대 최소 힙크기는 -Xms=<nnn>과 -Xmx=<mmm>으로 각각을 설정할 수 있습니다.

튜닝 전략


만약 기본 최대 heap size보다 더 크게 할 필요성을 알지 못한다면 heap을 최대값으로 설정하지 마세요. 딱 애플리케이션에서 충분한 만큼만 Throughput 목표로 설정하세요.
애플리케이션의 행동 변화는 heap이 늘었다 줄었다하는 크기 변화를 일으킬 수 있습니다. 예를 들면 애플리케이션이 어떠한 이유로든 메모리에 많은 할당을 한다고 합시다. 그러면 같은 throughput을 유지하기 위해 heap은 늘어나게 됩니다.
만약 힙 크기가 최대 크기로 늘어나고 throughput 목표가 충족되지 않는다면, 그건 throughput 목표 대비 heap 최대 크기가 너무 작은 것이라고 할 수 있습니다. 최대 heap 사이즈를 플랫폼의 최대 물리 메모리와 가까운 값으로 설정하되 메모리 swap이 일어나지 않도록 조정하세요. 그리고 다시 애플리케이션을 실행하시면 됩니다. 만약 그래도 throughput 목표가 여전히 충족되지 않았다면, 애플리케이션 실행시간에 대한 목표가 사용 가능한 메모리량에 비해 너무 높은 것입니다.
만약 Throughput 목표가 충족될 수 있지만, 정지시간이 너무 길다면, 최대 정지시간 목표를 설정하세요. 이 목표를 설정한다는 것은 throughput 목표가 충족되지 않을 수 있다는 것을 의미하며, 애플리케이션 특성에 따라 적절한 값으로 타협하여 설정하세요.


Garbage collector가 목표를 충족을 위해 heap사이즈를 위아래로 조정하는 것은 자연스러운 일입니다. 애플리케이션이 안정 상태에 도달했더라도 그럴 수 있습니다. Throughput 목표는 heap크기가 커져야 유리하며, 최대 정지시간은 작아져야 달성하기 쉽기때문에 이 두 목표는 상충될 수 있습니다.

댓글 없음:

댓글 쓰기

[TroubleShooting] sbt could not find or load main class file

Have you gotten this error message, when you execute sbt in git bash? Error: Could not find or load main class file Caused by: java.lang....