174. 분산 트랜잭션 한계 및 2PC (Two-Phase Commit) 배제 이유

핵심 인사이트: 2PC는 여러 DB에 흩어진 트랜잭션을 완벽하게 동시에 확정(Commit) 짓기 위해 군대식으로 통제하는 방법이다. "전원 준비됐나? 한 명이라도 안 됐으면 다 취소해!" 완벽해 보이지만, 단 1대라도 서버가 응답을 안 하면 나머지 서버가 하염없이 기다려야 하는 '블로킹(대기) 지옥'을 만들기 때문에 빠르고 유연한 MSA 환경에서는 절대 금기시된다.

Ⅰ. MSA에서 분산 트랜잭션(Distributed Transaction)의 딜레마

마이크로서비스 아키텍처(MSA)에서는 각 서비스가 독립적인 데이터베이스(DB per Service)를 갖습니다. 사용자가 상품을 구매하면, 1️⃣ 주문 DB에 INSERT 하고, 2️⃣ 결제 DB에 UPDATE를 해야 합니다. 그런데 만약 1번은 성공했는데 네트워크가 끊어져 2번이 실패한다면? 데이터의 일관성(정합성)이 깨지는 치명적인 문제가 발생합니다. 이를 해결하는 고전적인 방법이 분산 트랜잭션입니다.

Ⅱ. 2PC (Two-Phase Commit)의 개념과 동작 원리

전통적인 분산 트랜잭션 처리 기법인 2PC는 조정자(Coordinator) 가 중앙에서 여러 대의 DB를 통제하여 Prepare(준비)Commit(확정) 의 2단계로 트랜잭션을 처리합니다. (XA 트랜잭션 표준)

  1. Phase 1: Prepare (준비 단계)
    • 코디네이터가 주문 DB와 결제 DB 모두에게 "트랜잭션 확정할 준비(Lock) 다 됐어?"라고 묻습니다.
    • 각 DB는 테이블에 Lock(잠금)을 걸어두고, "준비 완료(Yes)" 또는 "문제 발생(No)"으로 응답합니다.
  2. Phase 2: Commit / Rollback (실행 단계)
    • 만약 모든 DB가 "Yes"라고 대답하면, 코디네이터는 "전원 Commit 해!"라고 최종 지시를 내립니다.
    • 단 하나의 DB라도 "No"라고 하거나 타임아웃이 나면, 코디네이터는 "전원 Rollback 해!"라고 지시하여 100% 무결성(ACID)을 보장합니다.

Ⅲ. MSA 환경에서 2PC를 배제(기피)하는 치명적 이유

완벽한 데이터 정합성을 보장함에도 불구하고, 넷플릭스 등 현대 클라우드/MSA 아키텍처에서는 2PC를 철저히 배제합니다. 그 이유는 극심한 동기식 블로킹(Blocking) 오버헤드 때문입니다.

2PC의 한계점설명
치명적인 성능 저하 (Lock 점유)Phase 1(준비)부터 Phase 2(종료)가 끝날 때까지, 관련된 모든 DB의 데이터(Row)는 무조건 강제로 락(Lock)이 걸립니다. 이 대기 시간 동안 다른 수만 명의 사용자들은 해당 데이터를 수정하지 못하고 대기(Blocking)해야 하므로 전체 시스템 성능이 폭락합니다.
코디네이터 SPOF 장애중앙 코디네이터 서버가 "전원 Commit!"을 외치기 직전 0.1초 만에 벼락을 맞아 죽어버리면? 각 DB는 락을 건 채로 영원히 대기 상태에 빠지는 교착 상태(Deadlock)의 지옥이 열립니다.
NoSQL / 메시지 큐 비지원클라우드 시대에 많이 쓰는 MongoDB, Redis, Kafka 등은 태생적으로 2PC(XA 트랜잭션)를 지원하지 않는 경우가 많아 폴리글랏 아키텍처에 적용이 불가능합니다.

Ⅳ. 2PC의 대안: 사가 패턴 (Saga Pattern)

블로킹 지옥을 만드는 2PC 대신, MSA에서는 최종 일관성(Eventual Consistency) 을 목표로 하는 비동기 트랜잭션 제어 기법인 사가 패턴(Saga Pattern) 을 사용하여 이 한계를 우아하게 극복합니다.

📢 섹션 요약 비유: 2PC는 친구 3명이 밥을 먹으러 갈 때 "나 갈 준비됐어, 너도 됐어? 너도? 셋 다 신발 신었지? 자 다 같이 문 열고 출발해!"(동기식 강제 통제) 방식입니다. 1명이라도 화장실에 가면 나머지 2명은 현관문에서 무한정 대기(Lock)해야 합니다. 이 대기 시간을 참을 수 없어 나온 것이, "일단 각자 먼저 출발하고 도착 못 한 애가 생기면 나중에 다시 모이자"는 비동기 방식의 사가 패턴입니다.