ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 카프카(Kafka)를 메시지 큐로만 쓰면 안 되는 이유: 'The Log'와 분산 커밋 로그 아키텍처
    ARCHIVE 2026. 9. 21. 09:03
    반응형

    참고: 본 글은 링크드인(LinkedIn)의 분산 인프라를 설계하고 아파치 카프카(Apache Kafka)를 창시한 제이 크렙스(Jay Kreps)의 기념비적 논고, "The Log: What every software engineer should know about real-time data's unifying abstraction" (2013)의 핵심 통찰을 바탕으로 현대 분산 시스템과 데이터베이스 아키텍처의 기저 원리를 심층 분석합니다.


    📌 한 줄 요약

    카프카는 단순한 고성능 메시지 큐가 아니라, 물리적 시계의 불완전성을 논리적 순번(Offset)으로 극복하는 분산 커밋 로그(Distributed Commit Log)이며, $O(N^2)$ 거미줄 파이프라인을 $O(N)$으로 단순화하고 모든 분산 시스템을 로그 레이어(SSOT)서빙 레이어(파생 뷰)로 해체·재조합하는 데이터베이스 언번들링(Unbundling)의 핵심 인프라입니다.


    1. 서론: 우리는 왜 카프카를 오해하는가?

    현업에서 카프카(Kafka) 도입 논의를 할 때 가장 흔히 듣는 질문은 다음과 같습니다:

    "RabbitMQ나 ActiveMQ보다 초당 처리량(Throughput)이 훨씬 높은 메시지 큐 아닌가요?"

    카프카를 "단지 처리량이 크고 빠른 큐"로만 이해하고 있다면, 카프카가 제공하는 설계 철학의 10%도 활용하지 못하고 있는 것입니다.

    메시지 큐(Message Queue)는 본질적으로 소비자가 메시지를 읽어가면 큐에서 즉시 삭제(Ack & Pop)되는 일시적 작업 버퍼입니다. 반면 카프카는 데이터를 지우지 않고 추가 전용(Append-only)으로 영구 보존하며, 소비자는 단지 읽기 포인터(Offset)만 이동시킵니다.

    이 작은 구조적 차이가 데이터 일관성, 시스템 복제, 데이터 통합, 그리고 현대 데이터베이스 아키텍처 전체를 어떻게 근본적으로 바꾸어 놓았는지 살펴보겠습니다.


    2. 분산 시스템에서 로그의 본질: 시계(Physical Clock)를 대체하는 순번

    2.1 로그의 엄밀한 정의

    Jay Kreps는 로그를 다음과 같이 엄밀하게 정의합니다:

    "로그(Log)란 추가 전용(Append-only)이며, 시간 순서로 정렬된 레코드들의 배열(Array of ordered records)이다."

    흔히 개발자들이 생각하는 log4j나 콘솔 출력 같은 비정형 텍스트 로그(Application log)와 달리, 분산 시스템에서의 로그는 프로그램이 읽고 처리하는 기계적이고 엄격하게 구조화된 상태 변경 트랜잭션 기록(Commit Log)입니다.

    2.2 물리적 시계의 맹점과 논리적 순번

    분산 환경에서 수십, 수백 대의 서버가 각자 가진 물리적 하드웨어 시계는 결코 완벽하게 일치하지 않습니다. NTP(Network Time Protocol) 동기화를 적용하더라도 네트워크 지연과 클록 드리프트(Clock Drift)로 인해 수 밀리초에서 수백 밀리초의 오차가 불가피하게 발생합니다.

    [노드 A의 로컬 시계]  03:24:00.001 ──> 이벤트 X 기록
    [노드 B의 로컬 시계]  03:24:00.002 ──> 이벤트 Y 기록
    
    질문: 절대적 우주 시간 기준으로 X가 먼저 발생했을까요, Y가 먼저 발생했을까요?
    답: 물리적 시계만으로는 결코 확정할 수 없습니다. (불확정성)
    

    이러한 물리 시계의 한계를 해결하는 유일한 해법이 바로 추가 전용 로그(Append-only Log)입니다.

    • 로그에 저장되는 순서는 물리적 시간과 완전히 분리된 논리적 타임스탬프(Logical Timestamp / Offset)입니다.
    • 오프셋 0에 기록된 이벤트는 오프셋 1에 기록된 이벤트보다 무조건 먼저 발생한 것입니다. 여기에 어떤 물리적 시계의 보정도 필요하지 않습니다.
    • 핵심 결론: 분산 시스템에서 "로그의 순서가 곧 시간이며, 이 순서 합의가 분산 일관성(Consistency)의 절대적 근간"이 됩니다.

    3. 상태 기계 복제 원칙(SMR)과 합의 알고리즘의 실체

    모든 현대 분산 데이터베이스(Spanner, Cassandra, CockroachDB, MySQL InnoDB 등)의 복제 메커니즘은 하나의 수학적 원리에 기반합니다.

    3.1 상태 기계 복제 원칙 (State Machine Replication Principle)

    "동일하고 결정론적(Deterministic)인 프로세스가 동일한 초기 상태에서 시작하여, 동일한 순서로 동일한 입력을 받으면, 반드시 동일한 출력을 생성하고 동일한 최종 상태로 끝난다."

      [동일한 초기 상태 S0]
              │
              ├──────────────────────────┐
              ▼                          ▼
      ┌───────────────┐          ┌───────────────┐
      │ 결정론적 노드 1 │          │ 결정론적 노드 2 │
      └───────▲───────┘          └───────▲───────┘
              │                          │
              └──────────┬───────────────┘
                         │
             [분산 커밋 로그 (Kafka)]
        엄격한 순서 보장: E1 -> E2 -> E3
                         │
              ┌──────────┴───────────────┐
              ▼                          ▼
      [동일한 최종 상태 Sn]      [동일한 최종 상태 Sn]
           (상호 일관성 100% 보장)
    

    여러 대의 노드를 동일한 데이터 상태로 유지하고 싶다면, 복잡한 상태 동기화 프로토콜을 돌릴 필요 없이 모든 노드에 "동일한 순서의 입력 로그"를 공급하기만 하면 됩니다.

    3.2 Paxos, Raft, Zab의 진짜 존재 이유

    분산 컴퓨팅 교과서에 나오는 Paxos나 Raft 같은 분산 합의 알고리즘은 단 하나의 질문을 해결하기 위해 존재합니다:

    "이번 오프셋에 들어갈 다음 이벤트가 무엇인지 모든 노드가 합의할 수 있는가?"

    결국 분산 시스템의 일관성 문제는 순서에 대한 합의(Order Consensus)이며, 분산 커밋 로그는 그 순서를 디스크에 영구적으로 고정하는 물리적 장치입니다.


    4. 음양(Yin-Yang)의 법칙: 테이블과 로그의 이중성 (Table-Log Duality)

    Jay Kreps는 로그와 테이블의 관계를 동양 철학의 음양(Yin-Yang) 기호로 비유했습니다. 겉보기에는 정반대의 개념 같지만, 사실 동일한 데이터의 두 가지 투영 형태입니다.

           ┌────────────────────────────────────────────────────────┐
           │                       로그 (Log)                       │
           │  - 과거부터 현재까지 발생한 불변(Immutable) 이벤트 스트림  │
           │  - 단일 진실 공급원 (Source of Truth)                  │
           └──────────────────────────┬─────────────────────────────┘
                                      │
                                      │ 재생 및 집계 (Replay / Aggregation)
                                      │
                                      ▼
           ┌────────────────────────────────────────────────────────┐
           │                      테이블 (Table)                    │
           │  - 특정 시점에 존재하는 데이터의 현재 상태 (Current State) │
           │  - 가변적 파생 뷰 (Derived Materialized View)          │
           └──────────────────────────┬─────────────────────────────┘
                                      │
                                      │ 변경 사항 캡처 (CDC / Changelog Feed)
                                      │
                                      ▼
                                [다시 로그 (Log)]
    

    4.1 로그가 원본이고, 테이블은 파생물이다

    • 로그 $\to$ 테이블: 이벤트 로그를 0번부터 순서대로 재생(Replay)하여 누적하면 현재의 테이블 상태가 됩니다.
    • 예시: 통장 입출금 거래 내역(Log)을 모두 합산하면 현재 잔고(Table)가 됩니다. Git 커밋 히스토리(Log)를 체크아웃하면 현재 작업 디렉터리의 파일(Table)이 됩니다.
    • 테이블 $\to$ 로그: 테이블의 행이 수정될 때마다 그 변경 내역(INSERT/UPDATE/DELETE)을 순서대로 방출하면 변경 로그(Changelog)가 됩니다.

    💡 아키텍처적 시사점:
    결과값인 '현재 상태(테이블)'만 저장하는 시스템은 과거의 맥락과 변경 이유를 잃어버립니다. 반면 불변의 원본인 '이벤트 로그'를 보존하면 언제든 과거 특정 시점으로 시간 여행(Time-travel 복구)이 가능하고, 감사 추적(Audit Trail)이 공짜로 확보됩니다.

    4.2 현대 아키텍처 패턴과의 연결

    패턴 / 기술 로그(Log)의 역할 테이블(Table)의 역할
    이벤트 소싱 (Event Sourcing) 상태 변경을 일으키는 도메인 이벤트를 불변 저장 이벤트를 리플레이하여 메모리에 조립한 엔티티 상태
    CQRS 쓰기(Command) 전용 이벤트 커밋 로그 빠른 읽기(Query)를 위해 로그를 비정규화 투영한 읽기 뷰
    Kafka Streams KStream: 실시간 변경 이벤트 스트림 KTable: 윈도우/키별 최신 집계 상태 테이블

    5. $O(N^2)$ 거미줄 파이프라인의 종말과 중앙 로그 허브

    링크드인 초기에 겪었던 가장 고통스러운 엔지니어링 문제는 시스템 간 데이터 통합이었습니다.

    [기존 점대점(Point-to-Point) 파이프라인: O(N^2)]
          서비스 A <────> 검색 엔진
             ▲  \      /  ▲
             │    \  /    │
             │      ╳       │
             ▼    /  \    ▼
          캐시 DB <────> 분석용 하둡
    
    [중앙 로그 허브 (Kafka): O(N)]
          서비스 A ───┐              ┌───> 검색 엔진 (ES)
                     ├──> [ Kafka ] ├───> 분석용 하둡 / Lake
          서비스 B ───┘  (중앙 로그)  └───> 인메모리 캐시 (Redis)
    

    5.1 $O(N^2)$ 통합의 한계

    RDBMS, 전문 검색 엔진, 캐시, 그래프 DB, 하둡 등 $N$개의 시스템이 서로 데이터를 주고받으려면 최대 $N(N-1)$개의 전용 파이프라인이 필요합니다.
    - 시스템이 10개면 90개, 30개면 거의 900개의 커스텀 파이프라인이 거미줄처럼 얽힙니다.
    - 파이프라인 하나가 깨져 데이터 정합성이 어긋나면, 어디서 데이터가 오염되었는지 추적하는 데만 수주가 소모됩니다.

    5.2 중앙 로그 허브의 $O(N)$ 해결책

    모든 시스템이 단 하나의 분산 커밋 로그만을 바라보게 만듭니다.
    1. 생산자(Producer)는 자신의 데이터 변경을 로그에 발행(Publish)하기만 합니다.
    2. 소비자(Consumer)는 로그를 각자의 목적에 맞게 읽어갑니다(Subscribe).
    3. 파이프라인의 복잡도가 $O(N^2)$에서 $O(N)$으로 즉시 축소됩니다.

    5.3 속도 차이의 완충재 (Backpressure & Buffer)

    실시간 검색 색인은 1초 안에 데이터를 소비해야 하지만, 대용량 분석 배치(DW/Hadoop)는 하루에 한 번 새벽에만 데이터를 읽어갑니다.
    카프카는 메시지를 소비해도 삭제하지 않으므로, 초 단위 컨슈머와 일(Day) 단위 배치가 동일한 토픽에서 각자의 오프셋 속도대로 데이터를 안전하게 읽어갈 수 있습니다.

    5.4 데이터 메시(Data Mesh)의 기원: 생산자 책임 원칙

    과거 중앙 데이터웨어하우스(DW) 팀은 전사 수백 개 테이블의 포맷 정제와 Null 처리를 떠안아 극심한 병목이 되었습니다.
    로그 중심 아키텍처에서는 "데이터를 가장 잘 이해하는 도메인 생산자 팀이 직접 정제된 이벤트를 로그에 발행하고, 다운스트림 팀은 이를 소비한다"는 거버넌스 원칙이 정립됩니다. 이것이 현대 Data Mesh 아키텍처의 기원입니다.


    6. 메시지 큐(RabbitMQ) vs 분산 커밋 로그(Kafka) 4대 차이

    비교 항목 전통적 메시지 큐 (RabbitMQ, SQS) 분산 커밋 로그 (Apache Kafka)
    데이터 보존 소비 완료(Ack) 시 큐에서 즉시 삭제 보존 기간 동안 디스크에 영구 보존 (Append-only)
    소비 메커니즘 브로커가 메시지를 컨슈머에게 밀어넣음 (Push) 컨슈머가 오프셋 포인터를 전진시키며 당겨옴 (Pull)
    다중 소비자 큐를 별도로 복제하지 않으면 다중 소비 제한 수백 개의 독립 컨슈머 그룹이 동일 로그를 각자 소비
    재소비 (Replay) 불가능 (이미 삭제됨) 오프셋만 되돌리면 과거 특정 시점부터 무한 재생 가능

    6.1 로그 컴팩션 (Log Compaction)

    일반적인 카프카 토픽은 보존 기간(예: 7일)이 지나면 오래된 세그먼트를 삭제합니다. 하지만 로그 컴팩션(Log Compaction)을 활성화하면 완전히 다른 시스템이 됩니다:

    • 원리: 동일한 레코드 키(Key)에 대해 가장 최신 값(Value)만 영구 보존하고 이전 버전을 백그라운드에서 정리합니다.
    • 의미: 카프카 토픽 자체가 "키별 최종 상태를 보장하는 불변의 영구 KTable 백본 저장소"로 동작할 수 있게 됩니다.

    7. "배치는 윈도우 크기가 1일인 스트림 처리다"

    Jay Kreps는 배치를 실시간 스트림 처리의 대척점으로 보는 통념을 정면으로 반박했습니다.

    "1790년 미국 최초의 인구조사 시절, 조사관이 말을 타고 전국을 돌며 종이에 숫자를 모아 한 번에 집계하던 물리적 한계에서 탄생한 인위적 개념이 바로 '배치(Batch)'다."

    현실 세계의 비즈니스 사건(사용자 클릭, 결제, 배송, 센서 신호)은 단 한 번도 멈추지 않고 연속적으로 발생합니다.
    - 데이터가 연속적으로 발생한다면, 처리 역시 연속적으로 일어나는 것이 가장 자연스럽습니다.
    - '배치 작업'이란 단지 "스트림 데이터 위에서 처리 시간 윈도우(Window Size)를 하루(24시간)로 길게 잡은 특수한 경우"에 불과합니다.


    8. 데이터베이스의 언번들링 (Unbundling of the Database)

    Jay Kreps가 제시한 가장 혁신적인 엔지니어링 통찰은 "데이터베이스의 해체와 재조합"입니다.

    과거 오라클이나 MySQL 같은 단일 모놀리식 RDBMS 안에는 수많은 하부 서브시스템이 강하게 결합되어 있었습니다:
    - 트랜잭션 커밋 로그 (WAL)
    - 복제 프로토콜
    - B-Tree 인덱스 / 테이블 스토리지
    - 캐시 계층
    - SQL 질의 파서 및 플래너

    현대 분산 시스템 생태계에서는 이 단일 DB 내부 부품들이 독립된 전문 오픈소스로 완전히 분해(Unbundling)되었습니다.

    ┌─────────────────────────────────────────────────────────────┐
    │             로그 레이어 (Log Layer) — 분산 SSOT              │
    │  - 분산 커밋 로그 (Apache Kafka)                             │
    │  - 순서 합의, 내구성 보장, 불변 이벤트 저장소, 무한 리플레이     │
    └──────────────────────────────┬──────────────────────────────┘
                                   │
                ┌──────────────────┼──────────────────┐
                ▼                  ▼                  ▼
    ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
    │  RDBMS (MySQL)   │ │  전문 검색 (ES)  │ │   캐시 (Redis)   │
    │  - B-Tree 인덱스 │ │  - 역색인 인덱스 │ │  - In-Memory KV  │
    │  - 트랜잭션 뷰   │ │  - 텍스트 검색   │ │  - 초저지연 읽기 │
    └──────────────────┘ └──────────────────┘ └──────────────────┘
    └─────────────────────────────────────────────────────────────┘
    │             서빙 레이어 (Serving Layer) — 목적별 파생 뷰     │
    └─────────────────────────────────────────────────────────────┘
    

    모든 분산 아키텍처는 다음 두 계층으로 단순하게 나뉩니다:
    1. 로그 레이어 (Log Layer): 데이터를 안전하게 순서대로 기록하고 내구성을 보장하는 단 하나의 원본(Single Source of Truth, Kafka).
    2. 서빙 레이어 (Serving Layer): 사용자의 다양한 질의에 초고속으로 응답하기 위해 로그를 읽어 목적별로 구축한 파생 뷰(Derived View).
    - Elasticsearch는 로그를 역인덱스로 변환한 파생 뷰입니다.
    - Redis는 로그를 키-값 메모리 구조로 변환한 파생 뷰입니다.
    - ClickHouse/Snowflake는 로그를 컬럼 기반으로 변환한 분석용 파생 뷰입니다.

    현대 아키텍트는 하나의 만능 데이터베이스를 찾는 사람이 아니라, 분산 커밋 로그(Kafka)를 뼈대로 삼아 목적에 맞는 최적의 서빙 레이어들을 조립하여 전사적 맞춤형 분산 데이터베이스를 만드는 사람입니다.


    9. 아키텍트를 위한 6대 자가 진단 체크리스트

    1. 순서와 일관성: 우리 시스템의 다중 노드 정합성을 불안정한 물리 시계나 타임스탬프 비교에 의존하고 있지는 않은가?
    2. 파이프라인 토폴로지: 서비스 간 동기화가 점대점($O(N^2)$) 거미줄로 얽혀 있어 새 서비스 연동 시마다 기존 코드를 뜯어고치고 있지는 않은가?
    3. 상태 vs 이벤트: 비즈니스 도메인의 최종 결과(상태)만 남기고 변경의 맥락(이벤트)을 유실하여 장애 복구나 과거 시점 조회가 불가능한 상태는 아닌가?
    4. 도구 본질 이해: 카프카를 단지 처리량 빠른 RabbitMQ 대체재로만 쓰고 있지는 않은가? (오프셋 리플레이와 로그 컴팩션을 제대로 활용하고 있는가?)
    5. 데이터 소유권: 중앙 데이터 분석팀에게 전사 데이터 정제 책임을 몰아주어 데이터 병목을 초래하고 있지는 않은가?
    6. 배치 관행 재검토: 관행적으로 돌리고 있는 일/월 단위 배치 작업 중, 이벤트 스트림 처리로 전환하여 비즈니스 가치와 피드백 속도를 극대화할 수 있는 영역이 있는가?

    10. 마치며

    2013년 Jay Kreps가 제시한 "The Log"의 철학은 10년이 지난 지금도 클라우드 네이티브, 마이크로서비스(EDA), 데이터 메시, 그리고 대규모 AI 데이터 파이프라인의 핵심 기저로 관통하고 있습니다.

    기술의 유행과 프레임워크는 빠르게 변하지만, "순서가 곧 시간이며, 로그가 원본이고 테이블은 파생물이다"라는 분산 시스템의 기본 원리는 변하지 않습니다. 시스템을 설계할 때 데이터의 '현재 모양'보다 데이터가 흘러가는 '불변의 로그'에 주목해 보시길 권합니다.

    반응형
Designed by Tistory.