동시성(Concurrency)
동시성은 운영체제에서 사용되는 용어로 동시에 실행되는 것처럼 보이는 것으로 논리적인 개념으로 싱글코어와 멀티코어에서 가능하다. 해당 글에서 사용되는 DB에서의 여러개의 스레드(요청)이 동시에 같은 주소의 값(데이터)을 참조하여 접근 및 수정하는 것을 의미한다.
예를들어, 트랜젝션 A가 알렉스라는 이름을 읽고 트랜젝션 B가 밥을 추가해 같은 트랜젝션에서 1번의 리드와 3번의 리드가 다른 것을 확인한다. 유령 레코드가 나타나는 현상으로 이를 팬텀리드(Phantom Read)라 한다.
일반적으로 문제 해결 방식에는 두 가지 방법이 존재한다.
1. 비관적 동시성 제어
데이터를 비관적으로 바라보며 다른 요청에 의해서 수정될 가능성을 염두하여 Lock을 거는 방식이다.
데이터베이스의 데이터를 잠그고 다른 사용자가 동일한 잠금을 보유하지 못하도록 한다. 이는 데이터베이스로 통하는 문을 하나만 놔두고 하나의 트랜젝션이 DB에 접근할 동안 다른 트랜젝션이 접근을 못하게 하는 방식이다.
장점
- 구현이 간단하다. 데이터 서버는 잠금을 지원하기 때문에 제어를 쉽게 구현할 수 있다.
- 매우 간단하다.
단점
- 확장성이 좋지 않다.
- 교착 상태(Dead Lock)에 빠지기 쉽다.
- 예를들어, 치킨집 지점관리자 1은 A지점 데이터에 대해서 수정을 하고 2는 B지점 데이터에 수정을한다. 수정을 하는 동안 각각의 A, B지점에 데이터는 '잠금'상태에 들어간다. 이후 관리자 1은 B를 2는 A를 수정하기 원하는데 '잠금' 상태로 인하여 각각 원하는 다음 지점에 대해서 기다리로 결정하면 교착상태가 발생한다.
- 잠금이 오래 지속될 수 있다.
적용방식
1. DB에서 제공하는 데이터 Lock수준을 높인다.
2. select for update 활용하여 Lock을 잡는다.
3. transaction의 write Lock(Exclusive Lock)을 사용한다. DB는 데이터를 수정할 경우, write lock이 발동되고 트랜젝션이 끝날때까지 Lock은 유지된다.
2. 낙관적 동시성 제어
데이터가 다른 요청에 의해 변경되지 않고 한 트랜잭션에 의해서 수정될 것을 염두한 방법으로
장점
- 확장성이 높다.
- 구현이 간단하다. 행 버전을 사용할 경우 구현하기가 비교적 쉽다.
- 교착상태의 위험이 적다.
단점
- 안전성이 떨어진다.
- 요청을 재시도하는 경우가 많아진다.
적용방식
1. 마지막 업데이트를 최신으로 덮어쓴다.
2. 사용자가 변경한 필드를 비교한다. 이는 데이터 변경 이후 커밋을 하기 이전에 사용자가 데이터를 읽을 때와 동일한지 확인하는 작업이다. 기존에 읽은 데이터와 데이터베이스의 데이터가 같지 않으면 서버는 사용자의 변경 사항을 커밋하지 않고 사용자에게 알린다.
3. 행 버전 비교한다. 데이터에는 서버가 데이터를 업데이트할 때마다 변경되는 타임스탬프 필드를 추가하여 행 버전을 관리하는 방식이다.
Reference