Skip to content

성능 테스트 ‐ 쿠폰 발급

Jae-Hyeon Kim edited this page Aug 14, 2024 · 4 revisions

환경

하나의 호스트에 KVM 으로 여러개의 VM을 띄우고 docker-swarm을 구성했다. 호스트와 각 VM에 대한 성능이다.

HOST

  • CPU : i5-10400 (6 Core, 12 Threads)
  • RAM : 32GB
  • DISK : 1.5TB (500GB M.2 SSD, 1TB M.2 SSD)

VM (모두 동일)

  • Master : 3개 (docker swarm master)
  • Worker : 2개 (docker swarm worker)
  • CPU : 2
  • RAM : 4GB
  • DISK : 50GB
  • NETWORK : Docker Network

그리고 이 모든 모니터링은 Grafana 에서 이루어진다.

docker 환경

다음은 서버 인스턴스 현황이다.

  • MySQL : 1개 (8.0.23, master)
  • Redis : 1개 (7.2.5, master)
  • JVM : 1개 (jshop-0.1.0)

테스트 도구

  • nGrinder/controller : 1개 (3.5.9-p1)
  • nGrinder/agent : 3개 (3.5.9-p1)

성능 테스트

시나리오

  • 사용자는 쿠폰을 발급받기 위해 로그인을 하고 쿠폰 발급을 요청한다.
  • 테스트 케이스마다 동시 요청 유저수를 조절한다.
  • 모든 사용자는 동시에 발급 요청을 한다.

목표치

  • 쿠폰 발급 오차 : 0%
  • 최대 동시 사용자수 : 1000명

테스트

1. 쿠폰 10개, 유저 10명 동시 요청

동시 요청이 잘 동작하기 검증하기 위한 테스트다.

수량 10개인 쿠폰을 10명의 vUser가 동시에 발급 요청을 한다.

모두 성공적으로 발급된 것을 확인할 수 있다.

2. 쿠폰 100개 유저 200명 동시 요청

제한된 수량만큼 쿠폰의 발급이 이루어지는지 검증하기 위한 테스트다.

198 명의 vUSER가 동시에 요청을 한다.

100명의 유저는 쿠폰을 발급받고, 98명의 유저는 쿠폰 발급에 실패했다.

3. 쿠폰 100,000개 유저 100명 동시 요청

100명의 vUser가 장기적으로 쿠폰을 발급할때 동작을 검증하기 위한 테스트다.

테스트 결과

테스트 결과 약 30TPS 정도로 발급에는 문제없이 동작했다.

또한 발급에 성공한 유저수와, 실제 줄어든 쿠폰의 수또한 일치했다.

최적화

발급 속도를 높이기 위해 모니터링 결과를 분석해 보았다.

JVM이 돌아가는 노드에서 테스트 기간동안 높은 CPU사용량과 부하를 확인할 수 있었다.

하지만 같은 기간 DB 노드(Redis, MySQL)를 확인해본 결과 DB 노드에는 큰 부하가 없었다.

즉 많은 요청(스레드)들이 락을 얻기 위해 경쟁하는 상황이다.

쿠폰 발급의 경우 반드시 락을 얻어야만 임계 구역에 들어가기 위해 lock.lock() 을 사용했고, 더이상 코드상 성능 최적화 부분이 없다고 판단해 수평 확장으로 인스턴스를 늘리기로 했다.

인스턴스를 2개로 늘려 테스트

동일한 테스트를 인스턴스를 2개로 늘려서 테스트를 진행해봤다.

TPS는 60까지 약 2배 정도 늘어났다. 그리고 각 노드의 CPU 부하 및 사용량이 크게 줄어들었다.

인스턴스를 4개로 늘려 테스트

혹시나 해서 인스턴스를 4개로 늘려 테스트도 해봤다.

하지만 TPS는 크게 늘어나지 않았다. 이는 단일 지점으로 동작하는 Redis 가 병목으로 작용한것으로 보인다.

그래도 각 노드에 가해지는 부하는 크게 줄어들었다.

정리

쿠폰 발급 성능테스트를 진행해본 결과 많은 요청이 들어오더라도 제한 수량 이상으로 발급되는 문제는 발생하지 않았다.

하지만 Redis 분산락을 사용해서, 인스턴스에 대기 요청이 많아질수록 노드에 부하가 많아지고 이로인해 성능이 느려지는 문제가 있었다.

이는 인스턴스를 수평확장해 해결해줄 수 있었다.

수평 확장을 통해 TPS를 30 에서 70까지 올릴 순 있었지만, 인스턴스를 더 추가한다 하더라도 더이상 TPS 가 올라가진 않았다.

이는 모든 노드가 하나의 Redis 클라이언트로부터 락을 획득하고 있었기 때문에 인스턴스의 병목이 제거되니 Redis가 병목으로 동작하게 되었기 때문이다.

Clone this wiki locally