[TIL] 데이터베이스 동시성 제어(Concurrency Control) (+트랜잭션)

syong·2021년 12월 14일
0

TIL

목록 보기
28/32

트랜잭션(Transaction)이란?

동시성 제어를 다루기에 앞서 트랜잭션의 정의에 대해 살펴보자.
트랜잭션은 데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말한다.
즉, 데이터베이스에 접근하기 위해 날리는 여러 개의 쿼리를 한 동작으로 묶어서 수행하는 것을 의미한다. 예시를 하나 들자면 다음과 같다.

1. A는 B에게 10,000원을 송금하려고 한다.
2. 첫 번째 동작에서 A의 통장 잔고는 -10,000원이 되었다.
3. 두 번째 동작에서 B의 통장 잔고는 +10,000원이 되었다.

만약 2번과 3번 동작 수행 도중 예외 상황이 발생하여 2번만 완료되고 3번은 수행되지 않았다면 
A의 10,000원은 공중으로 사라지게 되는 것...

위와 같은 일을 방지하기 위해 2번과 3번 동작이 한 번에 이루어질 수 있도록 쿼리 여러 개를 하나로 묶는다. 만약 예외 상황이 발생하여 2번만 수행되고 3번은 수행되지 않았다면 앞선 모든 쿼리들을 rollback한다.

트랜잭션에 관해서는 다른 포스팅에서 더 자세히 다루는 걸로.

동시성 제어란?

동시에 실행되는 여러 개의 트랜잭션이 작업을 성공적으로 마칠 수 있도록 트랜잭션의 실행 순서를 제어하는 기법이다.

...

무슨 말일까..? 처음엔 이게 무슨 말인지 정확히 와 닿지 않았다. 그래서 조금 더 자세한 설명을 통해 내 나름대로 이해를 해 보았다.

내가 오늘 배운 예시는 다음과 같다.

1. 유저의 포인트가 50점 미만이면 에러를 뱉고, 50점 이상이면 통과시켜서 작업을 수행하는 함수1이 하나 있다.
2. 위에서 말한 함수1을 호출해서 함수1이 에러를 뱉지 않으면 즉, 유효성 검사를 통과하면 선물을 보낼 수 있게 하는 함수2가 있다.
3. 함수1은 처리 하나 당 1초가 소요된다.
4. 0.5초 간격으로 같은 요청이 두 번 들어왔다. 이 때 
	a. 동시성 제어를 하지 않을 경우, 포인트가 딱 50점 있는 유저가 요청을 보내온 경우 유효성 검사 함수가 완전히 종료되기 전에 같은 요청을 두 번 수행하게 된다. 
    	(한 번 처리하는 데 1초 걸리는데 0.5초 간격으로 두 번 들어오니까 첫 번째 요청 수행 완료 전에 두 번째 요청 수행이 시작됨) 
    	그러면 유저 포인트가 -50점이 된다. 그리고 선물은 두 번 보내진다.(0점 미만의 포인트는 유효하지 않다고 가정)
    	b. 동시성 제어를 했을 경우, 첫 번째 요청 수행 전에 두 번째 요청이 들어왔다고 하더라도 첫 번째 요청 수행이 끝나기 전까지 특정한 제어 장치로 인해 요청을 바로 수행하지 않고 대기하게 된다. 
        따라서 유저가 실수로 선물하기 버튼을 두 번 눌러도 포인트가 -50점이 되고 선물이 두 번 보내지게 되는 경우는 발생하지 않는다.

이렇게 자세한 예시를 들면 이해가 쉽다. 이렇게 사용자가 의도했든 의도하지 않았든 동시에 같은 데이터를 수정하려는 요청을 하게 되면 이러한 경우를 대비해 서버에서 동시성 제어로 데이터 중복 수정을 막아준다. 즉, 일종의 안전장치이다.

동시성 제어에는 크게 두 가지가 있는데 이는 아래서 다루기로.

비관적 동시성 제어(Pesimistic Concurrency control - Locking)

비관적 동시성 제어는 사용자가 동시에 같은 데이터를 수정한다고 가정한 상태에서 사용자가 데이터를 조회하는 시점에 해당 데이터에 lock을 걸어 접근하지 못하게 한 다음 데이터 수정이 완전히 이루어질때까지 이를 유지하는 동시성 제어 방법을 말한다.

낙관적 동시성 제어(Optimistic Concurrency control - Timestamp)

낙관적 동시성 제어는 사용자가 데이터를 수정하기 전에 해당 데이터가 앞서 다른 사용자에 의해 수정되었는지에 대한 검증 절차를 거친 후 수정을 완료하는 방법이다. 따라서 낙관적 동시성 제어는 읽기 단계 -> 검증 단계 -> 쓰기 단계로 총 세 단계를 거쳐 트랜잭션을 완료한다.

0개의 댓글