마이크로서비스 아키텍처(MSA) 분산 트랜잭션의 난제 해결: 2PC 프로토콜과 보상 트랜잭션(Saga Pattern) 구조 설계 분석
기술 면접관으로 참여하면서 가장 많이 질문하지만 가장 답변을 못 듣는 주제입니다. 개발자라면 꼭 알아야 할 내용을 제 주관적인 시각으로 풀어봤습니다.
과거 모놀리식(Monolithic) 시스템의 경직성을 극복하기 위해 폭발적으로 유행하게 된 마이크로서비스 아키텍처(MSA)는 소프트웨어 거버넌스, 배포의 민첩성, 개별 스케일아웃 방면에서 탁월한 이점을 선사하지만, 데이터베이스 관리 측면에서는 끔찍하게 고통스러운 설계적 재앙을 엔지니어들에게 동반시킵니다. 각 마이크로서비스 마이그레이션 모듈이 다른 모듈과의 결합도를 낮추기 위해 물리적으로 철저히 격리된 독립적인 자체 데이터베이스를 소유하게 되는 순간, 과거의 전통적인 RDBMS가 가장 자랑스러워하던 절대적인 ACID(원자성, 일관성, 고립성, 지속성) 트랜잭션의 지배력은 네트워크라는 위태로운 공간과 함께 산산이 파편화되어 버립니다. 예를 들어, 사용자가 주문을 완료했을 때 '주문 서비스'의 장부가 생성되고 동시에 '결제 서비스'의 잔액이 차감되며 '재고 서비스'의 상품 갯수가 감소해야 하는 필수 상호작용 프로세스는, 각기 다른 서버의 독립 트랜잭션으로 철저히 분열됩니다. 만약 결제 처리를 완벽하게 끝낸 후 재고 서버에 트래픽 패킷 웜홀이 생겨 통신이 끊어지게 된다면 전체 비즈니스 정합성에 막대한 결함이 기인하는 것입니다.
이 피할 수 없는 분산 트랜잭션 문제를 원초적으로 해결하기 위해 고안된 전통적인 기법이 분산 데이터베이스 이론의 2단계 커밋(2-Phase Commit, 2PC) 프로토콜입니다. 2PC 메커니즘은 코디네이터(Coordinator)라는 강력한 통제 노드 트랜잭션 마스터를 두고, 1단계인 준비(Prepare) 페이즈에서 엮여있는 모든 마이크로서비스 노드들에게 데이터 반영을 수행할 준비가 완벽히 되었고 데이터베이스 잠금(Lock)을 걸었다는 응답 투표(Vote) 콜백을 대기합니다. 만장일치로 예스(Yes) 신호가 회신되어 오면 2단계인 커밋 페이즈에서 전체 커밋을 지시 명령합니다. 단 하나라도 실패하거나 응답 지연을 보이는 노드가 있다면 글로벌 트랜잭션 어보트(Abort)를 날려 롤백을 수행시킵니다. 언뜻 견고하고 완벽해 보이는 이 프로토콜은 치명적이게도 네트워크 파티션 오작동에 지나치게 취약한 단일 장애점(SPOF) 문제를 가지며, 커밋이 만장일치로 완료될 때까지 관련 테이블과 레코드의 잠금을 해제하지 못하므로 엄청난 성능 저하와 데드락의 원흉이 됩나다. 즉 최신 대규모 트래픽 지향의 인터넷 서비스에는 부적합한 이론입니다.
대규모 클라우드 아키텍처에서 이 데이터 블락 병목을 피하며 정합성을 보장하기 위해 현재로서는 거의 유일한 정답으로 채택받는 아키텍처 기법이 사가 패턴(Saga Pattern)입니다. 사가 모델은 전역적인 하나의 트랜잭션 록을 거부하는 대신, 긴 비즈니스 로직 플로우를 여러 개의 연속적인 단일 로컬 트랜잭션으로 분할하여 순차적으로 비동기 트리거(메시지 큐 활용) 시킵니다. 핵심은 각 트랜잭션 스텝마다 예외 처리를 위한 보상 트랜잭션(Compensating Transaction)을 명시적으로 코딩해 둔다는 점입니다. 앞선 예시에서 재고 차감 과정이 물리/논리적 결함으로 실패할 경우, 시스템은 에러 이벤트를 브로드캐스팅하고 결제 서비스로 되돌아가서 차감된 금액을 환불해 주는 역방향 롤백 코드를 자체 실행하며, 다시 주문 서비스로 돌아가 주문 상태를 '취소됨'으로 물리 업데이트 시키는 역순 로직을 연계 실행해 내는 구조입니다. 이는 데이터가 일시적으로는 시스템 간에 일치하지 않는 순간적인 부정합 상태(Base State)를 유연하게 관용하지만, 시간이 흐른 후 복구 절차 메커니즘이 모두 완수되었을 때는 최종적인 완벽한 데이터 일관성(Eventual Consistency) 모델을 보장하는 철학적 타협에 기반합니다.