10_Redis_활용 - loveAlakazam/hh-08-concert GitHub Wiki
목적
-
레디스는 key-value 기반의 NoSQL로서 빠른 읽기 성능을 가지며, 레디스가 갖는 각종 편의 기능을 활용하여 가벼운 비용으로 처리를 할 수 있습니다.
-
대기열토큰기능을 Redis로 마이그레이션시켜서 데이터베이스의 부담을 줄일 수 있습니다.
문제
-
만일 이 모든 기능들을 RDBMS가 처리한다면, 테이블에 맞춰야하며, 복잡한 연산을 사용해야되며 비용이 많이 듭니다.
-
정형적이지 않은 데이터 관리가 어렵습니다.
해결방안
-
Key-Value 기반의 NoSQL 데이터베이스는 정형적이지 않은 데이터관리가 가능합니다.
-
기존의 RDBMS는 읽기성능에 부하가 있습니다. 그러므로 싱글스레드로 데드락이 걸리지 않고, 빠른 읽기성능과 가벼운 비용을 갖는 Redis를 사용했고, Redis만이 제공해주는 자료형을 활용했습니다.
레디스의 자료형을 활용한 랭킹 시스템
일간 랭킹 설계도
활용한 레디스 자료구조: Sorted Set을 활용
(1) 콘서트 마지막 좌석을 예약후 5분이내로 결제를 완료하여 50석 모두 매진상태가 되었습니다.
-
제기준의 매진상태란, 50석모두 결제처리 완료 및 예약확정 상태를 의미합니다.
-
제가 만든서비스에서는 예약확정상태에서 취소는 비즈니스로직에 위반하기때문에 취소는 없습니다.
- 실제로 예약후 취소가 가능한 환경일경우를 고려해본다면, 예약취소이벤트가 발생했을때는 매진이 깨지므로 랭킹에서 ZREM 을 이용하여 제거해야하는 방안으로 했을겁니다.
(2) 매진이된 시점의 unix-timestamp 값을 score에 넣습니다.
- 일간랭킹의 TTL은 25시간으로 해놨습니다.
- 일간랭킹의 key는
soldout:daily_rank:{YYYY-MM-DD}
입니다. - 일간랭킹의 구성멤버는
concert:{concertId}:{concertDate}
형식입니다. (예:concert:1:2025-05-15
) - unix-timestamp값을 score로 하여 매진시점을 기록하고 ZADD로 SortedSet에 넣습니다.
주간 랭킹 설계도
활용한 레디스 자료구조: Sorted Set을 활용
- 주간랭킹의 TTL은 24시간으로 했습니다. 그 이유는 매일 0시마다 지난 6일치 데이터집계가 갱신되기 때문입니다.
- 주간랭킹의 key는
soldout:weekly_rank:{YYYY-MM-DD}
입니다. - 지난 일간랭킹들은 0시에 스냅샷으로 저장시켰습니다.
- 주간랭킹의 구성멤버는
concert:{concertId}:{concertDate}
형식입니다. (예:concert:1:2025-05-15
) - 일간랭킹과 다르게 주간랭킹은 구성멤버의
{concertId}
영역을 파싱합니다. concertId 는 콘서트 식별자입니다. 콘서트 식별자의 출현빈도를 score로 계산하며, 가장 높은 score를 가진순으로 주간인기콘서트로 나타냈습니다.
레디스의 자료형을 활용한 대기열 시스템
Redis를 활용하여 비동기로 동작하는 시스템의 전반적으로 나타내보면 아래와 같습니다.
활용 레디스 자료구조
- 대기열 : Sorted Set 자료형 사용
- 토큰관리 및 활성토큰 : Hash 자료형 사용 (TTL 사용)
개선점
유저가 여러개의 토큰을 발급할 수 있다
기존의 대기열토큰은 중복발급을 허용하지 않았으며, 유저1명은 토큰1개를 갖도록 하였습니다.
하지만 실시간 연결을 위해서 유저1명은 토큰을 여러개로 가질 수 있도록 했습니다. 즉 토큰자체의 유일성을 갖도록 하였습니다.
토큰활성화할때 대기열의 상위 100개의 토큰을 한번에 활성화할 수 있다
기존의 토큰활성화는 은행창구방식으로 자신의 순서가될 때(큐의 맨앞에 위치할때) 토큰을 활성화 했습니다.
이번에 한번에 불러와서 처리하는 놀이동산방식을 활용하여 한번에 처리할 수 있도록 했습니다.
성능 및 개선 결과
토큰관련 핵심기능 3개에 대한 처리속도 통합테스트 를 나타내봤습니다. 성능뿐만아니라 코드라인 수도 대폭줄었습니다. 비교에 활용되는 코드라인수는 주석과 줄바꿈문자를 제외한 코드블록내 코드라인수를 의미합니다.
토큰정보 조회
개선전 - 진행시간: 154ms
- 관련 서비스 코드: 개선전 getTokenByUUID 서비스로직 - 2줄
개선후 - 진행시간: 38ms
- 관련 서비스 소스코드: 개선후 getTokenByUUID 서비스로직 - 2줄
대기열 토큰 100개 발급
개선전 - 진행시간: 1835ms
- 관련 서비스 소스코드: 개선전 issueWaitingToken 서비스로직- 14줄
개선후 - 진행시간: 862ms
- 관련 서비스 소스코드: 개선후 issueWaitingToken 서비스로직- 4줄
대기열 토큰 100개 활성화
개선전 - 진행시간: 4081ms
- 관련 서비스 소스코드: 개선전 activeToken 서비스로직 - 12줄
개선후 - 진행시간: 403ms
- 관련 서비스 소스코드: 개선후 activeToken 서비스로직 - 2줄
보완점
대기열토큰에서 토큰 활성화는 이벤트로 발생하는게 아니라 특정 시간규칙으로 스케줄러로 호출하여 활성화가 일어났습니다.
그러므로 실제로는 스케줄러에 의해서 토큰활성화가 발생하고있으므로 보완점은 토큰활성화 이벤트를 발생시켜야합니다. 이는 메시지큐를 이용해서 사용합니다.
결론
-
데이터베이스의 토큰기능을 레디스에게 분담시켜서 데이터베이스의 성능부담을 줄일 수 있습니다.
-
레디스에서 제공하는 자료구조를 사용하여 복잡한 랭킹과 비동기시스템을 구축할수 있게되었습니다.
-
레디스에서는 TTL이라는 유효시간이 지나면, 알아서 삭제되므로 삭제스케줄러를 제거했습니다. 즉 유효시간이 지나면 알아서 삭제되므로 개발자가 토큰의 만료여부를 신경쓸 필요 없습니다.
-
레디스에서 제공하는 자료형을 사용하여 복잡한 시스템을 단순화시킬 수 있습니다. 특히 상태변경으로 인해서 상태점검로직이 제거되어 기존에는 10줄이 넘는 로직인데 단 3~4줄로 코드라인을 대폭줄일 수 있습니다.