6명이 동시에 요청하면 OOM 발생하는 서비스
영어회화 스터디 서비스를 개발하면서 부하 테스트를 위해 클라우드 환경에 필요한 서비스들을 컨테이너 환경으로 실행했다.클라우드 서비스는 Naver cloud platform의 서비스들을 이용했다. 🛠
happygimy97.tistory.com
📌 테스트 배경
지난 포스팅에서 50만 건의 데이터를 findAll()로 모두 조회하는 API를 테스트했다가 6명의 유저(vuser)만으로 힙메모리 초과로 OOM이 발생했었다.
이를 해결하고자 offset과 pageSize를 설정해 50만 건 중 조건에 맞는 데이터를 pageSize만큼 가져오는 것을 테스트했고, 에러 없이 정상적으로 테스트를 수행하는 것을 확인할 수 있었다.
이번 포스팅에서는 vuser를 늘려가며 테스트했던 과정과 이때 만난 에러에 대해서 이야기해보고자 한다.
🛠️ 테스트 환경 & 시나리오
- 서버 스펙
- CPU -> 2EA
- Memory -> 8GB
- Ngrinder로 테스트
- 검색 API
- 원하는 조건, offset, pageSize를 요청 데이터로 가진다.
- Vuser를 늘려가며 테스트
- Duration 8분으로 고정
- 검색 API
📌 테스트 진행
반복해서 같은 데이터를 조회하려고 하면 DB 캐싱으로 인한 조회 속도가 빨라지는 경우가 생길 수 있다고 판단하여 offset을 랜덤한 값으로 매번 요청하도록 설정하여 스크립트를 작성하였다.
vuser를 조절하면서 테스트를 진행했는데, vuser를 198로 설정해 테스트를 했을 때에는 조회에 실패한 케이스가 전체 케이스의 40%가 나왔고, Ngrinder에서 WARNING 표시를 보여주었다.
몇 명의 vuser까지 해당 API를 잘 받아내는지를 보고 싶어 vuser를 140과 80으로 설정하여 테스트했다.
결과는 위처럼 성공이었지만, 자세히 보니 에러가 발생하지 않은 것은 아니었다. vuser를 80으로 했을 때에는 에러가 없었지만 140의 경우에는 여러 번 테스트를 수행한 결과 평균 20% 정도 에러가 발생했다.
뒤늦게 안 것이지만, Ngrinder에서 요청 중 에러가 30% 이상이면 WARNING으로 나타내고, 30% 미만이면 SUCCESS로 나타낸다.
때문에 평균 20% 정도 에러가 발생하고 있음에도 불구하고 vuser 140의 테스트가 성공으로 나오고 있던 것이었다.
Ngrinder에서 제공하는 로그와 spring boot 앱 내에 출력된 로그를 살펴보니 아래와 같이 나와 있었다.
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms (total=10, active=10, idle=0, waiting=16)
DB와 통신하기 위해서는 hikari connection pool(hikaricp)
이 필요하다.
hikaricp가 다 차 있는 상태에서 요청이 들어오면 해당 요청들은 대기 상태(waiting)로 존재하게 되는데, 설정한 5분(30000ms)의 connectionTimeout이 끝날 때까지 active로 넘어가지 못하면 위와 같은 에러가 발생한다.
spring boot에서는 기본적으로 최대 커넥션(maximum-pool-size)을 10으로 둔다고 한다. 때문에, active가 10에서 늘어나지 않은 것이고, 더 이상 사용할 커넥션이 없어 에러를 뱉어내는 것이다.
이를 해결하기 위해서 pool size를 늘려보기로 했다.
📌 maximum-pool-size 늘리기
vuser를 20, 30, 50까지 늘려가며 다시 Ngrinder를 통해 테스트를 진행했다.
에러 비율은 확실히 낮아졌으나 여전히 에러가 존재했고, vuser를 198로 설정해서 테스트했을 때에는 여전히 에러 비율이 30% 이상이었다.
🧑💻 고찰
vuser를 198로 설정하고 테스트를 진행했을 때에는 TPS 3.5에 평균 응답 속도(Mean Test Time)가 31,143ms(약 31초)의 성능을 보여주고 있었다.
pool size를 더 늘려보는 것도 생각해 보았지만 응답 속도가 빠르지 않다면 maximum-pool-size를 아무리 늘린다고 해도 에러가 생길 수밖에 없다고 생각했다.
마치 테이블은 많은데 회전율이 낮은 가게 같달까..? 😲
게다가, pool-size 자체를 많이 늘리는 것도 DB와의 커넥션을 늘리는 것이기에 DB 성능에 영향을 줄 것이라 판단했다.
때문에, 응답 속도 개선을 우선적으로 해야겠다고 생각했다.
다음 포스팅에서는 속도 개선을 위해 무엇을 어떻게 왜 했는지에 대해서 이야기해 보겠다.
'TIL' 카테고리의 다른 글
offset 기반 페이징 방식의 단점 (0) | 2025.01.08 |
---|---|
서버 진화 ~~~ (서버 스케일업) (0) | 2025.01.07 |
6명이 동시에 요청하면 OOM 발생하는 서비스 (0) | 2025.01.07 |
Subnet 이해하기 (0) | 2024.12.21 |
VPC 이해하기 (1) | 2024.12.14 |