danuri
오늘의 기록
danuri
전체 방문자
오늘
어제
  • 오늘의 기록 (307)
    • java (150)
      • java (33)
      • spring (63)
      • jpa (36)
      • querydsl (7)
      • intelliJ (9)
    • kotlin (8)
    • python (24)
      • python (10)
      • data analysis (13)
      • crawling (1)
    • ddd (2)
    • chatgpt (2)
    • algorithm (33)
      • theory (9)
      • problems (23)
    • http (8)
    • git (8)
    • database (5)
    • aws (12)
    • devops (10)
      • docker (6)
      • cicd (4)
    • book (44)
      • clean code (9)
      • 도메인 주도 개발 시작하기 (10)
      • 자바 최적화 (11)
      • 마이크로서비스 패턴 (0)
      • 스프링으로 시작하는 리액티브 프로그래밍 (14)
    • tistory (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

태그

  • Kotlin
  • Saving Plans
  • AWS
  • Security
  • Jackson
  • SWAGGER
  • 트랜잭션
  • POSTGIS
  • DDD
  • Thymeleaf
  • 자바 최적화
  • 등가속도 운동
  • nuribank
  • CICD
  • gitlab
  • 도메인 주도 설계
  • JPA
  • mockito
  • Spring
  • connection
  • Bitmask
  • ChatGPT
  • PostgreSQL
  • reactive
  • docker
  • 마이크로서비스패턴
  • Java
  • RDS
  • Database
  • S3

최근 댓글

최근 글

hELLO · Designed By 정상우.
danuri

오늘의 기록

book/자바 최적화

[자바 최적화] 성능 테스트 패턴 및 안티패턴

2023. 8. 10. 01:20

자바 최적화 책 정리

 

자바 최적화(Optimizing Java) | 벤저민 J. 에번스 - 교보문고

자바 최적화(Optimizing Java) | 자바 애플리케이션 성능을 한 단계 높여줄 튜닝 이야기성능 튜닝은 실험과학이다. 추측과 구전 튜닝에 의존할 일이 아니다. 이 책은 복잡한 기술 스택을 다루는 중/고

product.kyobobook.co.kr

 

성능 테스트 유형

✅ 성능 테스트를 기획하는 요령

모든 성능테스트는 그 목표가 명확해야 한다.

-> 테스트로 확인하고 싶은 정량적 질문 리스트와, 그 테스트가 대상 애플리케이션 입장에서 중요한 이유를 생각해보자.

 

지연 테스트

✅ 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 환경 없이 최적화의 효용성을 판단하기는 어렵다.

-> 부하가 높을 때만 도움이 되고 평소에는 외려 성능을 떨어뜨리는 최적화는 아무 의미가 없다.

 

✅ 처방

운영계에서 스위치를 변경하기 전 다음 절차를 따르자.

  1. 운영계 성능 지표를 측정한다.
  2. UAT에서 한번에 스위치 하나씩 변경한다.
  3. 스트레스를 받는 지점이 UAT와 운영계가 동일한지 확인한다.
  4. 운영계에서 일반적인 부하를 나타내는 테스트 데이터를 확보한다.
  5. UAT에서 스위치를 변경하며 테스트한다.
  6. UAT에서 다시 테스트한다.
  7. 내가 추론한 내용을 다른 사람에게 재검토 요청한다.
  8. 내가 내린 결론을 다른 사람과 공유한다.

 

내 데스크톱이 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
    'book/자바 최적화' 카테고리의 다른 글
    • [자바 최적화] 가비지 수집 기초
    • [자바 최적화] 마이크로벤치마킹과 통계
    • [자바 최적화] 하드웨어와 운영체제
    • [자바 최적화] JVM이야기
    danuri
    danuri
    IT 관련 정보(컴퓨터 지식, 개발)를 꾸준히 기록하는 블로그입니다.

    티스토리툴바