Skip to content

Commit

Permalink
Mingi (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
meengi07 authored Jan 17, 2024
1 parent 5072f16 commit 43c901c
Show file tree
Hide file tree
Showing 8 changed files with 465 additions and 0 deletions.
168 changes: 168 additions & 0 deletions ch04/김민기.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# Chapter4. 성능 테스트 패턴 및 안티패턴

좋은 성능 테스트는 ‘정량적 quantitative‘ 이다. 어떤 질문을 던져도 실험 결과를 토대로 수치화한 답변이어야 한다.

## 1. 테스트 유형

### 1.1 지연 테스트 (Latency test)

가장 일반적인 테스트로 예를 들어 종단 트랜잭션에 걸리는 시간 이 있다.

### 1.2 처리율 테스트 (Throughput test)

현재 시스템이 처리 가능한 동시 트랜잭션 개수등을 테스트하며, 어떤 측면에서 처리율은 지연과 동등한 개념이라고 볼 수 있다. 지연 테스트를 수행할 때는 계속 진행 중인 동시 트랜잭션을 반드시 명시해야 한다.

모니터링을 통해 지연 분포가 갑자기 변하는 시점, 사실상 한계점(변곡점)이 ‘최대 처리율’이다.

### 1.3 부하 테스트 (Load test)

특정 부하를 시스템이 감당할 수 있는가? 등을 파악하며 처리율 테스트와 달리 ‘시스템이 이 정도 부하는 견딜 수 있을까?’ 에 대한 대답을 구하는 과정이다. 특정 비즈니스(광고, 이벤트,바이럴등 순간 부하 이벤트)에 대비하기 위함

### 1.4 스트레스 테스트(Stress test)

이 시스템의 한계점(breaking point)은 어디까지인가?

시스템 여력이 어느 정도인지 알아보는 수단으로 일정 수준의 트랜잭션, 즉 처리율을 시스템에 계속 걸어두어 동시 트랜잭션이 증가하고 시스템 성능이 저하되는 시점, 측정값이 나빠지기 시작하기 직적의 값이 최대 처리율이다.

### 1.5 내구성 테스트(Endurance test)

시스템을 장시간 실행할 경우 성능 이상 증상이 나타나는가?

메모리 누구, 캐시 오염, 메모리 단편화등 시간이 지나고 나서야 드러나는 문제점도 있다. 대개 이런 종류의 문제는 내구 테스트로 감지한다.

### 1.6 용량 계획 테스트(Capacity planning test)

리소스를 추가한 만큼 시스템이 확장되는가?

스트레스 테스트와 비슷하지만 스트레스는 현재 시스템을 기준으로 하지만 용량 테스트는 업그레이드한 시스템이 어느 정도 부하를 감당할 수 있는지 미리 파악하는 것이다.

### 1.7 저하 테스트 (Degradation)

시스템이 부분적으로 실패할 경우 어떤 일이 벌어지나?

## 2. 기본 베스트 프랙티스

성능 튜닝 시 주안점은 세 가지 기본 원칙에 따라 결정한다.

- 나의 관심사가 무엇인지 식별하고 그 측정 방법을 고민한다
- 최적화하기 용이한 부분이 아니라, 중요한 부분을 최적화한다
- 중요한 관심사를 먼저 다룬다

### 2.1 하향식 성능

전체 애플리케이션의 성능 양상부터 먼저 알아보는 방식을 의미한다. 테스트 환경을 구축한 뒤 무엇을 측정하고 최적화해야 하는지, 성능 활동을 전체 소프트웨어 개발 주기에서 어떻게 병행해야 하는지 이해해야 한다.

### 2.2 테스트 환경 구축

가급적 운영 환경과 똑같이 복제해야 하며, 서버 뿐아니라 웹서버, DB, 로드밸런서, 네트워크등 모든 환경을 가급적 맞춰야한다.

### 2.3 성능 요건 식별

전체 시스템 성능은 애플리케이션 코드 뿐 아니라 컨테이너, OS, 하드웨어 모두 영향을 미친다.

성능을 평가하는 지표는 코드 관점만이 아닌 시스템을 전체적으로 바라보며 측정값을 고려해야 한다. 이런 최적화하려는 핵심 지표를 성능 비기능 요건(NonFunctional Requirement, NFR)라고 한다.

### 2.4 자바에 특정한 이슈

JVM은 메모리 영역의 동적 튜닝 등 JVM 특유의 다이나믹한 자기 관리 능력이 추가되면서 복잡해졌다. 특히 JIT 컴파일은 중요한 부분이다. 최근 JVM은 어떤 메서드를 JIT 컴파일해서 최적화한 기계어로 변환할지 분석한다. 컴파일을 안하기로 결정한 메서드는 둘 중 하나다.

- JIT 컴파일할 정도로 자주 실행되는 메서드가 아니다.
- 메서드가 너무 크고 복잡해서 도저히 컴파일 분석을 할 수 없다.

JVM 기반 애플리케이션에서 성능 활동을 시작하는 첫 단추는 어떤 메서드가 컴파일 중인지 로그를 남겨 살피고 핵심 코드 경로상의 중요 메서드가 잘 컴파일되고 있는지 확인하는 것이다.

### 2.5 SDLC 일부로 성능 테스트 수행하기

일류 회사거나 수준 높은 팀일수록 성능 테스트를 전체 SDLC(Software Development LiftCycle, 소프트웨어 개발 수명주기)의 일부로서 수행하며 성능 회귀 테스트를 상시 수행한다.

## 3. 성능 안티패턴 개요

안티패턴(antipatten)은 사람들이 수많은 프로젝트를 수행하면서 밝혀낸 소프트웨어 프로젝트 또는 팀의 좋지 않은 패턴이다. 캐리 플리첼은 ‘왜 개발자는 잘못된 기술 선택을 밥 먹듯이 하나’ 라는 게시글에서 그 원인을 다섯 가지로 분류했다.

- 지루함

예를 들어 Collections.sort() 대신 복잡한 정렬 알고리즘을 구현해 필요 이상으로 복잡하게 코딩하거나, 잘 알려지지 않은 기술로 컴포넌트를 제작하거나, 맞지도 않은 유스케이스에 억지로 기술을 욱여넣는 등 여러 방법으로 지루함을 표출하기도 한다.

- 이력서 부풀리기

본인의 이력서를 과대 포장할 구실을 찾는 개발자도 있다. 이런 경우도 프로젝트를 불필요한 방향으로 끌고 가는 선택의 발단이 될 수 있다.

- 또래 압박

팀원들이 기술을 결정할 때 관심사를 분명히 밝히지 않고, 서로 충분한 논의 없이 진행하면 쓰디쓴 결과를 맛보기 쉽다.

- 이해 부족

사용하는 툴의 기능도 온전히 알지 못하는데 무턱대고 새로운 기술로 문제를 해결하려 하는 경우도 있다.

- 오해와 있지도 않은 문제

문제 자체가 무엇인지 제대로 이해하지 못한 채 오로지 기술을 이용해서 문제를 해결하려는 개발자도 있다. 성능 지표를 수집/분석해야만 비로소 문제의 본질을 정확히 이해할 수 있다.


## 4. 성능 안티패턴 카탈로그

1. 최신의 기술을 튜닝 타깃으로 정하고 레거시를 피한다면서 새로 나온 기술을 찾아 헤매는 강박에 사로잡힌다.
- 측정을 해보고 진짜 성능 병목점을 찾자
- 새 컴포넌트는 전후로 충분한 로그를 남기자
- 베스트 프랙티스 및 단순화한 데모를 참조하자
- 팀원들이 새 기술을 이해하도록 독려하고 팀 차원의 베스트 프랙티스 수준을 정하자
2. 전체적으로 애플리케이션을 프로파일링해서 객관적으로 아픈 부위를 들추려 하지 않고 무작정 시스템에서 제일 간단한 부분만 파고든다.
- 측정을 해보고 진짜 성능 병목점을 찾자
- 본인이 익숙치 않은 컴포넌트에 문제가 생기면 잘 아는 전문가에게 도움을 요청하자
- 개발자가 전체 시스템 컴포넌트르 골고루 이해하도록 독려하자
3. 성능 튜닝, ‘천재 해커’에 로망이 있는 사람
- 측정을 해보고 진짜 성능 병목점을 찾자
- 새로 채용된 팀내 전문가가 다른 팀원들과 지식을 공유하고 팀워크를 유지할 수 있게 리드하자
4. 인터넷 글을 보고 테스트도 안하고 그대로 따라한다.
- 시스템의 가장 중요한 부분에 영향을 미치는 기술은 확실히 파악하고 충분히 검증된 것만 적용하자
- 매개변수를 UAT에서 시험해보자, 어떤 변화라도 철저히 검증하고 효용을 프로파일링하는 일이 중요하다
- 다른 개발자나 운영 요원, 데브옵스팀과 함께 설정 문제를 리뷰하고 토의하자
5. 정작 이슈와 상관없는 컴포넌트를 문제 삼는다.
- 성급한 결론을 내리고픈 욕망에 굴하지 말자
- 정상적으로 분석하자
- 분석 결과를 (문제를 일으킨 원일을 구체화하기 위해) 모든 이해관계자와 의논하자
6. 전체적인 변경 영향도를 완전히 파악하지 않은 채 일단 변경하거나 국소적인 부분만 프로파일링한다.
- 운영계 성능 지표를 측정한다
- UAT에서 한번에 스위치 하나씩 변경한다
- 스트레스를 받는 지점이 UAt와 운영계가 동일한지 확인한다
- 운영계에서 일반적인 부하를 나타내는 테스트 데이터를 확보한다
- UAT에서 스위치를 변경하며 테스트한다
- UAT에서 다시 테스트한다
- 추론한 내용을 다른 사람에게 재검토 요청한다
- 내린 결론을 다른 사람과 공유한다
7. UAT 환경이 운영계 환경과 다른 경우가 많다.
- 서비스 중단 비용과 고객 이탈로 인한 기회비용을 잘 따져보자
- 운영 환경과 동일한 UAT 환경을 구입하자
- 나중에 고치는 비용이 더 많이 들 테니, 관리자들에게 사례를 제시하자
8. 데이터라이트(DataLite)라고도 하는 이 안티패턴은 사람들이 운영계와 유사한 데이터를 나타내고자 할 때 빠지는 함정이다.
- 데이터 도메인 전문가에게 컨설팅을 받고 운영 데이터를 UAT로 다시 이전하는 프로세스에 시간과 노력을 투자하자
- 다수의 고객이 몰리고 많은 트랜잭션이 예상되는 서비스는 출시 전 철저히 준비하자

## 5. 인지 편향과 성능 테스트

인지 편향 : 인간의 두뇌가 부정확한 결론을 내리게 이끄는 심리 작용으로 편향을 보이는 사람이 대개 자신이 그런 줄도 모르고 스스로는 아주 이성적이라고 믿는 게 더 큰 문제다.

### 5.1 환원 주의

시스템을 아주 작은 조각으로 나눠 그 구성 파트를 이해하면 전체 시스템도 다 이해할 수 있다는 분석주의적 사고방식이다. 문제는 복잡한 시스템은 그렇지 않다는 것이다.

### 5.2 확증 편향

성능 면에서 중대한 문제를 초래하거나 애플리케이션을 주관적으로 바라보게 한다. 고의는 아니지만 테스트 세트를 부실하게 선택하거나 테스트 결과를 통계적으로 건전하게 분석하지 않으면 확증 편향의 포로가 되기 쉽다.

### 5.3 전운의 그림자(행동 편향)

시스템이 예상대로 작동하지 않는 상황, 또는 아예 중단된 시간중에 발현되는 편향이다.

- 영향도를 분석해보지도 않고, 또 다른 사람에게 연락도 안하고 시스템 인프라를 변경한다.
- 시스템이 의존하는 라이브러리를 변경한다
- 연중 가장 업무가 빠듯한 날에 처음 보는 버그나 경합 조건이 발생한다

### 5.4 위험 편향

애플리케이션 문제가 발생했을 때 제대로 학습하고 적절한 조치를 못한 까닭에 더 고착화된다.

### 5.5 엘스버그 역설

알려지지 않은 미지의 것 보다 알려진 기지의 것을 추구하는 인간의 본연의 욕구에 관한 역설을 주장
74 changes: 74 additions & 0 deletions ch05/김민기.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Chapter5. 마이크로 벤치마킹과 통계

작은 자바 코드 한 조각의 성능을 정확히 측정(마이크로 벤치마킹)에 대해 알아보자

마이크로벤치마킹 툴의 업계 표준인 JMH(Java Microbenchmark Harness) 사용법을 설명한다.

## 1. 자바 성능 측정 기초

성능 분석은 기초 실험과학 분야로 귀결된 다양한 기술 측면을 종합한 것이다. 벤치마크란 입출력을 지닌 일종의 블랙 박스와도 같다. 어떤 결과를 추측하는데 필요한 데이터를 수집하려고 하지만 데이터를 모으는 것 뿐 아니라 그 데이터에 현혹되지 않도록 주의해야 한다.

목표는 벤치마크로 공정한 테스트를 하는 것이다. 시스템의 한 곳만 변경하고 다른 외부 요인은 벤치마크 안에 두고 통제하면 좋다.

자바 플랫폼을 벤치마크 할 땐 자바 런타임의 정교함이 가장 문제다. 자바 코드 실행은 JIT 컴파일러, 메모리 관리, 그밖의 자바 런타임이 제공하는 서브 시스템과 완전히 떼어놓고 생각할 수 없다. 테스트할 당시 OS, 하드웨어, 런타임 조건의 작용 또한 무시할 수 없다.

보통 벤치마크의 문제점은 JVM 웜업을 고려하지 않은 채 그냥 코드를 테스트했다는 것이다. JIT 컴파일러는 JVM에 내장된 덕분에 인터프리티드 바이트코드는 고도로 최적화된 기계어로 변환된다. JIT 컴파일러는 메서드를 몇 번 실행해본 다음 곧바로 임무를 개시한다.

JIT컴파일러는 코드를 조금이라도 효율적으로 작동시키려고 호출 계층을 최적화 하므로 벤치마크 성능은 캡처 타이밍마다 달라진다. 캡처 로깅을 할 땐 JVM이 웜업을 통해 가동 준비를 마칠 수있게 기간을 두는 게 좋다. 보통 타이밍 세부를 캡처하지 않은 상태로 벤치마크 대상 코드를 여러 번 반복 실행 하는 식으로 JVM을 예열한다.

또 한가지 고려할 외부 요인은 가비지 수집이다. 타이밍 캡처 도중에 GC가 안 일어나게 설정한 다면 좋지만 가비지 수집은 불확정적으로 어찌할 수 없다. GC가 일어날 가능성이 큰 시기에는 타이밍을 캡처하지 않는게 최선이겠다.

벤치마크에서 흔히 저지르는 또 다른 실수는 테스트하려는 코드에서 생성된 결과를 실제로 사용하지 않는 것이다. 방금 벤치마크서 copy는 사실상 죽은 코드이므로 JIT 컴파일러가 이를 죽은 코드 경로로 식별하고 정작 우리가 벤치마크하려던 것을 최적화해버릴 가능성이 있다.

벤치마크 코드를 바로잡는 일은 복잡하고 여러 요인을 고려해야 한다.

해결방안

1. 시스템 전체를 벤치마크한다. 저수준 수치는 수집하지 않는다.
2. 연관된 저수준의 결과를 의미있게 비교하기 위해 앞서 언급한 많은 문제를 공통 프레임워크를 이용해 처리하는 것이다. 이상적인 프레임워크는 몇 가지 문제는 어느 정도 해결할 것이다.

## 2. JMH 소개

위에 소개한 문제를 해결할 수 있는 툴로 JMH가 있다. 그전에 먼저 순진하게 접근하면 마이크로벤치마킹이 얼마나 잘못되기 쉬운지 그 이유는 무엇인지 알아보자

### 2.1 될 수 있으면 마이크로벤치마크하지 말자

신버전의 라이브러리와 기술들로 애플리케이션을 개발했는데 성능이 이전보다 나아지지 않았고, 문제를 찾지못해 소규모 벤치마크를 통해 확인하고 있었지만, CPU 사용률이 정점을 찍고 있다는 사실을 파악해보니 코드의 문제가 아닌 인프라 라이브러리가 문제였다.

### 2.2 휴리스틱:마이크로벤치마킹은 언제할까

일반적으로 저수준 분석이나 마이크로벤치마킹을 하는 주요 유스케이스는 다음 세 가지다.

- 사용 범위가 넓은 범용 라이브러리 코드를 개발한다
- OpenJDK 또는 타 자바 플랫폼 구현체를 개발한다
- 지연에 극도로 민감한 코드를 개발한다 (예: 저지연 거래)

### 2.3 JMH 프레임워크

JMH는 자바를 비롯해 JVM을 타깃으로 하는 언어로 작성된 나노,마이크로,밀리,매크로 벤치마크를 제작,실행,분석하는 자바 도구이다. JVM을 빌드한 사람들이 만든 프레임워크라 JVM버전 별 함정과 최적화 베어 트랩을 피하는지 잘 알고 있다.

### 2.4 벤치마크 실행

JMH는 벤치마크 툴에 관한 몇 가지 핵심적인 설계 이슈를 고려해서 만들었다. 벤치마크 프레임워크는 컴파일 타임에 벤치마크 내용을 알 수 없으므로 동적이어야 한다. 리플렉션을 써서 작성한 벤치마크를 실행하는 우회 방법도 있지만 벤치마크 실행 경로에 복잡한 JVM 서브시스템이 하나 더 끼어들게 된다. 그래서 JMH는 벤치마크 코드에 애너테이션을 붙여 자바 소스를 추가 생성하는 식으로 작동한다. 또한 최적화가 되지 않도록 반복 횟수를 설정한 루프안에 감싸넣어 피한다.

`@Benchmark` 어노테이션으로 프레임워크의 실행시킬 메서드를 나타낸다.

## 3. JVM 성능 통계

모든 측정은 어느 정도의 오차를 수반한다. 다음은 성능 분석 시 흔히 맞닥뜨리는 두 가지 주요 오차 유형이다.

### 3.1 오차 유형

- 랜덤 오차 : 측정 오차 또는 무관계 요인이 어떤 상관관계 없이 결과에 영향을 미친다.
- 계통 오차 : 원인을 알 수 없는 요인이 상관관계 있는 형태로 측정에 영향을 미친다.

> **정확도(accuracy)**는 계통 오차의 수준을 나타내는 용어로, 정확도가 낮으면 오차가 낮은 것
**정밀도(precision)**는 랜덤 오차를 나타내는 용어로, 정밀도가 높으면 랜덤 오차가 낮은 것
>
###

- 유스케이스를 확실히 모르는 상태에서 마이크로벤치마킹하지 말자
- 그래도 해야한다면 JMH를 이용하자
- 결과를 가능한 많은 사람과 공유하고 동료들과 의논하자
- 항상 잘못된 가능성을 염두에 두고 지속적으로 검증하자
Loading

0 comments on commit 43c901c

Please sign in to comment.