2차 프로젝트를 진행하며 Redis가 동시성 처리 등 다방면에 활용될 수 있다는 것을 알게 되었다.
나는 Redis를 활용해 대기 생성, 지연, 입장을 처리하고 싶었으나 Redis의 이해가 선행되어야 했다.
그래서 Redis의 기본 개념인 데이터 타입과 해당 데이터 타입이 어디에 활용되는지부터 살펴보고자 하였다.
위 두 가지를 살펴보기에 앞서, Redis가 무엇인지 간략하게 살펴보자.
Redis(Remote Dictionary Server)
Redis는 다수의 서버가 공유하는 해시 테이블이다.
해시맵처럼 key-value 형태로 되어 있다.
특징
인메모리에 모든 데이터를 저장한다.
기본적으로 휘발성 데이터지만 영속성 옵션(RDB, AOF)을 통해 데이터를 영속적으로 관리할 수 있다.
단일 스레드에서 모든 작업을 수행하므로 스레드 간의 자원 공유 문제가 발생하지 않는다.
AOF (Append Only File)
입력, 수정, 삭제 명령이 실행될 때마다 LOG 파일에 기록
RDB (Redis Database Backup)
특정 간격으로 Redis 메모리 내 데이터의 스냅샷을 남김
Redis 데이터 타입
Redis는 Strings, Lists, Sets, Hashes, Streams 등 다양한 데이터 타입을 가진다.
그중 자주 쓰이는 Strings, Sorted Sets, Lists에 대해 살펴보자.
Strings
문자열, 숫자, serialized object를 저장할 수 있다.
Sorted Sets
ZSets이라고도 부른다.
Sets과 유사하며 추가로 score 필드를 가진다.
값이 추가되는 순간 해당 필드를 기준으로 정렬된다.
예제를 살펴보면 아래와 같다.
기본은 오름차순 정렬이고 REV 명령어를 통해 내림차순 정렬이 가능하다.
Lists
String을 Linked List로 저장하는 형태이다.
각 노드가 이전 노드, 다음 노드를 가리키는 포인터를 가져서 push, pop에 최적화되어 있다.
이에 따라 Queue(FIFO), Stack(FILO)를 구현할 수 있다.
#큐
LPUSH queue job1 job2 job3
RPOP queue
#스택
LPUSH stack job1 job2 job3
LPOP stack
Redis 특수 명령어
Redis 데이터 타입에 따른 활용 사례를 살펴보기에 앞서 특수 명령어를 알아보자.
TTL(Time-to-Leave)
데이터의 유효한 시간을 정할 수 있다.
데이터 조회 요청 시 만료된 데이터는 조회되지 않는다.
만료되자마자 삭제하지 않고, 만료로 표시만 해놓고 백그라운드에서 주기적으로 삭제한다.
TTL 명령어로 잔여 시간을 알 수 있다.
해당 값이 마이너스일 경우 값이 만료되었기 때문에 조회할 수 없다.
Pub / Sub
Publisher와 Subscriber가 서로 알지 못해도 통신 가능한 메시지 패턴이다.
Publisher는 Subscriber에게 직접 메시지를 전송하지 않고, 채널에 메시지를 publish 한다.
그럼 Subscriber는 관심 있는 채널만 구독해 메시지를 수신하면 된다.
Transaction
작업의 원자성을 보장하기 위해 여러 Redis 명령을 하나의 작업처럼 처리한다.
DISCARD 시 트랜잭션 내 변경 사항이 반영이 안 되므로 number를 조회할 수 없다.
EXEC로 트랜잭션을 커밋한 후에야 작업 사항이 적용된다.
Redis 데이터 타입별 활용 사례
One-Time Password (Strings)
One-Time Password는 유저의 휴대폰 메시지로 가는 인증 번호를 말한다.
일정 시간 동안만 유효해야 하므로 Redis TTL을 사용하면 효과적이다.
key-value로 휴대폰 번호와 임시 코드 값을 저장하고, 해당 코드가 유효한 시간만큼 TTL을 주면 된다.
분산락 (Strings)
분산락은 다수의 프로세스에서 동일한 자원을 접근할 때 동시성 문제 해결을 위해 사용된다.
NX를 통해 lock 1이 존재하지 않을 경우 key-value를 추가해 준다.
Request2도 이후에 같은 명령어를 수행하지만, 이미 lock 1이 존재하기 때문에 lock 1이 존재하지 않을 때까지 대기한다.
최근 검색 목록 표시 (Sorted Sets)
아래와 같은 검색 기록 데이터베이스가 있다고 해보자.
해당 DB에서 최근 검색 목록을 가져올 때는 검색 날짜로 정렬한 다음 특정 개수만큼 데이터를 잘라야 한다.
select * from search_history where user_id = 123
order by created_date desc limit 3;
Redis Sorted Set은 중복을 허용하지 않고, 특정 값 기준으로 정렬해 주기 때문에 위의 작업을 간편화 해준다.
Time이라는 가중치를 기준으로 정렬한다면, 가장 나중에 들어온 아이템이 마지막 인덱스에 저장된다.
SNS 활동 피드 (List)
Redis 리스트 타입의 메세지 큐로 유저 피드를 구현할 수 있다.
유저 1이 어떤 게시물에 좋아요를 누르면, 해당 이벤트는 피드를 관리하는 서비스에 전달된다.
피드 서비스는 유저들 중 팔로워들을 필터링하여 해당 유저들에게 메시지를 전달한다.
이때 한 소스에서 여러 목적지로 전달하는 메시징 패턴을 Fanout이라고 한다.
반대로 유저 2의 피드를 가져온다고 하면, 큐에서 10개의 아이템을 최신부터 읽는다.
느낀 점
Refresh Token 저장소로 Redis를 사용할 수 있다는 사실만 알고 있었다.
이번 기회에 Redis 각 데이터 타입의 특징과 그에 따른 활용 사례를 알게 되어서 뜻깊었다.
더 깊이 공부해서 추후 스프링 프로젝트에도 활용해보고 싶다.
Reference
https://www.inflearn.com/course/%EC%8B%A4%EC%A0%84-redis-%ED%99%9C%EC%9A%A9