ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Redis(레디스) 소개 및 기본 개념 정리
    개발/Redis 2020. 8. 2. 21:34
    728x90

    Redis(Remote Dictionary System)란

     Redis는 메모리 기반의 key - value 저장소입니다. 다른 인메모리 솔루션들과 차이점 중 특별한 점은 다양한 자료구조(문자열, 리스트, 해시, 셋, 정렬된 셋 등)를 지녔다는 점입니다.

    Redis 특징

    • 장점

      • 리스트, 배열형식의 데이터 처리에 특화 : value 값으로 문자열, 리스트, set(key 1개에 n개의 중복되지 않은 value), sorted set, hash(key 1개에 filed-value쌍이 1개 이상 존재)형 등 여러 데이터 형식을 지원하며 리스트형 데이터의 입력과 삭제가 mysql에 비하여 10배 정도 빠릅니다.
      • 메모리를 활용하면서 영속적인 데이터 보존 : 명령어로 명시적으로 삭제하거나 expires(redis의 각 key는 만기시각을 설정할 수 있고, 만기 시각이 지난 key는 자동으로 메모리에서 제거)를 설정하지 않으면 데이터를 삭제하지 않습니다. 또한 스냅샷 기능을 제공하여 메모리의 내용을 파일로 저장하여 해당 시점으로 복구가 가능합니다.
      • 싱글 스레드: redis는 싱글 스레드로 처리되기 때문에 원자성은 보장되지만 여러 개의 명령어는 처리 못합니다. 따라서 시간 복잡도를 고려하며 명령어를 사용해야 합니다. O(N) 명령어는 주의해서 사용합니다.
    • 단점

      메모리 기반이므로 계속 메모리에 데이터를 추가하는데 한계가 존재합니다. 장기적 데이터 저장에는 불리합니다.

       

       

    Redis 자주 사용하는 곳

    • Remote Data Store: a, b, c 서버에서 데이터를 공유하고 싶을 때 사용
    • 인증 토큰 등을 저장
    • 랭킹 보드 사용(sorted set)
    • 유저 api limit
    • 잡 큐(list)

     

    Redis와 Memcached 비교

     redis를 검색하면 Memcached와 비교를 많이 합니다. 이는 레디스가 멤캐시드와 같은 동일한 캐시 기능을 제공하면서 영속성, 다양한 데이터 구조 같은 부가적인 기능을 지원하기 때문입니다.

    Redis와 Memcached 공통점은 In Memory, key-value 방식입니다. 차이점은 아래 표를 보겠습니다.

      Redis Memcached
    스레드 싱글 스레드 멀티 스레드
    데이터 구조 list, string, hashes, sorted sets, bitmaps 등 다양한 자료구조 지원 string과 integers만 지원
    데이터 저장 Memory, Disk Only Memory
    처리 속도  Memcached보다는 느리지만 큰 차이는 없다. 디스트를 거치지 않아 redis보다 더 빠르다.
    Replication 지원 지원 안함
    Partitioning method 지원 지원 안함
    영속성(Persistence) 영속성있는 데이터 사용 지원 안함

     


    Redis 자료 구조 및 기본 명령어

    redis는 아래와 같이 다양한 자료구조를 가지고 있습니다. 그중 가장 자주 사용되는 String, Hash, List, Set, Sorted set에 대해 알아보겠습니다. 여기서 다루지 않은 명령어들은 redis 사이트에서 확인할 수 있습니다.

    아래 명령어를 설치하지 않고 테스트하기 위해서는 https://try.redis.io/ 사이트에 들어가면 할 수 있습니다.

    https://redislabs.com/redis-enterprise/data-structures/ 참고

    1. 문자열

    문자열 데이터는 키 하나에 문자열 하나를 저장할 수 있습니다. 저장 가능한 문자열의 크기는 최대 512MB입니다.

    문자열 데이터 저장구조

    set

     주어진 키에 하나의 값만 저장합니다.

    • 입력 형식 : set 키 값
    • 시간 복잡도: O(1)
    • 응답: ok
    redis> SET mykey "Hello"
    "OK"
    redis> GET mykey
    "Hello"
    redis> SET anotherkey "will expire in a minute" EX 60
    "OK"

     

    append

     주어진 키에 마지막에 추가됩니다. 키에 값이 존재하지 않는 경우 set과 동일

    • 입력 형식 : append 키 값
    • 시간 복잡도: O(1)
    • 응답: 추가된 문자열을 포함한 전체 문자열 길이
    redis_dev:0>APPEND mykey_2 "Hello"
    "5"
    redis_dev:0>APPEND mykey_2 " World"
    "11"
    redis_dev:0>get mykey_2
    "Hello World"

     

    incr

     저장된 데이터의 값을 1 씩 증가합니다. 단 지정된 값이 숫자인 경우만 수행됩니다.

    • 입력 형식 : incr 키 값
    • 시간 복잡도: O(1)
    • 응답: 실행된 후의 키의 값(숫자)
    > set login:counter "0"
    OK
    > incr login:counter
    (integer) 1
    > incr login:counter
    (integer) 2
    > incr login:counter
    (integer) 3
    > get login:counter
    "3"

     

    decr

     키값을 1 씩 감소시킵니다.

    • 입력 형식 : decr 키 값
    • 시간 복잡도: O(1)
    • 응답: 실행된 후의 키의 값(숫자)
    > decr login:counter
    (integer) 2
    > decr login:counter
    (integer) 1
    > get login:counter
    "1"

     

    2. 리스트

    리스트 데이터 저장구조

     리스트 데이터를 다루기 위한 타입입니다. 레디스 리스트 데이터는 논리적으로 링크드 리스트 구현입니다. 그렇기 때문에 리스트 데이터에 하나의 요소를 추가할 때 O(1) 시간 안에 처리할 수 있다는 특징을 가지고 있습니다. 또 다른 특징으로는 입력 순서 유지가 된다는 것이다. 이런 특징으로 입력한 자료를 먼저 처리하는 큐로 사용되기도 합니다.

     

    lpush

    리스트의 맨 앞쪽에 저장됩니다.

    • 입력 형식 : lpush 키 값[값...]
    • 시간 복잡도 : O(1)
    • 응답: 명령이 수행되고 난 후의 요소의 수
    > LPUSH mylist "world"
    "1"
    >LPUSH mylist "hello"
    "2"

     

    lrange

    지정된 리스트의 시작 인덱스부터 종료 인덱스 범위의 요소를 조회합니다. 위에서 말했듯이 리스트는 링크드 리스트 구현으로 되어 있어 특정 인덱스에 접근을 O(1)에 하지 못합니다.

    • 입력 형식 : lrange 키 시작 인덱스 종료 인덱스
    • 시간 복잡도: O(S+N)
      • S: 시작 인덱스
      • N: 요소의 개수
    • 응답
    > RPUSH mylist "one"
    "1"
    >RPUSH mylist "two"
    "2"
    >RPUSH mylist "three"
    "3"
    >LRANGE mylist 0 0 
     1)  "one"
    
    >LRANGE mylist 0 -1
     1)  "one"
     2)  "two"
     3)  "three"

     

    3. 셋

    셋 데이터 저장 구조

     셋 데이터는 순서가 보장되지 않으며 중복이 허용되지 않는 타입입니다. 셋 데이터는 2^32-1개의 값을 저장할 수 있다. 그림과 같이 셋 데이터는 하나의 키에 여러 개의 요소가 저장되며 집합 연산이 가능합니다. 사용 가능한 집합 연산 명령으로는 합집합, 교집합, 차집합이 있습니다.

     

    sadd

    지정된 셋에 입력된 값을 저장합니다.

    • 입력 형식 : sadd 키 값[값...]
    • 시간 복잡도 : O(N)
      • N: 입력되는 요소 수
    • 응답: 성공이면 입력된 값 개수, 이미 존재하면 0
    >SADD myset "Hello"
    "1"
    >SADD myset "World"
    "1"
    >SADD myset "World"
    "0"

     

    smembers

     지정된 셋에 저장된 모든 값의 목록을 조회합니다.

    • 입력 형식 : semebers 키
    • 시간 복잡도 : O(N)
    • 응답: 조회된 값 목록. 값이 존재하지 않을 때 nill
    >SADD myset "Hello"
    "1"
    >SADD myset "World"
    "1"
    
    >SMEMBERS myset
     1)  "World"
     2)  "Hello"

     

     

    4. 정렬된 셋

    정렬된 셋 데이터 저장구조

     셋 데이터와 동일한 특징을 가지나 저장된 요소에 가중치를 부여하여 작은 값부터 큰 값(오름차순) 정렬을 제공합니다. 단 같은 가중치에는 정렬 안정성이 없어 같은 가중치인 경우는 순서가 변경될 수 있습니다. 가중치에 입력할 수 있는 값은 정수 또는 배정밀도 부동소수점입니다.

     

    zadd

    정렬된 셋에 가중치와 값으로 이루어진 데이터를 저장합니다. 단 이미 존재하는 값인 경우 기존 가중치를 입력된 가중치로 덮어쓰게 됩니다.

    • 입력 형식 : zadd 키 가중치 값 [가중치 값...]
    • 시간 복잡도: O(logN)
    • 응답: 성공이면 입력된 값의 개수. 이미 존재하는 값이면 0

     

    zrange

    정렬된 셋의 시작 인덱스부터 종료 인덱스 범위에 해당하는 값들을 가중치 오름차순으로 조회합니다.

    • 입력 형식 : zrange 키 시작 인덱스 종료 인덱스 [withscores]
    • 시간 복잡도: O(logN + M)
      • N: 입력되어 있는 값의 개수
      • M: 조회된 값의 개수
    • 응답: 조회된 값 목록. 값이 존재하지 않은 경우 nil
    > ZADD myzset 1 "one"
    (integer) 1
    
    > ZADD myzset 1 "uno"
    (integer) 1
    
    > ZADD myzset 2 "two" 3 "three"
    (integer) 2
    
    > ZRANGE myzset 0 -1 WITHSCORES
    1) "one"
    2) "1"
    3) "uno"
    4) "1"
    5) "two"
    6) "2"
    7) "three"
    8) "3"
    
    > ZADD myzset 3 "one"
    (integer) 0
    
    > ZRANGE myzset 0 -1 WITHSCORES
    1) "uno"
    2) "1"
    3) "two"
    4) "2"
    5) "one"
    6) "3"
    7) "three"
    8) "3"

     

    5. 해시

    해시 데이터 저장구조

     

     해시 데이터는 키와 값이 쌍으로 이뤄진 데이터를 저장하는 자료구조입니다. 해시 데이터에는 2^32-1개의 필드를 저장할 수 있습니다.

     

    hset

    지정된 해시에 요청한 필드와 값을 저장합니다. 단 요청한 필드가 존재한 경우 값이 업데이트됩니다.

    • 입력 형식 : hset 키 필드 이름값
    • 시간 복잡도: O(1)
    • 응답: 존재하지 않는 필드인 경우 1, 존재하는 필드인 경우 0

     

    hget

    지정된 해시에 저장된 필드의 값을 조회합니다.

    • 입력 형식 : hget 키 필드 이름
    • 시간 복잡도: O(1)
    • 응답: 지정된 필드가 존재할 때 지정된 값. 아니면 nil

     

    hgetall

    지정된 키에 저장된 모든 필드와 값을 조회합니다.

    • 입력 형식 : hgetall 키
    • 시간 복잡도: O(N)
    • 응답: 지정된 키에 저장된 모든 필드와 값의 목록
    > HSET myhash field1 "foo"
    (integer) 1
    
    > HGET myhash field1
    "foo"
    
    > HGET myhash field2
    (nil)
    
    > HSET myhash field2 "test"
    (integer) 1
    
    > HGETALL myhash
    1) "field1"
    2) "foo"
    3) "field2"
    4) "test"

     

     


    복제(replication)와 분산 기법(sharding)

     이전에 redis는 replication와 Partitioning을 지원한다고 했습니다. 스케일 아웃을 적용하기 위해 읽기 분산을 위한 복제와 쓰기 분산을 위한 샤딩을 알아볼 것입니다.

    복제와 샤딩의 혼합

    • 복제(replication): 클라이언트가 어느 노드에 접근해도 동일한 데이터를 읽을 수 있도록 복제하여 저장하는 것을 말합니다.
    • 샤딩(sharding): 데이터를 특정 조건에 따라 나누어 저장하는 것을 의미합니다.
    • 샤드(shard): 두 개의 노드를 사용하여 분할 저장하였을 때 각 노드를 샤드라고 부릅니다. 만약 각 샤드가 복제를 사용하여 여러 개의 노드로 구성되어도 하나의 샤드로 취급합니다.

     

    복제

     복제는 동일한 데이터를 다중 노드에 중복하여 저장하는 것을 말합니다. 레디스는 복제를 위해 마스터와 슬레이브 복제 개념을 사용합니다. 마스터는 복제를 위한 원본 데이터 역할이며, 슬레이브는 마스터 노드에 데이터 복제 요청을 하고 데이터를 수신하여 동기화합니다.

     

     

    샤딩(파티셔닝)

     데이터를 특정 조건에 따라 나누어 저장하는 것으로 샤딩을 사용하면 더 많은 데이터를 레디스에 저장할 수 있습니다. 또한 샤딩을 통해 쓰기 성능이 좋아질 수 있습니다. 레디스 2.6 버전에서는 서버 측 샤딩(데이터가 저장될 위치를 결정하는 것)은 지원하지 않습니다.

    레디스 클라이언트에서 적용 가능한 샤딩 방법은 아래와 같습니다.

    • 수직 샤딩: 관계형 데이터베이스의 테이블에 해당하는 정보를 노드별로 분할하는 방식
    • 범위 지정 샤딩: 키를 특정 범위 기준으로 분할하여 저장하는 방식
    • 해시 기반 샤딩: 키를 해시 함수에 대입해 결괏값을 특정 연산을 가해 데이터의 위치를 결정하는 방법을 말하는데 일관된 해싱이라고도 합니다.

     


    참고 사이트

    댓글

Designed by Tistory.