레디스(Redis) 파헤치기 (2) - 자료구조

김민건·2022년 5월 15일
2

기술

목록 보기
19/19

Redis 자료구조 종류

Redis는 다양한 자료구조를 공식적으로 지원하고 있다. 하지만 정작 그 자료구조의 특징과 내부 동작에 대해서 무지한 채로 남용하게 된다면, 사용하지 않는 것보다 못할 수 밖에 없다.

아래의 자료구조는 전부 Redis에서 공식적으로 지원하는 자료구조다.

  • String
  • List
  • Set
  • Sorted Set
  • Hash
  • Bit Map & HyperLogLog
  • Stream
  • Geospatial Index

여기서 Bit Map & HyperLogLog, Stream, Geospatial Index에 대해서는 이번에 다루지 않고, 가장 많이 사용되는 기본 5가지 자료구조에 대해서 먼저 살펴볼 계획이다.

들어가기 전에 잠깐!

간략한 명령어와 함께 살펴볼텐데, 여기서 []로 묶인 명령어는 임의로 설명하기 위한 부분이라는 점을 염두에 두고 보길 바란다.

또한, 많은 글에서 String이라는 자료구조를 Key-Value와 동일하다고 이야기를 하는데, 필자의 의견은 다르다. Redis의 자체가 Key-Value 형태를 지니고, 자료구조는 결국 Value의 구조를 정의하는 것이다. 따라서 String의 경우, Key에 매핑되는 Value를 곧바로 반환해주기 때문에, Key-Value라고 착각하는 것일 뿐, 따지고 보면 Redis 자체가 Key-Value의 형태를 따르고, String 자료구조는 여기서 Value가 String일 뿐이다.

추가적으로, keys, flushall과 같은 명령어를 통해 여러 데이터를 조회하는 것을 최대한 피하자. Key-Value 기반의 자료구조는 기본적으로 정렬된 공간에서 데이터를 제공하는 것이 아니라, Hash 기반으로 구성되어 있기 때문에 매칭되는 key들을 조회하기 위해서는 모든 데이터를 탐색해야한다. 따라서 O(N)의 시간복잡도가 필요하고, 남용하는 순간 Redis의 처리속도는 급격히 느려질 수 밖에 없다.

# 특정 패턴(share:로 시작하는)에 해당하는 key 여러개 조회
# 자료구조와 상관없이 모든 key를 반환
# keys [패턴]
> keys share:*
1) "list"
2) "set"
3) "string"

String

String은 Redis에서 사용되는 가장 기본적인 자료구조다. Redis 내부 데이터의 특정 Key에 대응하는 Value가 String인 구조이다.

# 특정 key에 value 저장
# set [key] [value]
> set share:1 2
OK

# 특정 key 조회
# get [key]
> get share:1
"2"

> set share:2 1
OK

List

List는 Linked List와 유사한 구조로 설계되어 있다고 이해하면 더 편할 것 같다. 따라서 랜덤 엑세스가 불가능하기 때문에, 중간 요소에 접근하기 위해서는 최대 O(N)의 시간복잡도를 필요로 한다. 하지만 양측의 포인터를 모두 가지고 있기 때문에, Queue, Stack 등 다양한 형태로 응용이 가능하다.

# 특정 key에 대응되는 list의 오른쪽에 값 추가
# 반환값은 해당 list에 속해있는 요소의 크기
# rpush [key] [value] [value] [value] ...
> rpush list1 a
(integer) 1
> rpush list1 b c
(integer) 3

# 특정 key에 대응되는 list의 왼쪽에 값 추가
# lpush [key] [value] [value] [value] ...
> lpush list1 d
(integer) 4

# 특정 key에 대응되는 list의 왼쪽 인덱스부터 특정 인덱스까지 범위 조회
# lrange [key] [시작인덱스] [끝인덱스]
> lrange list1 0 -1
1) "d"
2) "a"
3) "b"
4) "c"

Set

Set은 Java에서 HashSet과 유사한 구조로 설계되어 있다. 따라서 list와 달리 순서가 없으며, 데이터 조작 시, O(1)의 시간복잡도를 지니고 중복 데이터를 허용하지 않는다.

# 특정 key에 대응되는 set에 값 추가
# sadd [key] [value] [value] [value] ...
> sadd set there is no index index
(integer) 4

# 특정 key에 대응되는 set에서 요소 조회
# 요소가 있다면 1, 없다면 0 반환
# sismember [key] [value]
> sismember set there
(integer) 1

# 특정 key에 대응되는 set의 모든 원소 반환
# O(N)의 시간복잡도를 지니므로 사용에 유의!
# 대안으로 sscan을 사용할 수 있음
> smembers set
1) is
2) there
3) index
4) no

Hash

Hash는 Redis 자체 Key-Value 구조가 아닌, Value 내에서 또 다른 Key-Value 형태의 구조를 만드는 자료구조다. Java에서의 2차 HashMap과 유사한 형태로 생각하면 이해가 편할 것 같다. Set과 마찬가지로 데이터 조작에 필요한 시간복잡도는 O(1)이며, 순서가 없다. 다만, set은 value값이 중복을 허용하지 않았지만, hash는 value의 key값에 중복을 허용하지 않는다.

# 특정 key에 대응되는 hash의 내부 key, value 정의
# hmset [key] [innerKey1] [innerValue1] [innerKey2] [innerKey2] ...
> hmset hash place velog topic redis date 20220516
OK

# 특정 key에 대응되는 hash의 내부 key의 value 반환
# hget [key] [innerKey]
> hget hash place
"velog"
> hget hash date
"20220516"

Sorted Set

Sorted Set은 일반적으로 사용되는 자료구조와는 사뭇 다르다. 하지만 Sorted Set이라는 이 용어를 잘 뜯어보면 이해가 편하다. Java에서의 TreeSet과 유사한 느낌이지만, Value 그 자체로 순서를 정의하기 보다는, Score라는 새로운 개념을 더해서 요소들을 정렬한다.

즉, Set처럼 고유한 값을 지니는 Value들로 구성되어 있지만, 정렬된 리스트처럼 추가적으로 score를 사용해서 인덱스가 정해져 있으며, 요소를 정렬한다.
단, 만약 score가 동일하다면, value를 기준으로 정렬된다.

# 특정 key에 대응되는 sortedSet에 score가 정해진 value를 추가
# zadd [key] [score] [value]
> zadd sortedset 100 a
(integer) 1
> zadd sortedset 99 c
(integer) 1
> zadd sortedset 99 b
(integer) 1

# 특정 key에 대응되는 sortedSet안에서 score를 기준으로 정렬된 value들을 반환
# zrange [key] [시작인덱스] [끝인덱스]
> zrange sortedset 0 -1
1) "b"
2) "c"
3) "a"

References

profile
백엔드 꿈나무

0개의 댓글