주요 컨텐츠로 이동
공학

Zerobus Ingest 및 Debezium을 사용한 Unity Catalog로의 푸시 기반 CDC

브로커를 실행할 필요 없이, 오픈소스 Debezium Server에서 Delta 테이블로 변경 이벤트 전송

작성자: Victoria Bukta, Omkar Mehta , Wagner Santos

  • Debezium Server와 Databricks Zerobus Ingest가 결합하여 푸시 기반 아키텍처를 통해 CDC 이벤트를 Unity Catalog Delta 테이블로 직접 스트리밍합니다.
  • 인바운드 연결을 차단하는 보안이 강화된 사설 네트워크에서도 이제 중간 Kafka 메시지 브로커나 풀 기반 커넥터 없이 데이터를 외부로 안전하게 복제할 수 있습니다.
  • 조직은 원시 데이터베이스 변경 사항을 레이크하우스로 직접 푸시하여, 다운스트림 분석을 위한 최신 상태 테이블 구축에 필요한 인프라를 대폭 단순화할 수 있습니다.

운영 데이터베이스의 데이터는 비즈니스 결정을 내리는 데 중요한 역할을 하며, 이러한 분석의 대부분은 레이크하우스에서 이루어집니다. 외부 서비스의 인바운드 연결을 차단하는 네트워크 정책이 적용된 프라이빗 기업 네트워크, 고객 관리형 환경 또는 제한된 서브넷에 데이터베이스가 위치한 경우 데이터를 레이크하우스로 가져오는 과정은 까다롭습니다.

많은 팀이 Databricks 환경에서 PostgreSQL 변경 사항을 활용하고자 하지만, 데이터베이스를 관리하는 팀 또한 캡처 과정을 직접 관리하기를 원합니다. 해당 팀은 쓰기 선행 로그(write-ahead log)를 읽고 어떤 연결이 네트워크를 벗어날 수 있는지 결정하는 프로세스를 실행합니다. 반대편에서는 이 변경 사항들이 파이프라인과 분석가가 활용할 수 있는 관리되는 Delta 테이블에 저장됩니다.

Debezium은 팀이 전체 배포를 직접 관리하며 데이터베이스에서 변경 데이터 캡처(CDC) 피드를 추출할 수 있는 널리 사용되는 오픈소스 도구입니다. 데이터베이스 바로 옆에 위치하여 쓰기 선행 로그를 읽고 외부로 이벤트를 전송합니다. Zerobus Ingest는 레코드를 Unity Catalog Delta 테이블에 직접 쓰는 푸시 인터페이스 형태의 대상 시스템입니다. 오픈소스인 Debezium Server Zerobus 싱크는 캡처와 레이크하우스 사이에 기존의 Kafka 클러스터를 사용하지 않고 이 둘을 연결합니다.

NVIDIA와 Databricks의 엔지니어들이 협력하여 이 싱크를 개발하고 오픈소스 Debezium 프로젝트에 기여했습니다. Databricks는 타입이 지정된 Zerobus Ingest 싱크를 구축했습니다. 이어 NVIDIA는 멱등성 키 및 소스 오프셋이 진행되기 전의 내구성 있는 확인 응답과 같은 전송 안전 장치와 함께, 전체 Debezium 변경벤트를 전달하는 엔벨로프(envelope) 모드를 추가했습니다. Zerobus Ingest 싱크는 Debezium Server 3.7 릴리스에 포함되어 제공됩니다.

이 게시물에서는 Debezium과 Zerobus의 각각의 역할, NVIDIA가 싱크에 기여한 원시 변경 엔벨로프, 그리고 수집된 이벤트가 현재 상태 또는 이력 테이블로 변환되는 방식을 다룹니다. 로컬 PostgreSQL 테이블에서 현재 상태 테이블까지의 라이브 실행을 포함한 실습 가이드는 Databricks 커뮤니티의 관련 블로그 게시물을 참고하세요. 

과제

운영 데이터베이스의 변경 사항을 레이크하우스에 안정적으로 복제하려면 여러 문제를 동시에 해결해야 합니다.

  • 삽입, 업데이트, 삭제를 안정적으로 캡처합니다. 생성, 수정 및 나중에 제거된 행은 각 이벤트에 대해 정확한 스트림을 생성해야 합니다. 여기에는 쿼리 기반의 "테이블 복사" 방식에서 흔히 누락되는 삭제 작업이 포함되어야 합니다.
  • 순서 지정에 필요한 증거를 유지합니다. 현재 상태를 재구성하는 다운스트림 로직은 소스 테이블을 올바르게 복제하기 위해 소스 순서대로 변경 사항을 적용해야 합니다.
  • 소스 데이터베이스의 과부하를 방지합니다. 일정 주기로 데이터베이스를 폴링하는 방식(SELECT ... WHERE updated_at > ?)은 쿼리 부하를 가중시키며 확장성이 떨어집니다.
  • 프라이빗 및 고객 관리형 네트워크에서 작동합니다. 데이터베이스가 보안이 강화된 경계 내부에 있는 경우, 이러한 시스템에 연결하여 데이터를 수집하는 것이 어려울 수 있습니다.
  • 전송 전용으로 Kafka를 구축하는 것을 피합니다. Kafka는 강력한 이벤트 버스이지만, 데이터베이스에서 레이크하우스로 CDC 이벤트를 이동하는 목적으로만 클러스터를 운영하는 것은 별도의 필요성이 없는 팀에게는 큰 부담이 됩니다.
  • 데이터를 쉽게 처리할 수 있는 형태로 저장합니다. 변경 스트림은 추가 내보내기 단계가 필요한 사일로 형태가 아니라, 레이크하우스가 처리하고 쿼리할 수 있는 형태로 도착해야 합니다.

이러한 요구사항을 바탕으로 소스에서 싱크로 데이터가 흐르는 아키텍처를 살펴보아야 합니다.

전체 대상 아키텍처

이 블로그에서는 기존 메시지 버스 아키텍처와 Zerobus Ingest를 사용하는 아키텍처를 비교해 봅니다.

메시지 버스를 사용하는 아키텍처:
메시지 버스를 사용하는 아키텍처: 소스 기반 캡처

많은 기업 환경에서 경계 내부에서 외부로 나가는 아웃바운드(outbound) 연결은 안으로 들어오는 인바운드(inbound) 액세스보다 허용하기가 훨씬 수월합니다. 팀에서 변경 피드 추출 에이전트 배포를 실행하려 할 때 로컬 푸시 모델을 사용하면 데이터가 대상 방향으로 외부로 흐를 수 있습니다. 기존 설정에서는 이것이 Kafka와 같은 메시지 버스가 됩니다. Kafka를 운영하려면 물리적 확장을 위한 피크 부하 처리 능력을 예측하고 소비자가 생산 속도를 따라잡는 데 필요한 파티션 수를 추정하기 위한 용량 계획 리소스가 필요합니다. 이는 Kafka 배포 및 관리 경험이 있는 전담 팀을 필요로 합니다.

데이터가 Kafka에 저장되면, 다음 단계인 레이크하우스로의 이벤트 복제 작업을 수행해야 합니다. 이는 Spark, Kafka Connector 또는 기타 도구를 통한 수집 작업 배포를 통해 이루어질 수 있습니다. 그 결과 Debezium에서 레이크하우스로 이어지는 2홉(two-hop) 아키텍처가 구성됩니다.

Zerobus Ingest를 사용하는 아키텍처:
Zerobus Ingest를 사용하는 아키텍처: 소스 기반 캡처

최종 목적지가 레이크하우스뿐인 경우, Zerobus를 사용하면 메시지 버스와 같은 중간 단계를 우회할 수 있습니다. 이를 통해 엔드투엔드 아키텍처가 간소화되며 데이터 전송을 위한 Kafka 인프라를 배포하고 관리할 필요가 없어집니다. Debezium과 함께 Zerobus를 싱크로 사용할 경우 피크 시간대에도 별도의 튜닝 없이 원활하게 작동합니다.

Debezium이란 무엇인가요?

Debezium은 오픈소스 로그 기반 변경 데이터 캡처 플랫폼입니다. 테이블을 폴링하는 대신 PostgreSQL의 쓰기 선행 로그(WAL), MySQL의 binlog, MongoDB의 변경 스트림과 같은 데이터베이스의 트랜잭션 로그를 읽습니다. 그런 다음 각 변경 사항을 구조화된 이벤트로 발행합니다. 이 프로젝트는 2015년에 시작되었으며, 현재 PostgreSQL, MySQL, SQL Server, Oracle, MongoDB 등 다양한 커넥터 생태계를 지원합니다.

각 변경 이벤트에는 일관된 엔벨로프가 포함됩니다.

  • before — 변경 전의 행 상태 (삽입의 경우 null)
  • after — 변경 후의 행 상태 (삭제의 경우 null)\
  • op — 작업 유형: c (생성/삽입), u (업데이트), d (삭제), r (읽기/스냅샷)
  • source — 메타데이터: 데이터베이스, 스키마, 테이블, WAL 로그 시퀀스 번호(LSN), 트랜잭션 ID, 스냅샷 플래그
  • ts_ms — 이벤트 타임스탬프

Debezium은 변경 사항을 짧은 지연 시간으로 캡처하기 위해 폴링하는 방식 대신 로그 테일링(log tailing)을 사용하므로 주 데이터베이스에 최소한의 부하만 주며 커밋 순서를 유지합니다.

독립형(Debezium Server) 대 Kafka Connect 배포

Debezium에는 두 가지 운영 모델이 있습니다. 하나는 Kafka Connect에서 실행되는 모델이고, 다른 하나는 일반 컴퓨팅 환경에 구축할 수 있는 "독립형 서버(stand-alone server)" 모델입니다.

 

Kafka Connect의 Debezium

Debezium Server (스탠드얼론)

런타임

Kafka Connect 클러스터 내의 플러그인

스탠드얼론 Quarkus 애플리케이션

네이티브 타겟

Apache Kafka (이후 다른 시스템으로 싱크 아웃)

싱크 어댑터를 통해 Kafka가 아닌 타겟으로 직접 전송 (Zerobus Ingest 등)

사용 시기

Kafka가 표준 이벤트 버스인 경우, 그리고 Connect의 분산 워커, SMT, 스키마 레지스트리가 필요한 경우

Kafka를 운영하지 않거나, 특정 목적을 위해 구축된 대상 위치로 CDC를 직접 푸시하려는 경우

스탠드얼론 런타임인 Debezium Server는 트랜잭션 로그를 추적하고, 전송 역할을 하는 Kafka 클러스터 없이 변경벤트를 Databricks의 Zerobus Ingest로 직접 전송하는 소스 측 에이전트 역할을 합니다.

해결 방법: Debezium + Zerobus Ingest

로그 테일러로 Debezium을 선택했습니다. 이제 이벤트를 Databricks로 가져와야 합니다.

Zerobus Ingest는 실행할 메시지 브로커 없이 데이터를 Unity Catalog에서 거버넌스가 관리되는 Delta 테이블에 직접 쓰는 서버리스 푸시 기반 수집 서비스입니다. 프로듀서는 Zerobus 엔드포인트에 연결하고 오픈 형식 Delta 테이블에 안착하는 레코드를 스트리밍합니다. 고처리량 및 고동시성 워크로드를 처리하도록 설계되었습니다. 메시지 브로커 단계를 생략함으로써 아키텍처를 단순화할 수 있으며, 데이터를 레이크하우스로 이동하기 위해 수집 파이프라인을 확장하고 운영해야 하는 유지보수 부담을 줄일 수 있습니다.

Debezium과 결합하면 CDC 파이프라인은 다음과 같은 형태가 됩니다.

  • Debezium은 데이터베이스의 로그를 모니터링하고 각 변경 사항을 CDC 이벤트로 변환합니다.
  • Zerobus Ingest는 중간 전송 계층인 Kafka 클러스터 없이 이러한 이벤트를 Databricks로 직접 전송하여 Delta 테이블에 씁니다.
  • Databricks는 Delta 테이블에서 변경 스트림을 수신하고 다운스트림의 큐레이션된 테이블로 처리할 수 있습니다.

Zerobus Ingest는 추가 전용(append-only) 방식입니다. 변경 이벤트가 기록되면 다음 단계는 주어진 기본 키 조합의 최신 버전을 얻기 위해 병합(merge)을 수행하여 Type-1 차원 테이블을 빌드하는 것입니다.

NVIDIA의 기여: 봉투(envelope) 모드

Debezium의 Zerobus 싱크는 두 가지 테이블 계약을 제공합니다. 기본값인 Typed 모드는 각 변경벤트를 소스 자체의 컬럼이 있는 테이블에 매핑합니다. NVIDIA가 기여한 Envelope 모드는 전체 Debezium 변경벤트를 고정된 9개의 컬럼으로 구성된 테이블에 기록합니다.

  1. target_table
  2. destination
  3. partition
  4. operation
  5. idempotency_key
  6. key
  7. value
  8. source_position
  9. headers

레코드는 JSON(VARIANT 컬럼에 저장됨) 또는 Protobuf로 인코딩할 수 있습니다.

Envelope 모드는 다운스트림 처리에 필요한 증적을 유지합니다. source_position은 PostgreSQL LSN을 포함하여 소스 파티션과 오프셋을 전달합니다. idempotency_key는 목적지, 파티션, 키, 연산, 소스 위치에서 파생된 각 이벤트의 SHA-256 고유 식별자이므로, 다시 전달된 이벤트도 동일한 키를 가지게 됩니다. 키는 이벤트를 식별하며, 순서를 지정하거나 테이블을 자체적으로 중복 제거하지는 않습니다. 

Durability gates source acknowledgment
내구성 관문 소스 확인: 싱크는 하나의 테이블에 대한 연속된 각 레코드 그룹을 전송하고, Zerobus가 해당 레코드가 안정적임을 확인할 때까지 기다린 후에야 Debezium이 오프셋을 진행할 수 있도록 합니다.

이후 그룹에 실패가 발생하면 이전의 안정적인 그룹이 다시 전달될 수 있으므로 전달은 적어도 한 번(at-least-once) 보장되며 중복은 idempotency_key을(를) 사용하여 다운스트림에서 처리됩니다. 또한 Envelope 모드는 목적지 및 연산별로 필터링하며, 수집 전에 크기가 초과된 레코드를 거부하므로 해당 오프셋이 커밋되지 않습니다.

Databricks에서의 데이터 모델링

CDC 이벤트가 Delta에 기록되면 일반적인 메달리온 스타일 흐름을 통해 원시 변경 피드를 분석가와 애플리케이션이 사용할 수 있는 형태로 변환할 수 있습니다.

  • Bronze: 수신된 원본 변경 이벤트입니다. 엔벨로프 모드에서는 이벤트당 하나의 행으로 구성되며, 작업, 전/후 행 이미지, 소스 위치(LSN) 및 idempotency_key 정보를 포함합니다.
  • Silver: idempotency_key을(를) 기준으로 중복이 제거되고 소스 위치 순으로 정렬된 파싱된 변경 레코드입니다. 삽입, 수정, 삭제가 해석되어 현재 상태를 재구성할 수 있는 사용 가능한 소스 데이터 표현입니다.
  • Gold: 재무, 성과 지표 등의 보고를 위해 운영 데이터가 비즈니스 데이터로 변환되었습니다.

변경 피드를 구성하는 두 가지 방법은 다음과 같이 간단히 요약할 수 있습니다.

  • Type-1 (현재 상태): 각 키가 최신 값을 반영하도록 변경 로그를 축소하여 소스 테이블의 현재 상태 복제본을 만듭니다.
  • Type-2 (이력): 시간에 따른 각 버전을 보존하므로 특정 시점의 데이터를 조회할 수 있습니다.

Databricks 커뮤니티의 관련 사용법 블로그에서는 로컬 PostgreSQL 테이블을 사용하여 이 과정을 처음부터 끝까지 안내합니다. Zerobus 싱크로 Debezium 서버를 구성하고, 엔벨로프 테이블에서 삽입, 수정, 삭제를 확인한 다음, 소스 LSN을 기준으로 변경 사항을 정렬하여 AUTO CDC로 Type-1(현재 상태) 테이블을 빌드합니다.

결론

적절한 CDC 아키텍처를 선택하는 것은 궁극적으로 조직의 네트워크 제약 조건, 운영 선호도 및 기존 인프라에 따라 달라집니다. 

요구 사항 / 기능

Debezium + Zerobus (로컬 푸시)

DIY (Debezium + Kafka + Spark)

수집 방향

푸시 기반(소스 에이전트가 외부로 푸시)

푸시 기반(소스 에이전트가 Kafka로 외부 푸시)

네트워크 요구 사항

소스 네트워크에서 아웃바운드 액세스만 필요함

Kafka 클러스터 / 브로커에 대한 아웃바운드 액세스 필요

프라이빗 / 고객 네트워크

격리된 프라이빗 네트워크에 이상적

프라이빗 네트워크에 적합하지만 Kafka 연결 관리 필요

Kafka 인프라

필요 없음(Zerobus를 통해 직접 스트리밍)

필요함(중간 버퍼 역할을 하는 Kafka 클러스터)

커넥터 관리

Debezium Server를 로컬에서 실행해야 함

높은 운영 오버헤드 (Kafka, Connect 및 Spark 수집 작업 관리 필요)

에코시스템 호환성

전체 Debezium 커넥터 에코시스템 활용; 봉투 모드는 AUTO CDC 실버 및 골드 테이블을 위해 원시 변경 이벤트를 적재함

사용자 지정 Spark 스트리밍을 Delta(Bronze) 및 AUTO CDC 작업에 적용하여 전체 Debezium 및 Kafka Connect 에코시스템 활용

Debezium Server와 Zerobus Ingest를 결합하면, 중간 메시지 전송용 Kafka나 클라우드 오브젝트 스토리지의 스테이징 영역 없이 변경 사항을 Delta 테이블로 직접 스트리밍하는 로컬 푸시 아키텍처를 배포하여 엔드투엔드 수집 경로를 간소화할 수 있습니다.

이를 통해 데이터베이스를 소유한 팀이 PostgreSQL 캡처를 제어하는 동시에 데이터가 Unity Catalog에 적재되도록 유지할 수 있습니다. 

시작하기

이 파이프라인을 직접 구축하려면 Databricks 커뮤니티의 단계별 가이드를 참고하세요. Debezium Server와 Zerobus Ingest를 통해 PostgreSQL 변경 사항을 Unity Catalog 테이블로 실행한 후, AUTO CDC를 사용하여 현재 상태 테이블을 구축합니다. Zerobus Ingest 설정 및 기타 수집 인터페이스에 대해서는 Zerobus Ingest 문서를 참고하세요.

FAQ

Debezium Zerobus Ingest 싱크란 무엇인가요?

독립형 Debezium 런타임인 Debezium Server의 싱크로, 변경 이벤트를 Zerobus Ingest로 직접 보냅니다. Zerobus Ingest는 이를 Unity Catalog가 관리하는 Delta 테이블에 기록하므로 캡처와 레이크하우스 사이에 Kafka 클러스터가 필요하지 않습니다. NVIDIA와 Databricks가 오픈 소스 기여를 위해 협력했습니다.

봉투 모드란 무엇인가요?

봉투 모드는 소스 자체의 컬럼에 매핑하는 대신 전체 Debezium 변경 이벤트를 고정된 9개의 컬럼으로 구성된 테이블에 적재합니다. NVIDIA가 이 싱크에 기여했습니다. 다운스트림 처리를 위해 작업, 키, 값, 소스 위치 및 멱등성 키를 유지합니다. 기본값은 형식 지정 모드(Typed mode)입니다.

싱크가 각 변경 사항을 정확히 한 번만 전달하나요?

아니요, 전달은 적어도 한 번(at-least-once) 이루어집니다. 이후의 레코드 그룹이 실패하면 이전에 지속된 그룹이 다시 전달될 수 있습니다. 각 이벤트에는 idempotency_key가 포함되어 있으므로 다운스트림에서 이를 기준으로 중복을 제거합니다.

변경 피드를 현재 상태 테이블로 어떻게 변환하나요?

AUTO CDC를 사용하여 각 키의 최신 버전을 유지하는 Type-1 테이블을 구축합니다. 소스 LSN을 기준으로 변경 사항을 정렬하여 소스 순서대로 적용되도록 합니다. 대신 시간에 따른 모든 버전을 유지하려면 Type-2 테이블을 구축하세요.

(이 글은 AI의 도움을 받아 번역되었습니다. 원문이 궁금하시다면 여기를 클릭해 주세요)

최신 게시물을 이메일로 받아보세요

블로그를 구독하고 최신 게시물을 이메일로 받아보세요.