Redis란

  • key:value 구조의 저장소
  • In-memory 데이터 구조 저장소
  • 지원하는 데이터 구조
    • Strings, set, sorted-set, hashes, list
    • Hyperloglog, bitmap, geospatial index
    • Strea m
  • Only 1 Committer
    • Redis 소스 코드를 고칠 수 있는 권한이 있는 사람은 딱 한 명!

Cache

Redis는 캐싱에 많이 사용되므로 알아두면 도움이 된다.

Cache의 정의

  • Cache는 나중에 요청올 결과를 미리 저장해두었다가 빠르게 서비스 해주는 것을 의미
    • ex) DP, 10! = 10 * 9!= 10 * 9 * 8! = 10 * 9 * 8 * 7! (팩토리얼 숫자가 크다면 미리 캐싱해두면 연산이 훨씬 빨라짐)
  • 파레토 법칙
    • 20:80 법칙으로, 우리 사회에서 일어나는 현상의 80%는 20%의 원인으로 인하여 발생
    • 즉, 전체 트래픽의 80%는 20%의 특정 데이터 요청


웹 서버에서 사용되는 Cache 구조

img

  • 캐싱을 적용하지 않은 구조로, DB안에 모든 데이터가 존재하는 구조
  • 디스크에 데이터를 저장하는 일반적인 구조

Look aside Cache

img

  • Web Server는 데이터가 존재하는지 Cache를 연계 확인
    • Cache에 데이터가 있으면 Cache에서 가져온다.
    • Cache에 데이터가 없으면 DB에서 데이터를 가져와 Cache에 저장하고 값을 가져온다.

Write Back

img

  • Web Server는 모든 데이터를 Cache에만 저장
    • Cache에 특정 시간동안의 데이터가 저장된다.
    • 그리고 배치처리를 통해 Cache에 있는 데이터를 DB에 저장한다.
    • DB에 저장되었다면 Cache에는 해당 데이터를 삭제한다.
  • 이 방식의 단점
    • 서버 장애가 생기면 데이터가 날아갈 수도 있다.
    • Cache에 업데이트 하고 메모리에는 바로 업데이트를 하지 않기 때문에, Cache와 메모리가 서로 값이 다른 경우가 발생할 수 있다.
    • 그래서 데이터 손실 위험을 줄이기 위해 로그를 Redis에 넣어두고 배치적으로 데이터를 저장할 때 많이 사용된다.

insert 쿼리를 한번씩 500번 날리는 것과 insert 쿼리 한번에 500개를 붙여서 날리는 것중 어느 것이 더 빠를까?

후자가 훨씬 빠르다. Write Back 방식은 이와 같은 원리를 활용하여 데이터가 일시적으로 캐시에만 저장되고, 이후 배치 작업을 통해 DB에 한꺼번에 기록한다.

왜 Collection이 중요한가?

Redis의 장점과 Memcached보다 Redis가 왜 좋은지 이해하는데 도움이 된다.

Collection을 잘 사용함으로써 여러가지 개발 시간을 단축시키고, 문제를 줄여줄 수 있다.

개발의 편의성

랭킹 서버를 직접 구현한다고 생각해보자.

  • 가장 간단한 방법
    • DB에 유저의 Score를 저장하고 Score로 order by 정렬 후 읽어오기
    • 하지만 데이터가 많아지면 속도에 문제가 발생하게 된다. 결국에는 디스크를 사용하기 때문이다.
  • In-memory 기준으로 랭킹 서버의 구현이 필요
    • Redis의 Sorted Set을 이용하면, 랭킹을 구현 할 수 있음
    • 다만 가져다 쓰면 한계에 종속적일 수 있다.

개발의 난이도

친구 리스트를 KEY/VALUE 형태로 저장한다고 생각해보자.

  • 현재 유저123의 친구 Key는 friends:123, 현재 친구 A가 있는 중이고 예를 들어 [“A”]와 같이 현재 친구 A가 포함되어 있다.
    • 친구 B와 C를 추가한다고 가정한다면
    • Transaction 1 (B 추가), Transaction 2 (C 추가)가 서로 동일한 시간에 실행되면 B나 C중 하나는 추가가 안 될 수도 있다.(Race Condition)
  • 그렇다면 Redis는?
    • Redis의 경우는 자료구조가 Atomic하기 때문에, 해당 Race Condition을 피할 수 있다.

Redis는 언제 사용될까?

  • Remote Data Store
    • 여러 서버에서 데이터를 공유하고 싶을 때
    • 메모리 기반의 데이터 저장소로 빠른 응답 속도 제공, 싱글 쓰레드이기 때문에 원자성 보장
  • 서버 한 대에서만 필요하면, 전역 변수를 쓰면 되지 않을까?
    • Redis는 싱글 쓰레드로 동작하여 원자성을 보장하기 때문에
  • 주로 많이 쓰는 곳들
    • 인증 토큰 등을 저장
    • 랭킹 보드로 사용(Sorted Set)
    • 유저 API Limit
    • 잡큐(list)

Redis Collections

Redis가 지원하는 다양한 자료구조와 선택하는 기준에 대해서 다룬다.

img

Strings

  • 기본적인 key:value 형태
  • 사용법
    • 삽입
      • Single: Set <key> <value> (ex. SET token:1234567 "abcdefdkfdakd")
      • Multi: mset <key1> <value1> <key2> <value2> ... <keyN> <valueN> (ex. mset token abcd email mistyblue@gmail.com)
    • 조회
      • Single: Get <key> (ex. GET token:1234567)
      • Multi: mget <key1> <key2> ... <keyN> (ex. mget token email)

List

  • 일반적인 List와 동일
  • 앞과 뒤에서 넣는 것은 빠르지만 중간에 삽입이 느리다.
  • 사용법
    • insert
      • Lpush <key> <A> -> Key:(A)
      • Rpush <key> <B> -> Key:(A, B)
      • Lpush <key> <C> -> Key:(C, A, B)
      • Rpush <key> <D, A> -> Key:(C, A, B, D, A)
    • pop
      • Key:(C, A, B, D, A)
      • LPOP <key> -> Pop C, Key:(A, B, D, A)
      • RPOP <key> -> Pop A, Key:(A, B, D)
    • lpop, blpop, rpop, brpop
      • Key: ()
      • LPOP <key> -> No data
      • BLPOP <key> -> 누가 데이터를 Push하기 전까지 대기
    • String과 동일하게 key를 통해 카테고리를 만들 수 있다.

Set

  • 중복된 값을 넣지 않는 자료구조
  • 데이터가 있는지 없는지 체크하는 용도로 사용한다.
  • 사용법
    • SADD <key> <value> -> Value가 이미 Key에 있으면 추가되지 않는다.
    • SMEMBERS <key> -> 모든 Value를 반환.
    • SISMEMBER <key> <value> -> value가 존재하면 1, 없으면 0
  • 예시
    • 특정 유저를 Follow하는 목록을 저장할 때 많이 사용된다. (unique한 특징이 있을 때)

Sorted Sets

  • Set은 순서가 없지만, Sorted Set은 순서를 보장한다.
  • 사용법
    • ZADD <key> <score> <value> -> Value가 이미 key에 있으면 해당 Score로 변경된다.
    • ZRANGE <key> <startIdx> <endIdx> -> 해당 Index 범위 값을 모두 돌려준다. (모든 범위는 Zrange testkey 0 -1)
  • 특징
    • 유저 랭킹 보드로 사용할 수 있음.
    • Set의 숫자는 double 타입이기 때문에 값이 정확하지 않을 수 있다.

SQL을 대체한다면?

  • SQL: select * from rank order by score limit 50, 20;
    • Redis: Zrange rank 50 70
  • SQL: select * from rank order by score desc limit 50, 20;
    • Redis: Zrevrange rank 50 70

Hash

  • key:value안에 다시 key:value를 가질 수 있게 한다.
  • 사용법
    • Hmset <key> <subkey1> <value1> <subkey2> <value2>
    • Hgetall <key> -> 해당 key의 모든 subkey와 value를 가져온다.
    • Hget <key> <subkey>
    • Hmget <key> <subkey1> <subkey2> ... <subkeyN>

SQL을 대체한다면?

  • SQL: insert into Users(name, email) values ('juseon', 'mistyblue0302@gmail.com')
    • Redis: Hmset juseon name juseon email mistyblue0302@gmail.com

Collection 주의 사항

  • 하나의 컬렉션에 너무 많은 아이템을 담으면 좋지 않음
    • 10000개 이하 몇천개 수준으로 유지하는게 좋음.
  • Expire는 Collection의 item 개별로 걸리지 않고 전체 Collection에 대해서만 걸림.
    • 즉 10000개의 아이템을 가진 해당 Collection에 expire가 걸려있다면 그 시간 후에 10000개의 아이템이 모두 삭제될 수도 있다.


참고

https://redis.io/docs/latest/

우아한레디스

업데이트: