-
[Redis] Redis의 Data Type 공부 (Strings, Lists, Sets, Hashes, Sorted Sets, Bitmaps, HyperLogLog)📖 개발 공부/redis 2023. 8. 6. 16:47
목차
1. Strings 타입
2. Lists 타입
3. Sets 타입
4. Hashes 타입
5. Sorted Sets 타입
6. Bitmaps 타입
7. HyperLogLog 타입Strings 타입
- 가장 기본적인 데이터 타입이다.
- 바이트 배열로 저장된다. (binary-safe: 모든 문자를 표현할 수 있다.)
- 바이너리로 변환할 수 있는 모든 데이터를 저장 가능하다. (ex) JPG과 같은 파일 등)
- 최대 크기: 512MB
- Redis 하나의 아이템의 최대 value 크기는(key도) 512MB이다. 즉, 이론적으로는 512MB 키에 512MB 데이터를 만들 수 있다.
Strings 주요 명령어
명령어 기능 예제 SET 특정 키의 문자열 값을 저장한다. SET say hello GET 특정 키의 문자열 값을 얻어온다. GET say INCR 특정 키의 값을 Integer로 취급하여 1을 증가시킨다. INCR mycount DECR 특정 키의 값을 Integer로 취급하여 1을 감소시킨다. DECR mycount MSET 한번에 여러 키에 대한 값을 저장한다. MSET mine milk yours coffee MGET 여러 키에 대한 값을 한번에 얻어온다. MGET mine yours 127.0.0.1:6379> SET key1 hi OK 127.0.0.1:6379> GET key1 "hi" 127.0.0.1:6379> INCR key1 (error) ERR value is not an integer or out of range 127.0.0.1:6379> SET count_key1 10 OK 127.0.0.1:6379> GET count_key1 "10" 127.0.0.1:6379> INCR count_key1 (integer) 11 127.0.0.1:6379> DECR count_key1 (integer) 10 127.0.0.1:6379> MSET key1 hello key2 bye OK 127.0.0.1:6379> GET key1 "hello" 127.0.0.1:6379> MGET key1 key2 1) "hello" 2) "bye"
Lists 타입
- Linked-list 형태의 자료구조다.
- 인덱스 접근은 느리지만 데이터 추가/삭제가 빠르다.
- 주로 Queue와 Stack으로 사용할 수 있다.
Lists 주요 명령어
명령어 기능 예제 LPUSH 리스트의 왼쪽(head)에 새로운 값을 추가한다. LPUSH mylist apple RPUSH 리스트의 오른쪽(tail)에 새로운 값을 추가한다. RPUSH mylist banana LLEN 리스트에 들어있는 아이템 개수를 반환한다. LLEN mylist LRANGE 리스트의 특정 범위를 반환한다. LRANGE 0 -1 LPOP 리스트의 왼쪽(head)에서 값을 삭제하고 반환한다. LPOP mylist RPOP 리스트의 오른쪽(tail)에서 값을 삭제하고 반환한다. RPOP mylist - Stack: "나중에 들어온 것이 먼저 나가는" 자료구조
→ LPUSH로 리스트의 왼쪽에 요소를 추가하고, LPOP로 리스트의 왼쪽에서 요소를 가져오면서 Stack을 구현할 수 있다. - Queue: "먼저 들어온 것이 먼저 나가는" 자료구조
→ LPUSH로 리스트의 왼쪽에 요소를 추가하고, RPOP로 리스트의 오른쪽에서 요소를 가져오면서 Queue를 구현할 수 있다.
127.0.0.1:6379> LPUSH mylist jenny (integer) 1 127.0.0.1:6379> LPUSH mylist neil (integer) 2 127.0.0.1:6379> LPUSH mylist travis (integer) 3 127.0.0.1:6379> RPUSH mylist brock (integer) 4 127.0.0.1:6379> LLEN mylist (integer) 4 127.0.0.1:6379> LRANGE mylist 0 -1 1) "travis" 2) "neil" 3) "jenny" 4) "brock" 127.0.0.1:6379> LRANGE mylist 0 -2 1) "travis" 2) "neil" 3) "jenny" 127.0.0.1:6379> LPOP mylist "travis" 127.0.0.1:6379> LLEN mylist (integer) 3 127.0.0.1:6379> RPOP mylist "brock" 127.0.0.1:6379> LRANGE mylist 0 -1 1) "neil" 2) "jenny"
Sets 타입
- 순서가 없는 유니크한 값의 집합이다.
- 검색이 빠르다.
Redis의 Sets 타입은 내부적으로 해시 테이블을 사용하여 구현된다. 해시 테이블은 키-값 쌍을 저장하는 자료구조로서, 매우 빠른 검색 속도를 제공합니다. 해시 테이블은 평균적으로 O(1)의 시간 복잡도로 요소를 검색할 수 있어서 Sets에 포함된 값들을 빠르게 검색할 수 있다. - 개별 접근을 위한 인덱스가 존재하지 않고, 집합 연산이 가능하다. (교집합, 합집합)
Sets 주요 명령어
명령어 기능 예제 SADD Set에 데이터를 추가한다. SADD myset apple SREM Set에 데이터를 삭제한다. SREM myset apple SCARD Set에 저장된 아이템 개수를 반환한다. SCARD myset SMEMBERS Set에 저장된 아이템들을 반환한다. SMEMBERS myset SISMEMBER 특정 값이 Set에 포함되어 있는지를 반환한다. SISMEMBER myset apple 127.0.0.1:6379> SADD myset jenny (integer) 1 127.0.0.1:6379> SADD myset jenny (integer) 0 127.0.0.1:6379> SADD myset joanne (integer) 1 127.0.0.1:6379> SISMEMBER myset allen (integer) 0 127.0.0.1:6379> SISMEMBER myset joanne (integer) 1 127.0.0.1:6379> SREM myset jenny (integer) 1 127.0.0.1:6379> SCARD myset (integer) 1 127.0.0.1:6379> SMEMBERS myset 1) "joanne"
예제) 서비스가 특정 시간동안 유효한 쿠폰 발급한다고 치면 유저들은 한번씩만 쿠폰을 발급받을 수 있다. 해당 유저가 발급받았는지의 유무를 빠르게 체크할 수 있다.
Hashes 타입
- 하나의 key 안에 여러 개의 field-value 쌍을 저장한다.
- 여러 필드를 가진 객체를 저장하는 것으로 생각할 수 있다.
- HINCRBY 명령어를 사용해 카운터로 활용 가능하다.
Hashes 주요 명령어
명령어 기능 예제 HSET 한개 또는 다수의 필드에 값을 저장한다. HSET user1 name bear age 10 HGET 특정 필드의 값을 반환한다. HGET user1 name HMGET 한개 이상의 필드 값을 반환한다. HMGET user1 name age HINCRBY 특정 필드의 값을 Integer로 취급하여 지정한 숫자를 증가시킨다.
Strings 타입의 INCR, DECR와 다르게 지정한 숫자로 증가/감소 시킬수있다.HINCRBY user1 viewcount 1 HDEL 한개 이상의 필드를 삭제한다. HDEL user1 name age Hashes와 Strings의 차이는?
- (Json으로 다뤄서) Strings 타입을 이용해서 구현할 수 있지만, 필드 일부만 접근하고 싶을 때에도 전체 object를 가져와서 파싱해서 사용해야한다.
- Hashes는 특정 필드를 지정해서 값을 가져올 수 있다.Hashes는 각각의 필드를 따로 사용할 때 활용성이 커진다.
- 하지만 여러필드를 동시에 접근해야한다면 Hash를 사용하면 불편해질 것이다.
127.0.0.1:6379> HSET user1 name jenny age 23 (integer) 2 127.0.0.1:6379> HGET user1 (error) ERR wrong number of arguments for 'hget' command 127.0.0.1:6379> HGET user1 name "jenny" 127.0.0.1:6379> HMGET user1 name age 1) "jenny" 2) "23" 127.0.0.1:6379> HGET user1 viewcount (nil) 127.0.0.1:6379> HSET user1 viewcount 10 (integer) 1 127.0.0.1:6379> HGET user1 viewcount "10" 127.0.0.1:6379> HKEYS user1 1) "name" 2) "age" 3) "viewcount" 127.0.0.1:6379> HDEL user1 age (integer) 1 127.0.0.1:6379> HKEYS user1 1) "name" 2) "viewcount"
Sorted Sets 타입
- Set과 유사하게 유니크한 값의 집합이다.
- 각 값은 연관된 score를 가지고 정렬되어 있다.
- 정렬된 상태이기에 빠르게 최소/최대값을 구할 수 있다.
- 순위 계산, 리더보드 구현 등에 활용된다.
Sorted Sets 주요 명령어
명령어 기능 예제 ZADD 한개 또는 다수의 값을 추가 또는 업데이트한다. ZADD myrank 10 apple 20 banana ZRANGE 특정 범위의 값을 반환한다. (오름차순으로 정렬된 기준) ZRANGE myrank 0 1 ZRANK 특정 값의 위치(순위)를 반환한다. (오름차순으로 정렬된 기준) ZRANK myrank apple ZREVRANK 특정 값의 위치(순위)를 반환한다. (내림차순으로 정렬된 기준) ZREVRANK myrank apple ZREM 한개 이상의 값을 삭제한다. ZREM myrank apple 127.0.0.1:6379> ZADD myrank 10 a 20 b 30 c 40 d (integer) 4 127.0.0.1:6379> ZRANGE myrank 0 1 1) "a" 2) "b" 127.0.0.1:6379> ZRANK myrank b (integer) 1 127.0.0.1:6379> ZREVRANK myrank b (integer) 2 127.0.0.1:6379> ZREM myrank d (integer) 1
Bitmaps 타입
- 비트 벡터를 사용해 N개의 Set을 공간 효율적으로 저장한다.
- 하나의 비트맵이 가지는 공간은 4,294,967,295(2^32-1) 비트다.
- 비트 연산이 가능하다.
Bitmaps 주요 명령어
명령어 기능 예제 SETBIT 비트맵의 특정 오프셋에 값을 변경한다. SETBIT visit 10 1 GETBIT 비트맵의 특정 오프셋의 값을 반환한다. GETBIT visit 10 BITCOUNT 비트맵에서 set(1) 상태인 비트의 개수를 반환한다. BITCOUNT visit BITOP 비트맵들 간의 비트 연산을 수행하고 결과를 비트맵에 저장한다. BITOP AND result today yesterday 공간이 효율적이다. index에 들어가는 값은 0 or 1이다.
왜 공간을 효율적으로 쓸 수 있냐?
- 2^32 → 4byte → 보통 integer를 뜻함
- 레디스에서 비트맵을 사용하게되면, 그 공간 하나에 42억 개의 비트를 저장할 수 있다.
→ 0이나 1로만 표현 가능한 정보가 있다면, 공간을 효율적으로 사용할 수 있게 된다.
42억명의 유저들의 방문 현황을 저장해놔도 integer 하나를 저장하는 공간만 필요하다는 것이다. (매우 효율적)
비트 연산이 가능해서
today 방문 현황, yesterday 방문 현황 → AND 연산으로 두개 1인 것만 확인할 수 있다.
127.0.0.1:6379> SETBIT today_visit 2 1 (integer) 0 127.0.0.1:6379> SETBIT today_visit 3 1 (integer) 0 127.0.0.1:6379> GETBIT today_visit 2 (integer) 1 127.0.0.1:6379> BITCOUNT today_visit (integer) 2 127.0.0.1:6379> SETBIT yesterday_visit 2 1 (integer) 0 127.0.0.1:6379> SETBIT yesterday_visit 4 1 (integer) 0 127.0.0.1:6379> SETBIT yesterday_visit 5 1 (integer) 0 127.0.0.1:6379> BITCOUNT yesterday_visit (integer) 3 127.0.0.1:6379> BITOP AND result today_visit yesterday_visit (integer) 1 127.0.0.1:6379> BITCOUNT result (integer) 1 127.0.0.1:6379> BITOP OR result_or today_visit yesterday_visit (integer) 1 127.0.0.1:6379> BITCOUNT result_or (integer) 4
HyperLogLog 타입
- 유니크한 값의 개수를 효율적으로 얻을 수 있다.
- 확률적 자료구조로서 오차가 있으며, 매우 큰 데이터를 다룰 때 사용한다.
- 12KB까지 메모리를 사용하여 0.81%의 오차율을 허용한다.
- (2^64)개의 유니크 값을 계산 가능하다.
비트맵에서는 방문자수를 카운팅할 때 특정 offset을 가지고 계산하기 때문에, userId와 같은 숫자에 매핑할 수 밖에 없다.
하지만, hyperloglog를 사용하면 어떤 문자열이든 사용가능하다. (이름, 브라우저이름, 하드웨어 id 등등 문자열을 사용할 수 있다.)
HyperLogLog 주요 명령어
명령어 기능 예제 PFADD HyperLogLog에 값들을 추가한다. PFADD visit Jay Peter Jane PFCOUNT HyperLogLog에 입력된 값들의 cardinality(유일값의 수)를 반환한다. PFCOUNT visit PFMERGE 다수의 HyperLogLog를 병합한다. PFMERGE result visit1 visit2 확률적 자료구조를 사용한다. 100% 정확한 값을 보장하진 않지만, 더 큰 효율성을 얻을 수 있다.
2^64 → set을 사용하면 수백만개 사용해도 몇 MB의 메모리를 사용해야할 것이다. hyperloglog는 최대 12KB 메모리를 사용한다.
비트맵에서는 방문자수를 카운팅할 때 특정 offset을 가지고 해야해서, userId와 같은 숫자에 매핑할 수 밖에 없다.
→ 하지만, hyperloglog를 사용하면 어떤 문자열이든 사용가능하다. (이름, 브라우저이름, 하드웨어 id 등등 문자열을 사용할 수 있다.)
용도가 정확히 count를 위한 값이다.! → PFADD, PFCOUNT 이 두개명령을 주로 사용한다.
PFMERGE: 두개의 hyperloglog를 병합하면, 두개의 데이터가 합쳐진 형태로 중복은 거르고 유니크한 값의 개수를 구할 수 있다.
127.0.0.1:6379> PFADD pf_today_visit jenny joanne allen (integer) 1 127.0.0.1:6379> PFCOUNT pf_today_visit (integer) 3 127.0.0.1:6379> PFADD pf_today_visit neil (integer) 1 127.0.0.1:6379> PFADD pf_yesterday_visit jenny travis (integer) 1 127.0.0.1:6379> PFMERGE result pf_today_visit pf_yesterday_visit // 이미 result라는 키가 존재하기 때문에 err를 뱉는다. (error) WRONGTYPE Key is not a valid HyperLogLog string value. 127.0.0.1:6379> PFMERGE pf_result pf_today_visit pf_yesterday_visit OK 127.0.0.1:6379> PFCOUNT pf_result (integer) 5
반응형'📖 개발 공부 > redis' 카테고리의 다른 글
[Redis] 안정성과 가용성을 위한 클러스터 (0) 2023.08.16 [Redis] Redis 소개와 특징 (0) 2023.08.04