본문 바로가기
Web

DB의 트랜잭션과 Operational transformation (동시성 처리방법들)

by ttum 2024. 8. 20.

DB 트랜잭션(Transaction)

DB에서 트랜잭션이 동작하는 원리는 ACID라는 네 가지 기본 속성에 따라 운영된다. 트랜잭션은 DB에서 여러 작업을 하나의 단위로 묶어 실행하는 것을 의미한다. 모든 작업은 성공적으로 완료되거나, 실패하면 모든 작업이 취소되는 것을 보장받는다.

트랜잭션의 4가지 ACID 속성

  1. 원자성 (Atomicity): 트랜잭션 내의 모든 작업이 성공하거나, 아무 작업도 반영되지 않음을 보장한다. 트랜잭션 중 하나의 작업이라도 실패하면 전체가 롤백되어야 한다.
  2. 일관성 (Consistency): 유효한 상태라는 것은 데이터베이스가 기본적으로 갖춰야 할 요건들(제약 조건 유지, 데이터 무결성 보장, 트리거 및 저장 프로시저 실행)이 보장되어야 하는 것을 의미한다. 트랜잭션이 실행되기 전과 후에 데이터베이스가 항상 일관성 있는 상태를 유지해야 한다. 일관성은 데이터베이스가 트랜잭션 실행 전후에 항상 유효한 상태를 유지하도록 보장하는 것이다.
  3. 격리성 (Isolation): 동시에 실행되는 트랜잭션들이 서로 간섭하지 않도록 격리되어 있어야 한다. 이는 트랜잭션이 다른 트랜잭션의 중간 작업을 보지 못하게 해 독립적인 실행을 보장하는 것이다. 격리 수준에 따라 처리되는 방식이 달라질 수 있으며, 보통 "Read Uncommitted", "Read Committed", "Repeatable Read", "Serializable"와 같은 격리 수준을 사용한다.
  4. 지속성 (Durability): 트랜잭션이 성공적으로 완료된 후에는 그 결과가 영구적으로 저장되며, 시스템이 장애를 겪더라도 데이터가 유실되지 않음을 보장한다.
💡 격리성 (Isolation)
1. Read Uncommitted: 가장 낮은 격리 수준. 트랜잭션이 커밋되지 않은(미완료된) 데이터를 읽을 수 있다.
2. Read Committed: 커밋된 데이터만 읽을 수 있다. 즉, 다른 트랜잭션이 커밋되지 않은 데이터를 읽을 수 없습니다. (대부분의 상용 데이터베이스가 사용하는 격리 수준)
3. Repeatable Read: 트랜잭션이 시작된 후에 다른 트랜잭션이 데이터를 수정하거나 삭제하지 못하도록 막는다. 따라서 동일한 데이터를 여러 번 읽어도 그 값이 변하지 않는다.
4. Serializable: 가장 높은 격리 수준. 트랜잭션이 완전히 직렬화되어 실행된 것처럼 동작한다. 모든 트랜잭션은 순차적으로 실행되며, 동시성이 제한된다.
💡 일관성
1. Dirty Read: 다른 트랜잭션이 아직 커밋되지 않은 데이터를 읽는 상황을 말합니다. 이 상황에서, 읽은 데이터는 나중에 롤백될 가능성이 있기 때문에 잘못된 데이터를 읽게 되는 문제가 발생할 수 있습니다.
2. Non-Repeatable Read: 한 트랜잭션이 동일한 데이터를 두 번 읽을 때, 그 값이 첫 번째 읽기와 두 번째 읽기 사이에 다른 트랜잭션에 의해 수정되어 값이 달라지는 현상입니다. 즉, 트랜잭션이 처음 데이터를 읽었을 때와 이후 다시 데이터를 읽었을 때 그 데이터가 변경된 경우 발생합니다.
3. Phantom Read: 한 트랜잭션이 일정 범위의 데이터를 여러 번 읽을 때, 첫 번째 읽기와 두 번째 읽기 사이에 다른 트랜잭션에 의해 새로운 데이터가 삽입되거나 삭제되어 데이터의 범위 자체가 달라지는 현상입니다. 즉, 첫 번째 읽기 때는 존재하지 않던 새로운 데이터 행(팬텀)이 두 번째 읽기 때 나타나거나, 반대로 첫 번째 읽기에서 존재했던 데이터가 두 번째 읽기에서는 사라지는 경우입니다.

트랜잭션의 동작 과정

  1. 시작: 트랜잭션이 시작되면 DB는 트랜잭션이 완료되기 전까지 모든 작업을 메모리나 임시 저장소에 기록한다.
  2. 작업 수행: 트랜잭션 내에서 여러 작업(INSERT, UPDATE, DELETE 등)이 수행된다.
  3. 커밋: 트랜잭션 내 모든 작업이 성공적으로 완료되면, 데이터베이스는 이를 커밋해 변경사항을 영구적으로 저장한다.
  4. 롤백: 만약 트랜잭션 중 오류가 발생하거나 문제가 있으면, 트랜잭션은 롤백되어 변경된 사항들이 취소되고 데이터베이스는 트랜잭션 시작 전 상태로 돌아간다.

Operational Transformation

Operation Transformation(OT)는 분산 환경에서 여러 사용자가 동시에 같은 문서나 데이터에 실시간으로 작업할 때, 충돌 없이 일관된 상태를 유지하도록 도와주는 기법입니다. 주로 협업 편집 시스템에서 사용됩니다.

기본 개념

OT의 주요 목표는 여러 사용자가 동시에 같은 데이터에 수정 작업을 할 때, 이 수정들이 충돌 없이 올바르게 적용되도록 하는 것입니다. OT는 각 사용자의 작업(operations)을 전송하고, 해당 작업이 다른 사용자의 작업과 충돌하는 경우 이를 해결하여 최종적으로 모든 사용자가 동일한 결과를 보게 만듭니다.

OT의 작동 방식

  1. 작업: 각 사용자가 문서를 수정하면 해당 작업(삽입, 삭제 등)이 중앙 서버나 다른 사용자에게 전송됩니다.
  2. 변환(Transformation): 만약 다른 사용자의 작업이 충돌하는 경우, OT 알고리즘은 작업을 변환하여 서로 간섭하지 않도록 조정합니다. 이 변환 작업은 각 사용자의 작업 순서와 상관없이 일관된 최종 상태를 유지하는 데 중요한 역할을 합니다.
  3. 적용: 변환된 작업이 각 사용자에게 적용되고, 최종적으로 모든 사용자는 같은 상태의 문서를 보게 됩니다.

OT 알고리즘의 변환 함수

OT 알고리즘에서 중요한 부분은 두 개의 작업을 변환하는 함수입니다. 이 함수는 두 작업 간의 상호작용을 분석하고, 작업의 순서나 영향을 조정해 두 작업이 충돌하지 않도록 만듭니다. 가장 기본적인 변환 함수는 다음과 같습니다:

  • Transform(Insert, Insert): 두 삽입 작업이 서로의 위치에 영향을 주지 않도록 조정합니다.
  • Transform(Insert, Delete): 삭제 작업이 삽입 작업에 영향을 미치지 않도록 삽입 위치를 조정합니다.
  • Transform(Delete, Insert): 삽입 작업이 삭제 작업에 영향을 받지 않도록 위치를 조정합니다.

이 함수들은 작업의 위치를 기반으로 충돌을 해결하는데, 각 작업이 얼마나 서로 겹치는지에 따라 그 위치를 계산해 변환합니다.


(번외, 동시성 처리시 사용하면 좋은 패턴) Python의 with문

with 문

with문은 Python에서 자원을 안전하게 관리하기 위해 사용하는 구문이다. 주로 파일 작업, 데이터베이스 연결 등에서 사용되며, 블록이 끝나면 자원을 자동으로 해제해준다. 자원을 명시적으로 닫지 않아도 되므로 코드가 더 간결하고 안전해진다.(Syntactic sugar)

  • with 문은 컨텍스트 관리자 프로토콜을 따르는 객체를 사용합니다. 컨텍스트 관리자는 __enter__와 __exit__이라는 두 가지 중요한 메서드를 구현한 객체입니다.
  • __enter__ 메서드: with 문이 시작될 때 호출됩니다. 이 메서드는 필요한 자원을 준비하거나 초기화합니다.
  • __exit__ 메서드: with 블록이 끝나면 호출되며, 자원을 해제하거나 정리하는 역할을 합니다. 블록 내에서 예외가 발생하더라도 __exit__ 메서드는 항상 호출됩니다.

컨텍스트 관리자

컨텍스트 관리자는 __enter__와 __exit__ 메서드를 구현하여 with 문과 함께 동작하는 객체입니다. __enter__는 자원을 설정하고, __exit__는 블록이 종료될 때 자원을 정리하거나 해제하는 역할을 합니다. 이를 통해 예외가 발생하더라도 자원이 적절히 해제됩니다.