실전 프로젝트 3주차. 서버 응답시간 측정을 위해 aop를 구현 중이다. 오늘 TIL에는 어제 다 정리하지 못했던 분산락과 동시성제어를 하는 방법들이 헷갈려 총 정리를 했다.
웹 어플리케이션 프로세스를 단 하나만 쓰는 서비스라면 java의 synchronized로 동시성 제어를 할 수 있다. 하지만 여러 서버, 인스턴스, 프로세스 상태와 같은 분산 시스템에서는 단일 머신에서의 락 기법만으로는 동시성 제어가 힘들다. 이런 상황에서 공유 자원에 대한 동시접근을 제어하기 위해 분산 락을 사용해야 한다.
여러 독립된 프로세스에서 하나의 공유자원에 접근할 때, 데이터에 결함이 발생하지 않도록 원자성을 보장하기 위해 분산 락을 활용한다.
Zookeeper, etcd, Redis의 RedLock 알고리즘이 자주 쓰인다.
java에서는 redis client로 lettuce와 redisson을 쓸 수 있다.
Lettuce로는 간단하게 스핀락을 구현할 수 있는데, Lock의 expire time이 지정되어있지 않아 락이 풀릴 때 까지 무한정 대기상태가 되어 서비스의 장애가 생길 가능성이 있고, 이로 인해 redis에 많은 부하가 발생하게 된다.
Redis에서는 Redlock으로 분산락을 구현하기 위해 다양한 구현체를 제공하는데 Java에서는 별도의 Redisson 라이브러리를 통해 구현할 수 있다. Redisson에서는 Pub-Sub 기반으로 Lock을 구현한다. 채널을 하나 만들어 락을 점유중인 쓰레드가 Lock을 해제했음을 대기중인 쓰레드에게 알려주면 대기중인 쓰레드가 Lock을 점유하는 방식이다. 스핀락을 사용하지 않으며 Lock에 타임아웃이 구현되어 있다.
RLock : 락 인터페이스로 락 해제, 획득시 사용
tryLock(waitTime, leaseTime, unit)
waitTime - 락 획득을 할 수 있는 최대 시간.
leaseTime - 락을 가지고 있을 수 있는 최대 시간. 이 시간이 지나면 락을 반납
unit - 시간 단위
RLock으로 메서드 사용시 스레드가 중단된 경우 InterruptedException이 발생하기 때문에 try-catch문으로 lock의 처리가 반드시 필요하다.
Redisson은 @Transactional과 동시에 동작하지 않는다.
DB에서 데이터의 일관성과 동시성을 유지하기 위한 매커니즘
트랜잭션 격리 수준은 DB에서 동시에 실행되는 여러 트랜잭션간의 격리 정도를 정의한다. 격리 수준이 낮을수록 동시성이 높아지지만, 다양한 문제가 발생할 수 있다.
데이터베이스의 락은 동시에 여러 트랜잭션에서 같은 데이터에 접근하는 것을 제어하기 위한 메커니즘이다. 락은 트랜잭션을 순차적으로 실행하여 데이터의 일관성을 유지하고 동시성 문제를 해결한다.
데이터베이스 레벨이 아닌 애플리케이션 레벨에서 데이터 접근을 제어하는 메커니즘이다.
주로 Entity 레벨에서 적용된다.
(비관적 락은 DBMS의 락 기능을 쓰긴한다.)
여러 서버나 노드가 있는 분산 시스템에서 데이터의 일관성을 유지하기 위한 메커니즘.
분산 시스템에서 각 노드는 독립적으로 동작하기 때문에 각 노드간의 동기화를 보장하기 위해 사용된다.