![[Redis] Data Types 정리](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0SiCV%2FbtsL7gDhIeP%2FATqxsBnUNUNR7LN4ZpzL91%2Fimg.png)
https://redis.io/docs/latest/develop/data-types
레디스는 캐싱부터 큐잉, 이벤트 처리 등의 비즈니스 문제를 다양하게 해결할 수 있도록 다양한 데이터 타입들을 제공한다.
과금 모델인 Enterprise 명령어는 제외했으며, 포스팅 외의 공식문서를 참조하고 싶다면 각 링크들을 참조하자.
String
- 512MB 미만의 일반적인 문자열을 저장할 수 있다. 직렬화된 객체나 이진 배열을 포함한다.
- 바이너리 데이터를 포함할 수 있어 이미지 저장이 가능하다.
- HTML Fragments, 페이지 등의 캐싱에 유용하다.
- 증감 연산을 사용할 수 있다. (INCR, DECR)
- SETEX, PSETEX, SETNX는 2.6.12버전부터 deprecated되었고, SET에서 통합하여 사용이 가능하다.
127.0.0.1:6379> SET STRING1 "STRING1"
OK
127.0.0.1:6379> GET STRING1
"STRING1"
127.0.0.1:6379> SET STRING1 "STRING1" NX
(nil)
127.0.0.1:6379> SET STRING1 "STRING2" XX
OK
127.0.0.1:6379> GET STRING1
"STRING2"
127.0.0.1:6379> SET STRING2 "STRING2" EX 1
OK
# 1초 뒤
127.0.0.1:6379> GET STRING2
(nil)
SET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SET | key value [NX | XX] [GET] [EX s | PX ms | EXAT unix-s | PXAT unix-ms | KEEPTTL] |
데이터를 저장한다. key가 있으면 덮어쓴다. | O(1) |
SETRANGE | key offset value | 지정된 offset에서 시작하여 value의 전체 길이로 덮어쓴다. | O(1) |
MSET | key value [key value ...] | 여러 데이터를 한 번에 저장한다. | O(N) |
MSETNX | key value [key value ...] | 여러 데이터를 한 번에 저장한다. 이미 존재하는 키가 있을 경우, 아무 작업도 수행하지 않는다. |
O(N) |
APPEND | key value | 데이터가 존재하는 경우, value를 추가한다. 데이터가 존재하지 않을 경우 데이터를 저장한다 (=SET) |
O(1) |
- NX(Not Exists) | XX(Exists): key가 없을 경우에만 저장 | 존재할 경우 업데이트
- EX | PX: 초 단위, 밀리초 단위 만료 설정
- EXAT | PXAT: 초 단위의 unixtimestamp 만료 설정, 밀리초 단위의 unixtimestamp 만료 설정
- KEEPTTL: 업데이트 시 기존 TTL을 유지
GET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
GET | key | key에 해당하는 value를 조회한다. | O(1) |
GETRANGE | key start end | start ~ end의 idx에 해당하는 value를 조회한다. (substr) | O(N) |
MGET | key [key ...] | key에 해당하는 value들을 조회한다. | O(N) |
STRLEN | key | value의 길이를 조회한다. | O(1) |
INCR 명령어
64비트 Integer 혹은 Float를 증감시킨다.
명령어 | 구문 | 설명 | 시간복잡도 |
INCR | key | value를 1 증가시킨다. | O(1) |
INCRBY | key increment | increment만큼 value를 증가시킨다. | O(1) |
INCRBYFLOAT | key increment | increment만큼 부동소수점을 증감시킨다. | O(1) |
DECR | key | value를 1 감소시킨다. | O(1) |
DECRBY | key decrement | decrement만큼 value를 감소시킨다. | O(1) |
기타
명령어 | 구문 | 설명 | 시간복잡도 |
GETDEL | key | key에 해당하는 value를 조회하고, 삭제한다. | O(1) |
GETEX | key [EX s | PX ms | EXAT unix-s | PXAT unix-ms | PERSIST] |
key에 해당하는 value를 조회하고, 만료일을 설정할 수 있다. | O(1) |
GETSET | key value | key에 해당하는 value를 조회하고, value로 덮어씌운다. | O(1) |
LCS | key1 key2 [LEN] [IDX] [MINMATCHLEN min-match-len] [WITHMATCHLEN] |
O(key1*key2)의 LCS(Longest Common Subsequence)를 가져온다. | O(N*M) |
활용 예시
회원가입, 정보 변경 등에 사용되는 휴대폰 인증 등의 OTP 등에 사용할 수 있다.
List
LinkedList로 저장한다.
- LinkedList의 특성에 맞게 데이터 추가와 삭제에 최적화되어있다. (O(1))
- LPUSH + LTRIM으로 List의 크기를 항상 일정하게 고정시킬 수 있다.
- Queue (LPUSH + RPOP) / Stack (LPUSH + LPOP) 으로 사용할 수 있다.
- 위의 특성들로 메세지 브로커를 구축하는 데 적합한 구조이다.
SET(PUSH) 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
LPUSH | key element [element ...] | 리스트의 0번째 index에 element를 저장한다. 리스트가 존재하지 않으면, 생성 후 저장한다. |
O(1) |
LPUSHX | key element [element ...] | 리스트가 존재할 경우에만 LPUSH를 수행한다. | O(1) |
LSET | key N element | 리스트의 N번째 index를 element로 덮어씌운다. 범위를 벗어난 index의 경우 Out Of Range 에러가 반환된다. |
O(N) |
LINSERT | key <BEFORE | AFTER> N element |
첫 번째로 발견된 N 위치의 앞/뒤에 element를 저장한다. | O(N) |
RPUSH | key element [element ...] | 리스트의 마지막 index에 element를 저장한다. 리스트가 존재하지 않으면, 생성 후 저장한다. |
O(1) |
RPUSHX | key element [element ...] | 리스트가 존재할 경우에만 RPUSH를 수행한다. | O(1) |
GET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
LRAGNE | key S stop | start ~ end의 요소들을 조회한다. | O(S + N) |
LINDEX | key index | index의 value를 조회한다. | O(N) |
LLEN | key | 리스트의 LENGTH. | O(1) |
- O(S+N)에서의 S는 작은 리스트의 경우 HEAD에서부터 시작 인덱스 까지의 거리, 큰 리스트의 경우 HEAD / TAIL (가까운 끝지점)으로부터의 거리이다. N은 |stop - start| 값이다.
POP 명령어
기본적으로 POP이란, GET과 DELETE가 결합된, 데이터를 가져오고 리스트에서 삭제한다고 이해하면 된다.
명령어 | 구문 | 설명 | 시간복잡도 |
LPOP | key [N] | 리스트의 0번째 index부터 데이터를 POP한다. | O(N) |
LMPOP | N key [key ...] <LEFT | RIGHT> [COUNT M] |
여러 개의 리스트에서 여러 개의 요소를 한 번에 POP (N만큼의 리스트에서 LEFT|RIGHT의 방향에서 M만큼 POP) |
O(N + M) |
RPOP | key [N] | 리스트의 마지막 index부터 데이터를 POP한다. | O(N) |
BLOCK 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
BLPOP | key [key ...] timeout | 리스트의 0번째 index를 POP. 리스트에 데이터가 없다면 timeout만큼 BLOCKING된다. |
O(N) |
BLMOVE | source destination <LEFT | RIGHT> <LEFT | RIGHT> timeout |
LMOVE + BLOCKING | O(1) |
BLMPOP | timeout N key [key ...] <LEFT | RIGHT> [COUNT M] |
timeout만큼 BLOCKING되는 LMPOP | O(N + M) |
BRPOP | key [key ...] timeout | 리스트의 마지막 index를 POP. 리스트에 데이터가 없다면 timeout만큼 BLOCKING된다. |
O(N) |
BRPOPLPUSH | source destination timeout |
BRPOP + LPUSH source 리스트에서 데이터를 꺼내서 destination의 왼쪽에 넣는다. |
O(1) |
- 리스트에 데이터가 들어올 때 까지 대기 할 수 있다는 특성을 이용하여 Task Queue, 실시간 이벤트 처리, 로드 밸런싱 등으로 활용된다.
기타 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
LMOVE | source destination <LEFT | RIGHT> <LEFT | RIGHT> |
source의 POP위치, destination의 SET 위치를 결정하여 source 리스트에서 destination 리스트로 데이터 이동. |
O(1) |
LPOS | key element [RANK rank] [COUNT num-matches] [MAXLEN len] | 리스트 내에서 rank번째로 등장하는 element를 최대 count만큼 len 내에서 찾는다. |
O(N) |
LTRIM | key start stop | start ~ stop 범위에 속하지 않는 데이터를 삭제한다. | O(N) |
127.0.0.1:6379> RPUSH LPOS A B C B E C B D
(integer) 8
127.0.0.1:6379> LRANGE LPOS 0 -1
1) "A"
2) "B"
3) "C"
4) "B"
5) "E"
6) "C"
7) "B"
8) "D"
127.0.0.1:6379> LPOS LPOS B
(integer) 1
127.0.0.1:6379> LPOS LPOS B RANK 2
(integer) 3
127.0.0.1:6379> LPOS LPOS B RANK 2 COUNT 2
1) (integer) 3
2) (integer) 6
127.0.0.1:6379> LPOS LPOS B RANK 3 COUNT 2
1) (integer) 6
127.0.0.1:6379> LPOS LPOS B MAXLEN 1
(nil)
127.0.0.1:6379> LPOS LPOS B COUNT 2 MAXLEN 4
1) (integer) 1
2) (integer) 3
Set
우리가 아는 그 Set 자료구조이다.
- 집합 연산(교집합, 합집합, 차집합 등)을 수행할 수 있다.
- 주로 관계를 나타낼 때 사용한다.
- Set의 저장 가능한 최대 원소 개수는 2^32-1개이다.
SET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SADD | key member [member ...] | 데이터를 저장한다. 이미 존재하는 데이터는 무시된다. | O(1) |
SMOVE | source destination member |
source에서 destination으로 데이터를 옮긴다. 이미 존재한다면 추가되지 않는다. |
O(1) |
GET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SMEMBERS | key | SET 전체를 조회한다. | O(N) |
SISMEMBER | key member | SET 내부에 member가 있다면 1, 없다면 0을 반환한다. | O(1) |
SMISMEMBER | key member [member ...] |
SISMEMBER의 다중 검사 | O(N) |
SRANDMEMBER | key [N] | SET의 임의의 데이터 N개를 반환한다. | O(N) |
SCARD | key | 카디널리티를 반환한다. (SET은 중복이 불가능하므로 SIZE와 동일하다.) |
O(1) |
SSCAN | key cursor [MATCH pattern] [COUNT count] |
SET 내부의 일정 단위 개수만큼 데이터를 가져온다. |
- SRANDMEMBER의 N
- 양수일 경우 반복되는 요소는 없으며, SET의 SIZE보다 클 경우 SET 전체를 반환한다.
- 음수일 경우 반복되는 요소가 존재하며, SET의 SIZE보다 크더라도 N개 만큼의 요소가 완전히 무작위로 반환된다.
- SSCAN
- 작은 데이터셋일 경우 COUNT와 무관하게 전체 데이터를 가져올 수 있다.
- 패턴은 item*처럼 패턴을 사용할 수 있다.
Redis의 SCAN 명령어(SSCAN, ZSCAN, HSCAN)는 모두 Hash Bucket 기반으로 동작한다.
명령어의 COUNT 옵션은 버킷 개수를 조정하는 힌트 역할을 하며 정확한 개수를 보장하지는 않는다.
데이터셋이 작다면 위 사진처럼 COUNT값을 조정해도 전체 데이터를 한 번에 반환할 가능성이 크다.
이러한 특징으로 대용량 데이터를 순회하는 데 유리하다.
POP 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SPOP | key [N] | SET의 임의의 데이터 N개를 POP | O(N) |
REMOVE 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SREM | key member [member ...] | SET에서 지정한 요소들을 삭제한다. | O(N) |
집합 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SUNION | key [key ...] | SET들의 합집합 | O(N) |
SUNIONSTORE | destination key [key ...] | 합집합을 destination SET에 저장 | O(N) |
SINTER | key [key ...] | SET들의 교집합 | O(N * M) |
SINTERSTORE | destination key [key ...] | 교집합을 destination SET에 저장 | O(N * M) |
SINTERCARD | M key [key ...] [LIMIT limit] |
교집합의 카디널리티(개수)를 반환 | O(N * M) |
SDIFF | key [key ...] | SET들의 차집합 | O(N) |
SDIFFSTORE | destination key [key ...] | 차집합을 destination SET에 저장 | O(N) |
활용 예시
좋아요 기능을 Set으로 간단하게 구현할 수 있다. 좋아요 기능처럼 자주 I/O가 발생하고, UNIQUE를 동시에 제어해야하는 상황 등에 알맞게 사용할 수 있다.
SortedSet (ZSet)
정렬을 지원하는 SET으로 SET에 저장된 score를 기준으로 자동 정렬된다.
- Skip List 구조로 정렬된 상태를 유지하며, 탐색에는 O(logN)의 시간이 걸림.
- 시간 기반 정렬과 범위 삭제(Sliding Window)에 최적화되어있다.
- 리더보드(랭킹)나 우선순위 큐(Priority Queue)를 쉽게 구현할 수 있다.
- ZREMRANGEBYSCORE, ZCOUNT를 활용하여 Rate Limiter을 쉽게 구현할 수 있다.
특정 API에 Rate Limit을 설정하고 싶다고 해보자. 내가 설정한 정책은 1분에 5번의 요청만 가능하도록 설정해두었다. 이럴 때 아래처럼 URI:User로 SortedSet을 생성하여, 요청에 대한 시간값을 score로 담는다. 요청을 수행하기 전에 ZCOUNT로 60초 이내에 해당 유저가 몇 번 요청을 하였는지 확인하고 5번을 초과하였다면 429를 반환할 수 있다. 60초가 지났다면 ZREMRANGEBYSCORE를 통해 범위 밖의 데이터들을 초기화해줄 수 있다.
SET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
ZADD | key [NX | XX] [GT | LT] [CH] [INCR] score member [score member ...] |
score을 가진 요소를 추가한다. | O(logN) |
- NX(Not Exists) | XX(Exists): 새로운 요소만 추가 | 기존 요소를 업데이트
- LT(Less Than) | GT(Greater Than): 요소가 이미 있을 때, 현재 score보다 낮거나 높은 경우에만 추가한다.
- CH(Changed): 변경된 요소의 개수를 반환한다. (설정하지 않으면 변경되었는지 보이지 않는다.)
- INCR(Increase): 요소가 있다면 score만큼 누적시킨다. (없다면 요소를 추가)
GET 명령어
ZRANGEBYLEX, ZRANGEBYSCORE, ZREVERANGE, ZREVERANGEBYSCORE, ZREVERANGEBYLEX는 6.2.0버전부터 deprecated되었고, ZRANGE에 통합하여 사용이 가능하다.
명령어 | 구문 | 설명 | 시간복잡도 |
ZRANGE | key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES] |
start ~ stop의 인덱스 요소를 반환 | O(logN + M) |
ZCARD | key | 카디널리티(개수)를 반환 | O(1) |
ZCOUNT | key min max | score 범위의 개수를 반환 '(' 를 사용해서 초과, 미만 표현 가능 |
O(logN) |
ZLEXCOUNT | key min max | member로 범위의 개수를 반환 '['를 붙여 사용하며, '(' 를 사용해서 초과, 미만 표현 가능 |
O(logN) |
ZSCAN | key cursor [MATCH pattern] [COUNT count] |
SET의 SSCAN과 동일 | O(1) |
ZSCORE | key member | member의 score를 반환 | O(1) |
ZRANK | key member [WITHSCORE] |
member의 현재 rank를 반환 | O(logN) |
ZREVRANK | key member [WITHSCORE] |
member의 현재 rank를 DESC로 반환 | O(logN) |
- BYSCORE: score기준으로 범위 검색 (ZRANGEBYSCORE)
- BYLEX: 알파벳 정렬 범위 검색 (ZRANGEBYLEX)
- REV(Reverse): 내림차순 정렬 (ZREVRANGE)
- LIMIT: 페이징처리
- WITHSCORE: score도 함께 반환 (RANK)
POP 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
ZPOPMIN | key [count] | count개 만큼 score가 낮은(rank가 높은) 요소를 POP | O(logN * M) |
ZPOPMAX | key [count] | count개 만큼 score가 높은(rank가 낮은) 요소를 POP | O(logN * M) |
ZMPOP | K key [key ...] <MIN | MAX> [COUNT count] |
여러 개의 SortedSet에서 ZPOPMIN | ZPOPMAX | O(K) + O(logN * M) |
BZPOPMIN | key [key ...] timeout | BLOCKING이 추가된Z POPMIN 비어있으면 새 데이터가 추가될 때까지 timeout만큼 대기 후 POP |
O(logN) |
BZPOPMAX | key [key ...] timeout | BLOCKING이 추가된 ZPOPMAX 비어있으면 새 데이터가 추가될 때까지 timeout만큼 대기 후 POP |
O(logN) |
BZMPOP | timeout K key [key ...] <MIN | MAX> [COUNT count] |
여러 개의 SortedSet에서 BZPOPMIN | BZPOPMAX | O(K) + O(logN * M) |
REMOVE 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
ZREM | key member [member ...] |
member를 REMOVE | O(logN * M) |
ZREMRANGEBYRANK | key start stop | rank의 start ~ stop 범위를 REMOVE | O(logN + M) |
ZREMRANGEBYSCORE | key min max | score의 min ~ max 범위를 REMOVE '(' 를 사용해서 초과, 미만 표현 가능 |
O(logN + M) |
ZREMRANGEBYLEX | key min max | member의 min ~ max 범위를 REMOVE '['를 붙여 사용하며, '(' 를 사용해서 초과, 미만 표현 가능 |
O(logN + M) |
INCR 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
ZINCRBY | key increment member |
member의 score를 increment만큼 증가 | O(logN) |
집합 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
ZUNION | numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>] [WITHSCORES] |
여러 개의 SortedSet의 합집합 | O(N) + O(MlogM) |
ZUNIONSTORE | destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE <SUM | MIN | MAX>] |
여러 개의 SortedSet의 합집합을 새로운 ZSET에 저장 | O(N) + O(MlogM) |
- WEIGHTS: 가중치 (key들에 대한 곱연산 적용)
- AGGREGATE: 중복 요소를 합치는 방식 (SUM, MIN, MAX)
- destination: 새로 생성할 ZSET key
활용 예시
SortedSet을 활용하여 트래픽 제어를 통한 안정성 확보 뿐 아니라 위처럼 과금별 Rate Limits를 제어하는 등의 비즈니스 모델도 수립할 수 있다. 이와 같은 Window Rate Limiter을 SortedSet을 통해 정책 시간 별 카디널리티가 초과되었다면 429를 반환하여 Rate Limiter을 구현할 수 있다.
Hash
Field - Value형태로 Map / Dictionary 형태와 유사하다.
SET 명령어
HMSET은 4.0.0버전부터 deprecated되었고, HSET을 사용하여 Multi-Set이 가능하다.
명령어 | 구문 | 설명 | 시간복잡도 |
HSET | key field value [field value ...] |
field와 value를 SET | O(N) |
HSETNX | key field value | field가 없을 경우 value를 SET | O(1) |
GET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
HGET | key field | field의 value를 반환 | O(1) |
HMGET | key field [field ...] | field들의 values 반환 | O(N) |
HGETALL | key | Hash의 field, value를 전부 반환 | O(N) |
HKEYS | key | Hash의 fields를 반환 | O(N) |
HVALS | key | Hash의 values를 반환 | O(N) |
HLEN | key | fields 개수를 반환 | O(1) |
HSTRLEN | key field | field의 value LENGTH를 반환 | O(1) |
HSCAN | key cursor [MATCH pattern] [COUNT count] [NOVALUES] |
Hash 내부의 일정 개수만큼 field / value를 반환 NOVALUES를 사용하면 field만 반환 |
O(N) |
HEXISTS | key field | field가 있다면 1, 없다면 0을 반환 | O(1) |
REMOVE 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
HDEL | key field [field ...] | fields REMOVE | O(N) |
INCR 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
HINCRBY | key field increment | Integer을 increment만큼 증가시킨다. | O(1) |
HINCRBYFLOAT | key field increment | Float을 increment만큼 증가시킨다. | O(1) |
Streams
로그 데이터를 처리하기 위해 5.0버전에서 도입된 데이터 타입이다. Append-Only, 즉 데이터의 추가만 가능하다. Redis의 영속성을 지원하는 AOF(Append-Only File)도 Append-Only 로그의 일종이다.
- Stream에 추가되는 메세지(이벤트)는 UUID를 가지며 해당 field를 읽을 때 O(1)의 시간 복잡도를 가진다.
- Consumer Group이 포함되어있다. Consumer Group을 이용하여 분산시스템의 다수의 컨슈머의 메세지 처리 과정에서 중복 문제를 쉽게 해결할 수 있다.
- Kafka등의 메세지 스트리밍 시스템과 유사하게 동작한다.
- 주로 이벤트 로그 저장, 실시간 데이터 처리, Pub/Sub 메세지 큐 등의 용도로 활용된다.
- 데이터 순서 보장이 필요한 경우 적합하다.
SET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
XADD | key [NOMKSTREAM] [<MAXLEN | MINID> [= | ~] threshold [LIMIT count]] <* | id> field value [field value ...] |
Integer을 increment만큼 증가시킨다. | O(N) |
- NOMKSTREAM: 스트림이 존재하지 않으면 생성하지 않음
- MAXLEN | MINID: 최대 메세지 개수 제한 (FIFO) | 특정 ID보다 작은 메세지를 삭제
- MINID: 특정 ID보다 작은 메세지를 삭제
- = | ~: Strict | Approximate
- threshold: 최대 개수 | 최소 ID를 반환
- LIMIT count: 한 번에 삭제할 최대 개수
- * | id: 자동 ID 생성(unix timestamp) | 사용자가 직접 ID를 지정 (timestamp - sequence)
GET 명령어
XREAD를 사용하여 실시간 데이터 처리가 용이하다.
명령어 | 구문 | 설명 | 시간복잡도 |
XRANGE | key start end [COUNT count] |
start ~ end의 스트림 반환 | O(N) |
XREVRANGE | key start end [COUNT count] |
start ~ end의 스트림 역순 반환 | O(N) |
XREAD | [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...] |
여러 키의 스트림에서 특정 id 이후의 메세지를 동시에 반환 BLOCKING을 활용한 비동기처리 가능. |
|
XLEN | key | 스트림 내 총 메세지 개수 조회 | O(1) |
REMOVE 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
XDEL | key id [id ...] | 스트림 삭제 | O(1) |
XTRIM | key <MAXLEN | MINID> [= | ~] threshold [LIMIT count] |
조건에 따라 스트림의 메세지를 삭제 | O(N) |
컨슈머 그룹 명령어
XREADGROUP은 컨슈머 그룹을 사용해 메세지를 여러 개의 컨슈머에 분배하는 명령어이다. 한 메세지는 한 컨슈머에게만 전달되며, 그룹 내부에서는 PEL(Pending Entries List)을 관리하여 메세지 상태를 추적할 수 있으며 비동기 방식(BLOCK)으로 사용이 가능하다.
PEL(Pending Entries List)
컨슈머 그룹이 메세지를 읽을 때 Redis에서는 PEL에 메세지를 저장하고 XACK를 호출해야 메세지가 PEL에서 제거된다. PEL에 남아있는 메세지는 처리 중이거나 실패한 메세지로 간주된다. 하지만 NOACK 옵션을 통해 자동으로 Acked(확인)된 것으로 간주하여 PEL에 저장하지 않을 수도 있다.
명령어 | 구문 | 설명 | 시간복잡도 |
XACK | key group id [id ...] | 컨슈머에 메세지 처리 완료 알림 처리. 컨슈머 그룹의 PEL에서 메세지 삭제. |
O(1) |
XCLAME | key group consumer min-idle-time id [id ...] [IDLE ms] [TIME unix-mils] [RETRYCOUNT count] [FORCE] [JUSTID] [LASTID lastid] |
미처리 메세지를 다른 컨슈머에 재할당 | O(logN) |
XAUTOCLAME | key group consumer min-idle-time start [COUNT count] [JUSTID] |
오래된 미처리 메세지를 자동으로 재할당 XCLAME + XPENDING |
O(1) |
XREADGROUP | GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] id [id ...] |
컨슈머 그룹을 활용한 메세지 분배 후 POP | O(N) |
XPENDING | key group [[IDLE min-idle-time] start end count [consumer]] |
컨슈머 그룹의 미처리 메세지 조회 | O(N) |
XGROUP | CREATE key group <id | $> [MKSTREAM] [ENTRIESREAD entries-read] |
새로운 컨슈머 그룹 생성 | O(1) |
CREATECONSUMER key group consumer |
특정 컨슈머 그룹에 새로운 컨슈머 추가 | O(1) | |
SETID key group <id | $> [ENTRIESREAD entries-read] |
컨슈머 그룹의 마지막 메시지 ID 변경 | O(1) | |
DELCONSUMER key group consumer |
컨슈머 그룹에서 특정 컨슈머 제거 | ||
DESTROY key group | 컨슈머 그룹 제거 | O(N) |
- min-idle-time: 최소 대기 시간 (이 시간 동안 PEL에 있던 메세지만 가져옴)
- FORCE: 기존 컨슈머가 존재하지 않아도 강제로 메세지를 가져옴
- JUSTID: 메세지 ID만 반환
기타 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
XINFO | GROUPS key | 컨슈머 그룹 메타데이터 반환 | O(1) |
STREAM key [FULL [COUNT count]] |
스트림 메타데이터 반환 | O(1) |
Geospatials
좌표를 저장하고 검색할 수 있는 데이터 타입으로 거리 계산, 범위 탐색 등을 지원한다. SortedSet에 저장되기 때문에, ZSET 명령어를 통한 조회, 삭제 등이 가능하다.
SET 명령어
명령어 | 구문 | 설명 | 시간복잡도 |
GEOADD | key [NX | XX] [CH] longitude latitude member [longitude latitude member ...] |
지리 정보(경도, 위도, 이름)를 추가한다. | O(logN) |
GET 명령어
GEORADIUS 명령어들은 6.2.0버전부터 deprecated되었다. GEOSEARCH에 통합하여 사용이 가능하다.
명령어 | 구문 | 설명 | 시간복잡도 |
GEOPOS | key [member [member ...]] | 특정 위치의 좌표(Lat, Lon) 조회 | O(1) |
GEODIST | key member1 member2 [M | KM | FT | MI] |
두 지점 간의 거리 계산 | O(1) |
GEOHASH | key [member [member ...]] | 특정 위치의 Geohash 값을 반환 | O(1) |
GEOSEARCH | key <FROMMEMBER member | FROMLONLAT longitude latitude> <BYRADIUS radius <M | KM | FT | MI> | BYBOX width height <M | KM | FT | MI>> [ASC | DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH] |
지정된 범위 내 위치 검색 | O(logN + M) |
GEOSEARCHSTORE | destination source <FROMMEMBER member | FROMLONLAT longitude latitude> <BYRADIUS radius <M | KM | FT | MI> | BYBOX width height <M | KM | FT | MI>> [ASC | DESC] [COUNT count [ANY]] [STOREDIST] |
위치 검색 후 결과를 새로운 GEO에 저장 | O(logN + M) |
- FROMMEMBER: 특정 멤버 기준으로 검색
- FROMLONLAT: 특정 좌표에서 검색
- BYRADIUS: 특정 반경 내에서 검색
- BYBOX: width * height 크기의 BOX 내에서 검색
- COUNT: 가져올 결과 개수 (ANY를 사용 시 성능 최적화)
- WITHCORD: 위치 좌표를 함께 반환
- WITHDIST: 거리를 함께 반환
- WITHHASH: GEOHASH를 함께 반환
Geospatial을 이용해 홍대 ~ 강남역 까지의 직선거리를 구해보자.
GEOADD TEST 127.027583 37.497928 GANGNAM
(integer) 1
127.0.0.1:6379> GEODIST TEST GANGNAM HONGDAE KM
"11.2561"
추가로, 반경과 x*y 박스의 범위검색 또한 가능하다.
Bitmaps
실제의 데이터 타입은 아니며, String 타입을 기반으로 비트 단위 연산을 지원한다. 비트 단위로 값을 설정하고 읽을 수 있기 때문에, 매우 작은 메모리 공간으로도 데이터를 표현할 수 있으며, 효율적인 공간 활용 및 빠른 연산이 특징이다. 사용자 로그인 여부, 출석 체크, 중복 체크 등의 비트로도 수행할 수 있는 연산에 활용하면 효율적이다.
# 로그인 기록으로 사용
SETBIT user:1001 0 1 # 첫날 로그인
SETBIT user:1001 1 0 # 둘째 날 미로그인
SETBIT user:1001 2 1 # 셋째 날 로그인
명령어
명령어 | 구문 | 설명 | 시간복잡도 |
SETBIT | key offset value | offset에 value를 저장 | O(1) |
GETBIT | key offset | offset의 비트 값을 반환 | O(1) |
BITCOUNT | key [start end [BYTE | BIT]] |
1로 설정된 비트 개수를 반환 | O(N) |
BITOP | <AND | OR | XOR | NOT> destkey key [key ...] |
비트 연산 결과를 destkey의 새로운 Bitmaps에 저장 | O(N) |
BITPOS | key bit [start [end [BYTE | BIT]]] |
지정한 비트가 처음으로 등장하는 위치를 반환 | O(N) |
BITFIELD | key [subcommand [argument] ...] |
더 작은 크기의 정수 필드 단위로 읽고 수정하는 명령어. | O(1) |
활용 예시
온라인 상태 표시 등의 수시로 변경되는 값에 사용한다.
HyperLogLogs
집합의 카디널리티를 추정할 수 있는 확률형 자료구조이다.
- member의 값을 해싱하여 버킷에 해시 값에 맞게 표시한다.
- 동일한 아이템이 추가 될 경우 카디널리티를 일정하게 계산할 수 있다.
- Set과 유사하지만 실제 값을 저장하지 않기 때문에 매우 작은 저장 공간(12kb)을 사용한다.
- 실제 값을 저장하지 않기 때문에 저장된 데이터를 다시 확인할 수 없다.
- 확률적인 계산식을 사용하기 때문에 결과값이 실제와 일정 부분 오차가 발생할 수 있다.
- 정확성을 일부 포기하는 대신 저장 공간을 효율적으로 사용할 수 있으며, 평균 에러율은 0.81%이다.
명령어
명령어 | 구문 | 설명 | 시간복잡도 |
PFADD | key [element [element ...]] | 요소를 저장 | O(1) |
PFCOUNT | key [key ...] | 저장된 요소의 개수(카디널리티)를 반환 | O(1) |
PFMERGE | destkey [sourcekey [sourcekey ...]] |
로그들을 destkey로 병합 | O(N) |
활용 예시
일일 방문자 수를 Hyerploglog로 구현해보자. 유의할 점은 100% 정확한 수치가 아닐 수도 있다는 점이다.
참조
2023.04 ~ 백엔드 개발자의 기록
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!