-
1. DB Lock
1.1 개념
데이터베이스에서 여러 트랜잭션이 동시에 같은 데이터에 접근할 때, 데이터의 무결성(일관성)을 보장하기 위해 사용되는 메커니즘.
한 트랜잭션이 특정 데이터에 대해 작업을 하고 있을 때, 다른 트랜잭션이 그 데이터에 접근하지 못하도록 잠그는 것. 데이터의 일관성 유지 및 동시에 발생할 수 있는 충돌을 방지
1.2 필요성
DB 락을 통해 데이터에 대한 접근을 제어하면, 다음과 같은 상황에서 발생할 수 있는 데이터 무결성 문제를 예방할 수 있음.
- Dirty Read: 한 트랜잭션이 데이터를 수정 중일 때 다른 트랜잭션이 그 데이터를 읽는 상황
- Non-repeatable Read: 한 트랜잭션이 데이터를 읽은 후, 다른 트랜잭션이 그 데이터를 수정하고 커밋하여 첫 번째 트랜잭션이 동일한 데이터를 다시 읽을 때 값이 달라지는 상황.
- Lost Update: 두 개의 트랜잭션이 동시에 같은 데이터를 수정하려고 할 때, 한 트랜잭션의 수정 내용이 다른 트랜잭션에 의해 덮어쓰여져 사라지는 상황.
2. 락의 종류
- 공유 락(Shared Lock, S Lock) : 데이터베이스에서 데이터를 읽을 때 사용. 여러 트랜잭션이 동시에 같은 데이터를 읽을 수 있지만, 공유 락이 걸린 동안에는 데이터를 수정할 수 없음.
- 배타 락(Exclusive Lock, X Lock): 데이터를 수정할 때 사용. 배타 락이 걸린 데이터는 다른 트랜잭션이 읽거나 수정할 수 없음. 한 트랜잭션이 배타 락을 획득하면 다른 모든 트랜잭션은 해당 데이터에 접근할 수 없음.
- 비관적 락(Pessimistic Locking): 데이터를 읽을 때부터 락을 걸어 다른 트랜잭션이 접근하지 못하도록 하는 방식. 데이터의 충돌 가능성이 높을 때 유용.
- 낙관적 락(Optimistic Locking): 데이터를 수정하기 전까지 락을 걸지 않고, 수정 시점에만 충돌을 확인하는 방식. 주로 데이터의 버전 번호를 사용하여 동시성 문제를 해결.
- 명명된 락(Named Lock): 데이터베이스에서 특정 이름으로 락을 설정하여, 동시에 하나의 프로세스만 특정 리소스에 접근하도록 하는 방식. 주로 특정 리소스나 작업에 대한 접근을 직관적으로 제어하기 위해 사용.
- 분산 락(Distributed Lock): 여러 시스템이나 인스턴스에서 동시에 동일한 자원에 접근할 때, 자원의 일관성을 유지하기 위해 사용되는 락. Redis와 같은 분산 시스템을 사용하여 구현.
2.1. 비관적 락
종류
- Pessimistic Read: 읽기 락(Shared Lock)을 설정하여, 다른 트랜잭션이 해당 데이터를 읽을 수는 있지만, 수정은 할 수 없도록 함.
- Pessimistic Write: 쓰기 락(Exclusive Lock)을 설정하여 다른 트랜잭션이 해당 데이터를 읽거나 수정하지 못하도록 함.
DB 레벨에서의 락 동작
- 락 설정: 비관적 락을 사용하면 SQL쿼리나 트랜잭션이 데이터베이스에 접근할 때 락이 설정.
- 락 해제: 일반적으로 트랜잭션이 종료되거나 커밋될 때 해제. 롤백되는 경우에도 락이 해제.
비관적 락은 주로 데이터베이스 레벨에서 동작, 데이터 무결성을 보장하는 데 매우 유용.
그러나 DB레벨에서 동작하기 때문에 성능에 영향을 미칠 수 있으므로, 데이터 충돌 가능성이 높은 환경에서 신중하게 사용해야 함.
스프리부트와 같은 애플리케이션에 서 비관적 락을 설정하면, 데이터베이스가 이 락을 처리하고 관리하게 됨.
비관적 락이든, 낙관적 락이든, 이거를 설정했다고 해서 충돌이 완벽하게 해소되었다. 라고 표현할 수 없음. 환경에 따라 달라지기 때문.
따라서 어느 정도의 요청량이 들어올 거라는 것을 파악해야 함. 너무 많은 요청이 온다면, DB Lock보다 메시지 큐(RabbitMQ, Kafka)를 사용하여 쓰기를 대기열에 넣어서 지연시키는 방법으로 하는 것이 더 안전.
2.2 낙관적 락
동작방식
- 낙관적 락(Optimisitc Lock)은 트랜잭션 간의 충돌을 최소화하고 성능을 향상시키기 위해 사용되는 동시성 제어 메커니
즘.
- 비관적 락이 데이터베이스 레벨에서 락을 걸어 다른 트랜잭션의 접근을 차단하는 방식이라면, 낙관적 락은 DB락을 사용하지 않고, 대신 데이터가 변경되었는지 확인하여 충돌을 처리하는 방식.
- 버전 관리:
- version이라는 필드를 엔티티에 추가하여, 해당 엔티티의 수정 횟수를 추적.
- 트랜잭션이 엔티티를 읽을 때, 현재의 버전 번호가 함꼐 읽혀옴.
- 트랜잭션이 엔티티를 수정하고 저장하려고할 때, 현재 데이터베이스에 저장된 버전 번호와 트랜잭션이 처음 읽어온 버전 번호를 비교.
- 데이터 충돌 검출
- 트랜잭션이 데이터를 저장할 때, 데이터베이스에 저장된 버전 번호가 트랜잭션이 처음 읽어온 버전 번호와 동일하다 면, 데이터가 수정되지 않았다고 간주하고 업데이트를 수행. 이때 버전 번호는 증가.
- 반면, 버전 정보가 다르다면, 다른 트랜잭션이 데이터를 수정한 것으로 간주하고, 현재 트랜잭션을 롤백하거나 재시도
장단점
- 장점:
- 성능: DB락을 걸지 않으므로 병행 처리 성능 향상.
- 유연성: 충돌이 발생했을 때, 비즈니스 로직에 따라 트랜잭션을 재시도하거나 롤백할 수 있음.
- 단점:
- 충돌 가능성: 데이터가 자주 변경되는 경우, 충돌이 자주 발생할 수 있음. 이로 인해 여러 번의 재시도 필요 가능.
- 복잡성: 충돌을 처리하기 위한 로직이 추가로 필요.
낙관적 락은 데이터베이스 락을 최소화하면서도 데이터 일관성을 유지할 수 있는 효과적인 방법임.
특히, 데이터 충돌이 적고 병행 처리가 많은 시스템에서 유용하게 사용할 수 있음.
하지만, 충돌이 발생했을 때의 처리 로직을 잘 설계해야 하며, 특정 상황에서는 비관적 락보다 복잡할 수 있음.
2.3 데드 락
데이터베이스 환경에서 데드락은 2개 이상의 트랜잭션이 서로가 점유하고 있는 자원을 기다리면서 영원히 대기 상태에 빠지는 상황을 의미.
이 상황이 발생하면, 해당 트랜잭션들은 더 이상 진행될 수 없고, 시스템 성능에 큰 영향을 미칠 수 있음.
예시
- 트랜잭션A는 테이블 X의 일부 행을 잠금(Lock)하고 이후 테이블 Y의 행을 잠금하려고 시도
- 트랜잭션B는 Y의 일부 행을 잠금하고, 이후 테이블 X의 행을 잠금하려고 시도
- 이 경우, 트랜잭션 A와 B는 서로 상대방이 보유한 잠금을 기다리면서 영원히 대기하게 되며, 이로 인해 데드락 발생
'연습장' 카테고리의 다른 글
vite-react 프로젝트 생성 후 실행 시 error 사항 (작성 중) (0) 2024.12.20 SQLD 벼락치기... (0) 2024.08.24 SQLD 정리... (0) 2024.08.23 장애 대응 4 - 후속 조치, 예방 조치 (0) 2024.08.21 장애 대응 3 - 장애 복구 (0) 2024.08.21