CS/기타

Redis에 대해 알아보자 (자료구조, Cache)

Joonfluence 2024. 4. 14.

개요

  • 쿠팡에서 모든 상품이 품절 표시되는 문제가 발생하였다. 레디스 DB 때문이란 발표가 있었다.
  • Redis(Remote Dictionary Server)
    • Remote : 외부
    • Dictionary : Key-Value 형태 값 저장소
    • Server : 서버
  • Database, Cache, Message Broker로도 사용할 수 있다.
  • In-memory Data Structure Store
  • Supports rich data structures

Redis 자료구조

  • 비교군인 Memcached에선 Collection을 제공함.
  • String, Lists, Sets, Sorted Sets, Hashes 등이 있다. 용도에 따라, 아래와 같이 사용할 수 있다.
    • String
      • 독립적이고 연결하거나 정렬할 필요가 없는 경우
    • Lists
      • 시간순으로 저장되어야 하는 데이터, 순서가 필요한 데이터
        • LPUSH (생성), LRANGE (조회)
    • Sets
      • 글 간의 고유성을 보장해야 하는 경우
    • Sorted Sets
      • 순서를 보장하면서 고유성을 보장해야 하는 경우
    • Hashes
      • 글에 다양한 속성(예: 제목, 콘텐츠, 작성자)이 있는 경우 Redis 해시가 유용할 수 있습니다. 각 글은 해시로 저장할 수 있으며, 글 ID는 키로, 속성은 해시 내의 필드로 저장할 수 있습니다.
    • Counting : 우리 사이트에 접속한 유저 수를 세고 싶을 때
      • Strings : 카운팅 상황마다 값을 증가시킬 때
      • Bits : 저장공간을 절약할 수 있다
      • HyperLogLogs : 대용량 데이터를 카운팅 할 때 적절함
    • Messaging
      • Lists : Blocking 기능을 이용해 Event Queue로 사용함
      • Streams : 로그를 저장하기 가장 적절한 자료구조이다
  • Java의 HashMap
    • Session 데이터를 자바 프로그램에서 관리하지 않는 이유는 서버가 여러 대인 경우, Consistency 문제가 발생하기 때문이다. 또한 Multi-Threaded 환경에서 Race Condition 문제가 발생할 수도 있다.
    • Race Condition이란 여러 개의 Thread가 경합하면서 Context Switching에 따라 원하지 않는 결과가 나오는 것을 말한다.
    • Redis에서는 이 문제를 어떻게 해결하냐면, Redis는 기본적으로 Single Thread인데 Atomic Crictical Session에 대한 동기화를 제공한다. 서로 다른 Transaction Read/Write를 동기화한다.
  • Redis는 여러 서버에서 같은 데이터를 공유할 때 사용한다. 만약 Single Server라면 Atomic 자료구조 & Cache로 활용 가능하다.

Redis와 Cache

  • 캐시란 나중의 요청에 대한 결과를 미리 저장했다가 빠르게 사용하는 것이다.
  • 그렇다면 어디에 저장하는 것이 효율적일까?
    • Memory Hierarchy에서 CPU Register (12MB Cache Memory - SRAM)는 빠르지만 용량이 너무 작으므로 Main Memory (DRAM)을 사용한다.

Caching Strategy

  • 읽기 전략
    • Look-Aside
      • 캐시를 한 번 접근하여 데이터가 있는지 판단한 후, 있다면 캐시의 데이터를 사용하고 없으면 실제 DB 또는 API를 호출한다.
      • 반복적인 읽기가 많은 호출에 적합하다.
      • Cache Warming 작업을 하기도 한다.
        • 이 방식은 캐시에 장애가 발생하더라도 DB에 요청을 전달함으로써 캐시 장애로 인한 서비스 문제는 대비할수 있지만, Cache Store와 Data Store(DB)간 정합성 유지 문제가 발생할 수 있으며, 초기 조회 시 무조건 Data Store를 호출 해야 하므로 단건 호출 빈도가 높은 서비스에 적합하지 않다. 대신 반복적으로 동일 쿼리를 수행하는 서비스에 적합한 아키텍처이다. 이런 경우 DB에서 캐시로 데이터를 미리 넣어주는 작업을 하기도 하는데 이를 Cache Warming이라고 합니다.
  • 쓰기 전략
    • Write-Around
      • Cache miss가 발생하는 경우에만 DB와 캐시에도 데이터를 저장 따라서 캐시와 DB 내의 데이터가 다를 수 있다 (데이터 불일치)
      • Write Around 패턴은 속도가 빠르지만, cache miss가 발생하기 전에 데이터베이스에 저장된 데이터가 수정되었을 때, 사용자가 조회하는 cache와 데이터베이스 간의 데이터 불일치가 발생하게 된다. 따라서 데이터베이스에 저장된 데이터가 수정, 삭제될 때마다, Cache 또한 삭제하거나 변경해야 하며, Cache의 expire를 짧게 조정하는 식으로 대처해야 한다.
    • Write-Through
      • 데이터베이스와 Cache에 동시에 데이터를 저장하는 전략
      • 데이터 유실이 발생하면 안 되는 상황에 적합
      • 매 요청마다 두번의 Write가 발생하게 됨으로써 빈번한 생성, 수정이 발생하는 서비스에서는 성능 이슈 발생

Redis 사용 시, 주의사항

  • Single Thread 서버이므로 시간 복잡도를 고려해야 한다.
    • keys * → scan으로 대체하자
    • Hash, Sorted Set 등 자료구조
      • hgetall → hscan
      • del → unlink
  • In-memory 특성 상, OS와 메모리에 대한 지식이 필요하다. 메모리 파편화나 가상 메모리 등
    • Event Driven
    • IO-bound Process
    • Context Switching 효율이 적다
    • Signle Threaded
  • Redis = Single Threaded, Simple
    • 네트워크로부터 요청을 받아서 명령어를 처리하는데, 명령어 처리가 오래 걸리는 경우 나머지 요청에 병목현상이 생길 수 있다.
    • 따라서 O(N)만큼의 시간이 소요되는 KEYS, Flush, GetAll 같은 연산 사용에 주의해야 한다.

Memory 관리

  • 메모리 파편화
    • 메모리를 할당 받고 해제하는 과정에서 부분 부분 빈공간이 생기게 된다. 이 때, 빈 공간보다 더 넓은 데이터 공간을 필요로 하는 경우, 실제 잔여 메모리보다 더 작은 공간 밖에 사용할 수 없게 된다.
  • 가상메모리 Swap
    • 전체 프로세스를 메모리에 올리지 않고 일부만 올려서 사용하는데, 덜 쓰이는 프로세스는 디스크에 저장했다 필요할 때 메모리에 올려서 사용한다.
    • 그 과정에서 Latency가 발생하게 되는데, Latency가 길어지게 된다면 문제가 발생할 가능성이 높아진다.
  • Replication - Fork
    • 휘발성을 가진 인메모리 저장소이므로 항상 유실될 가능성에 대해 대비해야 한다. 이에 대한 방안 중 하나로 데이터 복제 기능을 통해, DB Slave에 저장한다던지 Disk
    • 이 과정에서 복사가 일어날 때, fork 연산을 사용하여 프로세스를 동일하게 복제해서 사용하는 방식을 사용하는데, 이 과정에서 메모리가 가득 차있다면 복사본이 제대로 생성되지 않고 장애로 이어질 수 있어 유의해야 한다.

Persistence

  • 기본적으로 Redis는 In-memory 데이터 저장소기 때문에 캐시 이외의 용도로 사용한다면 적절한 데이터 백업이 필요하다.
  • AOF (Append Only File)
    • 주기적으로 압축해야 한다
    • 자동 : redis.conf 파일에서 auto
  • RDB (Snapshot)

아키텍처 종류

  • Replication
    • 단순한 복제 연결
      • replicaof 커맨드를 이용해 간단하게 복제 연결
      • 비동기식 복제
      • HA 기능이 없으므로 장애 상황 시 수동 복구
        • replicaof no one
        • 애플리케이션에서 연결 정보 변경
  • Sentinel
    • 자동 페일오버 가능한 HA 구성
      • sentinel 노드가 다른 노드 감시
      • 마스터가 비정상 상태일 때 자동으로 페일오버
      • 연결 정보 변경 필요 없음
      • sentinel 노드는 항상 3대 이상의 홀수로 존재해야 한다
        • 과반수 이상의 sentinel이 동의해야 페일오버가 진행됨
  • Cluster
    • 스케일 아웃과 HA 구성
      • 키를 여러 노드에 자동으로 분할해서 저장(샤딩)
      • 모든 노드가 서로를 감시하여, 마스터 비정상 상태일 때 자동 페일오버된다
      • 최소 3대의 마스터 노드가 필요하다

추가학습

  • 영속적으로 저장하기 위해선 Redis Persistence, RDB, AOF
  • Scale Out, Back Up을 하려면 Redis Cluster
    • 그 외 Redis 아키텍처와 관련된 건 Replication, Sentinel
  • 클러스터링이 된 서버에 대한 부하 분산을 위해 Constant Hashing
  • 데이터베이스를 사용하지 않고 인메모리 DB만 사용하는 Data Grid 방식으로 사용하기 위해 Spring Gemfire, Hazlecast

레퍼런스

https://www.youtube.com/watch?v=92NizoBL4uA&ab_channel=NHNCloud
https://www.youtube.com/watch?v=mPB2CZiAkKM&ab_channel=우아한테크

반응형

댓글