Redis 아키텍처

장민근·2025년 1월 25일
0

Redis

목록 보기
11/14

Redis의 아키텍처

1. Simple Database

Redis 메인 서버를 하나만 구동하는 형식의 아키텍처이다. 배포가 매우 간단하며, 사용자가 큰 어려움 없이 구축할 수 있다는 장점이 있다. 그러나 단 하나의 인스턴스만 사용하는 구조이기 때문에 해당 인스턴스에 문제가 발생하면 서비스 사용이 불가능해진다는 치명적인 단점이 있다. 즉, 고가용성을 보장하지 못한다.

하지만 단일 서버 구조로 인해 모든 서버 리소스를 Redis에 집중적으로 할당할 수 있어 비교적 높은 성능을 제공한다는 점은 장점이다. 이러한 이유로, 단일 서버로 충분한 성능을 낼 수 있는 소규모 애플리케이션에서는 Simple Database 구조를 사용하는 경우가 많다.

2. HA Database (High Availability)

HA (High Availability) Database는 Replica라는 복제본을 생성하여 구성하는 아키텍처이다. 메인 서버(Primary)와 복제 서버(Replica)로 나뉘어 구성되며, 메인 서버는 실제 데이터를 처리하는 인스턴스를 의미하고, 복제 서버는 메인 서버의 데이터를 복제한 인스턴스를 의미한다.

데이터 복제는 비동기 방식으로 동작하며, 메인 서버에서 처리된 명령들을 버퍼 형태로 복제 서버에 전달하여 데이터를 동기화한다. 이 아키텍처는 메인 서버가 장애를 일으키더라도 복제 서버가 데이터를 보유하고 있어 어느 정도의 가용성을 보장한다.

그러나 HA Database는 자동화된 장애 복구(Auto-Failover)를 지원하지 않는다. 메인 서버에 장애가 발생했을 경우, 복제 서버를 메인 서버로 전환하려면 수동으로 SLAVEOF NO ONE 명령을 실행하여 메인-서브 관계를 끊고, 애플리케이션에서 Redis와의 연결 설정을 수정해야 한다. 이러한 과정은 서비스 중단 시간을 증가시킬 수 있어 실시간 장애 복구가 중요한 환경에서는 적합하지 않다.

그럼에도 불구하고, 읽기 요청은 복제 서버를 통해 분산 처리할 수 있어, 읽기 작업이 많은 경우 성능을 향상시킬 수 있다. 따라서 읽기 중심의 워크로드를 처리하는 애플리케이션에서 주로 사용된다.

HA(High Availability)란?

HA는 "High Availability"의 약자로, 이를 직역하면 고가용성을 의미한다. 이는 시스템이나 서비스가 24시간 중단 없이 안정적으로 운영될 수 있도록 대비 체계를 마련하는 것을 말한다. 쉽게 말해, 예상치 못한 장애나 과부하 상황에서도 서비스가 계속 정상적으로 작동할 수 있도록 자동화된 복구 및 대비 기능을 제공하는 시스템을 의미한다.

고가용성의 간단한 예시
병원을 예로 들어보자. 병원은 24시간 운영되며 언제 환자가 올지 예측할 수 없기 때문에, 의료기기를 단 한 대만 보유하는 것이 아니라 여러 대를 동시에 준비해 둔다. 이는 의료기기의 고장이나 갑작스러운 상황에 대비하기 위함이다. 이처럼, 어떤 서비스가 예상치 못한 상황에 대비해 여유분의 자원을 준비하고, 장애 발생 시 빠르게 대처할 수 있는 구조를 가지는 것이 고가용성의 기본 개념이다.

플랫폼에서의 HA
플랫폼 운영에서도 고가용성은 중요하다. 예를 들어, 특정 서비스에서 장애가 발생했을 때, 복제본(Replica)을 사용해 서비스 중단을 방지하거나, 자동으로 새로운 인스턴스를 구동시켜 문제를 해결하는 방식이 고가용성의 대표적인 사례이다. 이러한 HA 시스템을 통해 사용자는 서비스를 지속적으로 이용할 수 있으며, 플랫폼 운영자는 장애에 대한 걱정을 줄일 수 있다.

Redis Sync

1. ID와 Offset 개념

Redis는 복제본(Replica)과 메인(Primary) 인스턴스 간 데이터 동기화를 통해 일관성을 유지한다. 이 과정에서 Redis는 ID와 Offset이라는 두 가지 핵심 개념을 사용한다. 먼저, 동기화 과정과 관련된 기본 개념을 살펴보자.

앞으로 나올 아키텍처는 기본적으로 동기화 개념이 필요하기 때문에 간단하게 동기화에 대해서 알아보도록 하겠다.

1.1 ID

  • Redis에서 ID는 데이터 복제 그룹을 식별하는 값이다. 같은 복제 그룹에 속한 메인 인스턴스와 복제 인스턴스들은 동일한 ID를 공유한다.
    이 ID를 기준으로 동기화가 필요한 인스턴스를 그룹핑하여 관리한다.

1.2 Offset

  • Offset은 Redis가 데이터를 동기화하는 과정을 추적하기 위해 사용하는 순차적으로 증가하는 정수 값이다.
  • 메인 인스턴스와 복제 인스턴스 간 현재 데이터 상태를 비교할 때 사용된다.
    예를 들어, 복제본의 Offset 값이 메인보다 작으면 아직 동기화가 완료되지 않은 상태를 의미한다.

2. 동기화 과정

2.1 정상 동기화

  • 복제본의 Offset 값이 메인 인스턴스의 Offset보다 낮은 경우, 메인 인스턴스는 차이가 나는 데이터를 복제본에 전송하여 동기화를 진행한다.
  • 이 과정에서 ID 값이 동일한 경우, Redis는 메인-복제본 간 동기화 작업만 수행하며 효율적으로 데이터를 맞춘다.

2.2 ID 값이 다른 경우

  • 복제본의 ID 값이 메인과 다른 경우, Redis는 해당 복제본이 이전 상태나 다른 그룹에 속한 것으로 간주한다.

  • 이때 Redis는 개별 동기화를 진행하지 않고, 네트워크 전체를 동기화하는 방식으로 문제를 해결한다.

  • RDB 스냅샷 생성: 메인 인스턴스는 데이터를 스냅샷으로 저장한다. 이는 Redis의 RDB 방식과 동일하게 동작하며, 복제본에 전송된다.

  • 버퍼링: 스냅샷 생성 이후 메인 인스턴스에서 처리된 추가 요청들은 버퍼에 임시 저장된다. 이 버퍼링 데이터도 복제본으로 전송되어 최신 상태로 동기화가 완료된다.

3. 동기화 결과

  • ID와 Offset이 동일한 경우:
    메인과 복제본이 완전히 동일한 상태로 동기화된 상태이다. 이 경우에는 별도의 작업이 필요 없으며, 가장 이상적인 환경이다.

  • ID는 같으나 Offset이 다른 경우:
    메인은 Offset 차이에 해당하는 데이터를 복제본으로 전송하여 동기화를 완료한다.

  • ID가 다른 경우:
    메인은 전체 데이터를 스냅샷 방식으로 복제본에 전송하고 추가 데이터를 버퍼링하여 전송한다.

버퍼링이라는 것은 Redis가 스냅샷을 생성하여 복제본에 전송하는 동안에도 클라이언트로부터 계속 들어오는 추가 요청 데이터를 임시로 저장했다가, 스냅샷 전송이 완료된 이후 복제본에 순차적으로 전송하는 과정을 말한다.
Redis는 동기화 시 현재 메인 서버의 스냅샷을 기반으로 동기화를 진행한다. 그와 동시에 클라이언트로부터 계속해서 오는 요청들은 추가 동기화를 위해 버퍼 영역에 잠시 보관한다.
그 이후 스냅샷을 기반으로한 동기화가 완료되었으면 나머지 버퍼에 있는 데이터 또한 동기화를 추가적으로 진행한다.
이로써 모든 동기화 과정이 완료되고 버퍼는 비활성화된다.

Redis Cluster

Redis Cluster는 Redis의 메모리 부족 현상을 해결하기 위한 아키텍처이다. 이 경우 Redis Cluster를 통해서 샤딩 기법을 적용하게 된다면 수평적인 확장과 데이터를 분산 저장하게 된다.
그렇다면 샤딩이 무엇일까 ?

다른 데이터베이스에서도 사용되는 개념인 샤딩은 데이터 분산 저장 기법을 말한다. 데이터를 특정 인스턴스에 분산 저장한다. 이렇게 된다면 하나의 인스턴스가 모든 데이터를 들고 있는 것이 아니기 때문에 메모리나 디스크 부족 현상을 피할 수 있다.

그렇다면 Redis에서는 이 샤딩 기법을 사용한다고 했는데 들어오는 데이터의 키값은 어떠한 기준으로 어떤 인스턴스에 저장이 되는걸까 ?

Redis는 샤딩을 진행할 때 자체적인 Redis 알고리즘을 통해서 샤딩을 진행하게 된다. ( 특정 키 값이 들어오면 어떤 샤드에 분산시킬지는 mod 16384 연산을 통해 진행한다고 한다, 이는 Redis의 자체 알고리즘이라고 한다. 그래서 강사님이 16k로 나눈 후 할당한고 하신듯 하다)

키값이 들어오게 되면 해당 키값을 먼저 해싱 처리하고 전체 샤드의 개수로 나눠준다. 그리고 해시 함수를 사용해서 해당 키값이 어떤 샤드에 위치해야 되는지를 결정을 한다. 이 과정을 통해서 키값이 어떤 샤드에 저장되는지 맵의 형태로 관리가 된다.
그렇기 때문에 Redis 입장에서는 키값이 들어왔을 때 유추가 가능하다.

이러한 경우에 추가적인 스케일 아웃이 발생하여 샤드의 갯수가 늘어난다면 기존 샤드 키를 다시 재정립할 필요가 있다.
모든 샤드의 키를 다시 정립하는건 Redis 입장에서는 부담이 될 수 있다. 이 문제를 해결하기 위해 Redis는 Hash Slot이라는 방법을 사용하고있다.

Hash Slot은 기본적으로 모든 데이터가 맵핑이 되어있고 16k의 사이즈를 가지고 있다.

에를 들어 A와 B라는 샤드가 있다고 하자. 그리고 각 샤드 노드마다 할당된 Hash Slot이 다음과 같다고 한다.
A: 0~8192
B: 8193~16384

이 상황에서 X라는 키값이 들어온다고 하면 16k로 나눈 후의 값을 9000이라고 해보자. 그럼 X라는 키값은 현재 상황에서는 B에 할당이 되게 된다.

여기에서 C라는 샤드가 새롭게 등장했다. C라는 샤드에서 담당할 수 있는 Hash Slot을 지정해줘야 한다.

C:8192~12287 이라고 하자.

A: 0~8192
C: 8193~12287
B: 12278~16384

이렇게 된다면 다시 재정립을 진행한다. 이는 Redis가 자체적으로 처리한다.

Clustered Database

해당 자료는 잘 정리된 블로그 글로 대체하도록 하겠다.

profile
안녕하세요!! 백엔드 개발자를 희망하는 취준생입니다 !!

0개의 댓글