티스토리 뷰
동시성(Concurrency)이란?
• 여러 클라이언트가 동시에 하나의 데이터를 사용 및 공유하는 것을 뜻합니다.
• 다수의 사용자가 동일한 시스템을 공유하면서 발생하는 동시 접근 문제를 해결해야합니다.
동시성문제 (Concurrency Issue)
동시성 문제는 여러 클라이언트가 동시에 같은 데이터를 접근하려고 할때 발생합니다.
🔖 예시
철수가 은행에 가서 총잔액 10,000인 A계좌를 통해 1,000원을 인출하였습니다. (10,000원 → 9,000원 커밋X)
같은시간 민수가 은행에가서 철수와 같은시간에 A계좌에서 1000원을 인출하였습니다. (9,000원 → 8,000원)
철수가 인출했을 당시에는 9,000원이였지만 8,000원으로 되어 있는 에러가 발생하여 Rollback하였습니다.(10,000원)
민수는 그 상태 그대로 작업하여 커밋하게 되어 A계좌의 잔고는 8,000원으로 잘못표시되는 문제가 발생하였습니다.
→ 철수가 돈을 인출한 후에 발생한 롤백은 데이터베이스의 일관성을 유지하기 위해 사용되는 메커니즘입니다.
하지만 이후에 민수가 철수의 롤백 이력을 인지하지 못하고 작업을 진행한 결과, 데이터베이스의 일관성이 깨졌습니다.
즉, 철수의 트랜잭션의 결과가 롤백되었지만,
민수의 트랜잭션은 이 사실을 감지하지 못하고 계속 진행되어 잘못된 결과가 발생했습니다.
위의 예시에서 볼 수 있듯이,
동시에 여러 트랜잭션이 동일한 데이터에 접근할 때는 데이터의 일관성을 유지하기 어려울 수 있습니다.
이러한 문제는
동시성 제어 및 트랜잭션 관리 메커니즘을 통해 이러한 상황을 방지하고 데이터의 일관성을 유지하는 것이 중요합니다.
동시성 문제를 해결하기 위해, 자원을 사용하는 하나의 클라이언트만 해당 자원을 점유할 수 있도록 하여, 다른 사용자가 접근할 수 없도록 만들어 자원을 공유하는 원인을 제거하면 됩니다.
이 과정을 자원잠금(Resource Locking)이라 부르며, 락(Lock)이라는 개념이 나오게 됩니다.
락(Lock)이란?
동시성 제어를 위해 사용하는 기능입니다.
해당하는 데이터를 점유하여 다른 트랜잭션의 접근을 막아 동시성과 일관성의 균형을 맞추기 위해 사용합니다.
하나의 데이터를 여러 사용자들이 동시에 변경하려고 할 떄, 락이 존재하지 않는다면, 한번에 여러번의 수정이 발생하게 되고, 최종 수정된 결과 값을 인지할 수 없게 되는 상황으로 인해 데이터베이스의 일관성이 깨지게 됩니다.
이러한 상황을 방지하기위해 데이터베이스에서는 락(Lock)이라는 기능을 지원하게 되었습니다.
즉, 락이란 하나의 트랜잭션에서 사용 중인 데이터를 잠그는 방식으로,
다른 트랜잭션들이 그 데이터에 접근하지 못하도록 합니다.
이 방식을 사용한다면, 어떤 트랜잭션도 다른 트랜잭션의 중간 상태를 볼 수 없게 되므로 데이터 일관성을 유지할 수 있습니다.
락(Lock)의 종류
Lock의 종류 | 설명 및 예시 |
공유 락( Shared Locks ) | 읽기 락 (Read Locks ) | 다른 트랜잭션이 데이터를 읽는 것은 허용하지만 수정하는것은 금지한다 READ전용 락이라고 불리기도한다 해당 락을 사용하는 트랜잭션이 모든 작업을 수행하였다면 공유락은 해제된다. # CORINY 테이블을 조회할 때, 해당 데이터들에 공유 락을 설정합니다. SELECT * FROM CORINY LOCK IN SHARE MODE; |
배타 락( Exclusive Locks ) | 쓰기 락( Write Locks ) | 다른 트랜잭션이 데이터를 읽거나, 수정하는것을 금지한다. WRITE전용락이라고 불린다. 트랜잭션이 해당하는 데이터를 점유한후 다른 트랜잭션이 해당데이터에 접근할수 없도록 만든다. # CORINY 테이블을 조회할 때, 해당 데이터들에 배타 락을 설정합니다. SELECT * FROM CORINY FOR UPDATE; |
락킹 수준(Locking Level)
Locking Level | 설명 및 예시 |
글로벌락( Global Locks ) | 데이터베이스 락( Database Locks ) | 데이터베이스의 모든 테이블에 락을 걸어 현재 트랜잭션을 제외한 나머지 트랜잭션들이 모든 테이블을 사용할수 없도록 만든다. 가장 높은 수준의 락을 가지고 있으며, 가장 큰범위를 가지고 있다. # 글로벌 락을 획득합니다. # MySQL 서버에 존재하는 모든 테이블에 락을 겁니다. FLUSH TABLES WITH READ LOCK; |
테이블 락( Table Locks ) | 다른 사용자가 작업중인 테이블을 동시에 수정하지 못하게한다. # CORINY 테이블에 테이블 락을 설정합니다. LOCK TABLES CORINY READ; |
네임드 락( Named Locks ) | 테이블이나 테이블의 행과 같은 DB 오브젝트가 아닌, 특정한 문자열을 점유한다. # CORINY_name 문자열을 획득합니다. # 만약, 10초 동안 획득 하지 못한다면, NULL을 반환합니다. SELECT GET_LOCK(' CORINY_name', 10); |
메타 데이터 락(Metadata Locks) | 다른 사용자가 작업중인 테이블의 동일한 행 및 동일한 데이터베이스의 객체를 동시에 수정하지 못하도록 한다. # 테이블 구조를 변경할 때, MySQL은 내부적으로 메타데이터 락을 설정 ALTER TABLE CORINY ADD COLUMN Age Int; |
※ 주의
락은 다양한 락킹 수준(Locking Level)을 가지고 있는데, 잘못된 락 설정을 하게 될 경우
모든 API가 동작하지 않는 교착 상태(Dead Lock)가 발생하게 되어, 프로그램이 멈춰버리는 문제가 발생하게 될 수 있다.
해당하는 상황을 해결하기 위해 트랜잭션에서 사용하는 락(Lock)의 수준을 명확하게 이해하고,
적재적소에 필요한 락의 수준을 설정하여 트랜잭션을 구성해야한다.
테이블에 락(Lock)을 적용하여, 다른 작업이 처리되지 못하게 점유하고 있는 작업이 있을 때, 다른 작업을 끝나는 것을 무한정 기다리는것
격리수준(Isolation Level)이란?
여러 트랜잭션이 동시에 처리될 때 다른 트랜잭션에서 변경 및 조회하는 데이터를 읽을 수 있도록
허용하거나 거부하는 것을 결정하기 위해 사용하는 것
★ ‘데이터의 일관성’과 ‘동시성 처리 성능’ 사이에서 균형을 잡는 것이 가장 중요하다!
트랜잭션의 격리 수준 | 설명 |
READ UNCOMMITTED | 커밋 되지 않은 읽기(Uncommitted Read)를 허용하는 격리 수준 가장 낮은 수준의 격리수준이며, 락을 걸지 않아 동시성이 높지만 일관성이 쉽게 깨질 수 있다. |
READ COMMITTED | 커밋 된 읽기(Committed Read)만을 허용하고, SELECT 문을 실행할 때 공유락을 겁니다. 다른 트랜잭션이 데이터를 수정하고 있는 중에는 데이터를 읽을 수 없어 커밋되지 않은 읽기현상이 발생하지 않는다. |
REPEATABLE READ | 읽기를 마치더라도 공유락을 풀지 않으며, 트랜잭션이 완전히 종료될 때 까지 락을 유지한다. 공유락이 걸린 상태에서 데이터를 수정하는 것은 불가능하지만, 데이터를 삽입하는 것이 가능해진다. 그로인해 팬텀 읽기가 발생할 수 있는 문제점이 발생. |
SERIALIZABLE | 데이터를 읽는 동안 다른 트랜잭션이 해당 데이터를 읽거나 삽입할 수 없고, 새로운 데이터를 추가하는 것 또한 불가능합니다. 가장 높은 수준의 격리 수준이므로, 동시성이 떨어지는 문제점이 존재 |
다른 트랜잭션에 의해 작업중인 데이터를 읽게 되는 것을 나타낸다.
커밋되지 않은 읽기가 발생할 경우,
의도치 않은 데이터를 참조하게 되어 데이터의 일관성이 깨지게 되는 상황이 발생하게 된다.
트랜잭션을 수행하던 중 다른 트랜잭션에 의해 삭제된 데이터를 팬텀행(Phantom Rows)이라고 한다.
팬텀행에 해당하는 데이터를 읽는 것을 팬텀 읽기(Phantom Read)라고 부른다.
'프로그래밍 기초 > CS' 카테고리의 다른 글
IoC 와 DI에 대하여 (0) | 2024.03.05 |
---|---|
객체지향 프로그래밍 설계 5원칙이란? (0) | 2024.03.04 |
Access Token 과 Refresh Token (0) | 2024.02.16 |
JWT란? (0) | 2024.02.14 |
쿠키(Cookie)와 세션(Session) (0) | 2024.02.13 |