
성능 테스트 접근법빠르게 자주 테스트하자자바 성능 도구 상자CPU 사용률CPU 런 큐디스크 사용률네트워크 사용량자바 모니터링 도구기본 VM 정보스레드 정보클래스 정보구동 중인 GC 분석프로파일링 도구샘플링 프로파일러장착형 프로파일러네이티브 프로파일러자바 미션 컨트롤
성능 테스트 접근법
빠르게 자주 테스트하자
전부 자동화한다
모든 성능 테스트는 스크립트로 만들어야 한다. 스크립트는 신규 코드를 포함해서 (데이터베이스 연결, 사용자 계정 설정 등까지 포함해서) 전체 환경으로 설정하고 테스트 세트를 실행할 수 있어야 한다.
전부 측정한다
- 자동화를 할 때 이후의 분석에 유용할 데이터에 대해 수집 가능한 요소를 전부 모아야 한다.
- CPU 사용률, 디스크 사용률, 네트워크 사용률, 메모리 사용률 등 실행되는 동안 조사한 시스템 정보도 포함됨. 또한 애플리케이션 자체 로그와 가비지 컬렉터 로그도 포함
- 이상적으로 말하면 Java Flight Recorder(JFR)의 기록정보나 영향이 적은 프로파일링 정보, 주기적인 스레드 스택과 막대 그래프 같은 힙 분석 데이터 또는 전체 힙 덤프를 포함할 수 있다.
- 성능 저하의 원천을 찾아낼 때 탐정처럼 이용 가능한 데이터를 더 많이 모을수록 더 많은 단서를 얻게 된다. JVM이 반드시 성능 저하의 원인이 아니기에, 정확히 분석할 수 있도록 모든 요소에서 전부 측정하자.
- eg) CPU 사용률이 증가했다면 시간을 더 많이 쓰는 요소를 찾기 위해 프로파일 정보를 찾아봐야 한다. GC에 쓰는 시간이 증가 했다면 메모리를 더 많이 사용하는 요소를 찾기 위해 힙 프로파일을 찾아봐야 한다. 데이터베이스 로그는 데이터베이스 경쟁이 늘어난 요소를 나타낼 수 있다.
대상 시스템에서 실행한다
- 특정 제작 환경의 성능은 유사한 하드웨어에 예상 부하를 주어 테스트하지 않으면 결코 완전히 알 수 없다.
- 대규모 시스템은 여러 요소를 합친 것 이상이며 대상 플랫폼에서 적절한 부하를 주어 테스트하는 것을 대신할 수 없다.
자바 성능 도구 상자
성능 분석에서는 애플리케이션 내부와 그 환경에서 무슨 일이 벌어지는지 알 수 있도록 해주는 가시성(visibility)이 가장 중요하다. 가시성은 전부 도구를 통한다. 그리고 성능 튜닝은 도구를 이용해서 이뤄진다.
CPU 사용률
vmstat 1
: 유닉스에서 CPU 사용률 확인 명령어CPU 시간은 애플리케이션의 성능을 살펴볼 때 조사해야 할 첫 번째 요소다.
코드를 최적화하는 데 있어 목표는 (더 짧은 기간 동안) CPU 사용률을 내리는 것이 아니라 높이는 것이다.
애플리케이션을 조정하기 위해 시도하고 착수하기 전에 CPU 사용률이 낮은 이유를 이해하자.
- CPU 사용률은 전형적으로 두 개의 카테고리인 사용자 시간과 시스템 시간으로 나뉜다.
- 사용자 시간은 CPU가 애플리케이션 코드를 실행하는 시간의 백분율인 반면, 시스템 시간은 CPU가 커널 코드를 실행시키는 시간의 백분율이다.
- 예를 들어 애플리케이션이 I/O 작업을 수행한다면 커널은 디스크에서 파일을 읽거나 네트워크로 데이터를 쓰는 등의 코드를 실행시킬 것이다. 기반 시스템 자원을 사용하게 되면 애플리케이션은 시스템 시간을 더 쓰게 된다.
- 성능에서의 목표는 되도록 짧은 시간 동안 CPU 사용률을 가능한 한 높이는 것이다. 즉, CPU 의 유휴 상태를 줄이는 것
- CPU가 유휴 상태가 되는 가능한 이유들
- 애플리케이션은 동기화 기본 연산에서 차단되며 락이 해제될 때까지 실행될 수 없다.
- DB에 대한 호출로부터 되돌아오는 응답과 같은 뭔가를 기다릴 수 있다.
- 애플리케이션이 아무 것도 처리하지 않을 수 있다.
- 멀티 CPU 머신에서 실행되는 여러 개의 스레드는 작업을 완료하고 다음 작업을 기다리므로, 성능을 향상시키려면 (간격을 길게 하고) CPU가 느려지게 하거나 개별적인 스레드들이 차단되지 않도록 해서 CPU의 사용률을 더 높인다.
- 멀티스레드, 멀티 CPU에서 중요한 부가사항 : 작업을 처리할 프로그램에 가용 스레드가 없으면 CPU가 유휴상태가 될 수 있다.
- 행동방침을 결정하기 전에 프로그램이 CPU를 할당받지 않는 이유를 이해하는 것이 중요하다
CPU 런 큐
- 실행시킬 스레드가 가용 CPU 보다 많다면 성능은 저하되기 시작할 것이다. 일반적으로 윈도우에서는 프로세서 큐의 길이가 0이 되고, 유닉스 시스템에서는 CPU 숫자와 같길(또는 적길) 원한다.
- 런 큐의 길이가 특정 기간에 너무 크다면 머신이 과부하를 받는다는 표시
디스크 사용률
iostat -xm 5
1. 디스크 사용률의 모니터링은 모든 애플리케이션에 있어 중요하다. 디스크에 직접 쓰지 않는 애플리케이션에서 시스템 스왑은 성능에 영향을 미칠 수 있다.
2. 디스크에 쓰는 애플리케이션은 비효율적으로 데이터를 쓰거나 (너무 작은 처리량) 너무 많은 데이터를 쓰는 (너무 많은 처리량) 경우 둘다 병목 현상이 일어날 수 있다.
디스크 사용률 모니터링의 중요한 목표 두가지
- 애플리케이션 그 자체를 보는 것
- 애플리케이션이 디스크 I/O를 많이 일으키면 I/O는 병목되기 쉽다.
- 시스템의 스왑(swap) 현황을 모니터링하는 데 도움이 된다.
메인 메모리에서 데이터 페이지를 디스크로 옮기거나 그 반대로 스왑하고 있는 시스템은 일반적으로 성능이 나쁠 것이다.
네트워크 사용량
nicstat
: 네트워크 대역폭을 모니터링하는 유닉스 시스템에서 인기 있는 명령어 도구이 도구의 유용성은 인터페이스의 이용률을 계산한다는 점
자바 모니터링 도구
- jcmd : VM 프로세스에 대한 VM 정보, 기본 클래스, 스레드를 출력.
jcmd <pid> GC.heap_info
: VM의 Heap 정보 확인 가능 [ Baeldung : CLI Tools for java heap size ]
- jconsole : 스레드 사용률 및 클래스 사용률과 GC 활동 내역을 포함해서 JVM 활동 내역을 그래픽 형태로 노출
- jhat : 메모리 힙 덤프를 읽고 분석하는 데 도움을 준다. 후처리 유틸리티 임
- jmap : 힙 덤프와 JVM 메모리 사용률에 대한 정보를 제공한다. 힙 덤프는 후처리 도구에서 사용돼야 하지만 스크립팅에 적합하다.
- jinfo : JVM의 특성에 대해 가시성을 제공하고 일부 시스템 특성을 동적으로 설정하게 한다. 스크립팅에 적합
- jstack : 자바 프로세스의 스택 덤프를 뜰 수 있다. 스크립팅에 적합
- jstat: GC와 클래스 로딩 활동에 대한 정보를 제공. 스크립팅에 적합 [ 명령어 사용법, Oracle docs ]
- CGC : Concurrent Garbage Collection
- jvisualvm : JVM을 모니터링하고 실행 중이니 애플리케이션을 프로파일하고 JVM 힙 덤프를 분석하기 위한 GUI 도구다.
기본 VM 정보
- 가동 시간 :
jcmd process_id VM.uptime
- 시스템 속성 :
jcmd process_id VM.system_properties
,jinfo -sysprops process_id
- D 옵션이 있는 커맨드 라인의 모든 속성 세트, 애플리케이션에 의해 동적으로 추가된 속성, JVM을 위한 디폴트 속성 세트가 포함된다.
- JVM 버전 :
jcmd process_id VM.version
- JVM 커맨드 라인 :
jcmd process_id VM.command_line
- JVM 튜닝 플래그 :
jcmd process_id VM.flags [-all]
스레드 정보
jconsole
과jvisualvm
은 애플리케이션 내에서 동작하고 있는 스레드의 개수에 대한 정보를 (실시간으로) 노출한다.
클래스 정보
- 애플리케이션이 사용 중인 클래스의 개수에 대한 정보는
jconsole
이나jstat
을 이용해서 구할 수 있다.
jstat
은 클래스 컴파일에 대한 정보도 제공 가능하다.
구동 중인 GC 분석
사실상 모든 모니터링 도구는 GC 활동 내역에 대한 정보를 보고한다.
- jconsole은 힙 사용률에 대한 생생한 그래프를 보여준다.
- jcmd는 GC 동작이 수행되게 한다.
- jmap은 퍼머넌트 제너레이션에 대한 정보나 힙 요약 정보를 출력하거나 힙 덤프를 생성한다.
- jstat은 가비지 컬렉션이 하는 일에 대한 뷰를 달리해서 많이 만든다.
프로파일링 도구
- 프로파일링은 샘플링 모드나 장착형 모드 중 하나에서 진행된다.
- 샘플링 모드는 프로파일링의 기본 모드이며 최소한의 오버헤드를 야기시킨다.
- 프로파일링의 위험 요소 중 하나는, 애플리케이션에 측정 관련 설정을 하면서 기존 성능 특성을 변경한다는 점이다.
샘플링 프로파일러
- 샘플링 프로파일러에는 모든 종류의 에러가 발생할 수 있다.
- 샘플링 프로파일러는 주기적으로 타이머가 작동될 때 동작한다. 그다음 프로파일러는 각 스레드를 살펴보고 스레드가 실행되고 있는 방식을 알아낸다.
장착형 프로파일러
- 장착형 프로파일러는 샘플링 프로파일러보다 훨씬 더 결합도가 높지만 프로그램 내에서 일어나고 있는 상황에 대해 더 유익한 정보를 줄 수 있다.
- 그러나 장착형 프로파일러는 (호출 수를 세기 위한 코드를 삽입해서) 로드된 클래스의 바이트 코드 순서를 변경시키면서 동작하기에 애플리케이션에 성능상의 차이가 더 많이 생기게 한다.
- 예를 들어 JVM 은 작은 메서드를 인라인으로 만드므로 작은 메서드 코드가 실행될 때 호출될 필요가 없다. 컴파일러는 코드의크기를 바탕으로 결정을 내리기에 코드가 장착되는 방식에 따라 인라인 대상이 되지 않을 수도 있다.
네이티브 프로파일러
네이티브 프로파일링 도구는 JVM 자체를 프로파일한다. 이건 JVM이 하고 있는 일 뿐만 아니라 애플리케이션이 자체 네이티브 라이브러리를 포함하고 있다면 코드도 가시적으로 보이게 한다.
자바 미션 컨트롤
자바의 오픈 소스는 아니고 상용 라이선스로만 사용할 수 있다.
자바 미션 컨트롤의 주요 기능은 자바 플라이트 레코더(Java Flight Recorder, JFR)이다.
JFR의 기본 동작은 이벤트(예를 들어 스레드가 락 때문에 블록되는 이벤트)의 일부 세트를 활성화시키는 것이다. 선택된 이벤트가 일어날 때마다 이벤트에 대한 데이터가 (메모리나 파일로) 저장된다.