분산 시스템 — 하나의 진실을 여러 곳에서 지키는 법

모놀리식에서는 공짜로 주어지던 것이 분산 환경에서는 가장 어려운 문제가 된다. 바로 일관성이다. DB가 하나일 때는 트랜잭션이 ACID로 다 해결해줬고, 락은 synchronized 한 줄이면 됐다.

서비스와 서버가 여러 개로 쪼개지는 순간 둘 다 깨진다. 분산 시스템의 일관성 문제는 크게 두 축으로 나뉜다. 여러 서비스에 걸친 작업을 어떻게 원자적으로 만드나(트랜잭션), 그리고 여러 서버가 같은 자원을 동시에 건드릴 때 어떻게 조율하나(동시성).


왜 분산되면 일관성이 비싸지나

단일 DB의 트랜잭션은 한 노드 안에서 커밋/롤백을 보장한다. 서비스가 각자 DB를 가지면 이 경계가 사라진다. 한 서비스는 성공하고 다른 서비스는 실패하는 부분 실패가 생긴다. 또 한 대였던 서버가 여러 대가 되면, 한 프로세스 안에서만 유효하던 락이 다른 서버의 동시 접근을 막지 못한다.

두 문제 모두 “네트워크 너머의 상태를 믿을 수 없다”는 분산의 본질에서 나온다.

① 트랜잭션 — 여러 서비스에 걸친 작업

2PC는 모든 참여자를 잠가 가용성을 해치니 MSA에서 잘 안 쓴다. 대신 Saga로 각 단계를 로컬 트랜잭션으로 처리하고 실패 시 보상 트랜잭션으로 되돌린다. 그리고 “DB 쓰기 + 메시지 발행”의 원자성은 Outbox 패턴으로 푼다. 결국 강한 일관성을 포기하고 최종 일관성 + 멱등성으로 간다.

MSA 트랜잭션과 Outbox 패턴

② 동시성 — 여러 서버가 같은 자원을 건드릴 때

synchronized는 한 JVM 안에서만 유효하다. 서버 두 대면 무력하다. 그래서 모두가 바라보는 외부 저장소(Redis)에 락을 둔다. SET NX PX로 원자적 획득, UUID로 소유권 확인, Lua로 원자적 해제. 단일 노드의 한계에서 Redlock이 나왔고, GC pause 같은 현실적 허점과 Redisson Watchdog 같은 보완책이 따라온다.

분산락 — Redis로 구현하고 Redlock까지

두 축이 만나는 지점

이 둘은 별개가 아니다. 재고 차감 같은 시나리오는 동시성 제어(락 또는 원자적 카운터)로 오버셀을 막고, 그 결과를 이벤트로 발행해(Outbox) 다른 서비스에 최종 일관성으로 전파한다. 동시성으로 순간을 지키고, 트랜잭션 패턴으로 시간에 걸친 일관성을 맞춘다.

면접에서 이 그림이 유용한 이유

“분산 트랜잭션 어떻게 처리하나”, “서버 여러 대에서 동시성 어떻게 막나”는 사실 같은 뿌리의 두 질문이다. “분산되면 단일 DB 트랜잭션과 프로세스 락이 둘 다 깨진다. 그래서 트랜잭션은 Saga+Outbox로 최종 일관성을, 동시성은 분산락이나 원자적 연산으로 푼다. 둘 다 강한 일관성을 포기한 대가로 멱등성과 보상 설계가 따라온다”고 묶어 답하면 구조가 잡힌다.