개발/기타

선착순 티켓팅 개발기 2 (성능 테스트)

코리이 2025. 2. 1. 16:46

들어가며

이전 포스팅에서는 대학교 축제의 티켓팅 시스템을 안정적으로 운영하기 위해 어떤 아키텍처를 선택했는지에 대해 이야기했습니다. 특히, 동시 트래픽이 몰리는 순간에도 장애 없이 대응할 수 있도록 SQS 기반의 비동기 처리 구조, Redis Writeback 전략 등의 다양한 전략에 대해 설명드렸습니다. 이번 글에서는 설계한 아키텍쳐를 바탕으로 실제 티켓팅 전에 미리 성능을 검증하기 위해 진행했던 테스트 과정에 대해 공유드리고자 합니다.

성능 테스트 아키텍쳐 설계

 

성능 테스트를 시작하기에 앞서, 먼저 어떤 도구를 사용할지 결정해야 했습니다. 이전에 사용해본 도구로는 JMeter와 nGrinder가 있었습니다. 하지만 JMeter는 스크립트 작성 및 관리가 복잡하고 확장성 면에서 인프라 자동화와 잘 맞지 않는 한계가 있었으며 nGrinder는 스크립트를 Groovy로 작성할 수 있어 유연성이 좋지만, 높은 트래픽을 내기 위해선 여러 인스턴스를 수동으로 분산 구성해야 하는 번거로움이 존재했습니다. 이러한 이유로, 이번 프로젝트에서는 경량화된 CLI 환경, 스크립트 기반 작성, 인프라 자동화와의 궁합이 뛰어난 k6 를 선택하게 되었습니다.

 

k6 모니터링은 지속적인 데이터 축적이 필요한 용도는 아니었고, 테스트가 진행되는 동안만 일시적으로 성능 지표를 확인하면 충분했습니다. 때문에 비용 부담이 적고 구성도 간단한 Grafana를 선택하게 되었습니다. 또한, k6는 Grafana Labs에서 만든 도구이기 때문에, Grafana와의 통합이 매우 자연스럽고 설정도 간편했습니다.

 

k6 인프라는 Terraform 을 활용해 자동화 했습니다. 테스트가 필요한 시점에만 인프라를 동적으로 구성하고, 테스트가 끝난 후에는 리소스를 정리할 수 있도록 설계했습니다. 비용 효율성을 고려해 EC2 Spot Instance를 사용하였고, k6 실행 환경과 Grafana 모니터링 환경을 분리함으로써, 부하 테스트 도중 모니터링 인프라가 영향을 받아 중단되는 문제를 방지할 수 있었습니다. 이 구조 덕분에 테스트 중 주요 지표(요청 수, 응답 시간, 에러율 등)를 실시간으로 시각화하여 확인할 수 있었고, 테스트 종료 후에는 관련 리소스를 정리함으로써 불필요한 비용 없이 효율적인 모니터링이 가능했습니다.

 

테스트하기 위해 작성한 k6 스크립트들은 s3 에 업로드한 후 terraform 으로 인프라 구성 시 파일을 download 하여 시나리오 수정시에도 쉽고 빠르게 대응이 가능했습니다.

성능 테스트 계획 수립 및 수행

이번 성능 테스트의 목표는 다음과 같았습니다. peak 기준 30,000 RPS 이상의 상황, p95 응답 시간이 500ms 이하인 상태에서 1) API 서버의 CPU/Memory 사용률을 50% 이하로 유지할 수 있는 인스턴스 스펙과 개수 2)이를 처리할 수 있는 데이터베이스 인스턴스의 타입과 개수를 산출하는 것이었습니다.

 

테스트는 티켓팅의 특성상 특정 시점에 유저들이 일제히 '구매' 버튼을 누르는 순간적인 트래픽 급증이 발생하기 때문에, 이를 시뮬레이션하는 테스트(Spike Test)가 핵심이었습니다. 다만, 티켓의 종류에 따라 두 가지 서로 시나리오가 존재했습니다.

  1. 무료 티켓의 경우, 유저가 별도의 결제 과정 없이 버튼만 누르면 되기 때문에 결제가 이루어 질 때 Think Time이 사실상 없거나 매우 짧습니다.
  2. 반면 유료 티켓은 결제 정보를 입력해야 하기 때문에, 주문 생성부터 결제 사이에 Think Time이 발생합니다.

또한 이전 포스팅에서 설명한 대로 무료 티켓인 경우에는 Redis 에 재고를 미리 적재해 놓았기 때문에 구성도 조금 달라질 수 있었습니다. 아래 사진은 실제로 스펙을 지속적으로 조정해가면 얻은 테스트 결과의 일부입니다.

 

병목 개선

테스트하면서 여러가지 병목이 존재했는데 그 중 Redis lock 에 대한 이야기를 소개해보고자 합니다. 무료 티켓 시나리오에 대한 성능 테스트를 진행하던 중, p95 latency가 무려 3초에 달하는 비정상적인 수치를 확인할 수 있었습니다. 특히나 max latency 를 확인해보니 60초(1분) 이라는 굉장히 높은 수치를 기록하고 있었습니다. 이로 인해 HTTP 요청의 실패율도 함께 증가하는 현상도 발생했습니다.

 

참고: peak rps 는 27.3k/5 = 5.4 k 입니다.

 

Datadog APM을 통해 살펴본 결과, Redis Lock 처리 로직에서 병목이 발생하고 있음을 확인할 수 있었습니다

 

문제가 되었던 로직은, 주문 요청 시 해당 상품의 재고를 확인하기 위해 아래와 같이 방식으로 상품 id 단위로 Lock을 거는 구조 때문이였습니다.

lock (상품 id)
  재고 개수 확인
  유저별 최대 구매 제한 개수 검증
  재고 개수 차감(count)
unlock (상품 id)

 

이 구조에서는 같은 상품에 여러 사용자가 동시에 요청을 보낼 경우, 모두 동일한 Lock을 기다리게 되어 응답 지연이 누적될 수밖에 없습니다. 무료 티켓은 특히 특정 상품에 트래픽이 집중되는 경향이 강했기 때문에, 빠른 응답을 목표로 도입한 캐시 기반 재고 확인 로직이 오히려 전체 성능 저하의 원인이 되는 역효과가 발생했습니다.

 

이러한 문제를 해결하기 위해 재고 차감 로직을 수정해야 했습니다. 이전 포스팅을 보셨던 분이라면 이미 눈치채셨겠지만 재고 개수를 숫자로 저장하는 방식이 아니라, 상품별 재고 id 를 Redis의 List 구조로 미리 적재해두는 방식을 사용했습니다. 이 방식에서는 유저의 요청이 들어올 때 Redis 리스트에서 `pop` 을 수행하여 재고를 하나 꺼내는 방식으로 처리합니다. 만약 리스트가 비어 있다면 null이 반환되므로, 그 시점에서 재고 없음 처리를 하면 됩니다.

 

다만 여전히 문제가 되는 부분은 유저별 최대 구매 수량 제한입니다. 이 검증은 사용자마다 상태가 다르기 때문에 Lock이 필요했고, 이전과 달리 상품 id + 유저 id 조합을 기준으로 Lock을 걸도록 구조를 변경했습니다. 이렇게 되면 서로 다른 사용자의 요청 간에는 Lock 충돌 없이 병렬 처리가 가능해집니다

lock (상품 id, 유저 id)
  pop 재고
  유저별 구매 제한 검증
unlock (상품 id, 유저 id)

 

이 구조로 개선한 후 동일한 조건으로 다시 성능 테스트를 진행한 결과, latency 는 확연히 줄어들었고, 처리 가능 RPS는 약 2배가량 증가하는 효과를 확인할 수 있었습니다.

참고: peak rps 는 23.8k/2 = 11.9 k 입니다.

 

Redis lock 문제 외로도 slow query 문제, sqs 메시지 전송 성능 문제, aurora DNS 기반 라운드로빈 이슈로 인한 부하 쏠림 문제 등의 병목이 존재하여 이를 해결했습니다.

실제 티켓팅 결과

실제 운영 환경에서는 API 서버의 CPU 사용률이 예상보다 약간 높게 올라가 최대 50% 수준까지 도달했지만, 장애 없이 안정적으로 트래픽을 처리하며 마무리할 수 있었습니다. Worker 서버는 SQS로부터 메시지를 하나씩 소비하는 구조이기 때문에, 자연스럽게 처리량이 제한되며 CPU 사용률 역시 50% 내외로 안정적으로 유지되었습니다.

 

RDB 측면에서도 Writer 인스턴스(instance-1)는 티켓팅 처리에서 직접적으로 격리되어 있었기 때문에 트래픽이 몰린 상황에서도 안정적인 CPU 사용량을 보였습니다. 아래 그래프에서 일시적으로 사용량이 상승한 구간은 실제로 API 서버가 DB를 사용한 시점이 아니라, 티켓팅 트래픽이 몰린 후 Worker가 DB 저장 작업을 수행하는 구간이며, 이 또한 CPU 35%를 넘지 않는 수준에서 안정적으로 처리되었습니다.

 

결론적으로 RPS 1200+, 동시접속 10,000+ 환경에서 안정적으로 티켓팅을 마무리 할 수 있었습니다.

결론

이번 포스팅에서는 성능 테스트를 통해 아키텍처의 병목을 사전에 식별하고 개선한 과정, 그리고 실제 수천 명의 동시 접속자 속에서 티켓팅을 성공적으로 마무리한 운영 결과를 공유드렸습니다. 사전에 병목지점을 파악하고 개선했던 것이 실제 운영에서 큰 장애 없이 안정적으로 시스템을 유지할 수 있었던 핵심 요인이었습니다. 이 포스팅을 통해 티켓팅에 대해 고민하시고 있는 분들에게 도움이 되셨으면 합니다.