Skip to content

유저에게 더 좋은 쿼리 실행 환경을 제공할 수 있도록 with 부하테스트

mintaek edited this page Dec 1, 2024 · 9 revisions

좋은 쿼리 실행 환경이란 무엇인가

쿼리를 테스트해볼때 가장 중요하게 보는 지표는 당연 실행속도입니다.

이 실행속도가 쿼리외 다른 원인에 의해 느려진다면 이는 정확한 테스트를 할 수가 없게됩니다.

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")

어떤 쿼리로 테스트해야 할까?

쿼리가 느려지는 이유는 크게 두 가지로 나눌 수 있습니다:

  1. 연산 처리가 많아서 CPU를 많이 사용하는 경우.
  2. 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 측면에서도 더 나은 선택이라고 판단하였습니다.

Clone this wiki locally