Dragonflydb


Introduction

Dragonflydb 드래곤플라이DB 세상에서 가장 빠른 인-메모리 스토어
Dragonflydb를 소개하는 글입니다.

📦 주요 링크

📦 목차 Contents

📦 소개 Intro

Dragonfly is an in-memory data store built for modern application workloads.
Dragonfly는 현대 애플리케이션 작업을 위한 인-메모리 데이터스토어입니다.

Dragonfly는 Redis와 Memcached API와 완벽하게 호환되며, 이를 적용하기 위한 코드 변경을 필요로 하지 않습니다.   Dragonfly는 기존 인메모리 데이터스토어와 비교했을 때 25배 더 많은 처리량과 더 낮은 지연 시간(lower tail latency)과 함께 더 높은 캐시 적중률을 제공하며, 동일한 크기의 작업 부하에 대해 최대 80% 더 적은 리소스를 사용하여 실행할 수 있습니다.

📦 Benchmarks

◼️ m5.large 성능 테스트(싱글 스레드):
Redis는 원래 싱글 스레드이고 Dragonflydb는 멀티 스레드지만, 여기서는 동일한 조건에서 성능을 테스트하기 위해서 같은 싱글 스레드 머신(m5.large)로 테스트했습니다.
[memtier_benchmark -c 20 --test-time 100 -t 4 -d 256 --distinct-client-seed]

Dragonflydb는 Redis와 비슷한 성능을 보여줍니다. 싱글 스레드에서도 Dragonflydb는 Redis에 비해서 성능이 떨어지지 않는다는 것을 보여줍니다.

⦿ Test Server Spec: m5.large AWS
    - vCPU: 2
    - 메모리: 8 GiB
    - 네트워크 대역폭: 최대 10 Gbps
    - EBS 대역폭: 최대 4,750 Mbps
    - 프로세서: Intel Xeon Platinum 8175M, Intel Xeon Platinum 8259CL,
      또는 최신 세대의 커스텀 Intel Xeon 프로세서

◼️ m5.xlarge(vCPU: 4) 성능 테스트:
Dragonflydb 처리량은 인스턴스 크기에 따라 계속 증가하는 반면, 싱글 스레드 Redis는 CPU에 병목 현상이 발생하고 성능 측면에서 최대치에 도달합니다.
⦿ Test Server Spec: m5.xlarge AWS
    - vCPU: 4
    - 메모리: 16 GiB
    - 네트워크 대역폭: 최대 10 Gbps
    - EBS 대역폭: 최대 4,750 Mbps
    - 프로세서: Intel Xeon Platinum 8175M / 8275CL 또는 8259CL (AWS 전용 커스텀 2세대 Xeon)

◼️ 성능이 뛰어난 인스턴스 c6gn.16xlarge(vCPU: 64)에서 Dragonflydb와 Redis를 비교해 보면 Dragonflydb는 Redis 단일 프로세스에 비해 처리량이 25배 증가하여 380만 QPS를 넘었습니다.


파이프라인 모드 --pipeline=30 Dragonflydb는 SET 작업의 경우 1,000만 QPS, GET 작업의 경우 1,500만 QPS에 도달합니다.

⦿ Test Server Spec: r6g.16xlarge AWS
    - 프로세서: AWS Graviton2
    - vCPU: 64
    - 메모리: 512 GiB
    - 네트워크 대역폭: 최대 25 Gbps
    - EBS 대역폭: 최대 19 Gbps
    - 인스턴스 스토리지: N/A (EBS 전용)
    - 기타 특징: Arm 기반 AWS Graviton2 프로세서, 지원되는 AVX, AVX2, 그리고 NEON SIMD 명령어 세트

⦿ Test Server Spec: c7g.16xlarge AWS
    - 프로세서: AWS Graviton3
    - vCPU: 64
    - 메모리: 128 GiB
    - 네트워크 대역폭: 최대 30 Gbps
    - EBS 대역폭: 최대 20 Gbps
    - 인스턴스 스토리지: N/A (EBS 전용)
    - 기타 특징: Arm 기반 AWS Graviton3 프로세서, 개선된 컴퓨팅 성능 및 에너지 효율성,
      지원되는 AVX, AVX2, 그리고 NEON SIMD 명령어 세트

⦿ Test Server Spec: c6gn.16xlarge AWS
    - 프로세서: AWS Graviton2
    - vCPU: 64
    - 메모리: 128 GiB
    - 네트워크 대역폭: 최대 100 Gbps
    - EBS 대역폭: 최대 38 Gbps
    - 인스턴스 스토리지: N/A (EBS 전용)
    - 기타 특징: Arm 기반 AWS Graviton2 프로세서, 지원되는 AVX, AVX2, 그리고 NEON SIMD 명령어 세트

📦 Memory efficiency

메모리 효율성을 테스트하기 위해 우리는 "debug populate 5000000 key 1024" 명령을 사용하여 Dragonflydb와 Redis를 ~5GB의 데이터로 채웠고, bgsave 명령을 사용하여 스냅샷을 시작했습니다.
이 그림은 메모리 효율성 측면에서 각 서버가 어떻게 작동하는지 보여줍니다.
Dragonflydb는 유휴 상태에서 Redis보다 메모리 효율성이 30% 더 높았으며 스냅샷 단계에서는 메모리 사용량이 눈에 띄게 증가하지 않았습니다. 최고조에 달했을 때 Redis 메모리 사용량은 Dragonflydb의 거의 3배까지 증가했습니다.
Dragonflydb는 몇 초 내에 더 빠르게 스냅샷을 완료했습니다.
Dragonflydb의 메모리 효율성에 대한 자세한 내용은 Dashtable 문서(영문),   Dashtable 문서(한글)를 참조하세요.

📦 Configuration - 설정/구성

Dragonfly는 해당되는 경우 일반적인 Redis 인수를 지원합니다. 예를 들어, dragonfly --requirepass=foo --bind localhost를 실행할 수 있습니다.
Dragonfly는 현재 다음과 같은 Redis 관련 인수를 지원합니다.

  • port: Redis 연결 포트(default: 6379).
  • bind: localhost로컬 호스트 연결만 허용하거나 공용 IP 주소를 사용하여 해당 IP 주소에 대한 연결(예: 외부에서도 연결)을 허용하는 데 사용합니다. 0.0.0.0모든 IPv4를 허용하려면 사용합니다 .
  • requirepass: AUTH 인증을 위한 비밀번호(default: "")입니다.
  • maxmemory: 데이터베이스에서 사용하는 최대 메모리(사람이 읽을 수 있는 바이트 단위)에 대한 제한입니다(default: 0). 값 maxmemory은 0프로그램이 최대 메모리 사용량을 자동으로 결정함을 의미합니다.
  • dir: Dragonfly Docker는 /data기본적으로 스냅샷용 폴더를 사용하고, CLI는 "". Docker 옵션을 사용하여 -v이를 호스트 폴더에 매핑할 수 있습니다.
  • dbfilename: 데이터베이스를 저장하고 불러올 파일명(default: dump).

아래는 Dragonfly 전용 인수입니다:

  • memcached_port: Memcached 호환 API를 활성화하기 위한 포트입니다(default: disabled).
  • keys_output_limit: keys 명령(default: 8192)에서 반환된 키의 최대 개수입니다.
    이는 keys 위험한 명령입니다. 너무 많은 키를 가져올 때 메모리 사용량이 급증하는 것을 방지하기 위해 결과를 제한합니다.
  • dbnum: select에 대해 지원되는 최대 데이터베이스 수입니다.
  • cache_mode: 아래의 새로운 캐시 디자인 섹션 을 참조하세요.
  • hz: 키 만료 평가 빈도(default: 100).
    빈도가 낮을수록 제거 속도가 느려지므로 유휴 상태일 때 CPU를 덜 사용합니다.
  • snapshot_cron: 분 단위(default: "") 단위의 표준 크론 구문을 사용하는 자동 백업 스냅샷에 대한 크론 일정 표현입니다.
    아래에는 cron 일정 표현식의 예가 나와 있습니다.
  • primary_port_http_enabled: 참인 경우 기본 TCP 포트에서 HTTP 콘솔에 액세스하도록 허용합니다(default: true).
  • admin_port: 할당된 포트에서 콘솔에 대한 관리자 액세스를 활성화합니다(default: disabled).
    HTTP 및 RESP 프로토콜을 모두 지원합니다.
  • admin_bind: 관리 콘솔 TCP 연결을 지정된 주소에 바인딩합니다(default: any).
    HTTP 및 RESP 프로토콜을 모두 지원합니다.
  • admin_nopass: 인증 토큰 없이 할당된 포트의 콘솔에 대한 개방형 관리자 액세스를 활성화합니다(default: false).
    HTTP 및 RESP 프로토콜을 모두 지원합니다.
  • cluster_mode: 클러스터 모드가 지원됩니다(default: ""). 현재는 emulated.
  • cluster_announce_ip: 클러스터 명령이 클라이언트에 알리는 IP입니다.
  • announce_port: 클러스터 명령이 클라이언트와 복제 마스터에 알리는 포트입니다.

◻️ 널리 사용되는 옵션이 포함된 시작 스크립트 예:

인수는 다음을 통해 제공될 수도 있습니다.
• --flagfile <filename>: 파일은 키-값 플래그에 공백 대신 등호를 사용하여 한 줄에 하나의 플래그를 나열해야 합니다.   플래그 값에는 따옴표가 필요하지 않습니다.
• 환경 변수 설정. Set DFLY_x, x플래그의 정확한 이름은 대소문자를 구분합니다.

로그 관리 또는 TLS 지원과 같은 추가 옵션을 보려면 "dragonfly --help"를 실행하세요.

📦 Roadmap and status - 로드맵과 상태

Dragonfly는 현재 ~185개의 Redis 명령을 지원합니다. 이는 거의 Redis 5 API와 거의 동등하며, Dragonfly의 다음 이정표는 기본 기능을 안정화하고 복제 API를 구현하는 것입니다.
Draginfly 고유 복제기능을 위해, 저희는 몇 배 높은 속도를 지원할 수 있는 분산 로그 형식을 설계하고 있습니다. 복제 기능을 추가한 뒤에 저희는 Redis 3-6 API에 해당되는 누락 명령어들을 계속 추가할 예정입니다.
Dragonfly에 의해 현재 지원되는 명령어를 확인하기 위해서 명령어 레퍼런스를 참고해주시기 바랍니다.

📦 Design decisions - 설계 의사결정

◻️ Novel cache design - 새로운 캐시 설계

Dragonfly는 단순하고 메모리 효율적인 단일, 통합, 적응형 캐싱 알고리즘을 제공합니다.
--cache_mode=true 플래그를 전달하여 캐싱 모드를 활성화할 수 있습니다. 이 모드가 활성화되면, Dragonfly는 maxmemory 한도에 가까워질 때만, 미래에 재사용 될 가능성이 가장 낮은 항목을 방출합니다.

◻️ Expiration deadlines with relative accuracy - 상대적인 정확성을 가진 만료 기한

만료 범위는 최대 8년으로 제한됩니다.   밀리초 단위의 정밀한 만료 기한(PEXPIRE, PSETEX 등)은 2^28ms보다 큰 기한에 대해 가장 가까운 초로 반올림됩니다. 이는 0.001% 미만의 오차를 가지며, 큰 범위에 대해 적용될 때는 수용 가능한 수준입니다.
Dragonfly 만료 기한과 Redis 구현 간의 자세한 차이점은 여기를 참조하세요.

◻️ Native HTTP console and Prometheus-compatible metrics - 네이티브 HTTP 콘솔과 Prometheus 호환 매트릭

기본적으로, Dragonfly는 메인 TCP 포트(6379)에 HTTP 접근을 허용합니다.   즉, Redis 프로토콜과 HTTP 프로토콜 모두를 통해 Dragonfly에 연결할 수 있습니다. 서버는 연결 초기화 과정에서 프로토콜을 자동으로 인식합니다. 웹 브라우저를 통하여 시도해보시기 바랍니다. 현재 HTTP 접근은 많은 정보를 제공하지 않지만, 유용한 디버깅 및 관리 정보를 향후 추가할 예정입니다.
":6379/metrics"에 접근하게 되면, Prometheus 호환 매트릭을 확인할 수 있습니다.
Prometheus에서 내보내는 매트릭들은 Grafana 대시보드와 호환됩니다.
중요! HTTP 노출은 안전한 네트워크 내에서 접근하도록 설계되었습니다.
Dragonfly의 TCP 포트를 외부로 노출한다면, --http_admin_console=false 또는 --nohttp_admin_console과 같은 인수를 활용하여 콘솔을 비활성화하는 것을 조언해드립니다.

📦 Background - 개발배경

Dragonfly는 2022년에 인-메모리 데이터스토어를 설계한다면 어땠을까에 대한 실험으로 시작되었습니다. 클라우드 회사에서 근무한 엔지니어 및 메모리 스토어 사용자의 경험을 바탕으로, 저희는 Dragonfly에 핵심적인 두 가지 핵심 특성을 보존해야함을 알았습니다. ① 모든 작업에 대한 원자성 보장과 ② 밀리초 이하의 낮은 지연 시간과 동시에 매우 높은 처리량을 보장하는 것이었습니다.

첫 번째 문제는 오늘날 퍼블릭 클라우드 환경에서 사용 가능한 서버를 사용하여 CPU, 메모리 및 I/O 자원을 어떻게 최대한 활용할 수 있을지였습니다. 이 문제를 해결하기 위해 우리는 비공유 아키텍처(Shared Nothing Architecture)를 사용했습니다. 이는 메모리 스토어의 각 스레드 사이의 키 공간을 분할할 수 있게 하였습니다. 이를 통해 각 스레드가 자체 딕셔너리 데이터들의 조각을 관리할 수 있게 되었습니다. 우리는 이러한 조각을 "샤드(shards)"라고 부릅니다. 비공유 아키텍처에 대한 스레드 및 I/O 관리를 위한 라이브러리는 오픈소스 Helio로 제공됩니다.
비공유 아키텍처 Shared-nothing architecture(영문) - wiki
Helio - backend development framework in C++ using io_uring and epoll event-loop(영문) - github
Helio(한글) - redisGate

다중 키 작업(multi-key operations)에 대한 원자성 보장을 제공하기 위해 우리는 최근 학술 연구의 발전을 사용합니다.   우리는 Dragonfly의 트랜잭션 프레임워크를 개발하기 위해 "VLL: 주 메모리 데이터베이스 시스템을 위한 잠금 관리자 재설계"라는 논문을 선택했습니다. 비공유 아키텍처(shared-nothing architecture)와 VLL의 선택을 통해 우리는 뮤텍스(mutex)나 스핀록(spinlock)을 사용하지 않고 원자적으로 다중 키 작업을 구성할 수 있었습니다.
이것은 PoC의 주요 이정표였으며, 그 성능은 다른 상용 및 오픈 소스 솔루션보다 뛰어났습니다.
VLL: a lock manager redesign for main memory database systems(영문) - pdf

두 번째 과제는 새 저장소를 위해 보다 효율적인 데이터 구조를 설계하는 것이었습니다.   이 목표를 달성하기 위해, 우리는 "Dash(대시): 지속 메모리의 확장 가능한 해싱" 논문을 핵심 해시 테이블 구조의 기반으로 했습니다.
Dash: Scalable Hashing on Persistent Memory(영문) - pdf
Dash: Scalable Hashing on Persistent Memory(한글) - redisgate
논문 자체는 영구 메모리 영역을 중심으로 하며 주 메모리(main-memory) 저장소와 직접적인 관련이 없지만 여전히 문제를 해결하기 위해서 가장 적합했습니다.   논문에 제안된 해시 테이블 설계를 통해 Redis dictionary에 존재하는 두 가지 특수 속성을 유지할 수 있었습니다.   즉, 데이터 저장소 증가 중 증분 해싱 기능, 상태 비저장 스캔 작업을 사용하여 변화하는 딕셔너리을 탐색(SCAN 명령)하는 기능입니다. 이 두 가지 속성 외에도 Dash는 CPU 및 메모리 사용 측면에서 더 효율적입니다. Dash의 디자인을 활용하여 우리는 다음 기능을 통해 더욱 혁신할 수 있었습니다.
• TTL 레코드에 대한 효율적인 레코드 만료 처리
• 메모리 오버헤드 없이 LRU 및 LFU와 같은 다른 캐싱 전략보다 더 높은 적중률을 달성하는 새로운 캐시 제거 알고리즘
• 새로운 포크없는(fork-less) 스냅샷 알고리즘: BGSAVE 명령

Dragonfly의 기반을 구축하고 성능에 만족한 후, 계속해서 Redis 및 Memcached 기능을 구현했습니다. 우리는 현재까지 ~185개의 Redis 명령(Redis 5.0 API와 거의 동일)과 13개의 Memcached 명령을 구현했습니다.

마지막으로,
우리의 임무는 최신 하드웨어 발전을 활용하는 클라우드 작업을 위해 잘 설계되고 초고속이며 비용 효율적인 인 메모리 데이터 저장소를 구축하는 것입니다.   우리는 제품 API와 제안을 유지하면서 현재 솔루션의 문제점을 해결하려고 합니다.


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