항해 플러스 6기 9주차를 회고하며 - 카프카요? 제가 아는 이벤트 브로커 중에 최고였어요

1. 문제

이번 9주차의 과제는 다음과 같다.

* 카프카를 구축해보고, 우리의 서비스에 카프카를 연동 및 실제 Producer, Consumer를 구현하여 적용해보기
* 카프카 메시지 발행의 결과에 대한 일관성을 보장하기 위한 Transactional Outbox Pattern 전략을 실제로 구현해보기
* 카프카 메시지 발행에 실패한 케이스에 대한 재처리를 구현하기 (Scheduler or BatchProcess)

이번 과제는 본격적인 카프카, 주니어 개발자의 무덤이라고 불리는 이 시스템을 본격적으로 다루는 과제였다.

사실 이전 회고 글을 보면 알겠지만 나는 카프카는 이전 6주차 때 이미 구현하고 프로듀서와 컨슈머를 연동했었다. 그래서 이번 주 과제는 빠르게 끝낼 수 있을 줄 알았다…

그렇다. 이번 과제는 카프카 구축과 연동은 기본 과제이고, Transactional Outbox Pattern 전략을 시나리오에서 카프카 메시지를 발행하는 부분에 적용하고 실패 케이스에 대한 재처리도 구현해야 했다. 실제로 이 전략을 어떤 식으로 구현하는 게 좋을까 구상해보니 생각보다 고려할 점들이 많았다! 역시 과제 하나하나 쉽지 않다..😂

2. 시도 & 해결

우선 Transactional Outbox Pattern 전략의 설계와 발생할 수 있는 실패 케이스를 고려하고 해당 케이스를 재처리하는 동작에 대한 설계를 진행했다. 내 이커머스 서비스에서 카프카 메시지 발행을 적용한 부분인 결제 완료 후 외부 데이터 플랫폼에 전송하는 시나리오를 예시로 설계한 내용은 다음과 같다.

  1. 먼저 결제 요청이 들어오고 결제 동작의 트랜잭션 BEFORE_COMMIT 이벤트에서 결제 이벤트용 Outbox 테이블에 INIT (최초 등록) 상태인 메시지 데이터를 저장한다.
  2. 결제 동작의 트랜잭션이 커밋되면 AFTER_COMMIT 이벤트에서 결제 이벤트용 Outbox 테이블에 저장되어 있던 데이터의 상태를 PUBLISH (발행) 상태로 업데이트하고 메시지를 카프카 브로커에 발행한다.
  3. 컨슈머 그룹 중 outbox 그룹의 컨슈머가 메시지를 소비하면서 Outbox 테이블에 저장되어 있던 데이터의 상태를 COMPLETE (완료) 상태로 업데이트한다.
  4. 컨슈머 그룹 중 ecommerce 그룹의 컨슈머가 메시지를 소비하면서 외부 데이터 플랫폼에 전송하는 동작을 수행한다.

처음에는 Outbox 데이터의 상태를 INIT과 COMPLETE 두 값으로만 가져서 BEFORE_COMMIT 이벤트에서 저장할 때 INIT 상태로 저장하고, AFTER_COMMIT 이벤트에서 메시지를 발행하면서 COMPLETE로 업데이트하는 것으로 생각했다. 하지만 카프카라는 외부 시스템이 장애가 발생하거나 브로커 서버가 다운되는 등 예상치 못한 문제가 발생할 가능성이 있기 때문에 위와 같은 구조로 설계했다.

다음으로 스케줄러로 실패 케이스에 대한 재처리 설계이다. 그 전에 어떤 실패 케이스가 있는지 고려해보았다. 그 결과 두 가지 케이스를 도출했는데,

  1. INIT 인 상태에서 지연되는 케이스
  2. PUBLISH 인 상태에서 지연되는 케이스

이 두 가지 케이스가 나올 것으로 예상했다. 나는 따로 FAIL 과 같이 실패 상태는 관리하지 않았기 때문에 만약 이벤트 수행 도중 예외가 발생한다고 해도 INIT 또는 PUBLISH 상태에서 멈춰있을 것으로 예상했다. (또는 Outbox 테이블에 아예 데이터가 저장되지 않은 케이스일텐데 그 경우엔 다시 요청을 하는 식으로 처리할 수 있을 것이다.)

먼저 INIT 인 상태에서 지연되는 케이스의 재처리 동작은 해당 Outbox 상태를 PUBLISH로 업데이트하고 카프카 브로커에게 메시지를 발행하는 식으로 재처리를 할 수 있겠다.

그리고 PUBLISH 인 상태에서 지연되는 케이스의 재처리 동작은 단순하게 다시 카프카 브로커에게 메시지를 발행하는 식으로 재처리를 해줄 수 있을 것으로 보인다.

이와 관련하여 더 자세한 내용은 이전 포스팅에 남겨놓았다.📝

추가로 결제의 Outbox 테이블의 ERD는 다음과 같이 설계했다.

3. 알게된 것

이번 과제로 직접 Transactional Outbox Pattern 전략을 구현해보며 메시지 발행 이벤트의 실패에 대한 대응을 직접 경험해볼 수 있었다. 하지만 구현하면서도 느꼈고, 멘토링 시간에 코치님께도 들은 것처럼 Transactional Outbox Pattern을 과도하게 사용하면 오히려 시스템 복잡도가 급증하는 단점이 있다고 한다. 실제로 메시지 발행 부분을 추가할 때마다 이러한 Outbox 처리를 해줘야 한다면 상당히 복잡해질 것으로 생각했다.

이러한 Transactional Outbox Pattern에 대한 단점을 보완하면서 메시지 발행에 대한 결과적 일관성을 보장하는 다양한 방법들을 찾아보며 아키텍처에 대한 지식을 넓혀봐야겠다!😄


이번 과제도 패스를 받고 드디어 대망의 블랙 뱃지를 얻을 수 있었다!😋

솔직히 항해 플러스를 처음 시작할 때만 하더라도 블랙 뱃지는 높은 산처럼 보였고, 레드 뱃지만 받아도 만족할 거 같다고 생각했었는데, 막상 이렇게 블랙 뱃지를 받게되니 기분이 묘하다…😶‍🌫️

항해 플러스를 하기 전에는 일을 할 때도 과연 내가 올바르게 하고 있는건지, 내가 생각한 게 맞는지 의구심이 들 때가 많았는데, 내가 맞게 잘 하고 있었다고 증명해주는 것 같아 상당히 기쁘다!!👍👏

그 동안 고생한 나에게 수고했다는 의미에서 오늘 저녁은 치킨을 먹어야겠다ㅎㅎ🍗


🤩 다음 수료생 추천 할인 혜택!

혹시라도 항해 플러스에 합류하고 싶은데 비싼 수강료 때문에 망설여진다면…? 🤔

수료생 추천 할인 혜택으로 20만 원을 할인받으실 수 있다는 사실! 💡

결제페이지 → 할인 코드 → 수료생 할인 코드에 tJQjYK 입력하면 추가로 20만 원을 할인받는 혜택 꼭 챙겨가시길 바란다🚀🚀🌟


#추천인: tJQjYK #항해플러스 #항해99