Dev/Testing & Monitoring

성능 테스트 (1) - 목표 설정

kimyeonjae 2026. 2. 2. 16:55

최근 진행한 프로젝트의 성능을 평가하고 개선하기 위하여 성능 테스트와 모니터링을 하게 되었습니다.

현재 서버는 Synology NAS에서 3 tier 형태의 간단한 구조로 구성되어 있습니다.

 웹 서버(Nginx) - WAS(Tomcat) - DB(PostgreSQL, Redis)

처음에 테스트하기 전에는 Fetch Join을 통해 N + 1 같은 문제도 방지했고, 추가적인 캐싱이나 페이지네이션, 비동기 처리 정도 추가해주면 훨신 좋아지지 않을까? 라고 생각했으나, 의도치 않은 문제들이 많이 나올 수 있다는 것을 알았습니다.

목표성능

ShotHotspot South Korea 검색 페이지

Locationscout.net South Korea 검색 페이지

현재 테스트 하는 서비스와 성격이 비슷한 서비스들의 한국 검색 결과에 대해 먼저 확인해보겠습니다.

  • 확실하지는 않지만 주소지 기반으로 검색 최적화를 해 뒀을 것이라 생각됩니다.
  • 저는 좌표 기반 거리 비교로 검색했습니다

아래의 Locationscout의 Map 기능이 최종적으로 구현하고자 하는 기능과 비슷합니다, 그러나 해당 페이지를 확인하려면 맴버십 가입을 해야해서 Overview 페이지의 성능만 확인해보았습니다.

ShotHotspot - performance

Locationscout - performace

현재 프로젝트 - performance

현재 프로젝트 화면은 페이지 별 기능을 나누지 않은 개발용 임시 페이지입니다.
초기 화면은 현재 사용자의 위치 기준 반경 20km 내의 데이터들을 가져오도록 설정되어 있습니다.

동일한 종류의 데이터를 가져오는 것이 아니라 측정 항목들이나 방법들이 부정확하지만, 대략적인 성능 수준 파악을 위해 비교합니다.

각 성능 수치

  • 로딩 성능(LCP): 사이트의 로딩 시간을 나타냅니다. 특히, 사이트의 뷰포트에서 가장 큰 콘텐츠 요소를 로딩하는 데 걸리는 시간입니다.
  • 상호작용(INP): 사용자가 클릭 등 상호작용을 시도했을 때 웹페이지가 응답하는 속도를 측정합니다.
  • 시각적 안정성(CLS): 페이지 레이아웃을 변경하는 요소의 예상치 못한 움직임을 측정한 것입니다.

저는 여기서 LCP를 기준으로 성능을 비교하였습니다.

  • hotHotspot 같은 경우에는 우선 지도 위에 위치 데이터를 이용하여 사진 데이터가 있는 위치를 전부 점으로 표시합니다. 그러므로 LCP가 다른 Overview Page들에 비해 높을 수 밖에 없습니다. (그러나 12.1s는 너무 느림)
  • LocationScout은 LCP가 4.2s정도로 조금 느리긴 하지만 무난합니다. 그러나 CLS가 비교적 높은데, 이는 웹 페이지의 팝업광고의 영향을 받아 그렇다고 생각합니다.
  • 현재 프로젝트는 LCP가 5.7s입니다. (이 당시 db indexing이 적용이 안되어 있는 배포용 서버라 성능이 나쁘다 생각합니다)

목표

구글이 웹사이트의 실제 UX를 객관적으로 평가하기 위해 사용하는 Core Web Vitals(CWV)를 기준으로

  • LCP <= 2.5s
  • INP <= 200ms
  • CLS <= 0.1

이러한 조건을 만족하면 우수하다고 합니다.
저는 응답속도 (INP) 200ms 이내, 그리고 로딩 성능 (LCP) 3s 이내를 목표로 성능 개선을 진행해보았습니다.

성능 테스트

테스트 스크립트

테스트를 위한 스크립트가 필요합니다. 이를 위해 위의 성능 목표에 따른 RPS를 구해보겠습니다.

먼저 위에서 구한 목표 수치에 따른 정확한 목표를 정하겠습니다.

목표 LCP가 3000ms 였습니다. (복잡한 쿼리 기준)
그러나 저희는 서버측 API응답 속도를 최적화 하는것이 목표이고, 통신 프로토콜과 프론트 측에서 렌더링 시간도 필요하기에, 3000ms 전부를 쓸 수는 없습니다. 확실하진 않지만, 1/3 정도인 1000ms를 목표로 잡겠습니다.

또한 간단한 쿼리 및 응답 기준은 INP로 판단하였습니다.
위와 같은 이유로 이것저것 빼서 절반 정도인 100ms를 목표로 잡겠습니다.

위의 API 응답 기준을 잡았으니, 이제 DB 쿼리 처리 시간을 생각해봅시다.
API응답은 보통 
-> 네트워크를 통해 요청 수신 및 검증
-> 서버에서 비즈니스 로직 처리
-> DB 처리
-> 나온 결과를 JSON 같은 구조로 직렬화
-> 응답 전송
이러한 과정으로 이루어 집니다.
즉 DB 쿼리에 할당할 목표 시간은 위에서 정한 API 총 응답시간보다 적습니다.
(수치가 확실하진 않지만) 절반정도의 목표 시간을 할당해보면 
간단한 쿼리는 50ms
복잡한 쿼리는 500ms 정도의 목표 시간을 정할 수 있습니다.

다음으로는 Thread Pool과 HikcariCP Connection 수를 현재 상황에 맞는 권장 수치를 구해보겠습니다.

서비스의 예상되는 최대 부하를 추정하여 목표 RPS를 계산할 수 있습니다. 일반적인 계산 공식은 다음과 같습니다.
Little's Law의 공식
L = λ × W  
동시 요청 수(개) = 처리율(req/sec) * 평균 응답 시간(sec)
λ = L / W


목표 : 3000명의 동시 접속자를 언정적으로 처리, 사용자의 Think time 3초(사용자가 컨텐츠를 읽고 판단할 시간)을 고려했을 때, 시스템 내 동시 요청 수는 
실제 서버에서 처리하는 요청 수 = 총 접속자 수 * (평균 응답 시간 / 전체 측정 시간)
간단한 요청과 복잡한 요청 9:1이라 가정
간단한 요청 => 2700 * (0.1 / (3 + 0.1) = 87.1
복잡한 요청 => 300 * (1 / (3 + 1) = 75
합치면 162.1이 총 동시요청이 됩니다.
피크 트래픽 대응을 위해 Thread Pool 설정값은 200(기본값 200)으로 잡겠습니다.


1. 먼저 처리율을 Thread Pool 기반으로 생각해보면 
- Tomcat Thread Pool : 200
- 목표 평균 응답 시간 (간단한 요청) : 100ms (0.1s)
    200 / 0.1 = 2000RPS
- 목표 평균 응답 시간 (복잡한 요청) : 1000ms (1s)
    200 / 1 = 200RPS


2. DB 커넥션 풀 기반으로
HikariCP 커넥션 풀 공식 
connections = (cpu 코어 수 * 2) + effective_spindle_count

- 현재 배포용 서버 컴퓨터인 Synology Nas 같은 경우 4코어 CPU를 사용중, 로컬 테스트 용으로는 8코어 CPU

공식에 따르면, 4*2 + 1 = 9 정도가 적당합니다. (참고로 기본값은 10)
현재 트랜잭션은 쿼리를 실행하고 결과를 서비스 레이어에서 처리합니다. 즉, 커넥션을 보유하는 시간 전체가 DB CPU를 점유하지는 않는다. 따라서 DB는 실제 코어 수보다 훨씬 많은 동시 연결을 처리할 수 있다고 합니다. (근데 어차피 같은 서버 컴퓨터(호스트)에 앱 컨테이너와 db 컨테이너가 docker-compose로 함꼐 관리되는데, 서버의 cpu나 메모리, I/O 작업을 공유하니.. 흠)
일단 15로 정했습니다.

그렇다면 여기서도 Little's Law를 적용해서 계산해보면
- 목표 평균 응답 시간 (간단한 요청) : 50ms (0.05s)
    15 / 0.05 = 300RPS
- 목표 평균 응답 시간 (복잡한 요청) : 500ms (0.5s)
    15 / 0.5 = 30RPS (너무 널널하게 잡았나..?)

위의 계산에 따른 목표 성능을 분석해보았을 때
간단한 요청은
Tomcat 기준 2000 RPS, HikariCP기준 300 RPS로 DB가 병목입니다.
복잡한 요청 또한
200RPS, 30RPS로 DB 병목입니다.

-> DB 부하 감소 필요! (캐싱 적용?)

적절한 비율

Thread Pool 과 HikariCP Connection 수의 권장 비율은 일반적으로 5:1 ~ 10:1 이라고 합니다.
지금 설정한 비율을 확인해보면 200 : 15로 13.3:1 입니다. 권장 비율 대비 약간 높습니다.

  • DB 커넥션 대기 발생 가능성이 있습니다

참고

이후 진행한 테스트는 우선 여러 변화를 통해 성능을 최적화 할 수 있는지 확인하고자 편의상 8코어 cpu위에서 진행하여 위의 목표 설정과 성능이 맞지 않기도 하고, 배포용 환경에서 테스트한 것이 아니라 부정확한 수치 데이터가 나올 것이라 예상됩니다. 참고용으로만 확인해주시면 감사하겠습니다.

  • 테스트 서버도 같은 pc안에서 진행하였습니다. 정확한 성능 측정을 위해서는 테스트용 서버도 따로 분리해서 진행하는게 좋습니다.

Reference

https://velog.io/@harperkwon/Tomcat-%EC%8A%A4%EB%A0%88%EB%93%9C-%ED%92%80-%EB%B0%8F-HikariCP-%EC%BB%A4%EB%84%A5%EC%85%98-%ED%92%80-%EC%84%B1%EB%8A%A5-%EC%B5%9C%EC%A0%81%ED%99%94