자바 최적화 책 정리
성능 테스트 유형
✅ 성능 테스트를 기획하는 요령
모든 성능테스트는 그 목표가 명확해야 한다.
-> 테스트로 확인하고 싶은 정량적 질문 리스트와, 그 테스트가 대상 애플리케이션 입장에서 중요한 이유를 생각해보자.
지연 테스트
✅ Latency test: 종단 트랜잭션에 걸리는 시간은?
가장 일반적인 성능 테스트다.
-> '고객이 트랜잭션을 얼마나 오래 참고 기다려야 하는지'는 경영진들이 피부로 느끼는 관심사다.
처리율 테스트
✅ Throughput test: 현재 시스템이 처리 가능한 동시 트랜잭션 개수는?
처리율은 지연과 동등한 개념
-> 지연 테스트를 수행할 때는 계속 진행 중인 동시 트랜잭션을 반드시 명시해야 한다.
-> 지연 분포가 갑자기 변하는 지점(변곡점)이 바로 '최대 처리율'이다.
-> 최대 처리율을 측정하는 것이 처리율 테스트의 목표.
부하 테스트
✅ Load test: 특정 부하를 시스템이 감당할 수 있는가?
처리율 테스트와 다른 점은 '시스템이 이 정도 부하는 견딜 수 있는가?' 에 대한 예/아니오 답을 구하는 과정이다.
ex) 신규 고객을 유치하기 전, 애플리케이션 트래픽이 상당할 것으로 예상되는 특정 비즈니스 이벤트에 대비하기 위함.
스트레스 테스트
✅ Stress test: 이 시스템의 한계점(breaking point)은 어디까지인가?
시스템 여력이 어느 정도인지 알아보는 수단
-> 일정한 수준의 처리율(현재로서 최대치)을 시스템에 계속 걸어놓는다.
-> 처리율이 나빠지기 시작하기 직전의 값이 바로 최대 처리율이다.
내구 테스트
✅ Endurance test: 시스템을 장시간 실행할 경우 성능 이상 증상이 나타나는가?
메모리 누수, 캐시 오염, 메모리 단편화 등 한참 시간이 지나고 나서야 드러나는 문제점도 있다.
-> 평균 사용률로 시스템에 일정 부하를 계속 주어, 갑자기 리소스가 고갈되거나 시스템이 깨지는 지점을 찾는다.
-> 빠른 응답을 요구하는(지연이 낮은) 시스템에 많이 한다.
용량 계획 테스트
✅ Capacity planning test: 리소스를 추가한 만큼 시스템이 확장되는가?
스트레스 테스트와 다른 점은,
-> 스트레스 테스트는 현재 시스템이 어느 정도 부하를 버틸 수 있는지 알아보는 반면,
-> 용량 계획 테스트는 업그레이드한 시스템이 어느 정도 부하를 감당할 수 있을지 내다보는 것이다.
저하 테스트
✅ Degradation: 시스템이 부분적으로 실패할 경우 어떤 일이 벌어지나?
책에서는 복원 테스트라고 생각하면 된다.
-> 평상시 운영 환경과 동등한 수준의 부하를 시스템에 가하는 도중, 어떤 시스템이 갑자기 능력을 상실하는 시점에 벌어지는 일들을 확인.
-> 이 때, 눈여겨 봐야 할 값들은 트랜잭션 지연 분포와 처리율이다.
카오스 멍키: 저하 테스트의 하위 유형
-> 어떤 한 컴포넌트가 잘못돼도 다른 컴포넌트까지 연쇄적으로 무너뜨리면서 전체 시스템에 부정적 영향을 끼치면 안된다.
-> 실제로 운영 환경에 떠 있는 라이브 프로세스를 하나씩 랜덤하게 죽이면서 검증한다.
기본 베스트 프랙티스
✅ 성능 튜닝 시 주안점을 두어야 할 부분
- 나의 관심사가 무엇인지 식별하고 그 측정 방법을 고민한다.
- 최적화하기 용이한 부분이 아니라, 중요한 부분을 최적화한다.
- 중요한 관심사를 먼저 다룬다.
하향식 성능
✅ 전체 애플리케이션의 성능 양상부터 먼저 알아보는 접근 방식
자바 애플리케이션을 전체 벤치마킹 하는 것이 작은 코드 세션별로 수치를 얻는 것보다 쉽다.
-> 테스트팀이 테스트 환경을 구축한 다음, 무엇을 측정하고 무엇을 최적화 해야 하는지,
-> 성능 활동을 전체 소프트웨어 개발 주기에서 어떻게 병행하는지,
-> 전 팀원이 명확히 이해해야 한다.
테스트 환경 구축
✅ 성능 테스트팀이 가장 먼저 할 일
테스트 환경은 가급적 모든 면에서 운영 환경과 똑같이 복제해야 한다.
-> 논클라우드 환경에서는 비교적 수월하다. (운영 환경에서 가동 중인 기계 수만큼 구매해서 운영 환경과 똑같이 설정해주면 된다)
-> 클라우드 환경에서는 운영 환경과 유사한 성능 테스트 환경 구축이 버겁게 느껴질 수 있다. (이리저리 설정할게 많다)
성능 요건 식별
✅ 성능 비기능 요건(NFR)
시스템을 전체적으로 바라보며 고객과 경영진에게 중요한 핵심 지표(NFR)을 고려해야 한다.
-> 명확한 목표 예시: 95% 백분위 트랜잭션 시간을 100밀리초 줄인다.
-> 모호한 목표 예시: 일반 고객을 서비스하는 리소스 비용을 50% 줄인다.
-> 이해관계자들이 한 데 모여 측정 대상과 목표를 허심탄회하게 논의하는 자리가 필요하다.
자바의 특정 이슈
✅ JVM은 복잡하다
JVM은 메모리 동적 유닝 등 특유의 다이나믹한 자기 관리 기능이 추가되면서 복잡해졌다.
특히, JIT 컴파일은 유심히 잘 살펴야 한다.
+) JIT 컴파일 안 하기로 결정된 메서드
- JIT 컴파일 할 정도로 자주 실행되는 메서드가 아니다.
- 메서드가 너무 크고 복잡해서 도저히 컴파일 분석을 할 수 없다.
✅ JVM에서 성능 활동을 시작하는 첫 단추
1. 어떤 메서드가 컴파일 중인지 로그를 남겨 살핀다.
2. 핵심 코드 경로상의 중요 메서드가 잘 컴파일 되고 있는지 확인한다.
SDLC 일부로 성능 테스트 수행하기
✅ Software Development Life-Cycle: 소프트웨어 개발 수명주기
수준 높은 팀일수록 성능 테스트를 SDLC의 일부로서 수행하며, 특히 성능 회귀 테스트를 상시 수행한다.
-> 개발팀, 인프라팀이 서로 조율해서 어느 시점에 몇 버전 코드를 성능 테스트 환경에 배포할지 조정해야 한다.
성능 안티패턴 개요
지루함
✅ 개발자의 지루함은 여러 가지로 해악을 끼칠 수 있다
ex)
Collections.sort() 한 줄이면 될 것을 직접 정렬 알고리즘을 구현해 필요 이상으로 복잡하게 코딩하는 개발자
지금껏 알려지지 않은 기술로 컴포넌트를 제작하는 개발자
이력서 부풀리기
✅ 본인의 이력서를 과대 포장할 구실을 찾는다
이력서 부풀리기 탓에 불필요한 기술을 자꾸 덧댄 결과는 시스템에 지대한 영향을 미치게 된다.
또래 압박
✅ 기술을 결정할 때 충분한 논의 없이 진행한다
ex)
가급적 실수 안하려는 신입 개발자
자기가 잘 모른다는 사실을 두려워하는 개발자
이해 부족
✅ 지금 사용하는 툴의 기능도 온전히 알지 못한채, 새로운 툴로 문제를 해결하려 한다
기술 복잡도를 높이는 것과 현재 툴로도 할 수 있는 것 사이의 균형을 잘 맞추어야 한다.
오해와 있지도 않은 문제
✅ 문제 자체가 무엇인지 제대로 이해하지 못한체 오로지 기술을 이용해 문제를 해결하려 한다
그렇게 해서 성공한들, 성능 수치를 측정도 안해보고 성공을 장담할 수 없다.
-> 성능 지표를 수집/분석해야만 비로소 문제의 본질을 정확히 이해할 수 있다.
성능 안티패턴 카탈로그
화려함의 사로잡히다
✅ 처음이라(최신 기술) 말썽이 많군. 뭐가 문제인지 원인을 밝혀야 해
신생팀이나 숙련도가 떨어지는 팀에서 흔하다.
-> 오로지 최신의 '뜨고 있는' 기술을 숭배한다.
-> 신기술을 제대로 알지 못한 상태라 실제로 다른 문제가 불거지기 일쑤다.
✅ 처방
- 측정을 해보고 진짜 성능 병목점을 찾는다.
- 새 컴포넌트는 전후로 충분한 로그를 남긴다.
- 베스트 프랙티스 및 단순화한 데모를 참조한다.
- 팀원들이 새 기술을 이해하도록 독려하고 팀 차원의 베스트 프랙티스 수준을 정하자.
단순함에 사로잡히다
✅ 우리가 알고 있는 부분부터 한번 파봅시다
체계가 잘 잡힌 유지보수 팀에서 흔하다.
-> 포근한 울타리를 벗어나지 않고도 원하는 결과를 운 좋게 얻게 되기를 간절히 바란다.
✅ 처방
- 측정을 해보고 진짜 성능 병목점을 찾는다.
- 본인이 익숙지 않은 컴포넌트에 문제가 생기면 잘 아는 전문가에게 도움을 청한다.
- 개발자가 전체 시스템 컴포넌트를 고루 이해하도록 독려한다.
성능 튜닝 도사
✅ 나도 문제가 ...라는 건 알고 있어
모든 성능 이슈를 처음부터 다 간파한, 고독한 천재의 존재는 터무니없다.
-> 특정 이슈를 해결한 방법이나 자기가 알고 있는 걸 절대로 남과 공유 안 하려는, 초인을 지향하는 팀원은 매우 반생산적이다.
✅ 처방
- 측정을 해보고 진짜 성능 병목점을 찾는다.
- 새로 채용된 팀 내 전문가가 다른 팀원들과 지식을 공유하고 유지할 수 있게 리드한다.
민간 튜닝
✅ 스택 오버플로우에 이런 멋진 팁이 있더라고, 이제 다 끝났어
성능 팁은 유통 기한이 짧아 금세 낡은 유물이 되기 쉽다.
-> 7버전에서 잘 써온 가비지 수집 알고리즘 제어 스위치는 9버저넹 쓰면 VM이 시작조차 안되는 경우도 있다.
✅ 처방
- 시스템의 가장 중요한 부분에 직접 영향을 미치는 기술을 확실히 파악하고 충분히 검증된 것들만 적용한다.
- 매개변수를 인수테스트(UAT)에서 시험해보자. 어떤 변화라도 철저히 검증하고 효용을 프로파일링하는 일이 중요하다.
- 다른 개발자나 운영 요원, 데브옵스팀과 함께 설정 문제를 리뷰하고 토의한다.
안되면 조상 탓
✅ JMS, 하이버네이트, 그 머시기 라이브러리가 항상 문제라니깐
아무래도 뭔가 새로 조사하는 것보다는 보통 문제를 많이 일으키는 곳을 지목하는게 속 편하다.
-> 하이버네이트를 정확히 설정해서 사용하지 않고, 해당 기술을 비난한다.
✅ 처방
- 성급한 결론을 내리고픈 욕망에 굴하지 말자.
- 정상적으로 분석을 하자.
- 분석 결과를 (문제를 일으킨 원인을 구체화하기 위해) 모든 이해관계자와 의논하자.
숲을 못 보고 나무만 보다
✅ 이 설정만 바꾸면 성능이 좀 나아질 거야
시스템의 한 단면에만 집중하면 전체 시스템의 성능 튜닝이 어렵다.
-> 운영계를 그대로 모사한 UAT 환경 없이 최적화의 효용성을 판단하기는 어렵다.
-> 부하가 높을 때만 도움이 되고 평소에는 외려 성능을 떨어뜨리는 최적화는 아무 의미가 없다.
✅ 처방
운영계에서 스위치를 변경하기 전 다음 절차를 따르자.
- 운영계 성능 지표를 측정한다.
- UAT에서 한번에 스위치 하나씩 변경한다.
- 스트레스를 받는 지점이 UAT와 운영계가 동일한지 확인한다.
- 운영계에서 일반적인 부하를 나타내는 테스트 데이터를 확보한다.
- UAT에서 스위치를 변경하며 테스트한다.
- UAT에서 다시 테스트한다.
- 내가 추론한 내용을 다른 사람에게 재검토 요청한다.
- 내가 내린 결론을 다른 사람과 공유한다.
내 데스크톱이 UAT
✅ UAT 환경을 완벽히 갖추려면 돈이 너무 많이 들어
어떤 식으로든 유의미한 추정을 하려면 UAT 환경을 운영계와 반드시 동기화해야 한다.
✅ 처방
- 서비스 중단 비용과 고객 이탈로 인한 기회비용을 잘 따져보자.
- 운영 환경과 동일한 UAT 환경을 구입하자.
- 소 잃고 외양간 고치는 비용이 더 많이 들 테니, 이따금 관리자들에게 올바른 사례를 제시해야 한다.
운영 데이터처럼 만들기는 어려워
✅ 시스템에 맞게 데이터를 조작하는 건 정말 삽질이지
UAT에서 정확한 결과를 얻으려면 운영계 데이터와 최대한 맞추어야 한다.
-> 보안 정책 때문에 원본 데이터를 가져올 수 없다면 데이터를 뒤죽박죽 섞어서 테스트하는 방법도 있다 (마스킹, 난독화 등)
-> 운영계 디펜던시로 인한 성능 이슈가 발생할 수 있는 것을 항상 대비해야 한다.
✅ 처방
데이터 도메인 전문가에게 컨설팅을 받고 운영 데이터를 UAT로 다시 이전하는 프로세스에 시간과 노력을 투자하자.
다수의 고객이 몰리고 엄청난 트랜잭션이 예상되는 서비스는 출시 전 철저히 준비하자.
인지 편향과 성능 테스트
✅ 인지 편향
인간의 두뇌가 부정확한 결론을 내리게 이끄는 심리.
환원주의
✅ 시스템의 작은 조각을 이해하면 전체 시스템도 다 이해할 수 있다는 사고방식
단순히 구성 파트를 합한 것보다 시스템을 전체로서 바라봐야 문제의 원인을 찾을 수 있다.
확증 편향
✅ 원래 가지고 있는 생각을 확인하려는 경향성
확증 편향은 애플리케이션을 주관적으로 바라보게 한다.
-> 보통 강력한 동기가 부여되거나 감정 요 소가 개입되기 때문에 거스르기가 참 어렵다.
✅ 스위치 만지작거리기
'민간 튜닝' 안티패턴은 환원주의 + 확증 편향 결과로 나타난 안티패턴 사례다.
'민간 튜닝' 안티패턴의 일종인 '스위치 만지작거리기'는 특히 바람직하지 않은 하위 유형이다.
-> 성능 엔지니어가 수동으로 JVM의 스위치를 설정할 수 있는데, 이 때 해당 스위치 변경으로 인해, JVM의 700개가 넘는 스위치를 조합한 경우의 수를 따져가며 효과를 추론하기란 애당초 불가능하다.
전운의 그림자(행동 편향)
✅ 시스템 오류를 해결하기 위해 뭐라도 해야 한다는 생각
막연한 느낌으로 서두르기만 하기 보다는, 체계적으로 문제에 접근하는 태도를 길들여야 한다.
-> 하지만 이는 인간의 감정 영역에 속하는 문제라서, 시스템이 가동을 멈춘 상태에서 긴장을 풀고 여유를 가지기란 대단히 어려울 수 있다.
위험 편향
✅ 인간의 본성은 위험을 피하고 변화를 거부한다
단위 테스트 세트와 운영계 회귀 테스트 체계만 확실히 갖추가 나면 리스크를 상당히 줄일 수 있다.
-> 보통 애플리케이션 문제가 생겼을 때 제대로 학습하고 적절한 조치를 하지 못한 까닭에 더 고착화된다.
엘스버그 역설
✅ 알려지지 않은 미지의 것(unknown unknwons) > 알려진 기지의 것(known unknwons)
이 말이 무슨 뜻인지 알기 위해 간단한 예시를 들어 보자.
ex) 통 안에 90개의 공이 들어 있다.
그 중 30개는 파란 공, 나머지는 빨간 공 아니면 녹색 공이다. 빨간 공, 녹색 공 비율은 알 수 없다.
1. 어떤 내기를 선택할 것인가?
1-1. 통에서 꺼낸 공이 파란 공이면 상금 $100를 받는다.
1-2. 통에서 꺼낸 공이 빨간 공이면 상금 $100를 받는다.
-> 사람들은 대부분 A를 선택한다. 이길 확률이 정확이 1/3이기 때문이다.
그럼 다음 내기를 보자.
2. 어떤 내기를 선택할 것인가?
2-1. 통에서 꺼낸 공이 파란 공 또는 녹색 공이면 상금 $100를 받는다.
2-2. 통에서 꺼낸 공이 빨간 공 또는 녹색 공이면 상금 $100를 받는다.
-> 사람들은 대부분 D를 선택한다. 이길 확률이 2/3이기 때문이다.
그러나 역설적으로 A -> D는 비이성적인 선택이다.
A를 선택한건 녹색 공이 빨간 공보다 많을 거라는 의사를 암묵적으로 나타낸다.
-> 따라서 기왕 A를 선택했다면 논리적으로 D보다 이길 확률이 높은 C를 잇따라 선택하는 것이 더 우세한 전략이다.
참고자료
https://github.com/Netflix/SimianArmy/wiki/Chaos-Monkey
https://web.obsidianscheduler.com/why-developers-keep-making-bad-technology-choices/
'book > 자바 최적화' 카테고리의 다른 글
[자바 최적화] 가비지 수집 기초 (2) | 2023.08.28 |
---|---|
[자바 최적화] 마이크로벤치마킹과 통계 (2) | 2023.08.23 |
[자바 최적화] 하드웨어와 운영체제 (0) | 2023.07.30 |
[자바 최적화] JVM이야기 (0) | 2023.07.23 |
[자바 최적화] 성능과 최적화 (0) | 2023.07.17 |