더북(TheBook)

대책: 시맨틱 락

보상 가능 트랜잭션이 생성/수정하는 레코드에 무조건 플래그를 세팅하는 대책입니다. 레코드가 아직 커밋 전이라서 변경될지 모른다는 표시를 하는 것이죠. 플래그를 세팅해서 다른 트랜잭션이 레코드에 접근하지 못하게 락(lock, 잠금)을 걸어 놓거나, 다른 트랜잭션이 해당 레코드를 처리할 때 조심하도록 경고(warning)합니다. 플래그는 재시도 가능 트랜잭션(사가 완료) 또는 보상 트랜잭션(사가 롤백)에 의해 해제됩니다.

Order.state 필드가 좋은 예입니다. *_PENDING 상태가 바로 시맨틱 락을 구현한 것입니다. 이 필드를 이용하여 주문에 접근하는 다른 사가에 현재 어떤 사가가 주문을 업데이트하고 있음을 알립니다. 가령 주문 생성 사가 첫 번째 단계(보상 가능 트랜잭션)는 APPROVAL_PENDING 상태로 주문을 생성하고 마지막 단계(재시도 가능 트랜잭션)는 이 필드를 다시 APPROVED로 변경합니다. 보상 트랜잭션은 이 필드를 REJECTED로 바꿉니다.

락도 관리해야 하지만 잠금된 레코드를 어떻게 사가로 처리할지 사례별로(case-by-case) 결정해야 합니다. 예를 들어 클라이언트가 시스템 커맨드 cancelOrder()를 호출해서 APPROVAL_PENDING 상태의 주문을 취소하려면 어떻게 처리해야 할까요?

해결 방법은 몇 가지 있습니다. 먼저 cancelOrder()를 실패 처리하고 클라이언트에 나중에 다시 시도하라고 알리는 것입니다. 구현하기는 간단해서 좋지만, 재시도 로직까지 구현해야 하므로 클라이언트가 복잡해집니다.

락이 해제될 때까지 cancelOrder()를 블로킹하는 방법도 있습니다. 시맨틱 락을 사용하면 ACID 트랜잭션 고유의 격리 기능을 되살릴 수 있습니다. 같은 레코드를 업데이트하는 사가를 직렬화시킬 수 있어 프로그래밍 부담이 확 줄어들고, 클라이언트가 재시도해야 하는 부담도 덜 수 있죠. 물론 애플리케이션에서 락을 관리하는 부담은 감수해야 합니다. 또 데드락(deadlock) 감지 알고리즘을 구현해서 데드락이 발생하면 사가를 롤백시켜 데드락을 해소하고 재실행할 수 있게 조치해야 합니다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.