저번에 프로젝트 때문에 Redis를 찍먹한 경험이 있다. 근데 인메모리 관련 강의를 지급해주니 좋은 거 같다.
💡Spring Boot를 사용하면서 관계형 데이터베이스를 사용했습니다.
여기의 주된 목적은 영속성 데이터,
즉 파일시스템에 데이터를 저장함으로서 서비스가 종료되어도 유지되는 데이터를 위해서 입니다.
하지만 서비스를 만들다보면 때때로 일시적인 데이터를 저장해야 하는 상황이 발생합니다.
대표적으로 로그인 정보, 장바구니와 같은 기능은 사용자의 행동에 따라 빈번하게 데이터의 수정이 발생합니다.
이런 상황에서 파일시스템에 데이터를 저장하는 것은 그 특성상 속도가 느릴 수 밖에 없습니다.
그래서 특정 기능의 구현을 위해서 파일시스템을 사용하는 데이터베이스 대신,
메모리를 사용해 데이터를 일시적으로 보관하는 데이터베이스를 찾아볼 수 있습니다.
Redis는 Remote DIctionary Server를 줄인말로, Java의 Map과 같은 방식으로 데이터를 저장하는 데이터베이스.
💡2024년 3월 20일 Redis는 라이센스가 변경되어 완전히 오픈소스라고 하긴 어렵습니다만, 여전히 일반적인 사용 사례에 대해서는 무료로 사용
전역적인 자료구조를 쓰지 않고 Redis를 쓰는 이유는 서버가 여러 대인 경우 동시성을 제공할 수 있기 때문과 선택에 따라 서버가 꺼져도 데이터를 기억할 수 있기 때문이다.
SELECT * FROM users; 반면 Redis는 단순 문자열(String)부터, 리스트, 집합, Hash 등 다양한 형태의 데이터를 저장하며, 이 데이터를 회수하기 위해 SQL을 사용하지 않는다.SET greeting "Hello, Redis!"
GET greetingNot only SQL을 의미스키마와 SQL을 사용하는 관계형 데이터베이스와 달리, NoSQL 데이터베이스는 데이터를 관리하는 방법이 서로 다르며, 사용법도 판이
관계를 기준으로 데이터를 다루지 않기 때문에 스키마를 만들지 않고, 그렇기 때문에 비정형 대규모 데이터를 매우 빠르게 다룸
Redis는 NoSQL 중에서도 Key-Value Store로 작동하는 인메모리 데이터베이스이며, 지연이 적은 읽기 / 쓰기 성능. 그렇기 때문에 일시적인 데이터, 변경이 잦은 데이터를 다뤄야 되는 상황에서 많이 활용
뭐 WSL을 사용해서 다운받거나 Docker를 사용해서 받거나 하라고 한다.
그런데 나는 이미 local에 그냥 받아놨었다. 그래서 그걸로 사용하겠다.
Redis Insight라는 IDE가 있다고 함. IDE라고 해야 하나 싶긴한데 뭐 여튼 관리 Tool인 것 같다. 이것도 같이 다운 받아주면 좋다
도커 사용 시 이미지를 redis/redis-stack 을 선택하면 redis insight까지 같이 설치되고 8001 포트로 접근이 된다고 한다.
Redis는 앞서 설명한것 처럼 Key - Value 데이터베이스
String
가장 기본적인 자료형
Map<String, String>처럼 동작한다고 생각하면서 접근명령어
SET user:email alex@example.com
GET user:emailSET <key> <value>: key에 value 문자열 데이터를 저장, "으로 공백 구분GET <key>: key에 저장된 문자열 반환SET user:count 1
INCR user:count
DECR user:countINCR key: key에 저장된 데이터를 1 증가DECR key: key에 저장된 데이터를 1 감소MSET, MGET을 활용MSET user:name alex user:email alex@example.com
MGET user:name user:emailMSET key value [key value …]: key value의 형태로 주어진 인자들을 각 key에 value를 저장MGET key [key]: 주어진 모든 key에 해당하는 데이터를 반환.단순 문자열이지만, 문자열은 결국 바이트 배열 ⇒ 이미지, 음성, 영상, 파일, 또는 이메일 본문 등도 보관이 가능
분산된 구조에서 비교적 큰 사이즈의 데이터를 주고받아야 하는 상황에 Key만 전달해서 데이터는 여기있다 전달하는 방식으로 활용
List
Redis는 Key - Value 형태로 저장 ⇒ 즉 Map<String, List<String>>의 형태로 사용
명령어
LPUSH user:list alex # [alex]
LPUSH user:list brad # [brad, alex]
RPUSH user:list chad # [brad, alex, chad]
RPUSH user:list dave # [brad, alex, chad, dave]
LPOP user:list # brad
RPOP user:list # chadLPUSH key value: key에 저장된 리스트의 앞쪽에 value를 저장RPUSH key value: key에 저장된 리스트의 뒤쪽에 value를 저장LPOP key: key에 저장된 리스트의 앞쪽에서 값을 반환 및 제거RPOP key: key에 저장된 리스트의 뒤쪽에서 값을 반환 및 제거LLEN user:list
LRANGE user:list 0 3
LRANGE user:list 0 -1LLEN key: key에 저장된 리스트의 길이를 반환
LRANGE key start end: key의 start부터 end까지 원소들을 반환
LLEN은 없는 Key를 대상으로 하면 0이 되지만, 다른 자료형을 저장한 Key를 대상으로 하면 오류가 발생
LRANGE의 경우 (언제나 그렇듯) 시작을 0으로 생각하고,
end가 실제 길이를 벗어나도 오류가 발생하진 않습니다.
start > end일 경우 빈 결과가 반환됩니다.
음수의 경우 리스트의 뒤에서부터 데이터를 가져옵니다.
리스트의 경우 소셜 네트워크에서 많이 사용하는 자료형
대표적으로 X (구 트위터)가 List를 바탕으로 Timeline을 구성
Set
문자열의 집합입니다. 집합인 만큼 중복값을 제거하며, 순서가 존재하지 않습니다.
SADD user:java alex # [alex]
SADD user:java brad # [alex, brad]
SADD user:java chad # [alex, brad, chad]
SREM user:java alex # [brad, chad]
SMEMBERS user:java # [alex, brad, chad]
SISMEMBER user:java brad # true
SISMEMBER user:java dave # falseSADD key value: key에 저장된 집합에 value를 추가SREM key value: key에 저장된 집합의 value를 제거SMEMBERS key: key에 저장된 집합의 모든 원소를 반환SISMEMBER key value: key에 저장된 집합에 value가 존재하는지 반환SCARD key: key에 저장된 집합의 크기를 반환# 다른 Set에 추가한 뒤,
SADD user:python alex
SADD user:python dave
SINTER user:java user:python # [alex]
SUNION user:java user:python # [alex, brad, chad, dave]
SINTERCARD 2 user:java user:python # 1SINTER key1 key2: key1과 key2에 저장된 집합들의 교집합의 원소들을 반환SUNION key1 key2: key1과 key2에 저장된 집합들의 합집합의 원소들을 반환SINTERCARD number key1 [key2 ...]: number개의 key에 저장된 집합들의 교집합의 크기를 반환중복을 허용하지 않으며, 어떤 데이터의 존재 여부를 확인하는 SISMEMBER 같은 경우 O(1)의 시간복잡도
중복 없는 방문 수, 인증 토큰 블랙리스트 등을 구현할 때 활용
❗ 단, 매우 높은 방문수를 기록하는 서비스의 경우 실제 데이터가 필요하지 않다면, 근사값을 돌려주는 확률형 자료형을 사용하는게 권장Hash
Field - Value 쌍으로 이뤄진 자료형
Hash 데이터를 가져오기 위해 Key를 사용하고, 이후 다시 Key에 저장된 Hash 데이터에 Field - Value 쌍을 넣어주는 형식으로 동작 ⇒ Redis 전체가 Map 이라면 Hash는 Map<String, Map<String, String>>의 형식
HSET user:alex name alex age 25
HSET user:alex major CSE
HGET user:alex name
HGET user:alex age
HMGET user:alex age major
HGETALL user:alex
HKEYS user:alex
HLEN user:alexHSET key field value [field value]: key의 Hash에 field에 value를 넣는다. 한번에 여러 field - value 쌍을 넣어줄 수 있다.HGET key field: key에 저장된 Hash의 field에 저장된 value를 반환. 없는 field의 경우 null.HMGET key field [field]: key에 저장된 Hash에서 복수의 field에 저장된 value를 반환.HGETALL key: key에 저장된 Hash에 저장된 field - value를 전부 반환.HKEYS key: key에 저장된 Hash에 저장된 field를 전부 반환HLEN key: key에 저장된 Hash에 저장된 field의 갯수를 반환Hash는 본래 하나의 키에 복잡한 데이터 (객체의 데이터 라던지)를 하나의 키에 저장하는 용도로 주로 활용되고, 공식 문서에서도 여러 Key에 걸쳐 객체의 데이터를 표현하기 보단 Hash를 자주 활용할 것을 권장
장바구니 같은 기능은 사용자별로, 어떤 물품이 몇개나 담겨있는지와 같은 정보가 포함. 사용자 마다 Hash 데이터를 생성하고, 물품 - 갯수 형식으로 데이터를 저장하면 사용자별 장바구니를 쉽게 저장
Sorted Set
이름처럼 정렬된 집합
기본적으로 Set과 동일하게, 유일한 값들만 유지하지만 여기에 더해 각 값들에 score라고하는 실수를 함께 보관. 그리고 데이터를 가져올 때, score를 바탕으로 정렬하여 값들을 가져옴.
ZADD user:ranks 10 alex
ZADD user:ranks 9 brad 11 chad
ZADD user:ranks 8 dave
ZINCRBY user:ranks 2 alex
ZRANK user:ranks alex
ZRANGE user:ranks 0 3
ZREVRANK user:ranks alex
ZREVRANGE user:ranks 0 3ZADD key score member [score member ...]: key의 Sorted Set에 score를 점수로 가진 member를 추가, 이미 있는 member의 경우 새로운 score를 설정ZRANK key member: key의 Sorted Set의 member의 순위를 오름차순 기준으로 0에서 부터 세서 반환ZRANGE key start stop: key의 Sorted Set의 member들을 start 부터 stop 순위까지 오름차순 기준으로 반환ZREVRANK key member: key의 Sorted Set의 member의 순위를 내림차순 기준으로 0에서 부터 세서 반환ZREVRANGE key start stop: key의 Sorted Set의 member들을 start 부터 stop 순위까지 내림차순 기준으로 반환ZINCRBY key increment member: key의 Sorted Set의 member의 score를 increment 만큼 증가 (음수를 전달하면 감소)대표적으로 리더보드나 Rate Limiter, 즉 순위와 관련된 기능을 만드는데 사용
💡 Rate Limiter란, API 등을 제공할 때 짧은 시간에 지나치게 많은 요청을 막기 위한 기능을 의미합니다.그 외 공용 명령
그 외 자료형과 상관없이 사용할 수 있는 명령
이 중 대표적으로 많이 사용하는 건, Key를 제거하기 위한 DEL, 만료시각 설정을 위한 EXPIRE 등
SET somekey "to be deleted"
DEL somekey
SET expirekey "to be expired"
EXPIRE expirekey 5
EXPIRETIME expirekeyDEL key: key(와 저장된 데이터)를 제거EXPIRE key seconds: key의 TTL(유효시각)을 seconds로 설정, seconds초가 지나면 key 제거EXPIRETIME key: key가 만료되는 시각을 Unix Timestamp로 반환만약 저장된 모든 Key를 확인하고 싶다면,
KEYS *
을 사용할 수 있습니다. 이는 glob 패턴 형식을 전달하여, 패턴에 일치하는 키를 반환하는 메서드 입니다.
💡 여기서 `*`은 **Linux 파일시스템 등에서 흔히 사용하는 Glob 패턴**이며, `*`은 임의갯수의 글자를 대체하는 와일드카드입니다. 지금은 `*`만 있으므로, 모든 Key와 일치하는 패턴이기 때문에 모든 Key가 반환됩니다. 그 외 예시들이 공식문서에 있으며, 더 궁금하다면 검색을 해봅시다!h?llo - hello, hallo, hxllo
h*llo - hllo, heeeello
h[ae]llo - hello, hallo (not hillo)
h[^e]llo - hallo, hbllo, ... (not hello)
h[a-b]llo - hallo, hbllo마지막으로, 모든 Key를 제거하고 싶다면 FLUSHDB를 사용할 수 있습니다.
FLUSHDB