프로젝트를 진행하며 데이터 정합성을 위해 Pub/Sub 방식으로 분산락을 적용하게 되었다.
동시성 제어를 위해 어떠한 방식의 락을 적용할까 하다가 자연스레 스핀락(spinlock),세마포어(semaphore),뮤텍스(mutex)에 대한 개념을 다시 한번 정리하게 되었다.
이러한 개념을 이해하기 전에 알아야 되는 개념들 부터 차근 차근 정리해보았다.
DB, 멀티스레드, 분산 환경 등에서 동시성 제어가 중요하다는 것을 개발자라면 다들 들어봤을 것이다.
공유자원에 대해 동시성을 제어하지 않으면 의도치 않게 예상과 다른 결과가 발생 할 수 있고 그로 인해 데이터의 무결성, 일관성, 정합성.. 등을 해칠 수 있게 된다.
실 예시는 다음 글에서 송금 시 락을 통해 동시성 제어를 한 것으로 알아보도록 하고 이번 글에서는 OS 관점(프로세스, 쓰레드)에서 먼저 알아보도록 하자.
프로세스는 운영체제로 부터 독립적인 메모리 주소 공간을 할당 받기 때문에 각 프로세스가 서로 겹치지 않는 메모리를 사용한다.
따라서 공유 메모리를 사용하지 않는 한 일반적으로는 다른 프로세스가 같은 메모리 공간에 동시에 접근하는 일은 발생하지 않는다.
스레드의 경우는 하나의 프로세스 내에서 생성되고 해당 프로세스의 메모리 공간을 공유 하므로 스레드들이 같은 데이터와 자원에 대해 동시에 접근할 수 있게 된다.
그렇기에 스레드간의 동기화와 동시성 제어가 매우 중요하고 다양한 동시성 제어 기법이 존재한다.
동시성 제어 기법에 대해 알아보기 전에 먼저 알아야될 것이 있는데 Race Condition과 Critical Section이라는 개념이다.
여러 스레드가 동시에 같은 자원을 조작할 때 의도치 않게 결과가 달라질 수 있는 상황을 Race Condition(경쟁 상태) 라고 한다.
공유 자원을 동시에 접근하지 못하도록 하나의 프로세스/스레드만 진입해서 실행 가능한 영역을 Critical Section(임계영역) 이라고 한다.
Race Condition을 막고 Critical Section을 보장하기 위해서 몇가지 조건이 필요한데 아래에서 살펴볼 세가지 이다.
상호 배타(Mutual Exclusion),진행(Progress),유한 대기(Bounded waiting)
Race condition을 피하기 위해 어떤 프로세스가 임계 영역에 있는 동안 다른 모든 프로세스는 그 영역에 들어갈 수 없게 해야한다.
공유 자원에 대한 동시 접근을 방지하여 데이터의 일관성을 유지하기 위해 필요하다.
하지만 상호 배타를 시행하면 추가적인 제어 문제가 발생하는데 바로 Deadlock과 Starvation 문제이다.
두 개 이상의 프로세스가 서로 다른 자원을 보유하고 있으면서, 상대방이 보유한 자원의 해제를 무한히 기다리는 상태이다.
이 상태에서는 모든 프로세스가 작업을 진행할 수 없게 되며, 시스템이 멈춰버리는 상황이 발생한다.
특정 프로세스가 다른 프로세스에 의해 지속적으로 자원 접근 순서에서 밀려나, 무한히 자원을 기다리게 되는 상황이다.
우선순위가 낮은 프로세스가 고우선순위 프로세스에 의해 자원을 할당받지 못하고 끝없이 대기하는 경우에 발생한다.
위의 상호배제로 발생할 수 있는 문제를 해결하기 위해 다음과 같은 조건이 만족 되어야 한다.
임계 영역에서 실행중인 프로세스가 없을 때 들어가려는 프로세스가 여러 개라면 들어갈 순서가 유한 시간 내에 정해져야 한다.
어떤 프로세스/스레드라도 기다리고 있으면 유한한 시간 내에 임계구역에 들어갈 수 있어야 한다.
이제 여기까지가 기본 개념이고 이러한 조건을 만족하며 동시성 제어를 할 수 있는 기법에 대해 알아보도록하자.
다음글에 계속..