Skip to content

대기열 시스템 설계

hseong3243 edited this page Sep 6, 2024 · 2 revisions

설계 목표

  • 우아한 티켓팅의 대기열 시스템은 새로고침해도 사용자의 순서를 유지하는 친절한 대기열 시스템을 목표로 했습니다.
  • 사용자의 실수, 지루함에 의한 새로고침 클릭 정도는 용인해주어 사용자 경험을 향상시키고 싶었습니다.

아이디어

현실 세계에서 순서를 유지하는 대기열은 은행에서 찾아볼 수 있었습니다. 은행의 대기 시스템은 다음과 같은 흐름으로 동작합니다.

  1. 사용자는 은행에 입장하여 번호표 발급기에서 번호표를 뽑습니다.
  2. 사용자는 대기 공간에서 대기합니다.
  3. 사용자는 은행원의 앞에 있는 빨간 번호 표시기의 숫자와 자신의 번호표를 비교해서 남은 순서를 파악합니다.
  4. 빨간 번호 표시기가 띵동 하고 울리면 은행원 앞에 앉아 작업을 시작합니다.
스크린샷 2024-09-06 오후 10 44 54

저희 시스템은 여기에서 아이디어를 얻어 마치 은행과 같이 1) 대기 번호 발급기, 2) 대기열, 3) 입장 번호 표시기, 4) 작업 공간 까지 네 가지 핵심 요소로 구성하였습니다.

스크린샷 2024-09-06 오후 10 54 38

이를 기반으로 본격적인 설계를 진행하며 두 가지 핵심 문제를 정의했습니다.

문제

하나. 언제 대기열의 사용자를 작업 공간으로 옮겨줄까?

가장 간단한 방법으로는 스케줄링을 이용하여 주기적으로 행위를 실행시키는 방법이 있었습니다. 하지만 스케줄링의 경우 사용자가 대기열에 없어도 불필요한 동작을 반복한다는 단점이 있었습니다. 저희는 이러한 불필요한 동작을 줄이고 싶었습니다.

불필요한 동작을 줄이려면 사용자가 '자신의 남은 순서를 물어봤을 때', 작업 공간에 자리가 있는지 확인하고 대기열에서 빼주는 방법을 생각할 수 있었습니다.

스크린샷 2024-09-06 오후 11 08 25

하지만 대기열 페이지에서 자기 순서를 물어보는 사용자는 수 천, 수 만명 일 것입니다. 그렇다면 대기열에서 작업 공간으로 옮겨주는 동작도 수천번 수행하게 되는 문제가 발생할 것이라고 예측할 수 있었습니다.

스크린샷 2024-09-06 오후 11 09 05

이를 해결하기 위해 고민하던 찰나 디바운스라는 키워드를 떠올렸습니다. 사용자의 요청을 모아뒀다가 한 번만 실행시키는 겁니다. 수천 개의 요청 중 오직 하나의 요청이 작업 공간의 빈 자리만큼 대기열의 사용자를 빼서 작업 공간으로 이동시키는 겁니다. 그럼 첫번째 문제는 해결할 수 있습니다.

스크린샷 2024-09-06 오후 11 15 23

둘. 대기열에서 떠난 사용자와 활성 사용자를 어떻게 구분하지?

두번째 문제는 대기열 페이지의 속박을 벗어던지고 행복을 찾아 떠난 사용자입니다. 저희 대기열 시스템은 새로고침해도 순서를 유지하는 친절한 대기열입니다. 때문에 사용자가 중간에 자리를 비운 경우에도 사용자 정보를 유지하고 있습니다.

그런데 이 사용자가 완전히 떠나버린 경우에 문제가 발생합니다. 떠난 사용자가 작업 공간에 들어갈 차례가 되었고 실제로 들어가게 된다면 아무런 작업을 하지 않음에도 불필요하게 작업 공간을 점유하게 됩니다. 바로 뒤에서 기다리고 있는 사용자는 작업을 원하는 활성 사용자임에도 불구하고 불필요한 대기를 해야 합니다. 서버 자원 또한 낭비될 것입니다.

스크린샷 2024-09-06 오후 11 22 03

이를 해결하기 위해 생각한 방법은 작업 만료 시간에 있었습니다.

최초에 작업 공간의 빈자리를 대기열의 사용자로 채울 때, 사용자의 만료 시간은 30초 정도로 짧게 설정합니다. 그리고 사용자는 자신의 남은 순서를 알기 위해 마지막 요청을 보내는 순간이 옵니다. 그 때, 사용자의 대기 시간을 작업이 가능한 만큼 설정해주는 것으로 해결할 수 있었습니다.

스크린샷 2024-09-06 오후 11 25 46

다음으로

지금까지 우아한 티켓팅의 기본 설계 아이디어와 두 가지 핵심 문제를 정의하고 해결한 것에 대해 설명하였습니다. 저희는 이러한 설계를 바탕으로 Java 메모리 대기열, Redis 대기열을 구현하고 성능 비교를 진행하였습니다. 다음 편에서는 저희 팀이 어떻게 부하 테스트를 진행했는지, 어떤 것이 성능상에서 우위를 보였는지 다루겠습니다.