[Redis 기본 개념] Redis의 자료구조와 커맨드 정리

반응형
728x90
반응형

들어가며

Redis에 어떤 자료구조가 있고, 이 자료구조마다 어떤 커맨드를 수행해서 데이터를 관리하는지 기록하고자 포스팅한다. Redis 관련 도서를 찾지 못했었는데 최근, '개발자를 위한 레디스' 라는 책이 출간되어 읽고있는데 Redis 기본개념을 공부하기에 적합한것 같다. 

 

 

Redis (Remote dictionary server)

key-value 형태의 오픈소스 기반 데이터 저장소로, 인메모리(in-memory) NoSQL 데이터베이스다. 레디스에서 모든 데이터는 key에 연결되어있기 때문에 데이터를 저장하고, 저장된 데이터를 검색할 때에는 항상 key를 식별자로 이용한다. 

 

NoSQL

No SQL 혹은 Not Only SQL을 의미한다. SQL(Standard Query Language)을 사용하지 않는 데이터 저장소다.

 

In-Memory database

모든 데이터가 컴퓨터의 메모리에서 관리된다. 디스크에 접근하는 과정이 필요 없기 때문에 데이터의 처리 성능이 굉장히 빠르다.

 

싱글 스레드로의 동작

레디스는 싱글 스레드로 동작한다. 메인 스레드 1개와 별도의 스레드 3개로 총 4개의 스레드로 동작한다. 여기서 클라이언트의 커맨드를 처리하는 부분은 이벤트 루프를 이용한 싱글 스레드로 동작한다. 최소 하나의 코어만 있어도 레디스를 사용할 수 있다.

 

레디스가 싱글 스레드로 동작하기 때문에, 한 사용자가 오래 걸리는 커맨드를 수행한다면, 다른 사용자는 이 수행이 완료될 때까지 대기할 수 밖에 없다. 메모리에서 동작하기 때문에 대부분의 커맨드는 빠른 응답시간을 갖지만 반환이 느린 특정한 커맨드를 사용하면 인적 장애가 발생할 가능성이 높으므로 주의해야할 부분이 있다.

 

 

레디스의 자료 구조

https://ryu-e.tistory.com/9

 

레디스는 다양한 자료구조를 제공한다. key에 매핑되는 값에는 문자열(String) 뿐만 아니라 hash, set 등 더 복잡하고 다양한 데이터 구조를 저장할 수 있도록 지원한다. 레디스는 내장된 다양한 자료구조를 통해 임피던스 불일치를 해소하고 개발을 편리하게 할 수 있도록 지원한다.

 

임피던스 불일치 (Impedance mismatches)

기존 관계형 데이터베이스의 테이블과 프로그래밍 언어 간 데이터 구조, 기능의 차이로 인해 발생하는 충돌

 

 

string

string은 레디스에서 데이터를 저장할 수 있는 가장 간단한 구조다. key-value가 1:1로 연결되는 유일한 자료구조다.

SET hello world

GET hello // world

 

key : hello, value : world

 

▶ NX 옵션

NX 옵션은 동일한 key가 있으면 새로운 값이 저장되지 않는다.

SET hello newval NX

 

▶ XX 옵션

XX 옵션은 동일한 key가 있을 때에만 새로운 값으로 덮어쓴다. 새로운 키를 생성하지 않도록 동작한다.

SET hello newval XX

GET hello // newval

 

▶ INCR, INCRBY

string 자료 구조에는 모든 문자열 데이터를 저장할 수 있으므로 숫자 형태의 데이터 저장도 가능하다.

  • INCR : 저장된 데이터를 1씩 증가한다. 증가된 값이 반환된다.
  • INCRBY : 입력한 값만큼 데이터를 증가시킨다.
  • 감소시키는 DECR, DECRBY도 있다.

위 커맨드를 이용하면 string 자료 구조에 저장된 숫자를 원자적으로 조작할 수 있다.

커맨드가 원자적이라는 것은 같은 키에 접근하는 여러 클라이언트가 경쟁 상태를 발생시킬 일이 없음을 의미한다. 이미 실행한 커맨드가 무시되거나 같은 커맨드가 중복 실행될 일이 없다.

SET counter 100

INCR counter // 101

INCR counter // 102

INCRBY counter 50 // 152

 

▶ MSET, MGET

한번에 여러 키를 조작할 수 있다. 성능이 중요한 경우, 위 커맨드로 서비스 전체의 속도 향상으로 이어질 수 있다.

MSET a 10 b 20 c 30

MGET a b c
// 10
// 20
// 30

 

 

 

list

레디스에서의 list는 순서를 가지는 문자열의 목록이다. 인덱스로 데이터에 직접 접근할 수 있다.

 

▶ LPUSH

list의 왼쪽(head)에 데이터를 추가한다.

 

▶ RPUSH

list의 오른쪽(tail)에 데이터를 추가한다.

 

▶ LRANGE

list에 들어있는 데이터를 조회한다.

시작과 끝 아이템의 인덱스를 각각 인수를 받아 출력한다. 인덱스는 음수가 될 수 있으며, 가장 오른쪽(tail)에 있는 아이템의 인덱스는 -1이고 그 앞의 인덱스는 -2이다.

따라서 0 -1은 0부터 -1까지의 아이템을 출력한다. 즉, 전체 데이터를 출력한다.

LPUSH mylist E

RPUSH mylist B

LPUSH mylist D A C B A

LRANGE mylist 0 -1

 

LPOP

list에 저장된 첫번째 아이템을 반환하고, list에서 삭제한다. 숫자와 함께 사용하면, 지정한 숫자만큼의 아이템을 반복해서 반환한다.

 

LTRIM

list에서 시작과 끝 아이템의 인덱스를 인자로 받아, 지정한 범위에 속하지 않은 아이템을 모두 삭제한다. 위 LPOP과 다르게 아이템을 반환하지는 않는다.

 

list가 [A, B, C, A] 라고 할때

LTRIM mylist 0 1

 

LTRIM 커맨드 실행으로, list는 [A, B]가 된다.

 

이렇게 list의 양끝에 데이터를 넣고 빼는 커맨드는 O(1)로 처리할 수 있어 매우 빠르게 실행된다. 

 

LINSERT

원하는 데이터의 앞이나 뒤에 데이터를 추가할 수 있다. 앞은 BEFORE, 뒤는 AFTER 옵션을 추가하면 된다. 만약 지정한 데이터가 없으면 오류가 발생한다.

LINSERT mylist BEFORE B E

 

list [A, B, C, D] 에서 list [A, E, B, C, D]가 된다.

 

LSET

지정한 인덱스의 데이터를 신규 입력하는 데이터로 덮어쓴다. 만약 list의 범위를 벗어난 인덱스를 입력하면 에러를 반환한다.

LSET mylist 2 F

list [A, E, B, C, D] 에서 list [A, E, F, C, D]가 된다.

 

LINDEX

원하는 인덱스의 데이터를 확인할 수 있다.

LINDEX mylist 3

list [A, E, F, C, D]에서 "C"가 반환되겠다.

 

 

hash

필드-값 쌍을 가진 아이템의 집합이다. 레디스에서 데이터가 key-value 쌍으로 저장되는 것처럼, 하나의 hash 자료 구조 내에서 아이템은 필드-값 쌍으로 저장된다. 필드는 하나의 hash 내에서 유일하며, 필드와 값 모두 문자열 데이터로 저장된다. hash 에서는 각 아이템마다 다른 필드를 가질 수 있으며, 동적으로 다양한 필드를 추가할 수 있다.

 

 HSET

hash에 아이템을 저장한다. 한번에 여러 필드-값 쌍을 저장할 수도 있다.

 

HGET

hash에 저장된 데이터를 가져온다. 키와 아이템의 필드를 함께 입력해야한다.

 

HMGET

하나의 hash 내에서 다양한 필드의 값을 가져올 수 있다.

 

HGETALL

hash 내의 모든 필드-값 쌍을 차례로 반환한다.

HSET Product:123 Name "Happy Hacking"

HSET Product:123 TypeID 35

HSET Product:123 Version 2002

HSET Product:234 Name "Track Ball" TypeID 32

HGET Product:123 TypeID

HMGET Product:234 Name TypeID

HGETALL Product:234

 

 

Set

set은 정렬되지않은 문자열의 모음이다. 하나의 set 자료구조 내에서 아이템은 중복해서 저장되지 않는다. 유일한 원소를 구하는데에 적합하다.

 

SADD

저장되는 실제 아이템 수를 반환한다.

 

SMEMBERS

set 자료구조에 저장된 전체 아이템을 출력하는데, 저장한 순서와 관계없이 랜덤한 순서로 데이터가 출력된다.

SADD myset A

SADD myset A A A B D D F F F G

SMEMBERS myset // D, A, F, G, B

 

SREM

set에서 원하는 데이터를 삭제할 수 있다.

 

SPOP

set 내부의 아이템 중 랜덤으로 하나의 아이템을 반환하고, 그 아이템을 삭제한다.

SREM myset B

STOP myset

 

SUNION

합집합을 수행한다.

 

SINTER

교집합을 수행한다.

 

SDIFF

차집합을 수행한다.

 

SINTER set:111 set:222

SUNION set:111 set:222

SDIFF set:111 set:222 

 

 

Sorted Set

스코어(score) 값에 따라 정렬되는 고유한 문자열의 집합이다. 모든 아이템은 스코어-값 쌍을 가지며, 저장될 때부터 스코어 값으로 정렬돼 저장된다. 같은 스코어를 가진다면 사전 순으로 정렬된다.

set과 유사하게, 데이터는 중복 없이 유일하게 저장된다. 모든 아이템은 스코어로 정렬되어있어 list처럼 인덱스로 접근가능하다.

 

ZADD

sorted set에 아이템을 저장한다. 스코어-값 쌍으로 입력해야한다.

한번에 여러 아이템을 입력할 수 있고, 각 아이템은 저장되는 시점에 스코어 값으로 정렬된다.

ZADD score:220817 100 user:B

ZADD score:220817 150 user:A 150 user:C 200 user:F 300 user:E

 

만약 저장하고자하는 데이터가 이미 있다면 스코어만 업데이트되고 그 즉시 재정렬된다. 키가 이미 존재하지만 sorted set이 아닐 경우에는 오류를 반환한다.

 

 다양한 옵션 제공

XX 아이템이 이미 존재할 때에만 스코어를 업데이트한다.
NX 아이템이 존재하지 않을때에만 신규 추가한다.
LT 업데이트하고자 하는 스코어가 기존 아이템의 스코어보다 작을 때에만 업데이트 또는 신규추가 한다.
GT 업데이트하고자 하는 스코어가 기존 아이템의 스코어보다 클 때에만 업데이트 또는 신규추가 한다.

 

ZRANGE

sorted set에 저장된 데이터를 조회한다. start와 stop이라는 범위를 항상 입력해야한다.

ZRANGE score:220817 0 -1
// user:B
// user:A
// user:C
// user:F
// user:E


ZRANGE score:220817 0 -1 withscores
// user:B  100
// user:A  150
// user:C  150
// user:F  200
// user:E  300

 

 인덱스로 데이터 조회

ZRANGE 커맨드는 기본적으로 인덱스를 기반으로 데이터를 조회하므로, 검색하고자 하는 start, stop 인자에 인덱스를 넣는다.

  • WITHSCORES : 스코어 값이 함께 출력된다.
  • REV : 데이터는 역순으로 출력된다.
  • start:0, stop:-1을 두면 모든 데이터를 조회하겠다는 것을 의미한다.
ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]

 

  • BYSCORE : start, stop 인자 값으로 조회하고자하는 최소, 최대 스코어를 적으면 이 스코어를 포함한 값을 조회한다.
ZRANGE score:220817 100 150 BYSCORE WITHSCORES
// user:B  100
// user:A  150
// user:C  150

 

  • 인수로 전달하는 스코어이 ( 문자를 추가하면 해당 스코어를 포함하지 않는 값만 조회할 수 있다.
ZRANGE score:220817 (100 150 BYSCORE WITHSCORES
// user:A  150
// user:C  150

 

  • 스코어의 최솟값과 최댓값을 표현하기 위해 infinity를 의미하는 -inf, +inf라는 값을 사용한다. 스코어가 200보다 큰 모든 값을 출력한다.
ZRANGE score:220817 200 +inf BYSCORE WITHSCORES
// user:F  200
// user:E  300

 

  • ZRANGE <key> 0 -1과 마찬가지로 ZRANGE <key> -inf +inf BYSCORE 커맨드는 모든 데이터를 조회하겠다는 의미다.
    • REV를 넣으면 역순으로 조회한다.
ZRANGE score:220817 +inf 200 BYSCORE WITHSCORES REV
// user:E  300
// user:F  200

 

▶ 사전 순으로 데이터 조회

sorted set에 데이터를 저장할때 스코어가 같으면 데이터는 사전 순으로 정렬된다고 했다. 스코어가 같을때 BLEX 옵션을 사용하면 사전식 순서를 이용해 특정 아이템을 조회할 수 있다.

 

  • 사전순으로 비교하기 위한 문자열을 전달해야하며, (나 [ 문자를 함께 입력해야한다.
    • 입력한 문자열을 포함하려면 (, 포함하지 않으려면 [를 사용한다.
  • 사전식 문자열의 가장 처음은 -문자이고, 마지막은 + 이므로 ZRANGE <key> - + BYLEX 커맨드는 모든 데이터를 조회한다.
ZRANGE mySortedSet (b (f BYLEX
// banana
// candy
// dream
// egg

 

 

Hyperloglog

hyperloglog는 집합의 원소 개수인 카디널리티를 추정할 수 있는 자료구조다. 대량 데이터에서 중복되지 않은 고유한 값을 집계할때 유용하다. 중복을 피하기 위해 저장된 데이터를 모두 기억하고 있기 때문에 데이터가 많아질수록 그만큼 많은 메모리를 사용한다. 

입력되는 데이터를 그 자체를 저장하지 않고 자체적인 방법으로 데이터를 변경해 처리한다. 따라서 hyperloglog 자료구조는 저장되는 데이터 개수에 구애받지 않고 계속 일정한 메모리를 유지할 수 있으며, 중복되지 않는 유일한 원소의 개수를 계산할 수 있다.

 

▶ PFADD

hyperloglog에 아이템을 저장한다.

 

▶ PFCOUNT

저장된 아이템의 개수, 즉 카디널리티를 추정할 수 있다.

PFADD members 123

PFADD members 500

PFCOUNT members // 2

 

 

Key의 자동 생성과 삭제

1. 키가 존재하지 않을때 아이템을 넣으면 아이템을 삽입하기 전에 빈 자료구조를 생성한다.

DEL mylist

LPUSH mylist 1 2 3 // mylist 생성

 

2. 저장하고자 하는 키에 다른 자료구조가 이미 생성돼있을때 아이템을 추가하면 에러를 반환한다.

SET hello world

LPUSH hello 1 2 3 
// (error)

TYPE hello
// string

 

3. 모든 아이템을 삭제하면 키도 자동으로 삭제된다. (자료구조 stream은 예외)

아이템을 모두 pop해서 삭제시켰을 때에는 mylist라는 키 자체가 없어진다.

LPUSH mylist 1 2 3

EXISTS mylist // 1

LPOP mylist
LPOP mylist
LPOP mylist

EXISTS mylist // 0

 

4. 키가 없는 상태에서 키 삭제, 아이템 삭제, 자료구조 크기 조회 등과 같은 읽기 전용 커맨드를 수행하면 에러를 반환하지 않는다.

DEL mylist // 0
LLEN mylist // 0
LPOP mylist // nil

 

 

key 관련된 커맨드

EXISTS

키가 존재하는지 확인한다. 키가 존재하면 1, 존재하지 않으면 0을 반환한다.

LPUSH mylist 1 2 3

EXISTS mylist // 1

LPOP mylist
LPOP mylist
LPOP mylist

EXISTS mylist // 0

 

KEYS

레디스에 저자된 모든 키를 조회한다. 글롭 패턴(Glob pattern) 스타일로 동작한다.

  • h?llo : hello, hallo 등 매칭
  • h*llo : hllo, heeeello 등 매칭
  • h[ae]llo : hello, hallo 매칭, hillo는 매칭되지 않음
  • h[^e]llo : hallo, hbllo 등 매칭, hello는 매칭되지 않음
KEYS pattern

 

SCAN

KEYS를 대체해 키를 조회할때 사용할 수 있다. 한번에 모든 키를 반환한다.

커서를 기반으로 특정 범위의 키만 조회할 수 있다.

SCAN 0

 

  • cursor : SCAN 커맨으를 사용할때 인수로 사용해야 하는 커서 위치
    • 0이라면, 레디스에 저장된 모든 키를 반환해서 더이상 검색할 키 값이 없다는 것을 의미한다.
    • 17이라면, 그 다음은 SCAN 17로 검색해야, 다음 범위의 키 list를 조회할 수 있다는 것을 의미한다.
  • results : 저장된 키의 list

 

▶ MATCH 옵션

SCAN 커맨드 + MATCH 옵션을 이용해 키 값을 조회할 때에는 한번에 패턴에 매칭된 여러개의 키 값이 반환되지 않는다. 적은 수의 결과가 반환되거나 빈 값이 반환될 수 있다. SCAN 커맨드에서 MATCH 옵션을 사용할때에는 우선 데이터를 필터링 없이 스캔한 다음 데이터를 반환하기 직전에 필터링하는 방식으로 동작하기 때문이다.

SCAN 0 match *11*
// 1) 48
// 2) 1) "key:115"

SCAN 48 match *11*
// 1) 52
// 2) (empty array)

SCAN 52 match *11*
// 1) 190
2) 1) "key:111"

 

▶ TYPE 옵션

지정한 타입의 키만 조회할 수 있다. 이 옵션도 MATCH 옵션과 마찬가지로 반환되기 전에 필터되는 방식으로 동작하기 때문에 원하는 타입을 조회하기까지 오래걸릴 수 있다.

SCAN 0 TYPE zset

 

SORT

list, set, sorted set에서만 사용할 수 있는 커맨드다. 키 내부의 아이템을 정렬해서 반환한다.

SORT key [By pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC | DESC] [ALPHA] [STORE destination]

 

  • 대상이 문자열인 경우 ALPHA 옵션을 사용해서 사전 순으로 정렬하여 조회할 수 있다.
SORT mylist ALPHA

 

RENAME / RENAMENX

모두 키의 이름을 변경하는 커맨드다

  • RENAMENX : 오직 변경할 키가 존재하지 않을때에만 동작한다.
SET a apple

SET b banana

RENAME a aa

GET aa

SET a apple

SET b banana

RENAMENX a b // false

get b

 

 

COPY

COPY source destination [DB destination-db] [REPLACE]

 

Source에 지정된 키를 destination 키에 복사한다. Destination에 지정된 키가 이미 있으면 에러가 반환된다.

  • REPLACE 옵션을 사용해서 destination 키를 삭제한 뒤 값을 복사하기 때문에 에러가 발생하지 않는다.

 

TYPE

지정한 키의 자료 구조 타입을 반환한다.

TYPE key

 

OBJECT

OBJECT <subcomman> [<arg] [value] [opt] ...]

키에 대한 상세 정보를 반환한다.

  • ENCODING : 키가 내부적으로 어떻게 저장됬는지 확인
  • IDLETIME : 키가 호출되지 않은 시간이 얼마나 됬는지 확인

 

FLUSH ALL

레디스에 저장된 모든 키를 삭제한다. 

  • 기본적으로 SYNC한 방식으로 동작하여 모든 데이터가 삭제된 경우에만 OK를 반환한다. 커맨드가 실행되는 도중에 다른 응답을 처리할 수 없다.
  • ASYNC 옵션 : flush는 백그라운드로 실행되고, 커맨드가 수행됬을때 존재했던 키만 삭제해서 flush되는 중 새로 생성된 키는 삭제되지 않는다.
  • lazyfree-lazy-user-flush 옵션 : yes인 경우 ASYNC 옵션 없이 FLUSHALL 커맨드를 사용하더라도 백그라운드로 키 삭제 작업이 동작한다. 버전 7 기준으로 해당 옵션의 기본값은 "no"이다.
FLUSHALL [ASYNC | SYNC]

 

DEL

키와 키에 저장된 모든 아이템을 삭제하는 커맨드다. 기본적으로 동기적으로 작동한다.

DEL key [key ...]

 

UNLINK

DEL과 비슷하게 키와 데이터를 삭제하는 커맨드다. 하지만 이 커맨드는 백그라운드에서 다른 스레드에 의해 처리되며, 우선 키와 연결된 데이터의 연결을 끊는다.

  • DEL 커맨드는 동기적인 방식으로 FLUSH ALL을 수행하는 것과 같다. 100만개의 아이템이 저장돼있는 sorted set 키를 DEL 커맨드로 삭제하는 것은 이 긴 수행시간 동안 다른 클라이언트는 아무런 커맨드를 사용할 수 없다. 따라서 키에 저장된 아이템이 많은 경우는 DEL이 아닌 UNLINK를 사용하는 것이 좋다.
UNLINK key [key ...]

 

EXPIRE

EXPIRE key seconds [ NX | XX | GT | LT ]

 

키가 만료될 시간을 초 단위로 정의할 수 있다.

XX 해당 키에 만료 시간이 정의돼있을 때에만 커맨드 수행
NX 해당 키에 만료시간이 정의돼있지 않을때에만 커맨드 수행
LT 현재 키가 가지고 있는 만료시간보다 새로 입력한 초가 더 작을때에만 수행
GT 현재 키가 가지고 있는 만료시간보다 새로 입력한 초가 더 클때에만 수행

 

EXPIREAT

EXPIREAT key unix-time-seconds [ NX | XX | GT | LT ]

키가 특정 유닉스 타임스탬프에 만료될 수 있도록 키의 만료 시간을 직접 지정한다.

 

EXPIRETIME

EXPIRETIME key

키가 삭제되는 유닉스 타임스탬프를 초 단위로 반환한다.

키가 존재하지만 만료 시간이 설정돼있지 않은 경우에는 -1, 키가 없을때에는 -2를 반환한다.

 

TTL

TTL key

키가 몇초뒤에 만료되는지 반환한다. 키가 존재하지만 만료시간이 설정돼있지 않은 경우에는 -1, 키가 없을때에는 -2를 반환한다.

 

 

반응형

Designed by JB FACTORY