본문 바로가기

카테고리 없음

트랜잭션 관리 및 데이터베이스 전략

은행 시스템에서 이체, 입출금 같은 금융 거래는 매우 중요한 트랜잭션 관리가 필요합니다. 은행의 트랜잭션 관리 및 데이터베이스 전략은 일관성(Consistency), 가용성(Availability), **내결함성(Fault Tolerance)**을 보장해야 하며, 금융 시스템의 신뢰성과 안정성을 유지하기 위한 다양한 기술과 전략이 적용됩니다. 주요한 관리 방식과 전략은 아래와 같습니다.

1. 트랜잭션 관리의 기본 원칙: ACID

은행 시스템에서는 ACID 특성을 강하게 요구합니다. ACID는 다음과 같은 특성들을 포함합니다:

  • A (Atomicity, 원자성): 모든 작업이 전부 성공하거나, 실패하면 모두 롤백됩니다. 입출금 또는 이체 시 부분만 성공하는 일이 없도록 보장해야 합니다.
  • C (Consistency, 일관성): 트랜잭션이 성공적으로 완료된 후에는 데이터베이스가 항상 일관된 상태를 유지해야 합니다. 은행에서 금액의 오류나 잘못된 거래가 발생하지 않도록 보장합니다.
  • I (Isolation, 격리성): 동시에 수행되는 트랜잭션들이 서로 간섭하지 않고 독립적으로 처리되어야 합니다. 이를 통해 다른 트랜잭션이 진행되는 동안 중간 데이터가 노출되지 않습니다.
  • D (Durability, 지속성): 트랜잭션이 완료되면 그 결과는 영구적으로 저장되어야 하며, 시스템 장애가 발생하더라도 손실되지 않아야 합니다.

2. 이체 트랜잭션 관리: 2단계 커밋(Two-Phase Commit)

이체 트랜잭션의 경우 2단계 커밋(Two-Phase Commit) 프로토콜을 사용하여 은행 간 또는 계좌 간 이체의 원자성을 보장할 수 있습니다.

단계 1: 준비 단계 (Prepare Phase)

  • 트랜잭션 관리자는 각 참여자(은행, 계좌 등)에 준비 요청을 보냅니다.
  • 각 참여자는 해당 트랜잭션을 적용할 준비가 되었는지 응답하고, 데이터를 임시로 저장합니다.

단계 2: 커밋 또는 롤백 (Commit or Rollback Phase)

  • 모든 참여자가 준비되었다고 응답하면, 트랜잭션 관리자는 커밋 명령을 내려 트랜잭션을 실제로 적용합니다.
  • 만약 하나라도 실패하거나 준비되지 않은 참여자가 있다면, 트랜잭션 관리자는 롤백 명령을 내립니다.

이를 통해 계좌 간의 원자적인 트랜잭션을 보장할 수 있으며, 트랜잭션 중 하나라도 실패할 경우 전체 트랜잭션이 취소되고 상태가 이전으로 돌아갑니다.

3. 트랜잭션 격리 수준(Isolation Levels)

은행 시스템에서는 트랜잭션 격리 수준을 설정하여 동시성 문제를 해결합니다. 트랜잭션 격리 수준에 따라 성능과 일관성 사이의 균형을 조절할 수 있습니다. 주요 격리 수준은 다음과 같습니다:

  1. Read Uncommitted: 다른 트랜잭션에서 아직 커밋되지 않은 데이터를 읽을 수 있습니다. 은행 시스템에서는 잘 사용되지 않습니다.
    1. 가장 낮은 수준의 격리로, Dirty Read가 발생할 수 있습니다.
      • 특징:
        • 한 트랜잭션에서 아직 커밋되지 않은 데이터를 다른 트랜잭션이 읽을 수 있습니다.
        • 성능은 가장 좋지만, 데이터의 일관성이 매우 낮습니다.
      • 문제:
        • Dirty Read: 아직 커밋되지 않은 데이터를 읽어 트랜잭션이 롤백될 경우 잘못된 데이터를 읽게 됩니다.
      흐름 예시:
      • 트랜잭션 A: Account A에서 100 유로를 출금(아직 커밋되지 않음).
      • 트랜잭션 B: 트랜잭션 A가 커밋되기 전에 Account A의 잔액을 조회하고, 100 유로가 빠진 상태로 조회.
      문제점: 트랜잭션 A가 롤백되면, 트랜잭션 B가 잘못된 데이터를 읽게 됩니다.
  2. Read Committed: 다른 트랜잭션에서 커밋된 데이터만 읽을 수 있습니다. 대부분의 은행 트랜잭션에서 최소 이 수준을 사용합니다. 기본 값
    1. 대부분의 데이터베이스에서 기본값으로 설정된 격리 수준입니다. Dirty Read는 방지하지만, Non-repeatable Read가 발생할 수 있습니다.
      • 특징:
        • 한 트랜잭션에서 커밋되지 않은 데이터를 다른 트랜잭션이 읽지 못합니다. 즉, 커밋된 데이터만 읽을 수 있습니다.
      • 문제:
        • Non-repeatable Read: 한 트랜잭션 내에서 두 번 같은 데이터를 읽을 때, 그 사이에 다른 트랜잭션이 데이터를 수정하면 값이 달라질 수 있습니다.
      흐름 예시:
      • 트랜잭션 A: Account A에서 100 유로 출금.
      • 트랜잭션 B: 출금 이전에 잔액을 조회(500 유로), 출금 후 다시 조회(400 유로).
      문제점: 트랜잭션 B 내에서 동일한 데이터를 두 번 읽었지만, 값이 다를 수 있습니다.
  3. Repeatable Read: 하나의 트랜잭션 내에서 같은 데이터를 읽을 때 항상 동일한 값을 읽을 수 있습니다.
    1. Non-repeatable Read 문제를 해결하며, Phantom Read가 발생할 수 있습니다. MySQL에서 기본값으로 사용됩니다.
      • 특징:
        • 한 트랜잭션 내에서 읽은 데이터는 트랜잭션이 끝날 때까지 일관된 값을 유지합니다.
        • 다른 트랜잭션이 데이터를 수정할 수 없으므로, Non-repeatable Read가 방지됩니다.
      • 문제:
        • Phantom Read: 같은 조건으로 여러 번 조회할 때, 그 사이에 다른 트랜잭션이 데이터를 삽입하거나 삭제하여 결과가 달라질 수 있습니다.
      흐름 예시:
      • 트랜잭션 A: 특정 조건을 만족하는 거래 내역 조회(거래 내역 10건).
      • 트랜잭션 B: 트랜잭션 A가 끝나기 전에 새로운 거래 내역 추가.
      • 트랜잭션 A: 다시 같은 조건으로 조회하면 새로운 거래 내역이 포함될 수 있음.
  4. Serializable: 가장 엄격한 격리 수준으로, 트랜잭션이 완전히 직렬화된 것처럼 동작합니다. 성능이 떨어지지만 일관성이 가장 강하게 보장됩니다.
    1. 가장 높은 수준의 격리로, 모든 트랜잭션을 직렬화된 순서로 처리하여 동시성 문제를 완벽하게 해결합니다.
      • 특징:
        • 트랜잭션을 완전히 직렬화하여 동시성 문제를 모두 해결합니다.
        • 성능이 가장 낮지만, 데이터의 일관성이 가장 높습니다.
      • 문제 해결:
        • Dirty Read, Non-repeatable Read, Phantom Read 모두 방지됩니다.
      흐름 예시:
      • 트랜잭션 A와 트랜잭션 B는 동시에 실행되지 않고, 하나가 완료된 후에 다른 하나가 실행됩니다. 이를 통해 모든 동시성 문제가 해결됩니다.

은행 시스템에서는 보통 Repeatable Read 또는 Serializable 수준으로 설정하여 동시성 문제를 방지합니다.

4. 데이터베이스 전략: 다중 데이터베이스 및 파티셔닝

은행 시스템은 데이터의 일관성과 고가용성을 보장하기 위해 다양한 데이터베이스 전략을 사용합니다.

1. 파티셔닝(Partitioning)

  • 데이터를 계좌별, 지점별, 고객별로 수평 파티셔닝하여 확장성을 확보하고, 성능 최적화를 도모합니다.
  • 트랜잭션이 특정 파티션 내에서 발생하면 성능이 향상되며, 파티션 간 트랜잭션은 관리해야 할 복잡성이 추가됩니다.

2. 다중 데이터베이스

  • 여러 물리적 데이터베이스를 사용하여 데이터를 분산시킵니다. 예를 들어, 글로벌 은행의 경우 각 국가 또는 지역별로 데이터베이스를 운영할 수 있습니다.
  • 이를 통해 부하 분산데이터 접근 속도를 최적화할 수 있습니다.

3. 백업 및 복구 전략(필수)

  • 이중화된 데이터베이스지속적인 백업을 통해 데이터 유실을 방지합니다.
  • 특히 **Point-in-Time Recovery(PITR)**와 같은 기술을 사용하여 특정 시점으로 복구할 수 있게 하며, 장애가 발생하더라도 신속한 복구가 가능합니다.

5. 데이터 무결성 및 일관성 관리(필수)

은행 시스템에서는 입출금 또는 이체 시 데이터 무결성을 보장하기 위해 잠금(Locking) 및 **트랜잭션 로그(Transaction Logs)**를 활용합니다.

  • 낙관적 잠금(Optimistic Locking): 데이터가 변경될 가능성이 적은 경우 주로 사용되며, 동일한 데이터에 대해 충돌이 발생하면 트랜잭션을 다시 시도합니다.
  • 비관적 잠금(Pessimistic Locking): 충돌이 발생할 가능성이 높은 경우, 데이터를 수정하기 전에 잠금을 사용해 다른 트랜잭션이 접근하지 못하게 합니다.

6. 이벤트 소싱(Event Sourcing)

트랜잭션 기록을 이벤트 형태로 저장하는 이벤트 소싱 기법을 사용할 수도 있습니다. 모든 트랜잭션은 이벤트로 기록되며, 이 이벤트 로그를 기반으로 트랜잭션 상태를 재구성할 수 있습니다. 이를 통해 거래 이력 추적데이터 복구가 용이해집니다.


결론:

은행 시스템에서 트랜잭션 관리와 데이터베이스 전략은 매우 중요하며, ACID 트랜잭션, 2단계 커밋, 격리 수준 설정, 파티셔닝, 백업 및 복구 전략을 통해 데이터 일관성 및 신뢰성을 유지합니다. 트랜잭션이 항상 원자적으로 처리되고, 장애가 발생하더라도 신속하게 복구할 수 있도록 설계됩니다.

따라서, 스프링 부트 JPA로 은행 시스템을 구축할 때도 이러한 원칙과 전략을 잘 반영하여 트랜잭션과 데이터베이스를 관리하는 것이 중요합니다.