Search
🎲

CDC (Change data capture) 구현하기

작성일
2023/02/11 18:00
수정일
카테고리
아키텍처
태그
CDC
Postgresql
kafka
이 게시물은 시리즈로 작성됩니다. 해당 포스트는 서문에 해당합니다.

CDC란 무엇인가요?

CDC Change Data Capture는 우리 말로 변경 데이터 캡처 라고 부릅니다.
위키의 설명 중 일부를 발췌하면 다음과 같습니다.
데이터베이스에서 변경 데이터 캡처(change data capture, CDC)는 변경된 데이터를 사용하여 동작을 취할 수 있도록 데이터를 결정하고 추적하기 위해 사용되는 여러 소프트웨어 디자인패턴 들의 모임이다.
다른 말로 “DB에서 데이터가 변경된 것을 감지하여 어떤 행위를 유발하는 걸 CDC라고 부르는구나” 라고 표현할 수 있겠네요.
그렇다면 데이터가 변경된 것을 감지해야 하는 상황은 어떤 상황이 있을까요?

MSA와 이벤트 기반 아키텍처

과거 배달의 민족 코드가 MSA 기반으로 변경한 이야기를 들려준 MSA, 배달의 민족 마이크로서비스 여행기 정리 라는 글을 작성한 적이 있습니다. 모놀리식 Monolithic 아키텍처의 단점이 될 수 있는 거대한 복잡성을 감당하기 위해 각 서비스를 별도로 분리한 모델을 MSA Micro Service Architecture라고 합니다.

MSA site 추천

갑자기 레퍼런스 추천! Chris Richardson 라는 개발자 분이 MSA 패턴에 관한 다양한 아티클을 공유해주고 있는 사이트 입니다.

Micro Service 끼리의 소통을 위한 pub-sub messaging

만약 상품, 주문, 가게 코드가 뭉쳐있던 모놀리식 코드에서 Micro Service 서비스로 분리한다고 생각해보세요. 서버간의 호출은 API를 사용한다고 가정해봅니다.
모놀리식 주문 로직. API 호출 한 번이면 모든 로직이 수행된다.
MSA식 주문 로직. API 호출이 API 호출을 부른다.
모놀리식에선 주문한다 라는 하나의 API로 처리가 가능했지만, 마이크로 서비스에선 API 호출이 API 호출을 부릅니다. 대량의 API 호출을 위한 네트워크 비용도 문제지만, 각 클라이언트가 내가 호출해야 할 서버 주소를 모두 알아야 한다는 문제도 생깁니다.
로직이 알아야 하는 정보가 많을수록 호출해야할 클라이언트도 많아질텐데 많아진 서버는 각각이 단일 장애점이 되어 서버의 장애 가능성을 높입니다. 하나라도 고장나면 주문 로직이 실패하겠죠.
이 문제를 해결하기 위해선 각 서버가 서로간의 의존도를 낮추도록 해야 하는데, 이벤트를 활용한 메시징 처리도 이에 대한 대안입니다.
최초 1회 가게정보와 상품정보를 모두 주문DB에 저장해두고, 이후 변경사항은 이벤트로 처리
주문 서버 DB에 최초 1회 가게 정보과 상품 정보를 모두 migration 받고, 이후의 변경사항은 이벤트를 받아서 주문 서버 DB에 있는 가게 정보와 상품 정보를 갱신하는 방식으로 수정하였습니다. 이제 주문 서버는 이벤트 큐의 주소만 알면 되고, 해당 이벤트를 누가 채워주는지도 알 필요가 없어집니다. 가게 서버가 고장나더라도 알 필요 없고, 가게 서버가 복구 된 뒤 이벤트만 잘 채워주면 됩니다.
모두 행복해진듯 하네요. 하지만 해당 방식은 다양한 오류상황을 암시합니다.
큐가 고장나면?
상품 정보가 수정된 후 상품 스냅샷 데이터가 갱신되기까지 일정 시간이 소요될텐데, 그 동안의 불일치는?
이벤트 순서가 항상 올바르게 도착?
(비동기의 지옥에 오신것을 환영합니다)
하지만 이번 글에서는 MSA에서 이벤트 기반 처리가 어떤 효용을 지니는지 설명하기 위함이므로 위 문제 해결에 대해서는 다루지 않겠습니다.
자, 서버 가용성을 위해 이벤트 기반으로 구현하였습니다. 각 서버는 이벤트를 발행하고, 서로의 메시지를 확인하며 유저의 요청을 처리해 나갑니다.

이벤트 기반 아키텍처의 문제점(?)

하지만 데이터는 DB에 저장되고 이벤트는 어플리케이션 로직을 통해 발행된다는 사실이 발목을 잡는 상황이 있습니다.

DB 수기대응 시나리오

저희는 항상 서버 장애를 만듭니다.
죄송합니다. 최소한 저는 항상 장애를 만듭니다.
장애로 인해 틀어진 데이터를 DB 수기대응으로 보정해야하는 상황이 오곤 합니다. (Master DB에 대해 DDL 직접 수행)
혹은 구현되지 않은 기능을 DB 수정을 통해 해결해 달라는 요청이 쇄도하곤 하죠.
문제는 저희가 이벤트 기반 아키텍처를 구현해버렸다는 것에 있습니다. 이벤트는 어플리케이션 로직을 통해 발행되므로, 틀어진 데이터를 보정한 내역 또한 어플리케이션에서 발행해주어야 합니다.
제가 해당 이벤트를 구현했다면 문제는 없습니다. 상품 DB 수기 업데이트를 완료 후 미리 구현해둔 상품 이벤트 trigger API를 호출하여 변경된 내역에 대한 이벤트 발행까지 완료합니다.

남이 구현한 코드

하지만 항상 인생은 제가 안배한대로 흘러가는 법이 없습니다.
휴가자를 대신해 에라 모르겠다 DDL을 수행하는 경우, 어플리케이션 로직을 전부 점검해보지 않은 이상 두려움에 떨어야 합니다.
위와 같은 수기대응 시나리오가 아니더라도 누군가 수정로직에서 이벤트 발행을 누락한다면 시스템 전체에 영향을 미치게 됩니다.
아, 데이터가 수정되면 자동으로 이벤트가 발행되면 얼마나 좋을까요..
어라라?

데이터가 수정되면 자동으로 이벤트가 발행된다.

어디서 본 개념 아닌가요? 이 글을 시작하며 “DB에서 데이터가 변경된 것을 감지하여 어떤 행위를 유발하는 걸 CDC라고 부르는구나” 라고 표현하였습니다. 어떤 행위만 바꾸어 표현해보겠습니다.
“DB에서 데이터가 변경된 것을 감지하여 이벤트를 발행하는 것이 CDC”다.
아주 좋은 문장입니다. 이제 더 이상 개발자는 이벤트 발행에 대해 신경쓰지 않아도 됩니다. DB가 변경되면 이벤트가 발행될테니까요.
말은 항상 쉽다
CDC는 개념이니 구현 방법은 다양할 겁니다. 어떻게 구현해볼 수 있을까요?
제가 다루고 있는 서버는 Spring Boot, Postgresql, Kafka를 활용할 수 있는 구성입니다. 각 스택의 기술을 활용해 CDC를 발행하도록 구현해보겠습니다.
다음 flow를 구상 중 입니다.
PG WAL(Write-Ahead 로깅)를 통해 DB insert를 감지하여 메시지(kafka topic)를 발행한다
이때 메시지 발행은 debezium PG connector (kafka connector)라이브러리를 활용한다
어플리케이션에서 메시지를 consume해 트랜잭션 outbox 테이블에 데이터를 삽입한다.
outbox 테이블을 감지해(Message Relay) 비즈니스 이벤트 발행이나 비즈니스 로직을 처리하는데 활용한다.
다음 시리즈부터는 WAL, debezium PG connector, outbox pattern, message relay를 차례로 다뤄보겠습니다.