Dragonflydb Replication and High Availability


복제 및 고가용성 (Replication And High Availability)

Dragonfly는 Redis를 대체할 수 있는 고성능 인메모리 데이터베이스입니다. 버전 1.0부터 프로덕션 환경에서 사용할 수 있는 데이터베이스 복제(Replication) 기능을 지원하여, 고가용성(HA) 아키텍처 구축 및 Redis로부터의 마이그레이션을 쉽게 만들어 줍니다.

⬜️ Dragonflydb Replication and High Availability 원문(영어)

📦 데이터베이스 복제란 무엇인가요? (What is database replication?)

데이터베이스 복제는 기본(Primary) 데이터베이스의 내용을 대개 서로 다른 서버에서 실행 중인 복제본(Replica) 데이터베이스로 지속적으로 복사하는 프로세스입니다. 동일한 데이터베이스의 복사본을 여러 개 유지하면 시스템의 단일 장애점(SPOF, Single Point of Failure)을 방지할 수 있습니다. 기본 노드에 장애가 발생하면 복제본이 새로운 마스터 노드로 자동 승격되어 새로운 데이터 쓰기 대상이자 다른 남은 복제본들의 데이터 소스가 됩니다. 이를 통해 시스템은 데이터 손실, 성능 저하 또는 다운타임 없이 장애로부터 회복할 수 있습니다.

💡 해설
• 핵심 개념: 복제(Replication)의 기본 정의인 Primary-Replica(마스터-슬레이브) 구조를 설명합니다.
• 목적: 서버 한 대가 죽어도 서비스가 중단되지 않도록 단일 장애점(SPOF)을 제거하는 것입니다.
  메인 서버가 죽으면 복제본이 왕관을 이어받아(자동 승격) 서비스를 지속합니다.

📦 복제는 고가용성에 어떻게 도움이 되나요?
(How does replication help with high availability?)

데이터베이스 복제는 고가용성 인메모리 데이터베이스 시스템의 초석 중 하나입니다. 복제가 없다면 데이터베이스가 다운되었을 때 백업 파일로부터 수동으로 복구해야 합니다. 이는 시간이 오래 걸릴 뿐만 아니라, 가장 치명적인 점은 마지막 백업 이후에 데이터베이스에 기록된 모든 데이터를 잃게 된다는 것입니다. 불안정성이나 장애를 감지하는 모니터링 시스템과 함께 신뢰할 수 있는 데이터베이스 복제 구현체를 사용하면, 애플리케이션은 기본 데이터베이스 노드의 장애 발생 시 복제 노드로 자동 전환(Fallback)되어 정상적으로 계속 작동할 수 있습니다.

💡 해설
• 문제 제기: 복제가 없으면 장애 발생 시 '수동 복구'를 해야 하므로 시간이 오래 걸리고, 마지막 백업 이후의 데이터는 영영 사라집니다.
• 해결책: 복제 시스템과 모니터링 툴을 결합하면 시스템이 알아서 장애를 감지하고 복제본으로 전환하므로, 사용자는 서버가 터졌는지도 모르게 서비스를 이용할 수 있습니다.

📦 Dragonfly 복제 작동 방식 (How Dragonfly replication works)

개발자 입장에서 Dragonfly의 복제는 Redis 복제와 동일하게 작동하며, 호환성과 학습 편의성을 위해 완전히 동일한 API를 구현했습니다. 하지만 그 밑바탕에 흐르는 코드는 전부 Dragonfly의 자체 기술입니다. 핵심적인 차이점 중 하나는 성능에 큰 영향을 주지 않으면서도 복제를 안정적으로 만드는 Dragonfly만의 스냅샷 알고리즘입니다.

Dragonfly는 스레드당 하나의 연결을 사용하여 서로 다른 연결을 통해 데이터를 병렬로 복제할 수 있는 무공유(Shared-nothing) 아키텍처를 사용합니다. 이 아키텍처는 Dragonfly가 멀티스레드를 활용할 수 있도록 설계되었기 때문에 가능하며, 덕분에 엄청나게 빠릅니다. 저장된 데이터는 Dragonfly 내의 여러 샤드(Shard)에 분산되며, 각 샤드는 서로 다른 키 세트를 보유합니다. Dragonfly의 멀티스레드 디자인의 일환으로, 각 스레드는 특정 샤드를 책임지고 해당 샤드의 데이터를 복제하는 등의 작업을 수행합니다.

복제가 시작되려면 핸드셰이크(Handshake) 단계가 발생하며, 여기서 복제본과 마스터의 각 샤드 스레드 간에 연결이 열려 복제본으로 데이터를 전송합니다.


• [설명] 복제본이 마스터 노드와 연결을 설정하고 메타데이터 세부 정보를 교환합니다.

이러한 연결이 설정되면 "전체 동기화(Full Synchronization)" 단계가 진행됩니다. 이때 전체 데이터 세트가 마스터에서 복제본으로 복사됩니다. 전체 데이터베이스 스냅샷이 복사되는 동안 마스터 데이터베이스에서 발생하는 모든 업데이트는 복제본에 병렬로 전송됩니다. Dragonfly의 스냅샷 알고리즘은 파이버(Fibers, 경량 스레드 구조)를 사용하기 때문에 스냅샷 생성과 업데이트가 병렬로 일어날 수 있습니다.


• [설명] 전체 스냅샷과 함께 업데이트 사항이 복제본으로 푸시되므로, 상당한 양의 메모리를 절약하고 프로세스를 더 안정적으로 만듭니다.

각 샤드가 전체 동기화에서 자신의 역할을 마치면 상태를 "스트리밍 상태(Streaming State)"로 변경하며, 이는 복제본에 업데이트를 보내는 최종 단계인 "안정적 동기화(Stable Synchronization)" 단계를 시작할 준비가 되었음을 의미합니다. 모든 샤드가 이 상태가 되면 안정적 동기화 단계가 시작됩니다.

안정적 동기화 단계는 Dragonfly 복제의 표준 운영 단계입니다. 기본 데이터베이스에 업데이트가 발생할 때마다 변경 사항이 복제본으로 비동기식으로 스트리밍됩니다.

💡 해설
• 겉은 Redis, 속은 뼈대부터 다름: 겉보기엔 Redis 명령어를 그대로 쓰지만, 내부 아키텍처는 완전히 다릅니다.
• 멀티스레드 기반 샤딩: Redis가 단일 스레드로 끙끙앓는 반면, Dragonfly는 스레드마다 샤드(데이터 조각)를 하나씩 붙여서 병렬로 복제를 처리합니다. 속도가 빠를 수밖에 없는 구조입니다.
• 파이버(Fibers) 기술 활용: 전체 데이터를 복사(Full Sync)하는 와중에도 새로 들어오는 데이터 변경 사항을 버퍼에 가두지 않고 '파이버'를 이용해 실시간 병렬 전송합니다.

📦 Dragonfly 복제가 Redis와 다른 점
(How replication in Dragonfly is different from that in Redis)

Redis는 복제 프로세스에 단일 스레드를 사용하는 반면, Dragonfly는 멀티스레드이며 사용할 수 있는 모든 CPU 스레드를 복제 프로세스에 동원할 수 있습니다. 이 때문에 Dragonfly는 샤드 데이터를 병렬로 복제할 수 있어 복제 속도가 매우 빠릅니다.

Dragonfly의 효율적인 스냅샷 알고리즘 덕분에 복제본에 전체 스냅샷을 보내는 동시에 업데이트 명령도 함께 보낼 수 있습니다. 반면 Redis는 전체 스냅샷을 먼저 보내고, 스냅샷 생성이 완료될 때까지 업데이트 명령을 인메모리 버퍼에 저장한 후 나중에 복제본으로 전송합니다.

이러한 Redis의 복제 방식은 아래에서 설명하듯 거대한 메모리 스파이크(급증)를 유발할 수 있습니다. 이는 페이지 메모리가 복제되는 지연된 기록 중 복사(Lazy Copy-on-Write) 작업을 사용하기 때문에 발생합니다. 즉, 데이터베이스 크기가 커질수록 작은 쓰기 작업도 많은 메모리를 사용할 수 있습니다. 결과적으로 메모리가 순식간에 100% 용량에 도달하여 대규모 지연 시간(Latency) 스파이크가 발생합니다.

복제 중에 Redis의 메모리 사용량이 두 배로 뛰는 것은 흔한 일입니다. 이러한 현상은 큰 스파이크 형태로 일어나기 때문에 메모리 사용량을 예측하기 어렵게 만듭니다. 따라서 Redis를 사용하는 경우, 시스템이 메모리 부족으로 크래시(Crash)되는 것을 막기 위해 서버를 오버프로비저닝(필요 이상으로 과다 할당)해야 합니다. 반면 Dragonfly에서는 복제로 인한 메모리 오버헤드가 일정하며 데이터 세트 크기의 영향을 받지 않습니다. 덕분에 고가용성이 필요하지만 예상치 못한 트래픽 급증을 감당하기 위해 유휴 용량을 계속 온라인 상태로 유지(과다 비용 지출)하기 어려운 상황에 적합합니다.

마지막으로 언급할 만한 Redis 복제의 문제점은 스냅샷 복사 중에 업데이트를 저장하는 버퍼의 크기가 제한되어 있다는 점입니다. 워크로드가 높을수록 이 버퍼가 가득 찰 확률이 높아집니다. 버퍼가 꽉 차면 복제 프로세스가 아예 처음부터 다시 시작됩니다. 그 후 똑같은 문제가 반복됩니다. 버퍼가 다시 가득 차고 복제가 재시작되면서 끝없는 복제 루프(Infinite Replication Loop)에 빠지게 됩니다. Dragonfly의 스냅샷 알고리즘에는 복제 버퍼가 필요하지 않습니다. 대신 업데이트를 복제본에 즉시 전송합니다. 덕분에 복제 프로세스가 매우 안정적이며, 서버는 데이터를 복제하는 중에도 높은 워크로드를 안전하게 처리할 수 있습니다.

💡 해설
• Redis의 고질병 1 (메모리 뻥튀기): Redis는 복제할 때 OS의 `Copy-on-Write(CoW)` 기능을 씁니다. 이때 쓰기 작업이 들어오면 메모리 페이지가 복사되면서 메모리 사용량이 최대 2배까지 치솟습니다(메모리 스파이크). 이를 버티려면 돈을 더 내고 사양 좋은 서버를 사야 합니다(오버프로비저닝). Dragonfly는 독자 알고리즘으로 메모리 증가량이 일정합니다.
• Redis의 고질병 2 (무한 복제 지옥): Redis는 백업 중 들어오는 명령어를 일시적으로 '버퍼'에 담아두는데, 트래픽이 몰려 버퍼가 꽉 차면 복제가 터지고 처음부터 다시 시작합니다. 이게 반복되면 대형 장애가 터집니다. Dragonfly는 버퍼를 쓰지 않고 실시간 전송하므로 이 지옥에서 탈출할 수 있습니다.

📦 Redis와 Dragonfly 비교 — 벤치마크 테스트
(A comparison of Redis and Dragonfly — benchmark tests)

우리는 복제 진행 중 Redis와 Dragonfly의 성능을 테스트했습니다. 본 테스트는 36개의 가상 CPU와 96 GiB RAM을 갖춘 AWS `c5n.9xlarge` 인스턴스에서 Redis와 Dragonfly 단일 인스턴스를 대상으로 진행되었습니다. 테스트에는 Redis Labs의 `memtier_benchmark` 툴을 사용했습니다.

테스트 결과, 복제 중 Dragonfly의 처리량(Throughput)은 Redis보다 7.6배 빨랐으며, 평균 지연 시간은 7.6배 낮았고, 꼬리 지연 시간(P99 Latency)은 3.3배 낮았습니다. 또한 복제의 "전체 동기화(Full Sync)" 단계는 Dragonfly가 Redis보다 5.5배 쾌속이었으며, Redis와 달리 Dragonfly는 눈에 띄는 메모리 스파이크가 전혀 없었습니다.


• [설명] 처리량(Throughput): 복제 중 Dragonfly의 처리량은 초당 1,205,511.27 작업이었던 반면, Redis는 159,222.92 작업에 그쳤습니다.


• [설명] 평균 지연 시간(Average Latency): 복제 중 평균 지연 시간은 Dragonfly가 초당 0.44763 ms, Redis가 3.39067 ms로, Dragonfly가 높은 처리량과 낮은 지연 시간을 동시에 달성할 수 있음을 보여줍니다.


• [설명] P99 지연 시간(P99 Latency): 복제 중 P99 지연 시간은 Dragonfly가 2.399 ms, Redis가 7.839 ms였습니다. Dragonfly는 복제 프로세스가 메모리 스파이크를 일으키지 않기 때문에 꼬리 지연 시간(최악의 지연 시간)이 낮게 유지됩니다.


• [설명] 풀 동기화 속도 및 메모리(Memory Usage): Dragonfly의 풀 동기화 단계는 Redis보다 5.5배 빠르며, Redis가 복제 중 대규모 메모리 스파이크로 고통받는 반면 Dragonfly는 눈에 띄는 메모리 급증이 없습니다.  RDB(dfs) save는 물론이고 복제(Replication) 동안에도 메로리 급증이 없습니다.

💡 해설
• 수치 기반의 압승: Dragonfly 측의 자사 벤치마크 결과이지만, 멀티스레드의 이점을 극한으로 보여줍니다. 복제 작업이 부하를 주고 있는 상황에서도 처리량은 7.6배 많고, 반응 속도(지연 시간)는 훨씬 짧습니다.
• 시스템 안정성의 척도인 P99 Latency(상위 1%의 느린 요청) 역시 안정적인데, 이는 앞서 말한 메모리 스파이크가 없기 때문입니다.

📦 고가용성을 위한 Dragonfly 복제 구성 및 관리 방법
(How to configure and manage Dragonfly replication for high availability)

당사의 복제 문서는 Dragonfly 복제를 관리하고 복제 기능을 사용하여 Redis에서 Dragonfly로 마이그레이션하는 방법에 대한 자세한 내용을 제공합니다. Dragonfly의 복제 관리 API는 Redis API와 완전히 호환되며 사용자가 사용하는 두 가지 명령어인 `ROLE` 및 `REPLICAOF` (또는 `SLAVEOF`)로 구성됩니다.

API를 직접 사용하는 대신, Redis Sentinel과 같은 고가용성 모니터링 시스템을 사용하여 장애 조치(Failover)를 자동으로 관리할 수 있습니다. Dragonfly는 Redis Sentinel과 완벽히 호환되므로, Sentinel이 마스터 인스턴스의 장애를 감지하고 복제본을 다음 마스터 노드로 자동 승격할 수 있습니다.

💡 해설
• Drop-in Replacement (말 그대로 갈아 끼우기): 기존에 Redis에서 쓰던 복제 명령어(`REPLICAOF`)가 그대로 먹힙니다.
• 심지어 Redis의 오픈소스 장애조치 시스템인 Redis Sentinel도 그대로 호환됩니다. 즉, 기존 인프라와 모니터링 환경을 바꾸지 않고 알맹이(DB 엔진)만 Dragonfly로 쏙 바꿀 수 있다는 뜻입니다.


Email 답글이 올라오면 이메일로 알려드리겠습니다.