데이터 유실없이 이벤트 발행하는법 : MSA 방식의 아웃박스 패턴!
데이터 유실없이 이벤트 발행하기 : MSA 방식의 아웃박스 패턴!
안녕하세요. 지난번에는 마이크로서비스 아키텍처의 장점과 함께, 분산 시스템이 가져다주는 복잡성, 특히 ‘데이터 일관성’ 문제에 대해 잠깐 언급했습니다. 마이크로서비스 환경에서 서비스간의 통신은 대부분 비동기 이벤트 방식으로 이루어지는데, 이때 고민하는 문제중 하나가 ‘어떻게 하면 비동기 이벤트를 어떻게 동기화 하여 데이터 유실없이 처리할까?’ 입니다.
이러한 문제를 해결하는 방식 중 하나가 아웃박스 패턴이라고 하는데 자세히 알아보는 시간을 가져볼게요.
데이터 유실? 왜 발생할까?
마이크로서비스 환경에서 서비스 A 가 자신의 데이터베이스를 업데이트하고, 이어서 서비스 B에게 이벤트를 발행하는 시나리오가 있다고 가정해보겠습니다. 예를 들어, [주문 서비스]가 주문 상태를 ‘결제 완료’로 업데이트하고, 이어서 [재고 서비스]에게 ‘재고 감소’ 이벤트를 발행해야 하는 경우 입니다.
![[Pasted image 20250620103259.png]]
아웃박스 패턴: DB와 이벤트 발행의 원자성 보장!
아웃박스 패턴은 이 문제를 우아하게 해결합니다. 핵심 아이디어는 다음과 같습니다.
“이벤트 발행을 외부 메시지 큐로 직접 보내는 대신, 서비스 자신의 데이터베이스 내부에 ‘아웃박스(Outbox)’라는 테이블을 두고, 이 테이블에 이벤트 메시지를 먼저 기록한다.”
이때, 핵심 비즈니스 로직의 DB 변경과 아웃박스 테이블에 이벤트 메시지를 기록하는 작업은 ‘하나의 로컬 트랜잭션’으로 묶습니다.
그 후, 별도의 프로세스가 아웃박스 테이블을 주기적으로 모니터링하여 새로운 이벤트 메시지를 감지하고, 이를 실제 메시지 큐(Kafka, RabbitMQ 등)로 발행하는 방식입니다.
- OS as 주문 서비스
- ODB as 주문 DB
- OL as 아웃박스 리스너/릴레이 (별도 프로세스)
- MQ as 메시지 큐
- IS as 재고 서비스
![[Pasted image 20250620110131.png]]
아웃박스 패턴의 핵심 메커니즘
- 단일 로컬 트랜잭션:
- 핵심 비즈니스 로직의 데이터 변경 (예: 주문 상태 업데이트)
- Outbox 테이블에 이벤트 메시지 기록 (예: order_id, event_type, payload, status 등)
- 이 두 작업은 하나의 트랜잭션으로 묶어 원자성을 보장합니다. 둘 중 하나라도 실패하면 전체가 롤백됩니다.
- 아웃박스 테이블:
- 이벤트 메시지의 임시 저장소 역할을 합니다.
- 이벤트 데이터, 수신자 정보, 발행 상태, 타임스탬프 등을 저장
- 이벤트 릴레이(Event Relay) / 트랜잭션 로그 테일링:
- Polling Publish 방식 : 별도의 프로세스가 주기적으로 아웃박스 테이블을 스탠하여 미발행 상태의 이벤트를 찾아 메시지 큐로 발행합니다. 발행 후에는 아웃박스 테이블의 상태를 발행됨으로 변경하거나 삭제합니다.
- Transacional Log Tailing 방식 : 데이터베이스의 트랜잭션 로그를 직접 모니터링하여 변경 사항을 실시간으로 읽어와 메시지 큐로 발행합니다. Debezium 같은 도구가 이 방식을 구현합니다. 이 방식이 더 효율적이고 실시간성이 높습니다.
아웃박스 패턴의 고려할 부분
- 복잡성 증가 : 별도의 아웃박스 테이블과 이를 모니터링하고 이벤트를 발행하는 추가적인 컴포넌트가 필요해집니다.
- 추가 리소스 소모 : 아웃박스 테이블에 데이터를 저장하고, 주기적으로 읽어오는 과정에서 데이터베이스에 추가적인 부하 발생 합니다.
- 이벤트 순서 보장 : 여러 이벤트가 동시에 발생하고 비동기적으로 처리될 때, 이벤트의 순서를 정확하게 보장하는 것이 중요합니다. 아웃박스 패턴 자체는 순서를 보장하지 않으므로, 메시지 큐의 기능이나 별도 매커니즘이 필요합니다.
결론
아웃박스 패턴은 마이크로서비스 아키텍처에서 이벤트 기반 통신의 신뢰성과 데이터 무결성을 보장하는 데 필수적인 패턴입니다. 특히 ‘주문-결제’, ‘재고-배송’처럼 여러 서비스가 연루되어 데이터의 일관성이 절대적으로 중요한 시나리오에서 그 진가를 발휘합니다.
처음에는 시스템 복잡도가 늘어나는 것처럼 보일 수 있지만, 장기적으로 데이터 유실로 인한 치명적인 버그를 막고 시스템의 안정성을 크게 높여줄 수 있습니다. 마이크로서비스 환경에서 데이터 일관성과 이벤트 발행의 신뢰성을 고민하고 있다면, 아웃박스 패턴을 적극적으로 검토해 보시길 강력히 추천합니다!