2-Phase Commit (2PC)
2단계 커밋은 분산 데이터베이스 관리 시스템에서 트랜잭션의 일관성을 보장하기 위한 프로토콜입니다. MSA는 여러 독립적인 마이크로서비스로 구성되어 있으며, 이러한 서비스들 간의 트랜잭션 일관성을 유지하기 위해 2단계 커밋이 사용될 수 있습니다.
2PC의 원리
1. 준비 단계 (Prepare Phase)
- 트랜잭션 코디네이터(주로 분산 트랜잭션 매니저)는 모든 참여자 서비스에게 트랜잭션 수행에 동의할 것인지 물어봅니다.
- 각 서비스는 트랜잭션이 성공적으로 수행될 수 있는지 여부를 판단하고 준비 완료 시 코디네이터에게 알립니다.
- 만약 어떤 서비스라도 트랜잭션이 성공적으로 수행될 수 없다면 모든 참여자에게 롤백 명령이 전송됩니다.
2. 커밋 단계 (Commit Phase)
- 모든 참여자 서비스가 준비 완료를 보고하면, 코디네이터는 커밋 명령을 전송합니다.
- 각 서비스는 이 명령에 따라 트랜잭션을 커밋하거나 롤백합니다.
2PC의 한계
1. Blocking Issue
- 2PC는 참여자 서비스들이 트랜잭션에 참여하고 준비 완료 신호를 기다리는 동안 코디네이터가 블록될 수 있습니다. 특히, 하나의 서비스가 응답하지 않으면 전체 트랜잭션이 막힐 수 있습니다.
2. Single Point of Failure
- 코디네이터가 분산 환경에서 단일 장애 지점이 될 수 있습니다. 코디네이터의 장애는 전체 트랜잭션을 막을 수 있으며, 이는 시스템의 가용성과 내결함성에 영향을 미칠 수 있습니다.
3. 성능 저하
- 2PC는 트랜잭션 처리를 위해 여러 단계를 거쳐야 하기 때문에 성능 저하가 발생할 수 있습니다. 특히, 다수의 참여자 서비스가 있는 경우에는 트랜잭션 처리 시간이 증가할 수 있습니다.
2PC의 대안
1. 3단계 커밋 등의 확장된 프로토콜 사용
- 일부 시나리오에서는 3단계 커밋과 같은 더 복잡한 프로토콜을 사용하여 2PC의 일부 한계를 극복할 수 있습니다.
2. 분산 트랜잭션을 피하는 방법 고려
- 느슨하게 결합된 서비스 간의 통신을 통해 트랜잭션 일관성을 관리하는 방식도 고려할 수 있습니다. 이벤트 소싱, CQRS 등의 패턴을 활용할 수 있습니다.
2PC의 예시와 코드
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TwoPhaseCommitExample {
private static final String DB_URL = "jdbc:mysql://localhost:3306/example";
private static final String DB_USER = "username";
private static final String DB_PASSWORD = "password";
public static void main(String[] args) {
try {
// Step 1: Establish connection with the coordinator
Connection coordinatorConnection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
coordinatorConnection.setAutoCommit(false);
// Step 2: Participants (Services) prepare to commit
Connection service1Connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
Connection service2Connection = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
service1Connection.setAutoCommit(false);
service2Connection.setAutoCommit(false);
try {
// Perform operations in Service 1
executeOperationInService(service1Connection, "UPDATE table1 SET column1 = value1 WHERE id = 1");
// Perform operations in Service 2
executeOperationInService(service2Connection, "UPDATE table2 SET column2 = value2 WHERE id = 2");
// Step 3: Coordinator asks participants if they are ready to commit
boolean service1Ready = askParticipantIfReady(coordinatorConnection, "Service1");
boolean service2Ready = askParticipantIfReady(coordinatorConnection, "Service2");
// Step 4: Commit or Rollback based on participants' responses
if (service1Ready && service2Ready) {
coordinatorConnection.commit();
service1Connection.commit();
service2Connection.commit();
System.out.println("Transaction committed successfully.");
} else {
coordinatorConnection.rollback();
service1Connection.rollback();
service2Connection.rollback();
System.out.println("Transaction rolled back.");
}
} catch (SQLException e) {
coordinatorConnection.rollback();
service1Connection.rollback();
service2Connection.rollback();
e.printStackTrace();
} finally {
coordinatorConnection.close();
service1Connection.close();
service2Connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
private static void executeOperationInService(Connection connection, String query) throws SQLException {
PreparedStatement preparedStatement = connection.prepareStatement(query);
preparedStatement.executeUpdate();
}
private static boolean askParticipantIfReady(Connection connection, String serviceName) throws SQLException {
// Simulate the coordinator asking the participant if it's ready to commit
// In a real-world scenario, this communication might happen over a network protocol.
System.out.println(serviceName + ", are you ready to commit? (yes/no)");
// Assume the participant responds with "yes" for simplicity.
return true;
}
}
이 코드는 두 개의 서비스 (Service1, Service2)가 트랜잭션을 수행하고, 코디네이터가 각 서비스에게 커밋할지 롤백할지를 묻는 2PC의 간단한 시나리오를 시뮬레이션 합니다.
'인프라 > MSA' 카테고리의 다른 글
[MSA] 분산 트랜잭션 - 이벤트 소싱 (0) | 2023.12.20 |
---|---|
[MSA] 분산 트랜잭션 - 보상 트랜잭션 (0) | 2023.12.19 |
[MSA] 분산 트랜잭션 - ACID (1) | 2023.12.18 |
[MSA] Hexagonal Architecture (0) | 2023.12.07 |
[MSA] MSA가 어려운 이유 (0) | 2023.12.01 |