[TIL] Redis

김건우·2024년 8월 7일

[TIL]

목록 보기
10/25

Docker Redis 종류

기존엔 redis image 만 사용했었는데, 다른 이미지도 존재했다.
redis/redis-stack-server 는 여러 플러그인이 추가된 Redis Stack 서버 이미지이며, 확률형 데이터, JSON 문서 등을 사용하고 싶다면 선택하면된다.
redis/redis-stack는 redis/redis-stack-server에 Redis Insight가 추가된 이미지이다.
Redis Insight를 같이 사용하고 싶다면 선택하면 된다.

docker-compose.yml

services:
  redis-stack:
    image: redis/redis-stack
    container_name: redis-stack-compose
    restart: always
    environment:
      REDIS_ARGS: "--requirepass systempass"
    ports:
      - 6379:6379
      - 8001:8001

해당 yml 파일로 redis를 docker container 로 띄우게 된다면 id : defuault, password : systempass 인 redis가 6379 포트로 띄워지고, redis/redis-stack 이미지를 사용했기에 redis insight가 함께 설치된다.

8001 포트로 redis insight 에 접속할 수 있게 된다.

redis insight은 redis의 데이터들을 시각적으로 보여주는 역할을 하는 클라이언트 툴이다.


Redis Type

String

가장 기본적인 자료형이며, 저장할 수 있는 최대 크기는 512MB이다.

  • GET, SET
    SET user:email alex@example.com
    GET user:email
    • SET <key> <value>: keyvalue 문자열 데이터를 저장, "으로 공백 구분
    • GET <key>: key에 저장된 문자열 반환

만약 저장된 데이터가 정수 데이터라면 데이터를 바로 증가, 감소가 가능하다.

  • INCR, DECR
    SET user:count 1
    INCR user:count
    DECR user:count
    • INCR key: key에 저장된 데이터를 1 증가
    • DECR key: key에 저장된 데이터를 1 감소

여러 Key - Value를 한번에 다루고 싶다면 MSET, MGET을 활용할 수 있다.

  • MSET, MGET
    MSET user:name alex user:email alex@example.com
    MGET user:name user:email
    • MSET key value [key value …]: key value의 형태로 주어진 인자들을 각 keyvalue를 저장
    • MGET key [key]: 주어진 모든 key에 해당하는 데이터를 반환.

List

여러 문자열 데이터를 Linked List의 형태로 보관하는 자료형이다. Linked List이기 때문에, 중간의 데이터 보다는 양끝의 데이터, 즉 스택 또는 큐 처럼 사용할 수 있다.

PUSH 또는 POP을 L 또는 R과 조합하여, 왼쪽 또는 오른쪽에 데이터를 추가 / 제거가 가능합니다.

  • LPUSH, RPUSH, LPOP, RPOP
    LPUSH user:list alex  # [alex]
    LPUSH user:list brad  # [brad, alex]
    RPUSH user:list chad  # [brad, alex, chad]
    RPUSH user:list dave  # [brad, alex, chad, dave]
    
    LPOP user:list        # brad
    RPOP user:list        # chad
    • LPUSH key value: key에 저장된 리스트의 앞쪽에 value를 저장
    • RPUSH key value: key에 저장된 리스트의 뒤쪽에 value를 저장
    • LPOP key: key에 저장된 리스트의 앞쪽에서 값을 반환 및 제거
    • RPOP key: key에 저장된 리스트의 뒤쪽에서 값을 반환 및 제거

리스트를 사용하면서 흔히 사용하는 길이 구하기, 범위 내 원소 반환하기 등의 기능도 제공한다.

  • LLEN, LRANGE
    LLEN user:list
    LRANGE user:list 0 3
    LRANGE user:list 0 -1
    • LLEN key: key에 저장된 리스트의 길이를 반환
    • LRANGE key start end: keystart부터 end까지 원소들을 반환

LLEN은 없는 Key를 대상으로 하면 0이 되지만, 다른 자료형을 저장한 Key를 대상으로 하면 오류가 발생한다.

LRANGE의 경우 (언제나 그렇듯) 시작을 0으로 생각하고,

  • end가 실제 길이를 벗어나도 오류가 발생하진 않는다.
  • start > end일 경우 빈 결과가 반환된다.
  • 음수의 경우 리스트의 뒤에서부터 데이터를 가져온다.

Set

문자열의 집합이다. 집합인 만큼 중복값을 제거하며, 순서가 존재하지 않는다.

  • SADD, SREM, SMEMBERS, SISMEMBER, SCARD
    SADD user:java alex  # [alex]
    SADD user:java brad  # [alex, brad]
    SADD user:java chad  # [alex, brad, chad]
    SREM user:java alex  # [brad, chad]
    
    SMEMBERS user:java        # [alex, brad, chad]
    SISMEMBER user:java brad  # true
    SISMEMBER user:java dave  # false
    • SADD key value: key에 저장된 집합에 value를 추가
    • SREM key value: key에 저장된 집합의 value를 제거
    • SMEMBERS key: key에 저장된 집합의 모든 원소를 반환
    • SISMEMBER key value: key에 저장된 집합에 value가 존재하는지 반환
    • SCARD key: key에 저장된 집합의 크기를 반환

여기에 복수의 집합이 있다면, 교집합, 합집합 등의 기능을 제공한다. 결과 집합 자체를 반환하기도, 결과 집합의 크기를 반환하기도 한다.

  • SINTER, SUNION, SINTERCARD
    # 다른 Set에 추가한 뒤,
    SADD user:python alex
    SADD user:python dave
    
    SINTER user:java user:python        # [alex]
    SUNION user:java user:python        # [alex, brad, chad, dave]
    SINTERCARD 2 user:java user:python  # 1
    • SINTER key1 key2: key1key2에 저장된 집합들의 교집합의 원소들을 반환
    • SUNION key1 key2: key1key2에 저장된 집합들의 합집합의 원소들을 반환
    • SINTERCARD number key1 [key2 ...]: number개의 key에 저장된 집합들의 교집합의 크기를 반환

중복을 허용하지 않으며, 어떤 데이터의 존재 여부를 확인하는 SISMEMBER 같은 경우 O(1)의 시간복잡도를 가지고 있다. 그래서 중복 없는 방문 수, 인증 토큰 블랙리스트 등을 구현할때 활용할 수 있다.

단, 매우 높은 방문 수를 기록하는 서비스인 경우 실제 데이터가 필요하지 않다면, 근사값을 돌려주는 확률형 자료형을 사용하는게 권장된다.


Hash

Redis 전체가 Map 이라면 Hash는 Map<String, Map<String, String>>의 형식이라고 생각할 수 있다.

  • HSET, HGET, HMGET, HGETALL, HKEYS, HLEN
    HSET user:alex name alex age 25
    HSET user:alex major CSE
    
    HGET user:alex name
    HGET user:alex age
    
    HMGET user:alex age major
    HGETALL user:alex
    
    HKEYS user:alex
    HLEN user:alex
    • HSET key field value [field value]: key의 Hash에 fieldvalue를 넣는다. 한번에 여러 field - value 쌍을 넣어줄 수 있다.
    • HGET key field: key에 저장된 Hash의 field에 저장된 value를 반환. 없는 field의 경우 null.
    • HMGET key field [field]: key에 저장된 Hash에서 복수의 field에 저장된 value를 반환.
    • HGETALL key: key에 저장된 Hash에 저장된 field - value를 전부 반환.
    • HKEYS key: key에 저장된 Hash에 저장된 field를 전부 반환
    • HLEN key: key에 저장된 Hash에 저장된 field의 갯수를 반환

Hash는 본래 하나의 키에 복잡한 데이터 (객체의 데이터 라던지)를 하나의 키에 저장하는 용도로 주로 활용되고, 공식 문서에서도 여러 Key에 걸쳐 객체의 데이터를 표현하기 보단 Hash를 자주 활용할 것을 권장하고 있습다.

장바구니 같은 기능은 사용자별로, 어떤 물품이 몇개나 담겨있는지와 같은 정보가 포함되어야 한다. 사용자 마다 Hash 데이터를 생성하고, 물품 - 갯수 형식으로 데이터를 저장하면 사용자별 장바구니를 쉽게 저장할 수 있다.


Sorted Set

이름처럼 정렬된 집합이다. 기본적으로 Set과 동일하게, 유일한 값들만 유지하지만 여기에 더해 각 값들에 score라고하는 실수를 함께 보관한다. 그리고 데이터를 가져올 때, score를 바탕으로 정렬하여 값들을 가져올 수 있다.

  • ZADD, ZINCRBY, ZRANK, ZRANGE, ZREVRANK, ZREVRANGE
    ZADD user:ranks 10 alex
    ZADD user:ranks 9 brad 11 chad
    ZADD user:ranks 8 dave
    
    ZINCRBY user:ranks 2 alex
    
    ZRANK user:ranks alex
    ZRANGE user:ranks 0 3
    
    ZREVRANK user:ranks alex
    ZREVRANGE user:ranks 0 3
    • ZADD key score member [score member ...]: key의 Sorted Set에 score를 점수로 가진 member를 추가, 이미 있는 member의 경우 새로운 score를 설정
    • ZRANK key member: key의 Sorted Set의 member의 순위를 오름차순 기준으로 0에서 부터 세서 반환
    • ZRANGE key start stop: key의 Sorted Set의 member들을 start 부터 stop 순위까지 오름차순 기준으로 반환
    • ZREVRANK key member: key의 Sorted Set의 member의 순위를 내림차순 기준으로 0에서 부터 세서 반환
    • ZREVRANGE key start stop: key의 Sorted Set의 member들을 start 부터 stop 순위까지 내림차순 기준으로 반환
    • ZINCRBY key increment member: key의 Sorted Set의 memberscoreincrement 만큼 증가 (음수를 전달하면 감소)

대표적으로 리더보드나 Rate Limiter, 즉 순위와 관련된 기능을 만드는데 사용된다.


그 외 공용 명령

그 외 자료형과 상관없이 사용할 수 있는 명령들이 있다. 이 중 대표적으로 많이 사용하는 건, Key를 제거하기 위한 DEL, 만료시각 설정을 위한 EXPIRE 등이 있다.

  • DEL, EXPIRE, EXPIRETIME
    SET somekey "to be deleted"
    DEL somekey
    
    SET expirekey "to be expired"
    EXPIRE expirekey 5
    EXPIRETIME expirekey
    • DEL key: key(와 저장된 데이터)를 제거
    • EXPIRE key seconds: key의 TTL(유효시각)을 seconds로 설정, seconds초가 지나면 key 제거
    • EXPIRETIME key: key가 만료되는 시각을 Unix Timestamp로 반환

모든 Key를 제거하고 싶다면 FLUSHDB를 사용할 수 있다.


실습

블로그 별 조회수를 Redis로 확인하기

  • 로그인 여부와 상관없이 새로고침 될때마다 조회수가 1 증가
  • 이를 관리하기 위해 적당한 데이터 타입을 선정하고, 사용자가 임의의 페이지에 접속할 때 실행될 명령 작성.
-- String - INCR(++), DECR(--)
-- INCR posts:{id}
INCR posts:1
INCR posts:2
INCR posts:3

-- 오늘의 조회수를 따로 관리하고 싶다면
INCR articles:1:today
-- 하루가 지난 시점에서
RENAME articles:1:today articles:20XX-XX-XX

블로그에 로그인한 사람들의 조회수와 가장 많은 조회수를 기록한 글을 반환

  • 로그인한 사람들의 계정은 영문으로만 이뤄져 있다.
  • 이를 관리하기 위해 적당한 데이터 타입을 선정하고, 사용자가 임의의 페이지에 접속할 때 실행될 명령 작성.
-- 초기화
FLUSHDB
-- SET
SADD posts:1 alex
SADD posts:1 brad
SADD posts:1 chad

-- 해당 게시글의 조회수
SCARD posts:1

SADD posts:2 alex
SADD posts:2 chad
SCARD posts:2

-- 각 원소가 원래 있는 값이라면 0 , 하나라도 추가되었다면 1 반환
SADD posts:1 alex bard chad 

-- 그래서 0이라면 스킵하고, 1일 경우엔 Sorted Set에 넣어서 리더보드 기능 구현
ZINCRBY posts:ranks 1 posts:1
ZINCRBY posts:ranks 1 posts:2

-- 가장 높은 조회수의 글을 뽑아냄
-- 곧 사라질 예정인 명령어
ZREVRANGE posts:ranks 0 0

ZRANGE posts:ranks 0 0 REV

마무리

Docker 에서 제공하는 redis image 들의 종류를 알아봤는데, 클라이언트 툴 형식으로 제공되고 있는줄 처음 알았다. 지금은 IntelliJ 유료버전 에서 제공되는 DataGrip 을 통해 쉽게 여러 데이터베이스들을 통합해서 사용할 수 있는 툴을 사용하는데 익숙해져서 굳이 사용하지 않을 듯 하지만, Redis가 처음이고 데이터베이스 통합 연결 툴을 사용하지 않는 사람이라면 도커를 통해 쉽게 띄울 수 있어 사용할 만 한 것 같다.

Redis가 싱글스레드 기반의 빠른 입출력을 제공해주는 데이터베이스 이지만, 사용할때 O(1) 가 아닌 명령어들에 대해서는 한 번 더 생각하고 사용해야 한다.

profile
공부 정리용

0개의 댓글