Search
Duplicate

DB 분산락

이전에 비관적 락에 작성하였습니다.
비관적 락을 요약하자면 아래와 같습니다.
모든 트랜잭션이 충돌이 날 것이고, 우선적으로 Lock을 점유하여 접근하지 못하게 하는 방법입니다.
데이터를 수정할 때 x-Lock을 점유하고 있으므로, 충돌이 발생할 가능성이 적습니다.
사용자가 수정할 때 까지 다른 사용자는 스핀락으로 대기를 하고있습니다.
때문에 비관적락 같은경우 Time-out 설정을 통하여, 언제가지 대기를 할 것인지 꼭 지정해 줘야합니다.
비관적 락 경우 next-Lock(갭락)을 사용하기 때문에 갭락이 무엇이고, 어떻게 동작하는 지 알아두면 비관적락을 사용할때 큰 도움이 될 것입니다.
갭락 혹은 next-lock은 레코드 자체에 락을 거는 것 뿐만아니라, 해당 레코드의 앞뒤에 “갭”에도 락을 거는 방식입니다. 이는 트랜잭션이 실행하는 동안 새로운 레코드가 해당하는 범위에 데이터를 삽입되는 것을 방지합니다. [갭락 설명 블로그 : https://idea-sketch.tistory.com/46]
분산락이란 ?
분산락이란 멀티스레드 환경에서 공유 자원에 접근할 때, 데이터의 정합성을 지키기 위해 사용합니다.
1.
언노테이션 기반의 Redssion을 구현하여 사용하는 방법
커스텀 언노테이션 사용 방법
그렇다면 왜 분산락을 사용하는 것인가?
1.
비관적 락은 단일 데이터베이스 인스턴스 내에 동시성을 문제를 해결하는 데 적합하지만, 분산 환경에서의 여러 서버와 DB 간의 동시성을 해결해 주지는 못합니다. 때문에 분산환경에서도 동시성을 해결하기 위해서 분산락을 사용합니다.
a.
분산 환경에서는 네트워크 지연, 패킷 손실, 장애 등이 발생할 경우 락을 유지하기가 어렵기 때문입니다.
b.
비관적 락을 사용하게 되면, 락에 접근하려는 모든 노드가 대기상태가 되면서스핀락에 의해 병목현상이 발생될 수 있습니다.
c.
위와 같은 상황 때문에 분산 환경에서 지연이 발생 하고, 누적이 되면서 큰 문제로 야기될 수 있습니다.

락 획득 방식

비관적 락의 획득 방식 [스핀락] : 일전에 비관적 락 같은 경우 스핀락으로 락을 획득한다고 하였습니다. 이 때문에 락이 풀릴 때까지 시도함으로써 CPU 시스템 자원이 비효율적으로 사용됩니다.
Redission의 분산 락의 획득 방식 [pub/sub] :
1. 락 획득 시도
MySQL에서는 SELECT ... FOR UPDATE와 같은 쿼리를 사용하여 특정 행에 대해 락을 시도합니다. 만약 다른 트랜잭션이 이미 해당 행에 대해 락을 걸었으면, 현재 트랜잭션은 락이 해제될 때까지 대기 상태에 들어갑니다.
Redisson에서 락을 시도할 때, 클라이언트는 Redis에 특정 키(락을 나타내는)를 사용하여 SETNX 명령을 보냅니다. 이 명령은 "키가 존재하지 않으면 생성하고, 존재하면 아무 것도 하지 않는다"는 의미입니다. 만약 SETNX 명령이 성공하면 클라이언트는 락을 획득하게 됩니다. 실패하면 락을 획득하지 못하고, 대기 상태로 들어갑니다.
2. Pub/Sub 채널 구독 설정
락을 보유한 트랜잭션이 완료되거나 롤백되면, MySQL은 락을 자동으로 해제하고, 대기 중인 트랜잭션 중 하나가 락을 획득하게 됩니다.
락을 보유한 클라이언트가 작업을 마치고 DEL 명령을 사용해 Redis에서 락 키를 삭제하면, Redis는 Pub/Sub 채널을 통해 락이 해제되었음을 모든 구독자에게 알립니다. 이를 통해 대기 중이던 클라이언트들이 락이 해제되었음을 인지하게 됩니다.
이를 통해 우리는 이제 스핀락 처럼 지속적으로 CPU를 낭비하면서 확인할 필요 없이, Redis의 상태만을 확인하면 됩니다.
그렇다면 비관적 락을 사용하지 않고 분산락을 바로 사용하면 더 좋지 않을까?
1.
단일 데이터 베이스에서 사용하는 것이라면 내부 트랜잭션 단위로 동작하기 때문에 락을 걸고 해제하는 작업이 빠르기 때문에 굳이 redis라는 추가적인 작업을 할 필요는 없을 것입니다.
2.
분산락은 Redis나 Zookeeper같은 외부 시스템에 의존합니다. 이러한 시스템이 장애를 일으키면 신뢰성을 보장하기위해 시스템 자체적으로 관리가 필요합니다.
3.
비관적 락이 데드락이 발생하게 됐을 때 트랜잭션 타임 아웃 설정으로 빠르게 처리할 수 있습니다. 하지만 분산락을 도입하게 되면은 클라이언트 별로 타임아웃을 설정해야 되고, 해제되지 않을 경우 수동으로 해제해야되는 경우가 발생할 수 있습니다.
항상 개발 일을 하면서 trade off는 발생할 수밖에 없다고 생각합니다. 어느 시스템에 적절한 방법을 활용해야 될지 알고 있으면, 차후에 발생되는 문제에 대해 적절하게 선택할 수 있다고 생각합니다.
감사합니다.