본문 바로가기

스터디-ing/Cloud

[Redis] Redis 데이터 구조

Redis는 제공하는 Data Structures를 활용해 서비스 워크로드에 맞는 설계가 가능하다.
하지만 설계 시 주의할 점은 Redis는 싱글 스레드이기 때문에 BigO의 n 사이즈를 무조건적으로 고려해야한다.

Redis는 데이터를 key-value 형태로 저장하는데, 이때 key에 대한 전략도 중요하다.
aws 엔지니어가 말하기를 키를 저장할때는 일정한 길이, 고유 값을 고려해 해싱하여 사용하는게 좋은 방식이라 한다.

 

Redis Keys

  • key-value 형태 저장
  • 키 사이즈: 512MB
  • binary safe strings
  • 구분자 좋은 예: deliiter(,) standard is (:)
  • Example: app1:cart:123456

String

  • 최대 512MB 길이의 텍스트 또는 바이너리 문자열을 보유할 수 있는 간단한 데이터 유형
  • 특징
    • 사용자 세션, 캐싱 값, 카운터 등과 같은 작은 데이터 조각을 저장하는 데 효율적.
    • 설정, 가져오기, 추가, 증가 및 감소와 같은 기본 작업을 지원
  • 명령어 예
    • UNLINK: 삭제할때 자주 씀, 포인트를 제거하고 뒤에서 비동기적으로 처리
    • DELETE: 동기적으로 처리함

예제

redis-cli> GET mykey
"Hello"

Hash

  • 키-값 쌍의 모음
  • HMSET은 4.0.0 부터 Deprecated HSET사용 권장
  • 특징
    • 여러 필드가 있는 개체나 레코드를 저장하는 데 효율적
    • 해시 내의 개별 필드에 대한 액세스, 설정 및 삭제를 허용하여 데이터에 대한 보다 세부적인 제어를 제공
    • Redis에서 객체 또는 구조화된 데이터 유형을 나타내는 데 유용
    • 대부분의 작업에 대해 일정한 시간 복잡성 O(1)을 제공하므로 개체 내의 개별 필드에 대한 빠른 액세스가 필요한 시나리오에 적합
  • 명령어 예
    • HSCAN: keys를 대채하기 위해 생긴 명령어, Redis는 싱글 스레드의 O(n)의 알고리즘 속도를 가지고 있어 keys명령어를 실행하면 종료될 때 까지 다른 작업을 할 수가 없어 특정 COUNT만 불러오는 HSCAN로 권장
    • HSET, HGET

예제

redis-cli> HGET user:id:100 username
"john"
redis-cli> HGETALL user:id:100
1) "username"
2) "john"
3) "email"
4) "john@example.com"

List

  • 순서가 지정된 데이터 모음, 우리가 흔히 알고 있는 리스트와 동일(Head -ㅁ-ㅁ-ㅁ-ㅁ- Tail)
  • 특징
    • 목록의 양쪽 끝에서 요소를 삽입하고 삭제할 수 있으므로 큐, 스택 또는 간단한 메시지 브로커 구현에 적합함
    • 인덱스별로 요소에 액세스하는 데 선형 시간 복잡도 O(n)을 제공함
  • 명령어 예
    • LPUSH, RPUSH
    • RPOPLPUSH 같이 커맨드를 이어서 사용가능, RPOPLPUSH는 6.2.0부터 Deprecated 그래서 LMOVE 사용 권장(Ex. LMOVE todo later RIGHT LEFT)

예제

redis-cli> RPUSH mylist "hello"
redis-cli> LRANGE mylist 0 -1
1) "world"
2) "hello"

SET

  • 중복없는 데이터를 순서 없이 저장한 데이터 집합
  • 특징
    • 중복 데이터 자동 제거, 고유성이 중요한 시나리오에 적합
    • SUNION(합집합), SINTER(공집합), SDIFF(차집합) 커맨드 사용 가능
    • 유니크해야 하는 데이터를 저장할 때 사용
  • 명령어 예
    • SADD, SMEMBERS

예제

redis-cli> SMEMBERS myset
1) "apple"
2) "banana"
3) "cherry"

Sorted Set

  • 정렬된 세트는 일반 세트와 유사하지만 사용자 정의 점수에 따라 정렬된 순서를 유지
  • 특징
    • value score 같은 짝으로 데이터 삽입
    • 정렬 순서를 유지하는 데 사용되는 관련 점수와 함께 요소를 저장
    • 요소를 추가, 제거, 업데이트하고 순위 또는 점수 범위별로 요소를 검색하는 작업을 제공
    • 순위, 순위표 또는 우선 순위 대기열이 필요한 시나리오에 유용
    • 시간 복잡도 O(log N)를 제공하므로 많은 수의 요소가 있어도 정렬된 데이터 세트를 유지하는 데 효율적
  • 명령어 예
    • ZADD game:1 50 mike 123 luke 75 dan
    • ZREVRANGE gam:1 0 2 WITHSCORES → score가 높은 순서대로 출력

예제

  • select ~~ from ~~ limit 0, 10 같은 데이터 소팅 리밋 조회대신, sorted set에 날짜 index를 저장하면 날짜와 index 범위로 빠르게 조회 가능
redis-cli> ZADD leaderboard 200 "player2"
redis-cli> ZRANGE leaderboard 0 -1 WITHSCORES
1) "player1"
2) "100"
3) "player2"
4) "200"

Geospatial

  • 지리적 좌표를 처리하기 위한 지리공간 데이터 유형
  • 특징
    • 지리적 좌표(위도 및 경도)를 정렬된 세트 내의 구성원 값 쌍으로 저장
    • 좌표가 있는 멤버 추가, 지정된 반경 내의 멤버 쿼리, 멤버 간 거리 계산 등과 같은 작업을 지원
    • ZRANGE같은 Sorted Set 명령어 사용 가능

예제

> GEOADD cities 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
> GEORADIUS cities 15 37 200 km
1) "Catania"
> GEODIST cities Palermo Catania km
"166.2742"

Hyperloglog

  • 고유 값의 개수를 근사화하는 데 사용되는 확률적 데이터 구조, 저렴한 비용과 빠른 속도로 unique count 기능을 제공해주는 데이터 타입(set을 사용해 구현한다고 하더라도, 막대한 time complexity가 요구)
  • 누가 방문 했는지는 중요하지 않은 방문객 수를 저장하는 경우 적합함
  • 특징
    • 적은 양의 메모리를 사용하여 높은 정확도로 집합의 카운트를 추정합니다.
    • HyperLogLog의 크기가 증가함에 따라 감소하는 오류율을 제공(Standard error of < 1%(1프로 미만))
    • 메모리를 굉장히 적게 사용, 원소 개수와 상관 없이 12Kbite만 사용
    • Time: O(1): 속도 빠름
  • 명령어 예
    • 데이터를 추가하고(PFADD), 카운팅하고(PFCOUNT), 머지하는(PFMERGE) 3가지 기능 제공

예제

> PFADD visitors user1 user2 user3
(integer) 1
> PFCOUNT visitors
(integer) 3

Pub/Sub & Streams

  • Pub/Sub는 게시자가 채널에 메시지를 보내고 구독자가 관심 있는 채널로부터 메시지를 받는 구조(하지만 채팅에는 부적합)
  • 특징
    • 채널에 대한 메시지 게시 및 하나 이상의 채널에 대한 메시지 구독을 지원. 메시지가 딱 한번만 전달됨
    • 패턴 기반 구독을 제공하여 구독자가 지정된 패턴과 일치하는 채널로부터 메시지를 받을 수 있음
    • 구독자에게 비동기식 메시지 전달 및 알림을 제공
  • 명령어 예
    • PUBLISH: 지정된 채널에 메시지를 게시
    • SUBSCRIBE: 하나 이상의 채널을 구독
    • PSUBSCRIBE: 지정된 패턴과 일치하는 채널을 구독

예제

> PUBLISH notifications "New message received"
(integer) 1
> SUBSCRIBE notifications
Reading messages... (waiting for messages)
1) "subscribe"
2) "notifications"
3) (integer) 1
> PSUBSCRIBE notif*
Reading messages... (waiting for messages)
1) "psubscribe"
2) "notifications"
3) (integer) 1

Stream

  • 스트림은 Redis 5.0에 도입된 추가 전용 로그 데이터 구조. 메시지 대기열 또는 이벤트 로그와 유사하며 높은 처리량, 실시간 데이터 수집 및 소비자 그룹 지원을 통해 이벤트 스트림을 처리하도록 설계
  • 특징
    • 구조화된 이벤트 데이터를 메시지로 저장
    • 스트림에 메시지 추가, 스트림에서 메시지 읽기, 처리된 메시지 확인과 같은 작업을 지원
  • 명령어 예
    • XADD: 스트림에 새 항목(메시지)을 추가
    • XREAD: 하나 이상의 스트림에서 메시지를 읽음
    • XGROUP: 스트림 처리를 위한 소비자 그룹을 관리함

예제

> XADD stream1 * sensor_id 123 temperature 25.5
"1588848580226-0"
> XREAD COUNT 1 STREAMS stream1 0
1) 1) "stream1"
   2) 1) 1) "1588848580226-0"
       2) 1) "sensor_id"
          2) "123"
          3) "temperature"
          4) "25.5"
> XGROUP CREATE stream1 consumer-group1 $
OK

LUA Scripts

  • LUA 스크립트를 통해 여러 커맨드를 한번에 실행 가능. RDB의 Function 같은 역할
  • 특징
    • 단일 작업으로 처리되며 다른 명령이나 클라이언트에 의해 중단되지 않음.
    • Lua 스크립트는 단일 트랜잭션 내에서 여러 Redis 명령을 수행하여 모든 명령이 실행되거나 실행되지 않도록 할 수 있음
    • Lua 스크립트는 Redis 서버 내에서 직접 실행되어 네트워크 오버헤드를 최소화하고 데이터 조작 및 처리에 효율적인 성능을 제공
  • 사용 예
    • Lua 스크립트를 사용하여 Redis에서 속도 제한 메커니즘을 구현한다고 가정
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local current = tonumber(redis.call('GET', key) or "0")

if current + 1 > limit then
    return 0
else
    redis.call('INCR', key)
    redis.call('EXPIRE', key, 60)
    return 1
end

'스터디-ing > Cloud' 카테고리의 다른 글

[S3] Signed URL로 파일 업로드, 트래픽 줄이기  (0) 2024.05.24
[Redis] Common In-Memory Use Cases  (0) 2024.05.23
[Redis] AWS Redis에 대해  (0) 2024.05.23