📝테스트 계획
테스트에 들어가기 전에 테스트 계획부터 설정해야 한다.
부하 테스트는 시스템의 응답 성능과 한계치를 파악하기 위한 테스트이다.
- 서비스가 어느 트래픽까지 처리할 수 있는지(어느 정도의 부하를 견디는지) → 어떻게 대응할지 알 수 있음
- 병목이 발생하는 부분이 어디인지 → 어떻게 개선할지 알 수 있음
주의
성능 테스트는 실제 사용자가 접속하는 환경에서 진행해야 한다. 내부 네트워크에서 부하를 발생시킬 경우 응답시간에 차이가 발생할 수 있다.
테스트 DB에 들어 있는 데이터 양이 실제 운영 DB와 동일하여야 한다. 통상 전체 성능의 70프로 이상이 DB에서 좌우된다. 데이터 양이 다르면 쿼리 실행 계획이 달라질 수 있으므로 성능이 다르게 나타날 수 있다.
외부 요인의 경우 시스템과 분리된 별도의 서버를 구성해야한다. 객체를 Mocking하는 경우 Http Connection Pool, Connection Thread 등을 미사용하게 되고 IO가 발생하지 않는다. 같은 애플리케이션에서 더미 컨트롤러를 사용하는 경우 테스트 자원과 같이 리소스를 사용하므로 테스트의 신뢰성이 떨어진다.
EC2 프리티어에서의 부하테스트는 의미가 없을 것 같다.. 더 높은 사양의 EC2로 테스트를 진행해야 할텐데.. 아무 수익도 없는 취준생인 나에게 이를 부담할 금전적인 여유가 없는 관계로.. 개인 노트북인 Mac M2 Air 15를 기준으로 로컬에서 테스트를 진행해보도록 하겠다..!
전제 조건 정리
- 테스트하려는 Target 시스템의 범위를 정해야 한다.
- 아직 배포를 하지 않았으며, Reverse Proxy가 따로 존재하지 않기 때문에 WAS부터 DB(MySQL)까지를 Target 시스템의 범위로 산정하겠다.
- 부하 테스트시에 저장될 데이터 건수와 크기를 결정하자. 서비스 이용자 수, 사용자의 행동 패턴, 사용 기간 등을 고려하여 계산한다.
- 우리 서비스는 아직 배포도 하지 않은 개발 중인 서비스이기 때문에 서비스 이용자 수, 사용자 행동 패턴, 사용 기간 등의 정보가 없다. 따라서, 이번에는 임의로 데이터 수를 정해 단순 학습을 목적으로 테스트를 진행하는 것으로 한다.
- 해당 기능에 사용되는 member, todo, todo_instance, follow, title_name 테이블에 각각 10만 개의 초기 더미 데이터를 넣고 진행하려고 한다.
- 목푯값에 대한 성능 유지기간을 정해야 한다.
- 주요 기능의 성능이 30분 동안 유지되는 것을 목표로 테스트 & 개선해보려고 한다.
- 서버에 같이 동작하고 있는 다른 시스템, 제약 사항 등을 파악한다
- 현재 서버에는 batch 모듈이 함꼐 동작하고 있다. 하지만, 이를 모두 고려하기엔 테스트가 너무 복잡해질 것 같아서 일단 제외하도록 하겠다.
목푯값 설정
성능 목표를 정하기 위해서는 VUser를 구해야 한다. (부하 테스트의 경우)
VUser를 구하기 위해서는 다음과 같은 지표들이 필요하다.
- DAU(일일 활동 사용자 수)
- 피크시간대 집중률(최대 트래픽 / 평소 트래픽)
- 1명당 1일 평균 요청 수
마땅히 비슷한 서비스의 DAU 지표를 얻어올 수 있는 방법이 없어서 비슷한 서비스의 총 다운로드 수가 50만 정도 임을 통해 가정을 진행해보겠다.
총 50만명의 유저가 있다고 했을 때 해당 사용자의 2/3이 실제 활동 사용자이고 매일 활동을 한다고 가정하고 계산을 하겠다(= 약 33만명). 피크 시간대 집중률은 아침 시간대와 퇴근 시간대에 늘어날 것으로 예상은 되지만 최대 트래픽과 평소 트래픽이 크게 차이는 없을 것 같아서 넉넉잡아 3배로, 1명당 1일 평균 요청 수는 대충 투두를 생성하고, 이를 완료 처리하고, 유저 정보 조회, 펫 조회, 펫 먹이 주기 등등 다 합쳐서 15회 정도라고 하겠다.
- DAU(일일 활동 사용자 수) = 330,000
- 피크시간대 집중률(최대 트래픽 / 평소 트래픽) = 3
- 1명당 1일 평균 요청 수 = 15
위 정보를 통해 throughput(1일 평균 rps ~ 1일 최대 rps)를 계산할 수 있다.
- 1일 총 요청 수 = DAU * 1명당 1일 평균 요청 수
- 330,000 * 15 = 4,950,000
- 1일 평균 rps(request per second) = 1일 총 요청 수 / 하루 24시간을 초로 환산
- 4,950,000 / 86,400 = 약 57.3rps
- 1일 최대 rps(최대 트래픽) = 1일 평균 rps * 피크 시간대 집중률
- 57.3rps * 3 = 171.9 rps
⇒ 이를 바탕으로 throughput은 57.3rps ~ 171.9rps가 나온다.
VUser = (목표 rps * T) / R
- R: 시나리오에 포함된 요청의 수
- T: 시나리오 완료 시간보다 큰 값(VUser 반복을 완료하는데 필요한 시간보다 큰 값)
- T = (R * 왕복 시간(http_req_duration)) + 지연시간(내부망일 경우 추가)
- 왕복 시간 = 얼마 안에 끝내야 하는지(목표 latency)
- T = (R * 왕복 시간(http_req_duration)) + 지연시간(내부망일 경우 추가)
테스트 환경이 로컬이기에 실제 왕복 시간은 알 수 없음..
우리 테스트의 경우 각각 1개의 API에 대해서만 테스트를 진행할 것이므로, 목표 latency를 0.5s로 잡고, 지연 시간을 0s로 설정한다면
- R = 1
- T = (1 * 0.5) + 0 = 0.5s
- 평소 트래픽 VUser = 57.3 * 0.5 / 1 = 14.75 = 약 29
- 최대 트래픽 VUser = 171.9 * 0.5 / 1 = 44.25 = 약 86
테스트 목표
구현 값을 토대로 부하 테스트 목표를 정리하면 다음과 같다.
- 평소 트래픽 VUser: 29
- 최대 트래픽 VUser: 86
- Throughput: 57.3rps ~ 171.9rps
- Latency: 0.5s 이하
- 성능 유지 기간: 30분
시나리오
적절한 시나리오 대상
시나리오 대상으로 적절한 것들은 다음과 같다.
- 접속 빈도가 높은 기능 (홈페이지 등)
- 서버 리소스 소비량이 높은 기능
- CPU : 이미지, 동영상 변환, 인증, 파일 압축 및 해제
- NETWORK : 응답 컨텐츠 크기가 큰 페이지, 이미지 및 동영상 업로드 및 다운로드
- Disk : 로그가 많은 페이지
- DB를 사용하는 기능
- 많은 리소스를 조합하여 결과를 보여주는 페이지
- 여러 사용자가 같은 리소스를 갱신하는 페이지
- 외부 시스템과 통신하는 기능
- 결제 기능, 알림 기능, 인증/인가
나는 이중에서 접속 빈도가 많고, DB를 사용하는 기능을 위주로 시나리오 대상을 선택하기로 하였다.
투두몬 시나리오 대상
투두몬의 주요 기능은 투두 조회, 투두 등록, 투두 수정, 투두 상태 변경, 랭킹 조회 기능이다. 이들은 가장 접속 빈도가 높으면서 DB를 많이 사용하는 부분이다.
전체적인 조회에 대한 시나리오를 작성하면 좋겠으나, 아직 실제 서비스를 배포하지 않은 상태로 유저 행동 패턴에 대한 정보가 없으며 프론트엔드 개발도 안되어있는 상태이므로.. API 1개씩 시나리오를 산정했다.
- API(시나리오) 리스트
- 전체 랭킹 조회(다음 4개중 랜덤 1개)
- 전체 일간 투두 달성 랭킹 조회 API("/api/overall/rank/achievement/daily")
- 전체 주간 투두 달성 랭킹 조회 API("/api/overall/rank/achievement/weekly")
- 전체 일관성 랭킹 조회 API("/api/overall/rank/diligence")
- 전체 도감 랭킹 조회 API("/api/overall/rank/collection")
- 소셜 랭킹 조회(다음 4개중 랜덤 1개)
- 소셜 일간 투두 달성 랭킹 조회 API("/api/social/rank/achievement/daily")
- 소셜 주간 투두 달성 랭킹 조회 API("/api/social/rank/achievement/weekly")
- 소셜 일관성 랭킹 조회 API("/api/social/rank/diligence")
- 소셜 도감 랭킹 조회 API("/api/social/rank/collection")
- 투두 생성 API("/api/todo")
- 투두 조회(다음 3개 중 랜덤 1개) → OK
- 투두 일별 조회 API("/api/todo/day?date={date}")
- 투두 주별 조회 API("/api/todo/week?startOfWeek={startOfWeek}")
- 투두 월별 조회 API("/api/todo/month?yearMonth={yearMonth}")
- 투두 수정 API("/api/todo/{objectId}")
- 투두 상태 수정 API("/api/todo/{objectId}/status?isInstance={isInstance}")
- 전체 랭킹 조회(다음 4개중 랜덤 1개)
참고 자료
https://velog.io/@max9106/nGrinderPinpoint-test1
https://sasca37.tistory.com/239
https://velog.io/@sontulip/web-performance-budget
'Project' 카테고리의 다른 글
[TODOMON] EP.9 부하 테스트 진행(야매) (0) | 2025.02.04 |
---|---|
[TODOMON] EP.8 nGrinder + Prometheus + Grafana 설정 w/ Docker & Spring Actuator (1) | 2025.02.03 |
[TODOMON] Ep.6 Spring Batch 도입기 (+ 멀티스레드를 통한 성능 개선까지) (0) | 2025.02.02 |
[TODOMON] EP.5 견고한(?)결제 시스템 구축기.. with 포트원 (2) | 2025.01.31 |
[TODOMON] EP.4 아이템 기능 구현 (0) | 2025.01.30 |