[분산컴퓨팅] 중계자와 2단계 커밋 프로토콜

앵우·2026년 1월 13일

개요


분산 프로세스 간 올바른 거래의 어려움

Alice와 Bob이 둘다 만원을 가지고 있고 Alice가 Bob에게 천원을 이체한다고 하자. 그러면 Alice는 구천원, Bob은 만천원을 가지는 결과를 예상하고 싶다.

  • Alice 입장에서
    • 비동기적 통신으로 인해 Bob의 은행에서 이체 메시지를 확실히 받을 수 있는 보장이 없다.
    • Bob의 은행이 해당 메시지를 아직 받지 않은 상황에서 Alice가 잔고를 업데이트한다면 Alice만 손해를 입을 것이다.
    • Alice가 안전하게 잔고를 갱신하기 위해서는 Bob으로부터 이체를 받았다는 메시지 수신이 필요하다.
  • Bob 입장에서
    • Bob이 Alice로부터 이체 메시지를 받았다. Bob은 이대로 자신의 잔고를 늘려도 될까? -> X
    • Bob이 알리려는 내용이 Alice에게 정확하게 전달되지 않으면 Alice는 잔고를 갱신하지 않고 Bob의 잔고만 증가하게 된다.

안전성과 라이브니스


분산 컴퓨팅 시스템에게 요구하는 두 가지 기본 요건

  1. 안전성(Safety) - 잘못된 결과가 일어나서는 안 되는 원칙
  2. 라이브니스(Liveness) - 원하는 결과가 반드시 어느 시점에는 실현되어야 하는 원칙

안전성과 라이브니스 동시 충족 문제

  • 안전성에만 초점을 맞춘다면 서로 메시지를 반복적으로 주고 받다가 결국 라이브니스 요구사항을 충족하지 못하게 된다.
  • 안전성과 라이브니스를 모두 추구하다가 교착 상태에 빠질 수 있다.
  • 컴퓨터 네트워크가 비동기적 통신 문제를 완전하게 해결할 수 있는 상황이 아니라면 양자 합의 방식을 통해 안전성과 라이브니스를 모두 충족하면서 수행하는 것은 매우 어렵다.

2단계 커밋 프로토콜


트랜잭션: 분산 컴퓨팅 참여 프로세스들 간의 거래 행위

  • 트랜잭션이 안전하게 수행되려면 해당 트랜잭션은 ‘원자성(Atomicity)’을 가져야 한다.
  • 트랜잭션이 원자성이 있다고 하는 것은 트랜잭션에 참여하는 컴퓨팅 주체들이 모두 해야 할 일을 하거나, 아예 시작도 하지 않는다는 것

원자성을 보장하면서 트랜잭션이 수행될 수 있도록 하는 ‘2단계 커밋 프로토콜(Two-Phase Commit)’

  • 트랜잭션을 중계하는 코디네이터 TC(Transaction Coordinator)
  • 예: Alice의 이체 요청을 받아와 Alice와 Bob의 은행에 전달하여 트랜잭션이 안전하게 수행되도록 함

스트로우맨 프로토콜

예:
a. Alice가 천원을 Bob의 S 은행 계좌에 이체할 것을 TC에게 요청한다. (Go! 메시지)
b. 요청을 전달받은 TC는 K 은행에 Alice 계좌에서 천원을 출금하고, S 은행에는 Bob의 계좌에서 천원을 입금하라고 동시에 전달한다.
c. TC는 Alice에게 요청을 잘 전달했다고 회신한다.

중앙의 중계자가 존재해도 스트로우맨 프로토콜이 잘 작동하지 않는 경우들

  1. 만약 Alice가 천원도 없었다면
  2. 만약 Bob의 계좌가 없었다면 → Alice 천원 잃음
  3. (가정) Alice의 K 은행이 TC로부터 요청을 받기 전에 예기치 않은 정전 발생으로 시스템이 중단되었다.
    • TC는 일단 명령을 내린 후에 바로 Alice에게 요청을 잘 전달했다고 회신
    • 하지만 K은행이 시스템이 중단되어 전달을 받지 못했다면 TC의 회신이 Alice에게 전달되지 않음
  4. TC와 Bob의 S 은행 사이의 네트워크가 중단되었을 때 Alice의 계좌에서만 출금 발생
  5. TC의 동작 중 중단
    • Alice의 계좌에서는 출금되고 Bob의 계좌에는 입금되지 않은 상황 발생

장애가 일어날 수 있다는 것을 전제하고 ‘장애에 내성(Fault-tolerant)’을 가진 분산 컴퓨팅 시스템을 구축하여 안전성이 위반되는 일 자체를 막는 것이 더욱 현명한 방안이다.

원자적 커밋 프로토콜

장애가 발생하더라도 안전하게 트랜잭션을 수행할 수 있도록 스트로우맨 프로토콜의 문제 개선

a. Alice가 TC에게 K 은행에서 S 계좌로 이체할 명령을 내린다.

b. TC가 Alice의 명령을 받으면, 두 은행에게 준비하라는 명령을 동시에 내린다.

c. 각 은행은 준비 명령에 대해서 예(Yes) 또는 아니오(No)로 TC에게 회신한다.

TC는 두 은행으로부터 받은 회신들을 바탕으로 이행을 확약해야 할지, 아니면 명령을 취소해야 할지 결정해야 한다.

  • 두 은행에서 모두 ‘예’라고 했다면 TC는 이행하라면 메시지를 두 은행에 보낸다. + Alice에게 이체 요청을 잘 처리했다고 회신
  • 만약에 한 은행이라도 ‘아니오’라고 회신했다면, TC는 명령을 취소한다는 메시지를 보낸다. + Alice에게 요청 처리가 실패했다는 메시지를 보낸다.

안전성 보장을 위한 조치

TC가 Commit 메시지를 보낸 직후 TC가 중단된 경우

문제

  • TC가 중단되면 Alice에게 이체를 처리했는지 안 했는지에 대한 회신을 할 수 없고,
  • TC가 중단된 상태에서 정상 상태로 돌아왔을 때, TC가 Commit 메시지를 보냈는지에 대한 여부를 기억하지 못하고 있다면 사용자에게 이체 처리 결과를 알려줄 수도 없다.
  • TC의 Commit 메시지가 정상적으로 K 은행과 S 은행에 도달해서 각 은행들이 출금과 입금을 진행했는데, 막상 TC는 자신이 Commit 메시지를 보냈지만 이제 요청 처리 상태를 모르게 되었다.

⇒ TC가 Commit 메시지를 보낸 사실을 기억하지 못하는 상황

해결
→ 항상 중단될 것ㅇ르 대비하여 TC는 Commit 메시지를 보내기 바로 직전에 Commit 메시지를 보낼 것이라는 ‘기록(log)’을 디스크에 저장한다.

⇒ TC가 중단되고 다시 재구동했을 때, 디스크의 기록을 찾아 Commit 메시지를 보냈다고 기억할 수 있고, Alice에게 이체 명령 처리 상태를 온전하게 보내줄 수 있다.

K 은행과 S 은행 모두 준비 메시지에 대해서 ‘예’라고 답했지만, 메시지를 보낸 즉시 둘 중의 한 은행이 중단된 경우

문제

S 은행은 메시지를 수신하자마자 TC가 보낸 Commit 메시지를 전달받지 못하고, 시간이 지나 다시 S 은행이 정상적인 상태로 돌아왔지만 S 은행은 ‘예’라는 메시지를 보낸 기억이 없으며, 중단된 동안 TC가 보낸 Commit 메시지도 받지 못한 상황

해결

K 은행과 S 은행도 메시지를 보내기에 앞서 디스크에 해당 메시지를 보낸다는 저장을 먼저 진행

  • S은행에서 디스크에 저장한 기록을 보고 TC에게 ‘예’라고 회신했는데, Commit 사실 메시지를 받은 적이 없다는 것을 확인했다면
  • TC에게 ‘예’라는 메시지를 재전송하고 다시 Commit 메시지를 전달받아 자신이 해야 할 출금 작업을 이행할 수 있도록 해야 한다.

명령 또는 회신 메시지들을 디스크에 기록하려는 찰나에 중단 발생하는 경우

  • 만약 TC가 중단된 상태에서 정상으로 돌아와 기록을 확인했을 때, Commit 메시지를 보냈다는 기록이 없었다면 그대로 이체 명령을 취소한다.
  • 마찬가지로 은행들 역시 중단 상태에서 정상으로 돌아와 기록을 확인했을 때, ‘예’라는 메시지를 보냈다는 기록을 가지고 있지 않다면, 각자 이체를 위해서 해야 할 작업들을 그대로 취소한다.

라이브니스 보장을 위한 조치

<상황1>
K 은행이 ‘예’ 메시지를 보낸다는 것을 기록할 찰나에 중단되어 버렸고, S 은행은 준비 명령을 받은 후 TC에게 ‘예’라고 답했다.

  • TC 입장에서는 K 은행 자체가 문제가 있어 답변하지 않는 건지, 단순하게 네트워크 자원에 문제가 있어서 답변이 오지 않는 것인지 알기 어렵다.
  • 아무런 행동 없이 기다려야 한다는 것은 해야 할 일이 결국은 일어나야 한다는 조건, 라이브니스를 위반하게 되는 것이다.

해결

  • 메시지가 정해진 시간 내에 오지 않으면 당초의 명령을 취소하고, Alice에게 다시 이체 요청을 해야 한다고 알린다. (처음부터 모든 과정을 반복해야 하므로 시간 낭비)

<상황2>
K와 S 은행 모두 ‘예’라고 답했으며 디스크 기록까지 완료, 하지만 TC로부터 응답 X

  • 다른 은행이 동의했는지에 대한 여부를 모르기 때문에 Commit 메시지 없이 독단적으로 작업을 이행할 수 없다.
  • 두 은행은 TC의 후속 명령 없이는 마냥 기다려야 한다.

→ 안전성을 보장하지만 라이브니스 위반

해결 - 두 은행이 서로의 상태를 확인하는 과정을 추가

K은행은 S은행에게 직접 상황을 물어보기로 한다.

  • (경우1) S 은행이 무응답 → K 은행은 TC로부터의 후속 명령을 기다리기
  • (경우 2) S 은행이 TC로부터 Commit 또는 취소 명령을 받았다고 응답한다. → K 은행은 자신도 그 명령을 받은 것으로 간주
    • TC에서 S 은행 사이의 네트워크는 문제없었고, TC와 K 은행 사이의 네트워크에 문제가 있었다고 판단
  • (경우 3) S 은행이 K 은행에게 아직 TC에게 답변하지 않았다거나, 아예 ‘아니오’를 회신했다고 말한다. → K 은행은 더 이상 기다릴 것 없이 자신이 할 일을 취소해버리면 된다.
    • TC가 프로세스를 재시작하는 것이 훨씬 빠르다.
  • (경우 4) S 은행이 K 은행에게 TC에게 ‘예’라고 회신했다고 말한다. → K과 S은행은 TC로부터 후속 명령을 계속 기다리면 된다.

⇒ 두 은행 간에 상황 메시지 확인 절차를 통해 더 빠른 이행 확약 여부를 결정하는 프로토콜 종료 및 재시작의 기준을 프로토콜에 더하여 라이브니스 문제를 해소

2단계 프로토콜 수행 예시

2단계 커밋 프로토콜(Two-Phase Commit Protocol) 혹은 2PC 프로토콜

: 원자적 커밋 프로토콜에 선제적 메시지 기록을 통한 메시지 재전송과 프로토콜 종료 또는 재시작의 조건을 더해서 이행 확약의 안전성과 라이브니스를 보장하는 프로토콜

알고리즘

  1. 클라이언트가 TC(Transaction Coordinator)에게 트랜잭션 명령 메시지를 보낸다.
  2. TC가 트랜잭션에 참여하는 모든 프로세스들에게 트랜잭션을 수행할 준비를 하라는 메시지를 보낸다.
  3. 준비하라는 메시지를 받은 각 프로세스는 TC에게 ‘예’ 또는 ‘아니오’라고 답변한다.
  4. TC의 결정
    • 만약 모든 프로세스들이 ‘예’라고 답했다면 TC는 모든 프로세스에게 명령 이행을 확약하라는 메시지를 보낸다.
    • 만약에 어느 한 프로세스라도 ‘아니오’라고 답한다면 클라이언트의 이행을 취소한다는 메시지를 보낸다.

(예) S 은행이 ‘예’라고 메시지를 TC에게 보내기 전에 장애가 발생했지만, K 은행은 ‘예’라고 메시지를 이미 보냈고 TC도 해당 메시지를 받았다.

  • ‘예’라고 전달한 기록이 없다면 TC가 Commit 메시지를 전송했을리가 없을 것이므로 문의할 필요가 없다.
  • TC는 실제로 제시간 안에 S 은행으로부터 아무런 응답을 받지 못했으므로 취소 메시지를 보낸 상황
  • S은행이 중단되었다가 정상 상태로 돌아왔을 때, ‘예’ 메시지에 대한 기록이 없다면 바로 준비 상황을 취소하는 것으로 받아들이면 된다.

(예) S 은행이 ‘예’라고 답변한 후에 중단되었다.

‘예’라고 회신한 기록이 있기 때문에 K 은행의 회신에 따라서 TC는 어떤 결정을 내렸을 것이다.

  • TC가 Commit 메시지나 취소 메시지를 보낼 시점에서 S 은행이 회복됐다면, 해당 후속 메시지가 그림과 같이 S 은행에 도착할 것이다.
  • 만약 기다렸는데 오지 않으면 상대 은행인 K 은행에게 지금까지 어떤 결정이 있었는지 물어보면 된다.

(예) S 은행이 ‘예’ 메시지를 보낸 후에 중단되었고, 해당 회신 메시지도 네트워크 장애로 인하여 TC에 전달되지 않았다.

  • ‘예’ 메시지가 TC에 도달하지 않았고, TC는 기다리다가 실제 취소 메시지를 보냈다.
  • 이후 S 은행이 다시 정상적으로 작동하여 ‘예’ 메시지를 보냈었다는 것을 알았지만, 아직 어떤 결정이 난지는 알 수 없다.
  • 이때 ‘예’ 메시지를 다시 TC에 보내서 어떤 결정이 났는지를 물어 알아볼 수 있다.

(예) TC에게 문의했을 때 응답 X

  • TC가 회복할 때까지 기다리지 않고, S 은행이 K 은행에게 직접 문의하여 TC의 후속 명령이 무엇이었는지 질문하고 그에 맞게 자신이 할 일을 결정하면 된다.


도서 - 분산컴퓨팅 2장

0개의 댓글