대기열 서버 도입: polling 사용 로직과 테스트 결과

smj_716·2025년 7월 16일

한이음 드림업

목록 보기
6/9
post-thumbnail

1. 문제 시작: 서버가 터진다💥

우리 팀은 일반적인 MVC 구조로 수강신청 서비스를 개발했다.

사용자는 로그인한 뒤, 바로 수강신청 API를 호출하는 방식이었다.
처음엔 잘 작동했지만 JMeter 테스트에서 수천명이 동시에 접속할때 CPU와 DB 커넥션 풀이 빠르게 고갈되었고 서버는 병목 상태에 빠져 오류율이 컸다.

💡가장 먼저 든 생각은 “일단 한 번에 들어오지 않도록 막자”였다.
단순하게 생각하면, 입장할 수 있는 인원을 정해두고 그 외의 사람은 기다리게 하면 된다.
그렇다면 누가 기다려야 하고 누가 들어올 수 있는지 판단하는 서버가 따로 필요해진다.

🔽 그래서 수강신청 서버와는 별도로 대기열 서버를 구성하기로 했다.


2. 대기열 시스템 도입

기능을 나누면 아래와 같다.

  • 대기열 서버 : 사용자 순서 관리 및 입장 여부 판단 담당
  • 수강신청 서버 : 자리 발생 시 대기열 서버에게 알림, 실제 수강신청 DB 처리 담당

💡그런데 한가지 의문점이 들었다.
그럼 입장 가능하다는 건 사용자에게 어떻게 알려주지❓
클라이언트가 아래와 같이 대기열 시스템에 일정한 주기로 계속 물어보면 되지 않을까?

“지금 들어가도 되나요?”
"지금은요?”

그게 바로 Polling 방식이었다.

polling 방식 적용 후 아키텍처는 위와 같이 바뀌었다.
자세한 로직 🔽


3 Polling 방식 적용

🌟 내부 로직 흐름

1. 클라이언트 대기열 진입
클라이언트는 POST /join API를 통해 대기열에 진입한다.
서버는 토큰 기반으로 사용자 정보를 생성해 큐에 저장한다.
사용자에게 현재 대기 순번을 응답한다.

2. 상태 확인 (Polling)
클라이언트는 GET /{uuid} API를 일정 주기로 호출해 자신의 상태를 확인한다.
서버는 WAITING 또는 ALLOWED 상태와 남은 순번을 반환한다.
클라이언트는 상태가 ALLOWED가 될 때까지 polling을 계속한다.

3. 빈자리 발생 시 수강신청 서버 → 대기열 서버 알림
수강신청 서버는 빈자리를 감지하면 POST /notify API를 호출해서
앞 순서 n명의 사용자에게 입장 허용 요청을 보낸다.
대기열 서버는 해당 인원을 ALLOWED 상태로 바꾼다.

4. ALLOWED 사용자 로그인
ALLOWED 상태가 된 사용자만 수강신청 서버에 로그인할 수 있다.
로그인 시 해당 사용자는 큐에서 제거된다.

🔍 내부 구성 요약

구성 요소설명
QueueManager대기열 큐 및 순번 계산 관리
queue전체 대기열을 저장하는 큐 (Queue<QueueUser>)
userMap사용자 토큰으로 빠르게 조회하기 위한 맵
globalIndex전체 순번 계산을 위한 전역 카운터
BatchManagerALLOWED 상태 사용자 그룹 및 타이머 관리
batchTokenMap배치 단위 사용자 토큰 목록
batchFutures로그인 완료 여부 추적용 CompletableFuture 객체

📘 API 요약

API설명
POST /join대기열 진입. 토큰 기반 사용자 생성 후 큐 등록
GET /{uuid}사용자 상태 확인 (WAITING or ALLOWED) 및 현재 순번 확인
POST /notify수강신청 서버가 빈자리 발생 시 앞 사용자 n명 ALLOWED 처리 요청
GET /clear테스트용 전체 대기열 초기화

4. JMeter 테스트 결과

우리는 100명부터 10,000명까지 다양한 시나리오를 구성해 총 4가지 상황에서 부하 테스트를 진행했다.
📌 각 시나리오에 대한 상세 설명은 아래 글에 정리되어 있다.
🔗 시나리오 설명 보러가기

대기열 시스템 도입과 Polling 방식을 적용한 현재 아키텍처는 이전 구조와 비교했을 때 오류율이 눈에 띄게 감소했다.

동시 5,000명 접속 시나리오에서의 변화를 예로 들어보겠다.

📉 MVP 초기 구조 vs Polling 도입 후 오류율

시나리오1

시나리오2

시나리오3

시나리오4

위 결과를 보면

  • Polling은 사용자가 ALLOWED가 될 때까지 계속 요청하기 때문에 표본 수가 많은것을 볼 수 있고 그 결과 정상적으로 많은 요청을 처리할 수 있는것으로 판단된다.
  • 또한 대기열 도입으로 부하도 줄었다는것을 확인할 수 있다.

😲 평균적으로 약 80% 이상 오류율이 감소했다.
대기열 도입과 polling 적용 후 안정성 올라갔다는 걸 수치로 확인할 수 있었고 그 수치는 엄청난 차이였다.


🎯 마무리

우리 팀은 처음부터 대기열 시스템 도입과 polling을 쓰려고 했던게 아니다.
수강신청 서버가 트래픽을 감당하지 못하고 터지는 걸 경험하면서

  • 👉 "모두가 한 번에 들어오지 않게 하려면 어떻게 해야 하지?"라는 고민에서 대기열을 도입하게 되었고
  • 👉 "입장 가능 여부를 사용자에게 어떻게 알릴까?"라는 물음 끝에 Polling 방식이 자연스럽게 도출되었다.

❌ 물론 완벽한 구조는 아니다.
서버가 반복적으로 요청을 받아야 하기에 리소스가 소모되고 실시간성도 다소 부족하다.
그래서 이 방법말고 회의를 통해 나온 다른 후보의 방법들도 사용해보려고 한다.

0개의 댓글