안녕세계

[Redis] 분산 락은 어떻게 걸어야할까? 본문

[Redis] 분산 락은 어떻게 걸어야할까?

Junhong Kim 2024. 2. 18. 22:25
728x90
반응형

이전 포스팅에서 Redisson을 사용하여 Redis 분산 락을 손 쉽게 구현할 수 있는 방법에 대해서 알아보았습니다. 이번 포스팅에서는 분산 분산 락을 거는 위치에 따라 발생할 수 있는 문제에 대해 알아보고 권장하는 분산 락 위치에 대해 알아봅니다.

트랜잭션 이후 분산 락

분산 락을 건다는 의미는 결국 동일 자원에 대해 동시 작업하는 것을 제어하기 위함입니다. 그렇다면 우리는 분산 락을 건 상태에서 데이터베이스 트랜잭션과 관련된 작업을 시작해야합니다. 그런데 만약 데이터베이스 트랜잭션을 먼저 시작하고 분산 락을 걸게되면 어떻게 될까요? 종종 데이터베이스 트랜잭션이 먼저 시작된 이후 분산 락을 걸어도 별 다른 문제가 발생하지 않는고 생각할 수도 있습니다. 다음 그림을 살펴보겠습니다.

트랜잭션 이후 분산 락

위 그림에서 처럼 트랜잭션 시작 후 트랜잭션 내에서 수행되는 로직이 분산 락의 `leaseTime=3초` 보다 빠르게 끝난다면 문제가 없는 것 처럼 보일 수 있습니다. 그런데 트랜잭션 내부에서 데이터를 조회하고 조회한 값을 변경해야하는 경우는 어떨까요?

트랜잭션 이후 분산 락 - 데아터 조회 후 커밋

 

이 경우에도 별 문제가 없어 보입니다. 다만 `buy(1)`을 수행하는 도중에 수행시간이 오래 걸려 분산 락이 해제된 순간, 동일한 자원에 대한 요청이 대기하고 있다가 로직이 수행되면 어떻게 될까요?

트랜잭션 이후 분산 락 - 동시 작업

스레드A에 대한 처리하는 도중 분산락이 풀리면서 스레드B가 대기하고 있다가 락을 획득합니다. 락을 획득하고 트랜잭션 내부에서 quantity를 조회한 결과가 10으로 반환됩니다. 왜냐하면 스레드A가 분산 락을 먼저 획득하고 로직을 수행하고 있지만 트랜잭션 commit 이 되지 않았기 때문입니다. 따라서, 스레드B는 quantity 10에 대해 quantity 2를 감소 시키고 트랜잭션 커밋하여 quantity가 8로 반영됩니다. 그런데 이후 스레드A에 대한 작업이 완료되면서 quantity가 1 감소된 9로 다시 덮어씌워지면서 quantity가 스레드A, B의 요청 결과로 3개의 quantity이 감소되는 것이 아닌 9라는 수가 저장되는 상황이 되어 치명적인 오류가 발생합니다.

분산 락 이후 트랜잭션

그렇다면 분산 락 이후에 트랜잭션을 걸면 해결이 될까요?

분산 락 이후 트랜잭션 - 동시 작업(1)

 

이 경우에도 분산 락을 먼저 건다고하더라도 트랜잭션 내부에서 작업하는 내용에 비해 분산 락 해제가 빨리되면 이전과 동일한 문제가 발생합니다. 그렇다면 우리는 어떻게 해야할까요? 분산 락을 시작하고 트랜잭션이 커밋이 될때까지 분산 락이 풀리지 않도록 구현해야합니다. 트랜잭션이 커밋이된 이후에 분산 락을 해제하면 항상 안정적으로 데이터의 값을 보장할 수 있습니다.

분산 락 이후 트랜잭션 - 동시 작업(2)

만약, 트랜잭션 내부에서 너무 오래걸릴 수 있는 작업이라면 클라이언트 요청이 타임아웃이 발생할 수 있습니다. 따라서 분산 락 설정시 waitTime을 0으로하여 다른 작업에 의해 수행할 수 없음을 알리고 재시도하는 것으로 가이드하는 방법도 고려해볼 수 있습니다. 이처럼 분산 락 설정을 서비스의 특성에 맞게 적절히 설정한다면 사용자 경험을 높일 수 있는 방법이 될 수 있을것이라 생각합니다.

결론

트랜잭션이 시작된 이후에 분산 락을 걸게되면 분산 락 설정 이전에 데이터를 조회하는 등의 작업을 수행하면 문제가 발생할 수 있습니다. 따라서 트랜잭션 시작전에 원천적으로 자원에 대한 접근을 막아야합니다. 따라서, 분산 락은 항상 트랜잭션 밖에서 락은 건 이후 서비스 로직을 수행한 이후 트랜잭션 커밋 이후에 분산 락을 해제합니다. 즉, 수행하고하자는 로직 이전에 락을 걸고 시작합니다. 이렇게 함으로써 동일한 자원에 대해 다중 요청이 들어오더라도 데이터베이스 커밋 시점이 겹치지 않기 때문에 동시성 이유에 대한 처리를 안정적으로 할 수 있습니다.

728x90
반응형
Comments