블로그 목록

티켓팅 때마다 초가 안 맞아서 답답했다: TrueTime을 만든 이유

저는 티켓팅을 잘하는 사람이 아닙니다. 그래도 가끔은 꼭 가고 싶은 공연이 생기고, 그럴 때마다 오전 10시 정각에 맞춰 컴퓨터 앞에 앉아 있게 됩니다. 문제는 정각이 언제인지 확신할 수 없다는 점이었습니다. 휴대폰 시계, 노트북 시계, 손목시계가 모두 조금씩 달랐고, 어떤 날은 제가 본 시계로는 분명 10시 00분이었는데 예매 버튼은 아직 열리지 않았습니다. 몇 초 뒤 다시 눌렀을 때는 이미 좌석이 거의 사라진 뒤였습니다.

그때 처음으로 "내가 보고 있는 시계가 기준이 아니구나"라는 생각을 했습니다. 이 글은 그 답답함에서 시작해 TrueTime이라는 정밀 서버 시계 웹 서비스를 설계하고 만들게 된 이야기입니다.

정각에 눌렀는데 왜 늦었을까

원인은 단순했습니다. 예매 사이트나 수강신청 사이트는 제 휴대폰 시계가 아니라 그 사이트 서버의 시각을 기준으로 버튼을 엽니다. 운영체제의 NTP 동기화가 켜져 있어도 기기마다 수백 밀리초에서 1~2초까지 미세한 오차가 생길 수 있고, 브라우저에서 클릭한 요청이 예매 서버에 도달하기까지 걸리는 네트워크 왕복 지연(RTT)도 존재합니다. 평소에는 전혀 신경 쓸 일이 없는 차이지만, 1초 안에 대기열 순번이 갈리는 순간에는 그 차이가 당락을 가릅니다.

처음에는 휴대폰 시계를 보다가 "조금 늦게 열리는 것 같으니 1초쯤 뒤에 누르자" 같은 식으로 감에 의존했습니다. 당연히 결과는 들쭉날쭉했습니다. 운이 좋으면 들어갔고, 대부분은 수만 명의 대기열 뒤쪽에서 기다리다 끝났습니다.

기존 서버 시계 서비스를 써보면서 느낀 아쉬움

서버 시간을 보여주는 서비스들을 실제로 여러 곳 써봤고 도움도 받았습니다. 다만 실제 예매 환경에서 쓰다 보니 몇 가지가 계속 아쉬웠습니다.

  • 초 단위까지만 보이는 경우: 초가 바뀌는 순간을 기다리다 보면, 지금이 59초 100ms인지 59초 900ms인지 알 수 없어 클릭 타이밍을 잡기 어려웠습니다.
  • 화면을 계속 보고 있어야 하는 점: 예매 창과 시계 창을 번갈아 보다가 정작 예매 버튼에서 마우스 포커스를 놓치기도 했습니다.
  • 알람이 제대로 울릴지 모르는 불안: 알람을 맞춰 두었는데 브라우저 정책 때문에 오디오가 차단되거나 백그라운드 탭에서 타이머가 지연되면 아무 소용이 없었습니다.

제가 원한 건 "정각 직전의 몇 초를 덜 불안하게 보내고, 오직 예매 버튼에만 시선을 고정할 수 있게 해주는 도구"였습니다.

그래서 이런 구조로 만들었습니다

TrueTime은 복잡한 부가 기능보다 정각 직전 10초 동안 가장 필요한 핵심 동작에 집중했습니다.

  • 사이트 주소 기반 밀리초(ms) 시각 표시: 예매하려는 사이트 도메인을 입력하면 대상 서버의 응답 시각을 밀리초 단위까지 실시간으로 렌더링합니다. 초가 넘어가는 흐름이 숫자로 보이니 현재 59초의 어느 지점을 지나고 있는지 직관적으로 파악할 수 있습니다.
  • 네트워크 왕복 지연(RTT) 보정: 요청을 보내고 응답을 받기까지 걸린 왕복 시간의 절반을 반영해 네트워크 전송 지연을 보정합니다.
  • 10초 전 사전 경보(Pre-alarm): 목표 시각 10초 전에 알림음이 먼저 울립니다. 시계 화면을 뚫어지게 보지 않아도 소리만으로 "이제 예매 버튼 위에 마우스를 올리자"는 신호를 받을 수 있습니다.
  • 10초 뒤 테스트 알람: 본 게임에 들어가기 전에 현재 브라우저 탭에서 Web Audio 신호음과 시스템 알림이 정상 작동하는지 즉시 검증할 수 있습니다.
TrueTime 10초 전 사전 경보와 타이머 설정 화면

▲ 목표 시각 10초 전에 사전 신호음을 받을 수 있는 TrueTime 알람 화면

기능 하나하나의 자세한 사용법은 TrueTime 사용 가이드에 따로 정리해 두었습니다.

설계하고 구현하며 해결한 기술적 과제

겉으로는 단순한 시계처럼 보이지만, 브라우저 환경에서 밀리초 단위의 일관성을 유지하려면 몇 가지 까다로운 문제를 풀어야 했습니다. 가장 먼저 부딪힌 문제는 브라우저의 백그라운드 탭 타이머 스로틀링(Throttling)이었습니다. 일반적인 setInterval은 탭이 가려지거나 비활성화되면 브라우저가 배터리 절약을 위해 호출 주기를 1초 이상으로 늦추기 때문에 알람이 제때 울리지 않을 수 있습니다.

이를 해결하기 위해 화면 렌더링 루프(`requestAnimationFrame`)와 고정밀 단조 시계(`performance.now()`)를 결합하여 기기 절전이나 시스템 시계 흔들림의 영향을 최소화했고, 브라우저의 자동 재생 차단 정책(Autoplay Policy)으로 인해 정각에 소리가 안 나는 사고를 막기 위해 사용자가 직접 오디오 컨텍스트 활성화 여부를 사전 검증할 수 있는 '10초 테스트 알람' 플로우를 설계했습니다.

실제로 이렇게 활용합니다

예매가 있는 날이면 오픈 15~30분 전에 TrueTime을 열고 대상 사이트 주소를 조회해 둡니다. 그다음 10초 테스트 알람을 한 번 울려서 이어폰 연결 상태와 브라우저 오디오 권한이 정상인지 확인합니다. 정각 알람을 맞춰 두고 나면 예매 창으로 돌아가 로그인 세션과 본인 인증, 결제 수단 설정을 다시 점검합니다.

정각 10초 전 사전 경보음이 울리면 그때부터는 시계 창을 보지 않고 예매 화면의 버튼에만 집중합니다. 예전처럼 여러 시계를 번갈아 보며 조급해하던 시간이 사라진 것만으로도 클릭 정확도가 훨씬 높아졌습니다. 예매 당일 타임라인별 준비 사항은 티켓팅 준비 체크리스트에 상세히 정리해 두었습니다.

공연 예매뿐만 아니라 대학교 수강신청, 명절 기차표 예매, 한정판 응모처럼 정해진 시각에 문이 열리는 모든 상황에서 동일하게 활용할 수 있습니다. 핵심은 "정각 직전에 허둥대지 않는 루틴"을 만드는 것입니다.

TrueTime이 예매 성공을 100% 보장해 주지는 않습니다. 최종 좌석 확보는 서버 대기열 처리 방식과 운에 좌우됩니다. 다만 "내 시계가 틀려서 늦게 누른 건 아닐까" 하는 불확실성 하나는 확실히 줄여줄 수 있습니다.

한계점과 앞으로의 개선 방향

실제 환경에서 참고하셔야 할 기술적 한계도 명확히 안내드립니다.

  • HTTP 헤더의 초 단위 해상도와 RTT 변동성: 외부 웹 서버가 내려주는 표준 Date 헤더는 초 단위까지 표현되므로, 순간적인 네트워크 지터(Jitter)에 따라 측정할 때마다 수십~수백 ms 정도의 편차가 발생할 수 있습니다.
  • CDN 및 엣지 캐시 서버 응답: 대형 예매 사이트는 앞단에 CDN이나 로드밸런서를 두기 때문에, 조회된 시각이 백엔드 DB/주문 서버가 아닌 엣지 노드의 시각일 수 있습니다.
  • 브라우저 오디오 정책: 모바일 저전력 모드나 백그라운드 상태에서는 알람이 지연될 수 있으므로, 예매 직전에는 TrueTime 창을 별도 분할 창으로 띄워 두시길 권장합니다.

앞으로는 여러 번 샘플링한 응답 시간의 중앙값(Median)을 활용해 네트워크 튀는 값을 걸러내는 정밀도 개선과, 자주 찾는 예매처를 빠르게 불러오는 프리셋 기능을 차례로 다듬어 나갈 계획입니다.