티켓팅 대기열 처리
티켓 예약 서비스에 대한 팀 프로젝트를 진행중이고 개발자라면 당연히 떠오르는 한 가지의 생각..
티켓팅 일정 시간이 되었을 때 대규모 트래픽 처리에 대한 고민이 있다.
고민만 해보고 한 번도 해본적이 없는 트래픽 테스트에 대해 고민했던 것들과 어떻게 해결했는지 그 과정을 적어보려고 한다.
솔루션 선택
MQ와 같은 비동기 메세지 큐를 사용하여 들어온 수만건의 대한 요청을 순차적으로 큐를 통해 처리를 해주어야 한다고 생각했고 구글 검색을 통해 여러가지 방법을 알게 되었다.
1. Kafka, Rabbit MQ와 같은 MQ 사용
2. Redis SortedSet 자료구조를 이용한 대기열 기능 구현
Kafka, Rabbit MQ와 같은 MQ 사용
장점
- 미들웨어를 활용하므로써 정확한 MQ 시스템 구성
- 속도 및 안정성 최고
단점
- MQ 구축 경험이 없어 러닝 커브 있다!! ( 프로젝트 마감까지 3일 정도의 시간밖에 없었다.)
- 기존에 도입되지 않아서 구성 시간이 오래 걸린다.
Redis 를 이용한 대기열 기능 구현
장점
Cache의 장점, 속도는 압도적..
간단한 Redis 사용법으로 러닝 커브는 높지 않다.
단점
Redis가 다운된다면?? ......
Redis의 사용
Redis의 Sorted-Set 데이터 구조를 이용하여 대기열 Queue를 구현한다.
1번에 해당하는 Kafka, RebbitMQ 등 메세지 큐를 활용한 방안 대신 Redis를 사용한 이유는 모든 클라이언트에게 실시간 요청 순서를 제공해야하기 때문에 Redis를 사용한다.
Sorted-Set의 정렬 기준은 서버 시간을 기준으로 한다.
Redis Sorted-Set 자료 구조
특징
1. 집합이기 때문에 중복 문제를 해결해준다.
2. 대기를 요청한 멤버의 순위를 반환한다. (ZRANK)
기본 명령
Redis Sorted-Set의 대부분의 명령의 시간 복잡도는 O(log(n)) 이다.
- ZADD : 대기열에 입장을 요청한 클라이언트를 Sorted-Set 에 추가한다.
- ZRANGE : 주어진 범위 내에서 클라이언트들을 반환한다.
- ZRANK/ZREVRANK : 현재 연결 중인 클라이언트의 순위를 반환한다. (오름차순/내림차순)
티켓팅 예매 페이지 접속 과정
- React 단에서 컴포넌트 렌더링 시, Socket 연결을 하여 서버와 연결을 한다.
- 서버에서는 연결과 동시에, Redis SortedSet에 저장시켜 대기열을 구성한다.
- Scheduling을 수행하여 1초에 한 번씩 Redis로 구축한 대기열에서 N개의 요청을 꺼내어 해당 연결로 전송한다.
- “접속확인”이라는 전송을 받은 클라이언트는 Socket 연결을 해제하고 예매 페이지로 접속한다.
대용량 트래픽에 대한 기술적 고민
가정 : 50000개의 소켓 연결
- 대기열을 한번씩 훑으며 자신의 순번을 클라이언트로 전송할 것인가??
- STOMP를 사용했을 때 클라이언트로의 메세지 전송 방식을 브로드 캐스트 방식이 아닌 개개인 메세지 전송을 할 것인가?
부하 테스트
NGrinder 테스트
- Socket 연결을 수행하는 Front 요청 주소로 부하테스트를 진행한다.
- 요청에 따라 소켓 연결이 진행될 줄 알았지만 요청 X
- Nginx단에서 요청이 들어오지만 백엔드 API에 도달되지 않는다.
ngrinder를 이용하여 해당 URL에 요청을 보내보았다. 하지만, 서버 앞단에 설치된 nginx에 요청이 들어왔으나 소켓 연결 요청이 들어오는 BackEnd 단에 로그를 살펴보니 무소식이였다. 정확한 테스트를 진행하지 못한 채 Error로 종료.
NGrinder 테스트 도구에 대한 이해도가 부족하다고 생각하였다.
JUnit 테스트
- JUnit 테스트 코드를 작성
- 테스트 서버에서 5000개의 소켓을 연결하고 SessionArray(Java List)에 담는다.
- SessionArray 에 담아져 있는 연결정보로 각 Thread를 생성하여 연결 요청한다.
- SessionArray 전체의 연결정보에 대기열 입장 Message를 보내 입장한다.
마무리
- 5000개의 대한 요청 보다는 많은 5만 ~ 10만 그리고 그 이상의 트래픽을 견디기 위해서는 Kubernates 도입이 필수라고 생각한다.
- 전체 클라이언트에게 메세지를 전송해야 하는 것에 대한 효율적인 방법에 대한 고민이 필요함.
'BackEnd' 카테고리의 다른 글
세션 인증 방식과 토큰 인증 방식 (1) | 2023.07.13 |
---|---|
Interceptor 를 통해 회원 API 리팩토링하기 (1) | 2023.07.03 |
[Spring] Interceptor 와 Filter의 개념 및 차이점 (0) | 2023.06.20 |
Message Queue (3) | 2023.04.27 |
로그(Log) 확인해봤어?? 로그 제대로 알자 (5) | 2023.02.23 |