2016년 8월 Geeknet, InfoQ, Tingyun이 공동 주최한 APMCon 2016 중국 애플리케이션 성능 관리 컨퍼런스에서 Java 성능 튜닝 전문가 Monica Beckwith가 "Java Performance Tuning Must-Read Code"(원제: Java Performance Engineer's 생존 가이드) 프레젠테이션. 연설 중에 Monica는 튜닝이 필요한 성능 요구 사항을 설정하는 방법, 분석해야 하는 지표, 목표 설정 후 튜닝을 구체적으로 수행하는 방법 등 Java 튜닝 모범 사례에 대해 개인적인 제안을 했습니다.
Monica Beckwith는 엔터프라이즈 애플리케이션의 Java 가상 머신 및 가비지 수집기 최적화에 중점을 두고 있으며 가비지 수집기 및 Java 메모리 모델에 대한 많은 기사를 발표했습니다. 그녀는 이전에 Oracle에서 근무하면서 G1 가비지 수집기 성능 팀을 이끌었고 현재는 독립 컨설턴트로 활동하고 있습니다. 모니카의 연설 이후 InfoQ는 그녀와 단독 인터뷰를 진행했습니다.
성능 튜닝 전 준비
모니카는 성능 최적화 프로젝트가 성능 요구 사항 분석 및 계획, 성능 결과 분석의 두 부분으로 구성된다고 믿습니다. 두 가지가 폐쇄 루프를 형성하므로 성능이 지속적으로 향상됩니다.
1. 성능 요구 사항 분석 및 계획
성능 요구 사항을 결정할 때 엔지니어는 먼저 세 가지 질문을 자문해야 합니다.
무엇이 사용자를 행복하게 만들까요?
무엇이 사용자를 짜증나게 합니까?
현재 문제에 관심을 갖고 해결해야 합니까?
다음으로 QoS에 대해 사용자 관점에서 생각해야 합니다. 측정 가능한 지표, 즉 SLA 서비스 수준 계약은 SLA 성능 지표(처리량, 응답 시간, 용량, 요청 공간, CPU 사용량 등)를 정의하고 분류하며 우선순위를 지정합니다.
1. 처리량/속도:
목표 - 설정된 처리량보다 낮을 수 있나요? 그렇다면 이 상태는 얼마나 오래 지속될 수 있나요?
측정 - 측정 방법(초당 트랜잭션 수, 메시지 수/초 또는 둘 다) 측정 위치(클라이언트, 서버 또는 브라우저)
2. >목표—설정된 응답 시간을 초과할 수 있습니까? 그렇다면 이 상태는 얼마나 오래 지속될 수 있습니까?
테스트—측정 방법(시간을 기준으로 계산) 99% 응답 평균값, 특정 응답 시간(5~9초)만 계산, 최악의 경우 또는 전체) 측정 위치(클라이언트, 서버 또는 전체 루프)
3.
허용 가능한 용량은 얼마입니까? 시스템이 과부하된 경우(부하 균형 문제) 용량을 측정하는 방법은 무엇입니까? 하나의 시스템과 모든 시스템이 견딜 수 있는 최대 용량은 얼마입니까? 지표를 모니터링해야 합니까?
2. 성능 결과 분석
여기서는 성능 결과 분석에 대해서만 설명합니다. 최종 사용자 경험에 영향을 미치고 예상 QoS를 달성하지 못하는 요소를 분석하고 성능 지표를 모니터링합니다. 다음 그림은 계층화된 상황 다이어그램입니다.
애플리케이션 계층 생태계: 애플리케이션 서비스, 애플리케이션 서버, 데이터베이스, 생태계의 기타 서비스
JRE 계층: 클래스 로딩 상태, JIT 컴파일 상태, 가비지 컬렉션 상태, 스레드 상태
운영 체제 계층: 시스템/커널 상태, 잠금 상태, 스레드 상태
하드웨어 계층: 메모리 대역폭/메모리 처리량/메모리 사용량, CPU/코어 사용량, CPU 캐시 효율성/사용량/수준, 프로세서 구조, IO 상태
성능 튜닝 실행
두 가지 구현 모드
모니카는 두 가지 구현 방법을 제안했습니다. : 하향식 및 상향식. 어느 것을 사용할지는 달성하려는 목표에 따라 다릅니다.
애플리케이션 수준에서 개선을 원하고 코드 수정 능력이 있는 애플리케이션 엔지니어라면 하향식 접근 방식을 사용할 수 있습니다.
플랫폼 수준에서 개선하고 싶다면 상향식 접근 방식을 사용할 수 있습니다. 먼저, 개선이 필요한 플랫폼 모듈을 식별하고, 두 번째로 관련 애플리케이션을 나열하고 워크로드를 평가한 다음 적절한 도구를 찾아야 합니다.
4단계
어느 방향이든 4단계로 나눌 수 있는데 첫 번째 단계는 모니터링, 두 번째 단계는 유도, 세 번째는 단계 분석, 4단계 튜닝 및 적용.
일반적으로 다음과 같은 지표가 우려됩니다.
CPU: CPU 상태, 커널 상태, 캐시 적중 및 실패 횟수, 분기 예측, 파이프라인, 조건부 전송, 로드-스토어 작업 모드 등
메모리: 메모리 사용량, 메모리, 구조와 관련된 대역폭, 읽기 및 쓰기 상태, 읽기 작업의 최대 대역폭, 쓰기 작업의 최대 대역폭, 최대 용량.
JVM/GC: 변경과 관련된 정보 수집, 일반 또는 동시 GC의 다양한 단계, 동시 작업 큐 및 작업 상태, 내부 큐 또는 캐시 등에 대한 정보를 수집합니다.
1. 모니터링
우선 모니터링부터 시작합니다.
모니터링 방법은 능동(알람 설정), 수동(네트워크 분할), 오프라인(로그 캡처)의 세 가지 유형으로 구분됩니다.
다음 세 가지 유형의 도구 중에서 선택할 수 있습니다.
타사 - VisualVM, Java Flight Recorder
JVM에는 PrintCompilation, PrintGCDetails(+PrintGCDateStamps), jmap-clstats, jcmd GC.class-stats
운영 체제와 함께 제공되는 명령이 포함되어 있습니다. 그것 - Linux에는 mpstat, sysstat-iostat, pidstat, prstat, vmstat, dash, CPU-Z, cacti 등이 있습니다. Windows에는 성능 모니터, 작업 관리자, 리소스 모니터, CPU-Z, cacti 등이 있습니다.
2. 요약 및 분석
다음 단계는 요약 및 분석입니다.
이 시점에서는 개선이 필요한 영역을 식별하고 개선이 필요한 잠재적인 문제를 분석해야 합니다. 이 링크에서 사용할 수 있는 오픈 소스 도구에는 두 가지 유형이 있습니다.
타사 성능 분석 도구 - Oracle Solaris Studio Performance Analyser, perftools, PAPI, Code XL, Dtrace, Oprofile, gprof, LTT
Java 프로그램 수준 - Visual VM, Netbeans Profiler, JConsole
3. 튜닝
튜닝의 마지막 단계입니다. JVM/GC 튜닝의 초점은 올바른 힙과 올바른 가비지 수집 알고리즘을 선택하는 것입니다. 먼저 개체의 수명을 올바르게 나눈 다음 장기 생존 개체만 조정합니다. 각 가상 머신의 모든 GC 작업자 스레드(GC의 세계 정지 현상)와 동일한 VM의 여러 GC 스레드가 실행됩니다. 일반 개체 포인터 압축이 작동하는 경우 큰 힙에서는 AlwaysPretouch를 활성화하고 UseLargePages를 최적의 크기로 설정해야 할 수 있습니다. 또한 SLA 목표를 달성하기 위해 코드 수준에서 최적화하고, 적절한 램프 업 및 램프 다운, 개체 연령 분할 및 보존 정책(LDS 파일의 구성 이해)을 설정하고 올바른 측정을 보장합니다.
모니카와 대화하기
InfoQ: 성능 분석 중에 모든 로그를 수집해야 하나요?
모니카: 일반적으로, 조정해야 할 사항이 있다는 것을 알게 되면 사용자는 프로덕션 환경에서 로그를 보내주시면 이를 기반으로 환경을 복제한 후 이 복제된 환경에서 테스트 및 검사를 하게 됩니다. 프로덕션 환경은 안정적이어야 하기 때문에 실제 환경에서 테스트하는 것은 권장하지 않습니다. 어떤 상황에서 모든 로그가 필요합니까? 메모리 누수와 같은 특정 문제가 있다고 확신하는 경우 이때 가능한 모든 로그를 수집해야 합니다.
InfoQ: 여러 GC 방법을 분석하고 간단한 평가를 할 수 있습니까?
Monica: 가비지 수집은 Java 애플리케이션 튜닝의 핵심입니다. GC는 가비지 정보를 수집할 뿐만 아니라 힙 할당 정보도 관리합니다. 모든 할당은 유사합니다. 일반적으로 객체를 세대로 나눌 수 있는 공간이 작은 경우 핫스팟 JVM에서는 이전 세대 객체를 최적화하는 것이 좋습니다. 왜냐하면 젊은 세대가 대다수를 차지하고 죽을 것이기 때문입니다. 이전 세대 수집 알고리즘의 일반적인 기본값은 가비지 표시 압축 알고리즘입니다.
CMS 가비지 수집기는 이전 세대의 재활용을 목표로 하며 루트 개체부터 시작하여 살아남은 개체를 표시합니다. 공간에 더 이상 살아있는 개체가 없으면 점유된 리소스가 해제되고 사용 가능한 목록으로 업데이트됩니다. CMS가 수행하는 작업은 사용 가능한 목록에 속해야 하는 모든 이전 세대를 여기에 나누는 것입니다.
또 다른 디자인은 G1입니다. 자원을 지역으로 나누는 방식으로, 일부 지역은 함께 젊은 세대를 구성하고, 일부 지역은 구세대를 구성합니다. 즉, 같은 세대의 모든 지역이 반드시 인접할 필요는 없습니다. 각 지역은 처음에는 임의적이며 젊은 세대 또는 오래된 세대로 선언되어야 합니다. 수집기간 동안 반드시 기성세대가 모두 참여하는 것은 아니다. G1은 쓰레기가 많은 지역을 수거하는 데 관심이 있습니다. 또한 G1은 젊은 세대의 간격 크기도 조정하려고 노력할 것입니다.
InfoQ: 현재 Java에서 가장 변경하고 싶은 것은 무엇입니까?
Monica: JDK 9 또는 JDK 10에서는 Java의 비힙 메모리 관리도 개선될 수 있습니다. 매우 어렵다. 개선해야 할 부분이 많다고 생각한다.
InfoQ: 더 나은 성능을 얻기 위해 Java 소프트웨어 개발 엔지니어가 주의해야 할 점은 무엇이라고 생각하시나요?
Monica: 프로그래밍할 때 Java GC가 어떻게 작동하는지 생각해야 합니다. 자원을 차지하는 것은 기한이 지난 물건이 아니라 살아있는 물건을 유지해야 하는 것입니다. 프로그래밍할 때 객체 생성, 보존 전략 및 가비지 수집기 작동 방식을 이해해야 합니다. 이 세 가지 점을 고려하는 것이 좋습니다. 모든 일이 조화롭게 조화를 이루면 좋습니다.