PostgreSQL: Prepared Transaction(2PC)
※ PostgreSQL: Prepared Transaction(Two-Phase Commit).
안녕하세요. 듀스트림입니다.
오늘은 분산 시스템에서 트랜잭션의 원자성을 보장하기 위해 사용하는 2PC 프로토콜의 일환인 Prepared Transaction 기능에 대한 내용입니다.
1. Prepared Transaction?
Prepared Transaction은 분산 시스템에서 트랜잭션의 원자성을 보장하기 위해 사용하는 기술로, PostgreSQL을 포함한 많은 데이터베이스에서 지원하는 기능입니다.
Prepared Transaction은 트랜잭션을 두 단계로 나누어 처리하는 2단계 커밋(2PC, Two-Phase Commit) 프로토콜의 일환으로 동작합니다.
이 기술은 분산 트랜잭션 처리에서 중요한 역할을 하며, 특히 여러 데이터베이스 시스템 간에 트랜잭션을 일관성 있게 처리해야 할 때 유용합니다.
+ 배경 지식
① 트랜잭션(Transaction):
- 트랜잭션은 데이터베이스에서 일련의 작업들을 하나의 단위로 묶어 처리하는 과정입니다.
- 트랜잭션은 ACID(Atomicity, Consistency, Isolation, Durability) 원칙을 따라야 하며, 이는 트랜잭션이 성공적으로 처리되거나 실패하면 전혀 처리되지 않은 것처럼 보이게 하여 데이터의 일관성을 유지합니다.
- Atomicity(원자성): 트랜잭션 내의 모든 작업은 모두 완료되거나, 전혀 실행되지 않은 것처럼 보이게 됩니다.
- Consistency(일관성): 트랜잭션이 끝나면 데이터베이스가 일관된 상태가 되어야 합니다.
- Isolation(격리성): 트랜잭션이 동시에 실행될 때, 다른 트랜잭션의 영향을 받지 않도록 격리됩니다.
- Durability(지속성): 트랜잭션이 커밋되면 그 결과는 영구적으로 저장됩니다.
② 2단계 커밋 프로토콜(2PC):
- 분산 트랜잭션을 처리하는 데 사용하는 프로토콜로 여러 데이터베이스 시스템에서 이루어지는 트랜잭션을 원자적으로 처리할 수 있도록 도와줍니다.
- 2단계 커밋은 두 가지 단계로 나뉩니다:
- 1단계 (Preparation phase): 트랜잭션이 실행되면 각 참가자(예: 여러 데이터베이스 노드)가 준비 상태로 트랜잭션을 확인하고, 커밋할 준비가 되었음을 알립니다.
- 2단계 (Commit phase): 모든 참가자가 준비 상태로 확인되면 트랜잭션이 커밋됩니다. 하나라도 준비되지 않으면 롤백이 이루어집니다.
2. Prepared Transaction 동작 방식
PostgreSQL에서는 PREPARE TRANSACTION, COMMIT PREPARED, ROLLBACK PREPARED 명령어를 사용하여 준비된 트랜잭션을 관리합니다.
※ Prepared Transaction을 사용하려면 max_prepared_transactions 설정을 활성화해야 합니다.
# postgresql.conf
max_prepared_transactions = 10
- Preparation(트랜잭션 준비):
- 트랜잭션이 시작된 후, PREPARE TRANSACTION 명령어를 사용하여 트랜잭션을 "준비" 상태로 만듭니다.
- 준비된 트랜잭션은 커밋 또는 롤백을 할 수 있는 상태가 되며, 트랜잭션에 포함된 모든 변경사항은 시스템 로그(WAL)에 기록되어 복구가 가능합니다.
BEGIN;
PREPARE TRANSACTION 'txn_id';
- Commit(트랜잭션 커밋):
- Prepared Transaction이 커밋될 때, COMMIT PREPARED 명령어를 사용하여 트랜잭션을 확정합니다.
- 커밋된 트랜잭션은 데이터베이스에 영구적으로 반영됩니다.
COMMIT PREPARED 'txn_id';
- Rollback(트랜잭션 롤백):
- Prepared Transaction을 롤백하려면 ROLLBACK PREPARED 명령어를 사용하여 트랜잭션을 취소하고, 이전 상태로 복구합니다.
- 롤백된 트랜잭션은 모든 변경 사항이 취소되고, 데이터베이스는 원래 상태로 복구됩니다.
ROLLBACK PREPARED 'txn_id';
+ ERROR: prepared transaction with identifier does not exist

이 오류는 Prepared Transaction의 식별자가 잘못됐을 때 발생합니다.
PREPARED 시 사용한 식별자와 COMMIT, ROLLBACK 시점에서 사용한 식별자가 다르거나, 이미 커밋이나 롤백이 된 트랜잭션일 경우 발생합니다.
Prepared Transaction의 상태는 pg_prepared_xacts 뷰에서 확인하실 수 있습니다.
3. Prepared Transaction의 장점
- 원자성(Atomicity) 보장:
- Prepared Transaction은 분산 시스템에서 원자성을 보장합니다. 여러 데이터베이스 시스템에서 이루어지는 트랜잭션을 안전하게 처리할 수 있습니다.
- 만약 어떤 노드에서 오류가 발생하면 다른 노드의 트랜잭션을 롤백하여 전체 트랜잭션이 원자적으로 취소될 수 있도록 합니다.
- 시스템 장애 복구:
- Prepared Transaction은 장애 발생 시 데이터베이스가 안전하게 복구할 수 있도록 합니다.
- 시스템이 종료되거나 장애가 발생해도 트랜잭션은 시스템 로그(WAL)에 기록되어 커밋되거나 롤백할 수 있습니다.
- 분산 트랜잭션 지원:
- 여러 데이터베이스 시스템이 분산된 환경에서 트랜잭션을 처리할 때, 준비된 트랜잭션을 사용하면 모든 시스템이 트랜잭션을 일관되게 처리할 수 있습니다. 이는 대규모 시스템에서 데이터 일관성을 보장하는 데 매우 중요합니다.
4. Prepared Transaction의 제한 사항
- 성능 오버헤드:
- Prepared Transaction은 시스템 로그에 트랜잭션 상태를 기록하고 트랜잭션을 커밋하거나 롤백하는 과정에서 성능 오버헤드가 발생할 수 있습니다. 특히 트랜잭션이 많이 발생하는 시스템에서는 성능 저하가 발생할 수 있습니다.
- 복잡성:
- 분산 트랜잭션을 구현하는 데 필요한 추가적인 복잡성이 존재합니다. 이를 관리하고 모니터링하려면 추가적인 관리 작업이 필요할 수 있습니다.
- max_prepared_transactions 설정:
- Prepared Transaction을 사용하려면 max_prepared_transactions 파라미터를 적절하게 설정해야 합니다. 이 값이 0으로 설정되어 있으면 준비된 트랜잭션을 사용할 수 없으므로 활성화하려면 해당 값을 변경해야 합니다.
5. 분산 시스템에서 Prepared Transaction 사용 예시
분산 시스템은 여러 대의 서버가 협력하여 작업을 처리하는 시스템입니다.
각 서버는 서로 다른 데이터베이스 인스턴스를 실행할 수 있으며, 이들 간에 트랜잭션을 처리할 때 데이터 일관성을 유지하는 것이 중요합니다.
5.1 은행 시스템
여러 지점에서 동시에 트랜잭션을 처리하는 은행 시스템에서의 예시입니다.
- 시나리오:
- A 은행의 지점에서 사용자가 100만원을 송금합니다.
- 송금 대상은 B 은행에 있는 사용자입니다. 두 은행 시스템은 서로 다른 데이터베이스에 분산되어 있습니다.
- 두 데이터베이스가 독립적으로 운영되기 때문에 송금 트랜잭션을 처리할 때 반드시 두 시스템에서 동시에 처리가 이루어져야 하며, 실패 시 두 은행의 데이터가 일관성 있게 복구되어야 합니다.
- 과정:
- 트랜잭션 시작:
- 사용자 A가 송금을 요청하면 A 은행의 데이터베이스에서 출금 트랜잭션이 시작됩니다.
- 동시에 B 은행의 데이터베이스에서 입금 트랜잭션이 시작됩니다.
- PREPARE TRANSACTION:
- 각 은행의 데이터베이스는 트랜잭션을 Prepared 상태로 만듭니다.
- A 은행과 B 은행 모두 PREPARE TRANSACTION 명령어를 실행하여 Prepared Transaction을 만들어 둡니다.
- 이때 트랜잭션은 실제로 커밋되거나 롤백되지 않고 준비 상태로 유지됩니다. 각 은행은 pg_prepared_xacts 테이블에 해당 트랜잭션을 기록하여 Prepared 상태임을 명확히 합니다.
- COMMIT PREPARED:
- 양측 은행에서 모든 준비가 완료되면 두 은행은 COMMIT PREPARED 명령어를 실행하여 송금 트랜잭션을 커밋합니다.
- A 은행은 출금 트랜잭션을 커밋하고, B 은행은 입금 트랜잭션을 커밋합니다.
- 두 은행이 모두 커밋을 완료하면 송금은 성공적으로 이루어집니다.
- ROLLBACK PREPARED (실패 처리):
- 만약 A 은행에서 송금 트랜잭션을 Prepared 했지만 B 은행에서 입금 트랜잭션을 Prepared 하지 못했거나 오류가 발생한 경우 두 은행은 ROLLBACK PREPARED 명령어를 실행하여 트랜잭션을 취소합니다.
- 이로 인해 두 은행은 트랜잭션이 커밋되지 않았고 시스템의 데이터는 일관성 있게 유지됩니다.
- 트랜잭션 시작:
- 장점:
- 원자성(Atomicity):
- 송금 트랜잭션은 A 은행과 B 은행에서 모두 성공적으로 처리되거나, 하나라도 실패하면 전체 트랜잭션이 롤백되어 데이터 일관성이 유지됩니다.
- 시스템 장애 복구:
- 두 은행의 시스템 중 하나가 장애가 발생해도 트랜잭션이 Prepared 상태로 로그에 기록되므로 장애가 복구된 후 트랜잭션을 정상적으로 커밋하거나 롤백할 수 있습니다.
- 원자성(Atomicity):
5.2 전자 상거래 시스템 (MSA)
전자 상거래 시스템에서 주문과 결제가 다른 시스템에서 이루어지는 경우의 예시입니다.
- 시나리오:
- 고객이 웹사이트에서 상품을 주문하고 결제하려고 합니다.
- 결제는 결제 시스템 데이터베이스에서 이루어지고 주문 정보는 주문 시스템 데이터베이스에 기록됩니다.
- 주문과 결제는 서로 다른 시스템에서 관리되므로 결제와 주문이 원자적으로 이루어져야 하며 두 시스템의 데이터가 일관성을 유지해야 합니다.
- 과정:
- 트랜잭션 시작:
- 고객이 결제 정보를 입력하면, 결제 시스템과 주문 시스템에서 각각 트랜잭션을 시작합니다.
- PREPARE TRANSACTION:
- 결제 시스템과 주문 시스템은 트랜잭션을 Prepared 상태로 만듭니다.
- 결제 시스템은 결제 금액을 차감하는 작업을 준비하고 주문 시스템은 주문 데이터를 기록할 준비를 합니다.
- COMMIT PREPARED:
- 결제와 주문이 모두 준비되면 두 시스템에서 각각 COMMIT PREPARED 명령어를 실행하여 트랜잭션을 커밋합니다.
- 결제 시스템은 결제 정보를 커밋하고 주문 시스템은 주문 정보를 커밋합니다.
- ROLLBACK PREPARED (실패 처리):
- 만약 결제 시스템에서 결제 실패가 발생하거나 주문 시스템에서 오류가 발생하면 두 시스템은 ROLLBACK PREPARED 명령어를 실행하여 트랜잭션을 취소하고 모든 변경사항을 롤백합니다.
- 트랜잭션 시작:
- 장점:
- 분산 트랜잭션:
- 결제 시스템과 주문 시스템이 분리되어 있어도 Prepared Transaction을 사용하면 두 시스템 간의 데이터 일관성을 보장할 수 있습니다.
- 높은 신뢰성:
- 트랜잭션이 완전하게 처리되지 않으면 자동으로 롤백되므로 고객 데이터와 거래가 안전하게 보호됩니다.
- 분산 트랜잭션:
5.3 전자 상거래 시스템 (대규모 분산 시스템)
대규모 분산 데이터베이스 환경에서는 여러 데이터베이스 인스턴스가 서로 다른 서버에 분산되어 운영됩니다.
이 경우 한 데이터베이스에서 발생한 트랜잭션이 다른 데이터베이스에 영향을 미칠 수 있습니다.
- 시나리오:
- 여러 데이터베이스 노드가 서로 다른 데이터 Shard를 관리하며, 하나의 트랜잭션이 여러 노드에 걸쳐 데이터를 삽입, 업데이트 또는 삭제해야 합니다.
- 예를 들어 지역 A와 지역 B의 데이터를 각각 다른 노드에서 관리하는 대규모 온라인 서비스에서는 한 사용자가 지역 A에서 상품을 주문하고 지역 B에서 해당 상품을 배송 준비해야 하는 경우 두 지역의 데이터베이스를 모두 일관되게 처리해야 합니다.
- 과정:
- 트랜잭션 시작:
- 사용자가 상품을 주문하면 지역 A의 데이터베이스에서 주문 트랜잭션을 시작하고 지역 B의 데이터베이스에서도 배송 준비 트랜잭션을 시작합니다.
- PREPARE TRANSACTION:
- 두 지역의 데이터베이스에서 각각 트랜잭션을 Prepared 상태로 만듭니다.
- 지역 A는 주문을 기록하고 지역 B는 배송 준비를 위해 데이터를 준비합니다.
- COMMIT PREPARED:
- 두 지역 모두 준비 상태에 도달한 후, 트랜잭션을 커밋하여 주문과 배송 준비를 동시에 처리합니다.
- ROLLBACK PREPARED (실패 처리):
- 만약 한 지역의 데이터베이스에서 문제가 발생하면, ROLLBACK PREPARED 명령어를 사용하여 두 지역의 트랜잭션을 모두 롤백합니다.
- 트랜잭션 시작:
오늘은 여기까지~