Skip to content

트랜잭션 격리

사가를 사용하는 경우, 여러 서버와 도메인에 걸친 트랜잭션을 보장해줄 수 있지만 트랜잭션의 완전한 격리를 완벽히 보장할 순 없다. 따라서 dirty read나 nonrepeatable read 등의 문제들이 생길 수 있는데, 이런 문제들을 해결하기 위해선 사가의 격리를 위한 전략을 사용해줘야한다.

이를 위한 전략으로는 아래와 같은 것들이 있다.

시맨틱 락(Semantic Lock)

  • 보상 가능 트랜잭션이 생성/수정하는 레코드에 무조건 플래그를 세팅하는 대책이다. 레코드가 아직 커밋 전이라서 변경될지 모르니, 다른 트랜잭션이 레코드에 접근하지 못하도록 락을 걸어놓는 것이다. 그 플래그는 재시도 가능 트랜잭션(사가 완료) 또는 보상 트랜잭션(사가 롤백)으로 인해 해제될 수 있다.

  • 잠금된 레코드를 어떻게 처리할지는 각 사례별로 결정을 해줘야한다. 만약 클라이언트가 PENDING 상태의 Order를 cancel 해달라고 요청한다면 해당 요청을 실패 처리하거나 하는 식이다. 시맨틱 락을 사용하면 ACID 고유의 격리 기능을 되살릴 수 있다. 물론 애플리케이션에서 락 상태를 관리해야한다는 부담이 있고, Deadlock이 일어날 수 있는 경우 감지하여 해소할 수 있는 알고리즘이 필요할 수도 있다.

교환적 업데이트

  • 업데이트를 교환적(Commutative)으로, 즉 어떤 순서로도 실행 가능하게 설계하면 소실된 업데이트 문제를 방지할 수 있다.

  • 보상 가능 트랜잭션이 계좌에서 돈을 인출 후 사가를 롤백시켜야 하는 상황이라면 보상 트랜잭션은 다른 사가의 업데이트를 덮어쓸 일 없이 단순히 돈을 다시 입금해주기만 하면 된다.

비관적 관점(Pessimistic View)

  • 비관적 관점은 dirty read로 인한 리스크를 최소화 하기 위해 사가 단계의 순서를 재조정하는 것이다. 다른 사가의 주요 작업의 조건이 되는 도메인을, 사가의 마지막 단계에서 수정하여 충돌 가능성을 낮춘다.

값 다시 읽기(reread value)

  • 업데이트가 소실되는 것을 방지하기 위해 레코드 업데이트 전, 값을 다시 읽어 값이 변경되지 않았는지 확인하는 방법이다. 값을 다시 읽었을때 변경되었다면, 사가를 중단하고 나중에 재시작한다. 이 대책은 일종의 낙관적 오프라인 락(Optimistic Offline Lock)이라고 볼 수 있다.

  • 이 대책을 주문 생성사가에 적용하면 주문이 승인되는 도중 최소되는 불상사를 막을 수 있다. 주문이 처음 생성된 이후, 다시 조회 과정을 거쳐 변경 여부를 확인하면 데이터 충돌 여부에 따라 사가를 멈추고 롤백하거나, 사가를 계속 진행해나가는 둘 중 하나의 동작만을 수행할 수 있다.

버전 파일

  • 버전 파일(version file)은 레코드에 수행한 작업을 하나하나 기록하는 대책이다. 즉, 비교환적(noncommutative) 작업을 교환적(commutative) 작업으로 변환하는 것이다. 예를 들어 주문 생성 사가와 주문 취소 사가가 동시에 실행되었다고 해보자. 시맨틱 락 대책을 쓰지 않으면 주문 생성 사가가 소비자 신용카드를 승인하기 전에 주문 취소 사가가 해당 신용카드를 승인 취소하는 말도 안 되는 상황이 벌어질 수 있다.

  • 순서가 안 맞는 요청을 회계 서비스가 받아 처리하려면, 작업이 도착하면 기록해 두었다가 정확한 순서대로 실행하면 된다. 위와 같은 경우라면, 회계 서비스는 일단 승인 취소 요청을 기록하고, 나중에 신용카드 승인 요청이 도착하면 이미 승인 취소 요청이 접수된 상태이니 승인 작업은 생략해도 되겠구나라고 인지할 수 있도록 하여 충돌을 막는 것이다.