- 데이터 입력/수정/삭제/조회 (String)
- Redis 에서 제공하는 자료구조
- Hash
- List
- Set (Sorted Set)
- Stream
- Hyperloglog
- Geospatial index
데이터 입력/수정/삭제/조회 (String)
key / value 의 구조를 가지고 O(1)의 get/set/mget/mset command 를 제공한다.
#명령어
종류 | 내용 |
set | 데이터 저장할 때 (key, value) |
get | 저장된 데이터 검색할 때 |
rename | 저장된 데이터 값을 변경할 때 |
randomkey | 저장된 key 중 하나의 key를 랜덤하게 검색할 때 |
keys | 저장된 모든 key를 검색할 때 |
exits | 검색 대상 key가 존재하는지 여부를 확인할 때 |
mset / mget | 여러 개의 key와 value를 한번 저장하고 검색할 때 |
- mset/mget 은 O(1) * N 이기 때문에 mget/mset의 경우 많은 item을 요청하면 전체 응답이 느려진다.
- mset/mget은 하나의 transaction으로 묶이기 때문에 실행하는 도중에 다른게 들어와서 실행하지 못한다.
- 특히, cluster에서는 mget은 여러 서버의 응답을 모아야 하므로 더 느려지는 경향을 보인다.
- Redis 내부에 데이터를 저장할 때에는 set [key] [value] 형태로 저장한다.
- key를 통해 value 값을 가지고 올 때에는 get [key] 형태로 가지고 온다.
- Redis 는 사용할수록 점점 사용하는 메모리를 아끼는게 중요하다.
- 같은 데이터 사이즈를 유지하는게 나중에 메모리 파편화를 줄이는데 도움이 된다.
- 메모리를 아끼기 위한 노력으로 value 를 Json serialize 형태로 집어넣어서 파싱하여 사용하는 경우도 많다.
- 초반에 데이터를 직접 볼 수 있다는 장점때문에 사용한다.
- 메모리를 아끼기 위해 Protobuf(직렬화 프로토콜) 등의 바이너리 인코딩을 할 수 있다.
- 자바 구조체를 Serialize 해서 사용하면 자바계열(JVM) 위에서만 읽을 수 있어서 피하는게 좋다.
- 그러나 Json Serialize 사용하면 Race Condition 이 발생할 가능성이 생긴다.
- 개별 데이터의 변경이 필요하면 hash 자료구조를 사용하는 것이 유리하다.
Redis 에서 제공하는 자료구조
Redis에서 제공하는 자료구조는 효율적으로 데이터를 저장/관리 할 수 있도록 다양한 타입의 데이터 속성을 제공하고 있다.
기본적으로 Redis의 자료구조는 Atomic하기 때문에 RaceCondition을 피할 수 있다.
Hash
Redis에서 기본 자료구조로 Hash Table은 Key-Value 쌍으로 이루어져 있다. Redis 4.x버전부터는 'SipHash'를 지원한다.
인코딩 타입은 OBJ_ENCODING_HT 이다.
- Redis 에서 데이터를 표현 할 때 기본 타입은, 하나의 key - (하나 이상의 Field/Element) value 값으로 저장된다.
- key에는 아스키 값을 저장하고, value에는 string 데이터 및 redis에서 제공하는 컨테이너 타입의 데이터를 저장한다.
(기본적으로 key값은 String 구조로 저장된다. / value값은 set, sorted set, list..) - hash 타입의 데이터를 처리할 때는 hmset, hget, hgetall, hkey, hlen 등의 명령어를 사용한다.
#Siphash?
- Redis dict에서 hash로 사용된다. Redis 4.x부터 도입되었으며 참고로 Python도 Siphash를 3.x 부터 도입하였다.
- Siphash를 쓰는 이유?
- 일반 Hash는 언제나 같은 key에 대해서 동일한 결과를 준다.
- 어떤 서버에서 동작하든 간에 같은 결과를 가지므로 데이터 DDos 의 원인이 될 수 있다.
(특정 버킷으로만 키가 들어가도록 호출하도록 하는 방법)
- Siphash는 서버가 시작하는 시점마다 시드값을 사용해서 서로다른 결과가 나오도록 한다.
- Hash알고리즘은 같고 해당 프로세서 내에서는 매번 같은 hash결과를 주지만, 다른 서버나 재시작시에는 다른 hash값을 주도록 하여 추측하기 어렵도록 한다.
#Redis 에서 해시충돌을 줄이기 위한 방법
- Redis에서는 선형리스트 갯수를 줄이는 방식을 채택한다. linked list 테이블에 두배의 버킷을 할당하고 key를 복사한다.
- 기존 key들은 버킷 단위로 새 ht_table로 이동
- 새로운 key들은 새 ht_table에만 저장한다.
- 양 쪽에 키가 존재하지는 않는다.
- Redis에서 RB Tree 사용하지 않고 선형리스트 주로 쓰는 이유?
- 복잡하지 않아서 주로 사용된다. 많이 들어갈 때에만 중요하고 bucket을 빨리 늘리는 구조로 만들어서 구현하는게 더 효율적
- RB Tree를 사용하는게 우아하지만 복잡성이 증대한다.
- 참고로 Java 에서의 HashMap 자료구조는 Java7 버전에서 Java8 버전으로 넘어가면서 서로 다른 구현방식을 채택하고 있다.
- 해시충돌이 Java8 에서는 Linked List가 아닌 Red/Black Tree를 사용한다. (O(N) 에서 O(logN))
# Redis에서의 Key
List
Redis 에서의 list는 Array 형태가 아니라 Linked list로 구현되어 있다.
- list 타입은 기존 관계형 테이블에서는 존재하지 않는 데이터 유형이다. (제 1정규화를 위반하게 되므로)
- Redis에서의 list는 Array 형태가 아닌 linked list 로 구현되어 있어서 list의 head 또는 tail 에 데이터를 삽입을 상수시간에 처리 할 수 있다. Redis 내부 자료구조가 linked list 형태로 구현한 이유는 DB에서의 데이터를 고속으로 넣는것이 더 중요하기 때문이다.
- Redis에서는 nested 한 자료구조를 지양하기 때문에 트리구조를 지원하지 않는다. 따라서, 트리구조를 나타내기 위해 Hash / list 를 parent-child 관계를 가지는 형태로 구현한다.
- 내부의 Task Queue, Prioirty Queue 등 Queue의 구현이 List 형태로 되어있다.
- string타입의 경우 배열에 저장할 수 있는 데이터 크기의 제한은 512MB 이다.
- list 타입의 데이터를 처리할 때 lpush, lrange, rpush, rpop, llen, index 명령어를 사용한다.
Set , Sorted Set (Unique 집합)
유일한 데이터를 저장하는 자료구조이다. 인코딩 타입에 따라서 데이터 저장 타입이 달라진다.
- Set에서의 OBJ_ENCODING_HT 인코딩 타입
- 내부적으로 hash table이 존재한다(dict 가 하나 더 존재함)
- Set에서의 OBJ_ENCODING_INTSET 인코딩 타입
- hash table은 메모리 사용량이 크므로 정수 배열을 사용하여 메모리 사용량을 낮출 수 있다.
- 정수 타입만 들어있을 경우는 정수의 배열을 만들어서 사용한다.
- 2byte, 4byte, 8byte 크기 값에 따라 다르게 구성된다.
- 찾을때는 bisect로 확인한다.
- Sorted Set 에서의 OBJ_ENCODING_SKIPLIST 인코딩 타입
- 메모리를 상당히 많이 사용한다.
- 내부적으로 skiplist 라는 자료구조를 사용한다.
- 'zscore' 명령을 위해서 dict 자료구조도 사용한다.
- Sorted Set 에서의 OBJ_ENCODING_LISTPACK 인코딩 타입
- 메모리 사용량을 아끼기 위해 선형 메모리에 저장하는 형태이다.
- Score 은 Integer 가 아니라 Double 형태로 저장된다.
- Double과 Long의 부동소수점 정밀도가 서로 다르기 때문에 여기서 버그가 생길 수 있는 여지가 존재한다.
- 특정 데이터가 존재하는지를 체크하는 용도로 사용하기 쉽다는 장점이 있다.
- list 타입은 하나의 필드에 여러개의 배열을 저장할 수 있었지만, set타입은 여러개의 원소(element)로 데이터를 표현할 수 있다.
(중복되는 값이 존재하지 않는다.) - set 타입의 데이터를 처리할 때 sadd, smembers, scard, sdiff, sunion 명령어를 사용한다.
- sorted set 타입은 set과 동일하지만 정렬된 상태이면 sorted set이라고 한다.
- sorted set 타입의 데이터를 처리할 때 zadd, zrange, zcard, zcount, zrank, zrevrank 명령어를 사용한다.
#skiplist
- O(LogN)의 속도를 가지는 자료구조 이다. Tree구조를 사용해서 나오는 시간 복잡도와 동일한 효율을 보여준다.
(비유를 하자면 일반선과 급행선이 있는 9호선과 동일하다.) - Redis에서는 Sorted Set을 저장하기 위한 자료구조로 사용된다.
- skiplist의 높이는 Random 하게 결정된다.
아래와 같은 skiplist가 만들어졌고 '30' 의 값을 찾기위한 절차는 다음과 같다.
- Layer1 에서 시작하여 5까지 간다음, 다음 연결리스트와 목표지점을 비교하고 다음 Layer으로 내려간다.
- Layer2 로 내려와서 15까지 간다음, 다음 연결리스트와 목표지점을 비교하고 다음 Layer으로 내려간다.
- Layer3 에서 목표지점인 30 까지 다다를 수 있기 때문에 값을 찾을 수 있다.
결론적으로, skiplist로 연결리스트를 사용하는 단점중 하나인 인덱싱에 걸리는 시간을 대폭 낮춰주는 역할을 해준다.
HyperLogLogs
- Hyperloglogs 타입은 관계형 DB의 테이블 구조에서 Check 제약조건과 유사한 개념의 데이터 구조이다.
- 관계형 DB에서 Check 제약조건을 사용하는 이유는 해당 컬럼에 반드시 저장되어야 할 특정 데이터 값만 저장되도록 제한을 가하는 것이다.
- Redis에서도 저장되어야 할 데이터 값을 미리 생성하여 저장한 후 필요에 따라 연결하여 사용할 수 있는 데이터 타입이다.
- Hyperloglogs 타입의 데이터를 처리할 때 pfadd, pfcount, pfmerge 명령어를 사용한다.
Geospatial
- 위치정보를 저장하는 데이터를 저장, 관리하는 타입이다.
- 내부적으로는 Sorted Set을 사용한다.
- Geospatial 타입의 데이터를 처리할 때 geoadd, geopos, georadius, geohash 명령어를 사용한다.
Streams
- 로그를 처리하기 위해 최적화된 데이터 타입입니다. 차별화된 다양한 장점이 있지만, 가장 큰 특징은 소비자(Consumer)그룹을 지정할 수 있다.
출처:
https://redis.io/docs/data-types/
'Redis' 카테고리의 다른 글
[完][OSSCA Redis] Redis 오픈소스 컨트리뷰션 (0) | 2024.01.31 |
---|---|
[OSSCA Redis / 빅데이터 저장 및 분석을 위한 NoSQL & Redis] Part2 (1) | 2023.10.26 |
[OSSCA Redis / 빅데이터 저장 및 분석을 위한 NoSQL & Redis] Part1 (1) | 2023.10.24 |
[OSSCA Redis] Redis 오픈소스 컨트리뷰션 Week3 (1) | 2023.10.23 |
[OSSCA Redis] Redis 오픈소스 컨트리뷰션 Week1, 2 (0) | 2023.10.15 |