Redis의 분산 락을 활용한 동시성 제어
전자상거래(E-Commerce), 증권이나 은행 등 업무 관련 시스템에서 안정성과 직결되는 부분인 동시성(Concurrency) 제어를 고려하지 않고 개발하게 되면 데이터 정합성(Consistency)이 중요한 상황에서 여러 가지 이슈가 발생할 수 있다. 다중 쓰레드(Multi thread) 환경에서 서로 다른 쓰레드(Thread)가 공유 자원에 접근하여 가변 데이터를 동시에 연산 작업을 수행하는 상황에 데이터 정합성이 보장되지 않아 일관성 있는 데이터 조회가 어려울 수 있다. 이를 해결하기 위해 동기화 작업을 수행해야 하며 별도의 처리가 필요하다.
동시성이란?
싱글 코어에서 멀티 쓰레드를 동작시키기 위한 방식으로, 멀티 태스킹을 위해 여러 개의 쓰레드가 번갈아가면서 실행되는 성질을 말한다. 멀티 쓰레드로 동시성을 만족시킬 수 있는 것이지 동시성과 멀티 쓰레드는 연관이 없다.
동시에 실행되는 것처럼 보이는 것!
- 멀티 코어에서 멀티 쓰레드를 이용하여 동시성을 만족할 경우에는 실제 물리적 시간으로 동시에 실행된다.
- 싱글 코어에서 멀티 쓰레드를 이용해 동시성을 구현하는 일부 케이스에 대한 내용이다.
동시성 제어는 왜 필요한가?
- Race condition
- 두 개 이상의 쓰레드가 동시에 같은 데이터를 접근하여 값을 변경하고자 할 때, 데이터의 예상치 못한 변경이 발생할 수 있다.
- DeadLock
- 두 개 이상의 쓰레드가 서로의 작업이 완료될 때까지 기다리면서 결국 아무도 완료되지 않는 문제가 발생할 수 있다.
- Data corruption
- 두 개 이상의 쓰레드가 동시에 같은 데이터에 접근하여 값을 변경할 때, 예상치 못한 데이터의 변형이 발생할 수 있다.
위와 같은 문제를 방지하기 위해 동시성제어를 통해 보다 안정적인 서비스를 제공할 수 있다.
분산 락(distributed Lock)
자바 스프링 기반의 웹 애플리케이션은 기본적으로 멀티 쓰레드 환경에서 구동이 된다. 따라서, 여러 쓰레드가 함께 접근할 수 있는 공유 자원에 대해 Race condition이 발생하지 않도록 별도의 처리가 필요하다. 자바는 synchronized라는 키워드를 언어차원에서 제공하여, 모니터 기반의 상호배제 기능을 제공하게 된다. 하지만, 이런 메커니즘은 같은 프로세스에서만 상호 배제를 보장한다. 웹 애플리케이션 프로세스를 단 하나만 사용하는 서비스라면 상관없지만, 대부분 일반적으로 서버를 다중화하여 부하 분산 처리를 한다. 이러한 분산 환경 속에서 상호 배제를 구현하여 동시성 문제를 다루기 위해 등장한 방법이 바로 분산락이다.
분산 락을 구현하기 위해 락에 대한 정보를 ‘어딘가’에 공통적으로 보관하고 있어야 한다. 그리고 분산 환경에서 여러 대의 서버들은 공통된 ‘어딘가’를 바라보며, 자신이 임계 영역(critical section)에 접근할 수 있는지 확인한다.
락을 획득한다는 것은 “락이 존재하는지 확인한다”, “존재하지 않는다면 락을 획득한다” 두 연산이 atomic하게 이루어져야 한다. 레디스는 “값이 존재하지 않으면 세팅한다” 라는 setnx 명령어를 지원하는데, 이 setnx를 이용하여 레디스에 값이 존재하지 않으면 세팅하게 하고, 값이 세팅되었는지 여부를 리턴 값으로 받아 락을 획득하는데에 성공했는지 확인한다.
- try 구문 안에서 락을 획득할때까지 계속 락 획득을 시도
- 락을 획득한 후에 연산을 수행
- 락을 사용 후에는 꼭 해제하도록 finally에서 락을 해제
이렇게 분산 환경에서 원자성(atomic)을 보장할 수 있게 된다.
Comments