마이크로서비스 아키텍처(MSA) 설계 패턴: Saga와 API Gateway로 데이터 일관성 정복하기
1. MSA의 양날의 검: 분산 데이터 관리
마이크로서비스 아키텍처(MSA)는 거대한 애플리케이션을 작고 독립적인 서비스 단위로 분리하여 개발 유연성과 확장성을 극대화하는 현대적인 아키텍처 스타일입니다. 각 서비스는 자체적인 데이터베이스를 소유하며(Database per Service 패턴), 다른 서비스에 대한 의존성 없이 독립적으로 개발, 배포, 확장이 가능합니다. 이러한 특징은 팀의 생산성을 높이고 서비스 장애가 전체 시스템으로 확산되는 것을 막아주는 큰 장점을 가집니다.
하지만 이 '독립성'은 데이터 관리 측면에서 복잡한 문제를 야기합니다. 전통적인 모놀리식(Monolithic) 아키텍처에서는 단일 데이터베이스 내에서 ACID(원자성, 일관성, 고립성, 지속성) 트랜잭션을 통해 데이터의 정합성을 손쉽게 보장할 수 있었습니다. 그러나 여러 서비스에 걸쳐 데이터베이스가 분산된 MSA 환경에서는 여러 서비스의 DB를 하나의 트랜잭션으로 묶는 것이 거의 불가능에 가깝습니다. 이것이 바로 MSA 도입 시 개발자들이 가장 먼저 부딪히는 '분산 트랜잭션'과 '데이터 일관성' 문제입니다.
2. 왜 전통적인 분산 트랜잭션(2PC)은 MSA에 적합하지 않은가?
분산 트랜잭션을 구현하는 기술로 2PC(Two-Phase Commit)가 존재합니다. 하지만 2PC는 모든 참여자가 트랜잭션에 동의해야 커밋하는 방식으로, 참여하는 서비스가 많아질수록 전체 시스템의 성능을 저하시키고 특정 서비스에 장애가 발생하면 전체 트랜잭션이 중단되는 '결합도' 문제를 발생시킵니다. 이는 서비스 간의 느슨한 결합(Loose Coupling)을 추구하는 MSA의 근본 철학과 정면으로 배치됩니다. 따라서 MSA 환경에서는 다른 접근 방식이 필요합니다.
3. MSA 데이터 일관성을 위한 핵심 패턴: Saga 패턴
Saga 패턴은 장시간 실행되는 비즈니스 프로세스를 여러 개의 '로컬 트랜잭션(Local Transaction)'의 순차적인 집합으로 구성하는 데이터 관리 패턴입니다. 각 서비스는 자신의 데이터베이스에 대한 로컬 트랜잭션을 성공적으로 완료한 뒤, 다음 서비스를 트리거하기 위해 이벤트를 발행합니다. 만약 중간 단계에서 하나의 로컬 트랜잭션이 실패하면, 이전에 성공했던 모든 트랜잭션을 취소하는 '보상 트랜잭션(Compensating Transaction)'을 역순으로 실행하여 데이터의 최종 일관성(Eventual Consistency)을 보장합니다.
예를 들어, 온라인 쇼핑몰의 '주문' 프로세스를 생각해 봅시다.
- 주문 서비스: 주문 생성 (로컬 트랜잭션 1) -> 'OrderCreated' 이벤트 발행
- 결제 서비스: 'OrderCreated' 이벤트 수신 -> 결제 처리 (로컬 트랜잭션 2) -> 'PaymentCompleted' 이벤트 발행
- 재고 서비스: 'PaymentCompleted' 이벤트 수신 -> 재고 차감 (로컬 트랜잭션 3) -> 'StockUpdated' 이벤트 발행
만약 3단계에서 재고가 부족하여 '재고 차감'이 실패하면 어떻게 될까요? Saga 패턴은 보상 트랜잭션을 실행합니다. '결제 서비스'는 결제를 취소하고, '주문 서비스'는 주문 상태를 '취소'로 변경하여 전체 프로세스를 원상 복구합니다. 이처럼 Saga는 엄격한 즉시적인 일관성 대신, 최종적으로 데이터가 일관된 상태에 도달하도록 보장하는 실용적인 해법입니다.
Saga 구현 방식:
- 코레오그래피 (Choreography): 중앙 관제탑 없이 각 서비스가 이벤트를 발행하고 구독하며 자율적으로 동작하는 방식입니다. 서비스 간 결합도가 낮아 유연하지만, 전체 프로세스를 파악하기 어렵다는 단점이 있습니다.
- 오케스트레이션 (Orchestration): '오케스트레이터'라는 중앙 관리 서비스가 전체 프로세스의 흐름을 제어하고 각 서비스의 트랜잭션을 순차적으로 호출하는 방식입니다. 흐름이 중앙 집중화되어 관리와 모니터링이 용이하지만, 오케스트레이터가 단일 실패 지점(SPOF)이 될 수 있습니다.
4. 게이트웨이의 재발견: API Gateway 패턴의 역할
API Gateway는 클라이언트의 모든 요청을 받는 단일 진입점(Single Point of Entry) 역할을 합니다. 클라이언트는 여러 마이크로서비스의 존재를 알 필요 없이 게이트웨이와만 통신하면 됩니다. API Gateway는 요청을 적절한 서비스로 라우팅하고, 여러 서비스의 응답을 조합하여 클라이언트에게 전달하는 역할을 수행합니다.
데이터 일관성 측면에서 API Gateway는 Saga 패턴의 '오케스트레이터' 역할을 수행할 수 있습니다. 클라이언트로부터 하나의 복합적인 요청(예: '상품 주문 및 결제')을 받은 API Gateway가 내부적으로 주문 서비스, 결제 서비스, 재고 서비스를 순차적으로 호출하고, 중간에 실패가 발생하면 보상 트랜잭션까지 직접 호출하여 전체 비즈니스 로직의 흐름을 관리할 수 있습니다. 이는 비즈니스 트랜잭션 로직을 각 서비스에서 분리하여 게이트웨이에서 중앙 관리하는 효과를 가져옵니다.
5. 또 다른 중요 패턴: CQRS (명령과 조회의 책임 분리)
CQRS(Command Query Responsibility Segregation)는 시스템의 상태를 변경하는 '명령(Command)' 모델과 데이터를 조회하는 '조회(Query)' 모델을 분리하는 패턴입니다. 쓰기 작업(Command)은 Saga 패턴 등을 통해 데이터 일관성을 관리하고, 읽기 작업(Query)은 미리 최적화된 조회용 데이터 모델을 사용합니다. 이 패턴을 적용하면 복잡한 조회 로직이 쓰기 로직에 영향을 주지 않아 시스템의 성능과 확장성을 크게 향상시킬 수 있습니다.
마이크로서비스 아키텍처에서 데이터 일관성을 유지하는 것은 결코 간단한 문제가 아닙니다. ACID 트랜잭션의 단순함을 포기하는 대신, 우리는 Saga, API Gateway, CQRS와 같은 다양한 설계 패턴을 통해 '최종 일관성'을 달성해야 합니다. 어떤 패턴을 선택할지는 비즈니스의 요구사항, 데이터의 중요도, 팀의 기술적 성숙도에 따라 달라집니다. 성공적인 MSA 구축은 단순히 서비스를 잘게 나누는 것에서 끝나는 것이 아니라, 분산된 데이터의 흐름을 어떻게 일관성 있게 관리할 것인가에 대한 깊은 고민에서 시작됩니다.
댓글
댓글 쓰기