-
Notifications
You must be signed in to change notification settings - Fork 1
유저에게 더 좋은 쿼리 실행 환경을 제공할 수 있도록 with 부하테스트
쿼리를 테스트해볼때 가장 중요하게 보는 지표는 당연 실행속도입니다.
이 실행속도가 쿼리외 다른 원인에 의해 느려진다면 이는 정확한 테스트를 할 수가 없게됩니다.
QLab은 nest와 독립적으로 실제 쿼리 실행 시간을 반환하는데 자세한 내용은 아래 링크에 있습니다.
QLab은 유료 서비스가 아니기 때문에, 각 사용자에게 서버를 개별적으로 할당하는 것은 현실적으로 어렵습니다.
그러므로 최대한 제한된 서버안에서도 외부환경에 영향을 덜 받을 수 있는 실행환경을 제공해야합니다.
이를 테스트해보기 위해 부하테스트를 진행해보았습니다.
부하테스트는 locust로 진행하였습니다.
현 부하테스트 목적은 api응답속도가 아닌,쿼리 실행시간이 어느정도 보장되는가 입니다.
그래서 쿼리 실행시간을 파일에 기록하는 코드를 추가하였습니다.
if response2.status_code == 201:
# 응답 데이터 파일에 저장
data_to_write = response2.json().get('data', {}).get('text', '')
User.log_to_file("locust_output.txt", data_to_write)
@staticmethod
def log_to_file(filename, data):
with open(filename, "a") as file:
file.write(data + "\n")쿼리가 느려지는 이유는 크게 두 가지로 나눌 수 있습니다:
- 연산 처리가 많아서 CPU를 많이 사용하는 경우.
- I/O 작업이 많아서 대량 데이터를 처리하거나 디스크 접근이 빈번한 경우.
I/O 작업을 테스트하려면 테이블 생성이나 데이터 삽입 같은 사전 작업이 많이 필요합니다.
이러면 준비 과정도 복잡해지고, 테스트 결과를 명확히 파악하기도 어려울 수 있습니다.
그래서, 사전 작업 없이 CPU에 부하를 줄 수 있는 benchmark 쿼리를 활용해 테스트를 진행했습니다.
이 쿼리는 반복적인 연산을 수행하는 작업이라 별도의 데이터 준비 없이도 CPU 부하를 효과적으로 테스트할 수 있습니다.
- 최대 동접자: 100명
- 유저 증가 속도: 1초당 1명
- 테스트 실행 시간: 테스트 실행 시간 2분
- 쿼리 실행 주기: 한 유저는 5~10초마다 쿼리를 실행
-
실행 쿼리:
SELECT BENCHMARK(20000000, POW(2, 1))- 이 쿼리는 한 유저가 실행시 서버 기준 0.6초 정도 시간이 소요됩니다.
| 방식 | 최대 실행 시간 | 특징 및 결과 |
|---|---|---|
| 1. Query DB Connection을 세션으로 유지 | 20,000ms (20초) | - 단일 실행 시와 비교해 약 33배 차이 발생 - 사용자 수와 환경에 따라 결과 변동이 큼 - 서비스 신뢰성 저하 가능성 존재 |
| 2. 요청마다 Connection 생성 | 25,000ms (25초) | - 커넥션을 즉시 제거했으나, 성능 저하 발생 - 커넥션 생성 비용이 부하를 더 크게 유발 - 기대한 성능 개선 효과 미미 |
| 3. 요청마다 Connection 생성 + 제한 적용 | 4,000ms (4초) | - MySQL max_connections 제한(20) 설정- 최대 실행 시간 대폭 감소 - 실패 요청 발생 - 유저가 최대치 일때 성공에 대한 RPS는 이전보다 3배증가 |
요청마다 Connection 생성 + 제한 적용 방식을 택하였습니다.
이 방식은 제한된 자원에서도 쿼리 실행 시간을 줄이고 성공 요청 수를 최대화할 수 있는 방법입니다.
특히, 커넥션 생성에 실패하면 바로 에러를 반환해서 실행 완료를 무한히 기다리는 상황을 방지합니다. 덕분에 사용자도 빠르게 알림을 받을 수 있어 UX 측면에서도 더 나은 선택이라고 판단하였습니다.