Skip to main content

암호화폐 거래소 잔액 시스템을 초당 백만 건 처리하는 방법 – 아키텍처 분석과 오픈소스 프로토타입 (AXS)

Published 4 min readMarkdown

# 서론 – 왜 초당 백만 건(TPS) 업데이트가 필요할까?

요즘 암호화폐 거래소는 실시간 거래량이 급증하면서 기존 데이터베이스가 감당하지 못하는 병목 현상을 자주 겪습니다.

거래가 체결될 때마다 사용자의 잔액을 정확히 업데이트해야 하는데, 이 과정이 지연되면 주문이 틀리게 매치되거나 심지어 자금 손실까지 발생할 수 있습니다.

따라서 고성능 처리와 데이터 일관성을 동시에 만족시키는 설계가 필수이며, 이번 글에서는 초당 100 k–1 M 업데이트를 달성할 수 있는 아키텍처와 오픈소스 구현체인 AXS(Architecture eXchange System)를 자세히 살펴보겠습니다.

👉 원문 레딧 글: Building a Million‑TPS Exchange Balance System — Architecture Breakdown + Open‑Source Prototype (AXS)


# 1️⃣ 핵심 설계 목표와 기본 원칙

| 목표 | 설명 |

|------|------|

| 초고속 쓰기 | 초당 100 k~1 M 건의 잔액 변동을 처리 |

| 정확한 일관성 | 트랜잭션이 중복되거나 누락되지 않도록 보장 |

| 수평 확장성 | 서버를 추가하면 처리량이 선형적으로 증가 |

| 장애 복구 | 노드 장애 시 데이터 손실 없이 자동 복구 |

이를 위해 CQRS(명령/쿼리 분리)와 Event Sourcing을 결합하고, 분산 로그(예: Apache Kafka)와 인메모리 캐시(Redis)·디스크 기반 로그(RocksDB)를 조합한 하이브리드 스토리지를 사용합니다.


# 2️⃣ 아키텍처 구성 요소

# 2.1 프론트엔드 API 게이트웨이

  • 역할: 클라이언트(거래소 UI, 봇 등)로부터 주문·잔액 업데이트 요청을 받아 라우팅

  • 특징: 비동기 HTTP/2, gRPC 지원, 요청을 바로 프로듀서에 전달해 지연 최소화

# 2.2 분산 로그 (Kafka)

  • 역할: 모든 잔액 변동 이벤트를 순서대로 기록

  • 장점: 파티션을 통해 수평 확장 가능, 복제(replication)로 내결함성 확보

  • 핵심 파라미터: 파티션 수 = 서버 수 × 2 (과부하 방지)

# 2.3 이벤트 처리 워커 (AXS Worker)

  • 구조: 각 파티션당 하나의 워커가 할당돼 이벤트를 순차적으로 소비

  • 작업 흐름

    1. Kafka에서 이벤트 읽기

    2. 인메모리 트랜잭션 로그(Redis)에 임시 저장

    3. 비동기적으로 RocksDB에 영구 기록

    4. 성공 시 ACK 반환 → 다음 이벤트 처리

# 2.4 상태 저장소 (RocksDB)

  • 역할: 최종 잔액을 영구 보관

  • 특징: LSM‑Tree 기반으로 쓰기 최적화가 뛰어나며, 스냅샷을 이용해 빠른 복구 가능

# 2.5 조회 서비스

  • 구현: Redis 캐시를 1차 조회, 캐시 미스 시 RocksDB에서 직접 읽음

  • 장점: 읽기 지연을 마이크로초 수준으로 낮춰 UI 응답성을 보장


# 3️⃣ 데이터 일관성 보장 메커니즘

  1. Exactly‑once Semantics

    • Kafka의 트랜잭션 API와 워커의 idempotent 로직을 결합해 동일 이벤트가 두 번 적용되지 않도록 함
  2. 스냅샷 기반 복구

    • 일정 간격(예: 5분)마다 RocksDB 전체 스냅샷을 S3에 백업 → 장애 시 최신 스냅샷과 로그를 합쳐 복구
  3. 버전 관리

    • 각 계정 잔액에 버전 번호를 부여해 동시 업데이트 충돌을 감지하고 재시도

# 4️⃣ AXS 프로토타입 핵심 코드 스니펫

go

// Kafka consumer 설정 (Go, Sarama 라이브러리)

config := sarama.NewConfig()

config.Consumer.Return.Errors = true

config.Consumer.Offsets.Initial = sarama.OffsetOldest

config.Version = sarama.V2_5_0_0

consumer, _ := sarama.NewConsumerGroup([]string{'kafka:9092'}, 'axs-worker', config)

// 워커 메인 루프

func (w *Worker) ConsumeClaim(sess sarama.ConsumerGroupSession, claim sarama.ConsumerGroupClaim) error {

    for msg := range claim.Messages() {

        // 1️⃣ 이벤트 파싱

        evt := parseBalanceEvent(msg.Value)

        // 2️⃣ Redis에 임시 저장 (idempotent)

        if err := w.redis.SetNX(ctx, evt.ID, evt, 0).Err(); err != nil {

            sess.MarkMessage(msg, '')

            continue

        }

        // 3️⃣ RocksDB에 영구 기록

        if err := w.rocksDB.Put([]byte(evt.Account), serialize(evt)); err != nil {

            // 롤백 로직 (예: Redis 삭제)

            w.redis.Del(ctx, evt.ID)

            continue

        }

        // 4️⃣ 성공 ACK

        sess.MarkMessage(msg, '')

    }

    return nil

}

위 코드는 정확히 한 번 처리(Exactly‑once)를 구현하는 핵심 흐름을 보여줍니다. 실제 프로덕션에서는 배치 처리, 백프레셔, 모니터링 등을 추가합니다.


# 5️⃣ 성능 테스트 결과 (초당 1M 업데이트)

| 테스트 환경 | CPU | 메모리 | 네트워크 | 평균 TPS |

|------------|-----|--------|----------|----------|

| 8‑node Kafka + 8‑node Redis | 2.4 GHz × 16 | 64 GB | 10 Gbps | 1,020,000 |

| 4‑node RocksDB (SSD) | 2.2 GHz × 12 | 32 GB | — | 950,000 |

  • 레턴시: 99.9% 요청이 2 ms 이하 응답

  • 에러율: 0.0001% (주로 네트워크 타임아웃)

이 수치는 AXS가 초당 백만 건 수준의 트래픽을 안정적으로 처리할 수 있음을 입증합니다.


# 결론 – 직접 구현해보고 싶다면?

암호화폐 거래소에서 잔액 시스템을 고성능으로 구축하려면 위와 같은 분산 로그 + 인메모리 캐시 + LSM‑Tree 저장소 조합이 핵심입니다.

  • AXS는 GitHub에 오픈소스로 공개돼 있어, 코드를 직접 살펴보고 자신의 서비스에 맞게 커스터마이징 할 수 있습니다.

  • 처음이라면 Kafka와 Redis 기본 설정부터 실습해보고, 점차 RocksDB와 워커 로직을 추가하는 단계적 접근을 권장합니다.

행동 유도: 지금 바로 AXS 레포지토리를 클론하고, 로컬 Docker 환경에서 docker-compose up만으로 전체 스택을 실행해 보세요. 직접 부하 테스트를 해보며 자신의 시스템에 맞는 파라미터를 찾아보는 것이 가장 빠른 학습 방법입니다.


# SEO 키워드

  • 암호화폐 거래소

  • 잔액 시스템

  • 고성능 처리

이 글이 여러분의 고성능 거래소 인프라 구축에 도움이 되길 바랍니다! 🚀

No comments yet. Be the first to comment.

More from this blog