낙관적 락과 비관적 락의 개념적 차이 위주로 서술한 글입니다.
락(Lock)의 필요성
여러 사용자나 프로세스가 동시에 동일한 수정하려고 하는 상황에서, 데이터가 충돌하거나 일관성이 깨질 수 있습니다. 이것을 방지하기 위해 락을 사용합니다.
락이란 데이터베이스에서 여러 트랜잭션이 동시에 동일한 데이터를 변경할 때, 충돌을 방지하고 데이터 무결성을 유지하기 위해 하나의 트랜잭션만이 데이터를 변경할 수 있도록 하는 매커니즘입니다.
이 락은 비관적 락과 낙관적 락으로 나뉘게 됩니다.
비관적 락(Pessiimistic Lock)
비관적 락은 데이터의 충돌이 자주 발생할 것으로 가정하고, 트랜잭션이 데이터를 읽거나 수정할 때 즉시 락을 걸어 다른 트랜잭션이 해당 데이터에 접근하지 못하게 하는 방식입니다. 즉, 데이터 충돌 가능성을 사전에 차단하는 방법입니다.
비관적 락은 두 유형으로 나눠집니다.
- 읽기 락(Shared Lock)
- 트랜잭션이 데이터를 읽을 때, 다른 트랜잭션이 해당 데이터를 수정하지 못하도록 읽기 전용 락을 겁니다.
- 동시에 여러 트랜잭션이 같은 데이터를 읽을 수 있지만, 해당 데이터를 수정하려는 트랜잭션은 락이 해제될 때까지 대기해야 합니다.
- 쓰기 락(Exclusive Lock)
- 데이터를 읽거나 수정하려는 트랜잭션은 단독으로 락을 획득해야 합니다.
- 쓰기 락이 걸리면 다른 트랜잭션은 해당 데이터를 읽거나 수정할 수 없습니다.
- 트랜잭션 완료 후에 락이 해제될 때까지 대기 상태에 들어갑니다.
실제 쿼리를 보자면,
BEGIN TRANSACTION;
SELECT * FROM accounts WHERE id = 1 FOR UPDATE;
-- 이 시점에 계좌 1번에 대해 비관적 락이 걸리며, 다른 트랜잭션은 해당 데이터를 수정하지 못함
UPDATE accounts SET balance = balance + 100 WHERE id = 1;
COMMIT;
FOR UPDATE는 데이터베이스가 해당 행에 대해 Exclusive Lock을 걸도록 합니다. 다른 트랜잭션이 동일한 데이터를 수정하려고 시도하면 락이 해제될 때까지 대기하게 됩니다.
비관적 락의 장점은 다음과 같습니다
- 충돌이 자주 발생할 것으로 예상되는 환경에서 데이터 무결성을 강력하게 보장합니다.
- 데이터를 수정하는 동안, 다른 트랜잭션이 데이터에 접근할 수 없기 때문에 데이터가 다른 트랜잭션에 의해 변경되지 않도록 안정성 보장합니다.
단점은 다음과 같습니다.
- 성능 저하: 트랜잭션이 락을 해제할 때까지 다른 트랜잭션이 대기해야 하기 때문에 성능 저하가 발생할 수 있습니다. (특히 대규모 시스템에서는 병목 현상이 일어날 수 있습니다.)
- 데드락(Deadlock) 가능성: 두 트랜잭션이 서로의 락을 기다리는 상황에서 데드락이 발생할 수 있습니다.
따라 비관적 락은 데이터 일관성이 매우 중요한 환경, 데이터 수정이 빈번하고 충돌 가능성이 높은 시스템에 사용됩니다. (e.d. 은행 시스템, 재고 관리 시스템)
낙관적 락(Optimistic Lock)
낙관적 락은 충돌이 발생하지 않을 것이라고 가정하고, 트랜잭션이 데이터를 수정하려고 할 때만 충돌을 처리합니다. 즉, 트랜잭션이 데이터에 락을 미리 걸지 않고, 데이터를 업데이트 하는 순간 다른 트랜잭션에 의해 변경되지 않았는지 확인합니다.
낙관적 락에서는 데이터를 수정할 때, 충돌이 발생하지 않았는지 검증하는 과정이 필요합니다. 이를 위해서 일반적으로는 데이터의 버전 필드나 타임스탬프를 사용합니다. 트랜잭션이 데이터를 수정할 때, 해당 데이터의 버전을 확인하고 수정 시점에서 버전이 변경되지 않았을 때만 업데이트를 적용합니다.
- 버전 관리(Versioning) 방식
- 각 데이터 항목에는 버전(Version) 번호가 존재합니다
- 트랜잭션이 데이터를 수정할 때, 현재 버전과 이전에 읽은 버전이 일치하는지 확인한 후 업데이트를 수행합니다.
- CAS (Compare-And-Swap) 방식
- 메모리에서 주로 사용되는 방식으로, 현재 값과 예상 값이 동일한지 비교하고, 동일한 경우에만 값을 변경합니다.
- 데이터베이스보다는 주로 동시성 제어가 필요한 메모리 구조에서 많이 사용됩니다.
이 검증 과정들은 DB에서 제공하는 기능을 사용하기 보단 Application Level에서 이루어집니다.
쿼리를 살펴보자면
UPDATE accounts
SET balance = balance + 100, version = version + 1
WHERE id = 1 AND version = 1;
이 쿼리는 version 필드가 1일대만 업데이트를 수행합니다. 만약 다른 트랜잭션이 먼저 이 데이터를 수정하려 버전이 2로 변경되었다면, 이 쿼리는 실패하게 됩니다. 실패 시, 트랜잭션은 충돌을 감지하고 재시도하거나 사용자에게 알림을 보냅니다.
낙관적 락의 장점은 다음과 같습니다.
- 데이터 읽기 작업에 락을 걸지 않기 때문에 성능에 뛰어납니다. (낙관적 락은 락 오버헤드가 거의 없으므로, 대규모 읽기 위주의 시스템에서 매우 효과적입니다.)
- 데드락 문제가 발생하지 않습니다. 락을 걸지 않기 때문에 트랜잭션 간의 교착 상태가 발생하지 않습니다.
단점은 다음과 같습니다.
- 충돌이 자주 발생하는 경우, 트랜잭션이 실패할 가능성이 높습니다. 트랜잭션이 반복적으로 실패할 경우, 재시도를 해야 하므로 성능이 떨어질 수 있습니다.
- 충돌을 감지한 후, 트랜잭션을 재시도하거나 오류 처리를 하는 추가 작업이 필요합니다.
따라 낙관적 락은 읽기 작업이 많고 수정이 적은 시스템, 대규모 트랜잭션이 빈번하게 발생하지 않는 환경에서 주로 사용됩니다. (e.d. SNS, 게시판 등)
요약
- 비관적 락은 데이터 충돌 가능성이 높고, 일관성이 중요한 환경에서 트랜잭션이 시작되면 즉시 락을 걸어 다른 트랜잭션이 해당 데이터에 접근하지 못하도록 합니다.
- 낙관적 락은 충돌이 적을 것이라고 예상하고, 트랜잭션이 데이터를 수정할 때만 충돌을 확인하며, 락을 미리 걸지 않고 충돌 시 처리합니다.
제 글이 도움이 되길 바라며 마치겠습니다.
'CS' 카테고리의 다른 글
[CS] OSI 7계층과 TCP/IP (0) | 2024.07.06 |
---|---|
[CS] 비선형 자료구조 그래프, 트리, 힙, 맵, 셋, 해시 테이블에 대해 알아보자 (0) | 2024.05.07 |
[CS] 선형 자료구조에 대해 알아보자 (연결 리스트 / 배열 / 백터 / 스택 / 큐) (0) | 2024.05.04 |
[CS] 데이터베이스의 정규화 (0) | 2024.04.17 |
[CS] 토큰 기반 인증과 JWT (0) | 2024.04.12 |