본문 바로가기
DB

[Redis] 공식문서를 보면서 Redis에 대해 알아보자!

by 떤떤 2023. 7. 19.

key-value 구조이며 in-memory 저장으로 인해 데이터 처리 속도가 빠르다고 잘 알려진 Redis에 대해서 알아보겠습니다. 저는 로그인 세션 관리나 자주 읽어오는 데이터를 캐싱할 때 쓰거나 실시간 업데이트를 위해서 사용 해봤었는데요. 생각보다 제공하는 기능들이 많은 것 같아서 공식 문서를 보면서 공부하는 시간을 가져보자 합니다.

 

Redis(Remote Dictionary Server)란?

데이터베이스, 캐시, 메시지 브로커, 스트리밍 엔진으로 사용되는 오픈소스 in-memory 데이터 구조 저장소입니다.

원래 BSD 라이선스였으나 향후 릴리스에서 이중 라이선스(RSALv2 또는 SSPLv1 중 선택)가 적용 될 거라고 합니다.

in-memory 저장이란?

데이터를 메모리(RAM)에 저장하고 관리합니다. 메모리 내에 저장하므로 디스크 기반 데이터베이스 보다 훨씬 읽고 쓰기가 훨씬 빠릅니다. 왜냐하면 메모리는 CPU가 직접 접근할 수 있지만 디스크 같은 보조기억장치는 직접 접근할 수 없기 때문입니다.

속도는 빠를 수 있으나 메모리는 휘발성이기 때문에 중요한 정보인 경우 하드디스크와 같은 보조기억장치에 저장해야 합니다.

 

어떤 이유로 만들어졌을까?

Salvatore Sanfilippo(a.k.a. antirez)라는 개발자가 실시간 웹 로그 분석 기능을 개선하기 위한 목적으로 만들어졌다고 합니다. 당시 사용자의 웹사이트 방문을 실시간으로 추적하고 분석하는 서비스를 제공하고 있었는데, 기존의 디스크 기반 데이터베이스로 데이터를 읽고 쓰기에는 속도와 효율성이 부족하다고 생각되어 메모리 기반의 데이터 저장 시스템을 개발했다고 합니다.

분석이 끝난 로그 데이터는 삭제하는 걸까요..?

 

제공하는 데이터 유형들

Strings

  • 가장 기본적인 데이터 구조 유형
  • 텍스트, 직렬화된 객체 및 이진 배열 등의 바이트 시퀀스 저장
  • 캐싱, 카운터, 비트 연산 등 다양한 용도로 사용
  • 대부분 시간 복잡도 O(1) 이지만 SUBSTR, GETRANGE, SETRANGE 과 같은 명령어 수행 시 O(n)
    (대용량 문자열 처리 시 성능 문제 발생 할 수 있음)
  • 기본적으로 하나의 문자열은 최대 512 MB까지 가능

Lists

  • 문자열 값의 연결 리스트
  • 큐 또는 스택 구현, 백그라운드 워커 시스템에 대한 대기열 관리 구축 등의 용도로 사용
  • 리스트의 head 또는 tail에 접근 시 시간복잡도 O(1)이지만, 리스트 내 요소를 조작하는 명령은 일반적으로 O(n)
  • 리스트 최대 길이는 2^31 - 1 (4,294,967,295) 까지 가능

Hashes

  • 필드와 값의 매핑을 저장하는 레코드 타입
  • 사용자 프로필, 객체 특성 등과 같이 구조화된 데이터 저장 시 유용
  • 대부분 시간 복잡도는 O(1) 이지만, HKEYS, HVALS, HGETALL 과 같은 명령어 수행 시 O(n)
  • 해시는 최대 4,294,967,295 (2^32 - 1) 개의 필드-값 쌍 저장 가능
  • 실제로 해시의 크기는 Redis가 설치된 VM의 전체 메모리에 의해서만 제한됨

Sets

  • 중복 없이 고유한 문자열 요소들의 모음
  • 태그, 구독자 목록, 친구 목록 등을 관리 시 유용
  • 최대 크기  2^32 - 1 (4,294,967,295) 까지 가능
  • 대부분 시간 복잡도는 O(1) 이지만, SMEMBERS 명령어 수행 시 전체 목록을 단일 응답으로 반환해서 O(n)
    대안으로 SSCAN을 사용해서 반복적으로 검색하는 것이 좋음 

Sorted sets

  • 중복된 요소 없이 집합의 각 요소에 대해 순서가 지정된 값(스코어)를 가짐
  • 리더보드(랭킹), 범위 쿼리 등과 같은 경우 유용
  • 대부분 시간 복잡도는 O(log(n)) 이지만, 대량의 반환 값을 처리할 때 ZRANGE 명령어 수행 시 O(log(n)+m)
    (n = 멤버의 수, m = 반환된 결과의 수)
  • 집합 A와 B가 있다고 가정했을 때 동일한 점수라면 A 문자열이 B문자열보다 사전식으로 크다면 A > B

0 -1은 요소 인덱스 0부터 마지막 요소까지 조회

Bitmap

  • 문자열 유형에 정의된 비트 지향 작업 집합 (빅트 벡터처럼 취급)
  • 주로 특정 상태의 여부를 나타내는 데 사용
    •   a. 특정 위치의 비트를 설정하여 해당 위치에 해당하는 요소가 집합에 속하는지에 대한 여부
    •   b. 각 비트를 특정 권한에 매핑하여 객체의 권한 나타내는 데 사용 (e.g. 파일 시스템 rwx 권한)
  • offset으로 비트 설정 가능, offset은 0부터 2^32-1까지만 지정 가능
  • offset이 2^32-1인 경우 키에 저장된 문자열 값이 작거나 보유하지 않을 때
    Redis는 모든 중간 메모리를 할당해야 하므로 서버를 잠시 차단할 수 있음

예시)

1000명의 자전거 선수가 자전거에 부착된 센서를 통해 추적 서버에 연락했는지 여부 확인 시

센서는 0~999까지 선수 인원에 맞게 라벨 지정된다.

  1. 라이더123은 2024년 1월 1일 0시에 서버에 연락했을 때 1로 설정
  2. 라이더456이 2024년 1월 1일 0시에 서버에 연락했는지 확인 했을 때 한적 없으므로 0으로 조회됨

Hyperloglogs(HLL)

  • cardinality(집합의 기수)를 추정 시 사용되는 확률적 데이터 구조
  • 효율적인 공간 활용을 위해 완벽한 정확성 대신 확률적인 데이터 구조 사용
  • 데이터를 요약하여 대략적인 카운트를 제공, 정확한 수치는 아니지만 오차율 0.81% 내외
  • 메모리 사용량이 매우 낮게 유지됨, 최대 12KB
    • 일반적으로 아이템의 수에 비례하여 메모리 양이 필요하지만(중복 아이템 체크하기 위함)
      HLL 구현에 사용하는 알고리즘은 세고자 하는 아이템의 수에 비례하는 메모리 양을 더 이상 사용하지 않아도 됨(대신 상수 메모리 양을 사용할 수 있음)
  • 고유 방문자 수 같은 지표를 계산하는 데 많이 사용됨 (e.g. 이 영상을 몇 명의 고유한 사용자가 시청했는지)
  • 최대 18,446,744,073,709,551,616 (2^64) 개의 멤버를 갖는 cardinality(집합의 기수)를 추정할 수 있음

bikes, commuter_bikes에 바이크 추가
두 집합을 병합했을 때 고유한 멤버 수의 근사치

 

Hyperloglog 알고리즘 설명자료 링크

http://redisgate.kr/redis/command/hyperloglog.php

https://d2.naver.com/helloworld/711301

geospatial indexes

  • 좌표를 저장하고 해당 좌표를 검색하는 데 사용
  • 특정 반경 내의 인접한 지점을 찾는 데 유용
  • Sorted Set을 기반, Geohash 기술을 사용해서 위도와 경도를 조합하고 고유한 52비트 정수로 변환하여 구현

자전거 대여소의 위도와 경도 그리고 자전거 대여소 정보 추가
특정 위치에서 5km 반경 내의 자전거 대여소와 남은 거리 조회

streams

  • 일반적인 append-only 로그의 한계를 극복하기 위해 여러 작업을 구현하는 데이터 구조
  • 각 스트림 항목(stream entry)은 하나 이상의 필드-값 쌍으로 구성되어 있으며, dictionary나 Redis hash와 비슷
  • 각 스트림 항목에 대한 고유한 ID가 생성되고 이 ID를 사용하여 스트림의 나중에 연결된 모든 항목을 읽고 처리 가능
  • ID는 <millisecondsTime>-<sequenceNumber> 조합
    • 로그 파일과 유사
    • 추가된 새 항목은 과거 항목보다 높은 ID로 생성
    • 밀리초시간(millisecondsTime)은 로컬 Redis 노드의 로컬 시간이지만 현재 밀리초 시간이 이전 항목 시간보다 작은 경우 이전 항목 시간이 대신 사용됨
  • 스트림에서 데이터 추출 3가지 방법
    • 범위 쿼리: 시간 범위 별로 메시지 가져오거나 커서를 사용하여 모든 이력을 점진적으로 확인
    • 실시간 구독: 새 항목이 스트림에 추가 될 때마다 클라이언트가 수신
    • consumer 그룹을 통한 처리: 여러 consumer 그룹이 스트림의 메시지를 처리할 수 있도록 구성 후 각 그룹은 자체 consumer를 가지며 메시지 처리
  • 사용 사례
    • 이벤트 소싱 (e.g. 사용자 작업, 클릭 추적 등)
    • 센서 모니터링 (e.g. 현장 장치에서의 읽기)
    • 알림 (e.g. 각 사용자의 알림 기록을 별도의 스트림에 저장)
  • 항목 추가, 삭제 시간복잡도는 O(1) 이지만, 어떤 단일 항목에 대한 접근은 O(n)
    (n은 ID의 길이, 일반적으로 스트림 ID는 짧고 고정 길이라 상수 시간 조회로 축소될 수 있음)

race:france key의 스트림에 rider name, speed, position, location_id 항목 추가('*'은 서버에서 새 ID 생성)
1712836150041-0 부터 시작하는 스트림 항목 두 개 조회

제공하는 기능들

  • 복제(Replication)
  • 루아 스크립팅(Lua scripting)
  • LRU 추방(LRU eviction)
  • 트랜잭션
  • 다양한 수준의 디스크 기본 영속성
    • 두 가지 메커니즘 제공
    • RDB(Redis Database), AOF(Append Only File) 데이터 영구 저장 지원
  • Redis Sentinel을 통한 고가용성
  • Redis Cluster를 통한 자동 분할 기능

 

Redis에서 데이터 유형 별로 제공해주는 커맨드는 굉장히 많습니다.

글에 다 담기엔 길어질 것 같아서 공식 문서를 확인하면 좋을 것 같습니다.

 

Redis에서 다양한 데이터 구조를 살펴봤는데 제대로 알지 못하고 사용했다는 것에 아쉬운 마음 뿐입니다.

Hyperloglog 알고리즘은 이번에 처음 알게 되었는데 개념 이해하는데도 오래 걸렸습니다. 왜 이렇게 공부할게 많은 걸까요?

그래도 이번에 알게 되었으니 개발 할 때 다양하게 사용해봐야겠습니다!

'DB' 카테고리의 다른 글

[MySQL] 특정 쿼리 결과 세로 출력  (0) 2024.03.23
sequelize dataTypes  (0) 2021.01.14
[MySQL] 데이터 수정  (0) 2020.11.28
[MySQL] 외래키로 설정되어 있는 키 속성 변경하기  (0) 2020.10.18
[MySQL] 컬럼 값 더하기  (0) 2020.10.11