데이터베이스에 저장되어 있는 데이터는 클라이언트에 의해 생성, 조회, 수정, 삭제(CRUD)작업이 지속적으로 발생한다. 복수의 클라이언트가 동시에 동일한 데이터에 접근할 수 있고 데이터를 조작을 할 수 있기 때문에 동시성 문제가 발생될 수 있다.
RDBMS에서는 ACID 준수와 동시성 문제의 해결을 위해 Transaction
이라는 작업 단위를 사용하며, 트랜잭션이 수행되는 과정에서 Lock
과 Isolation Level
이라는 두가지 메커니즘이 동작한다.
이 글에서는 Isolation Level
에 대해 공부한 내용을 예시와 정리해보고자 한다.
(본 글의 내용들은 MySQL을 기준으로 작성되어 다른 RDB에는 적용되지 않는 내용이 일부 있을 수 있다.)
Read Uncomitted
Read Uncomitted에서는 다른 트랜잭션의 커밋되지 않은 데이터를 읽을 수 있다. 데이터에 별도 락을 걸지 않기 때문에 좋은 퍼포먼스를 보이지만 Dirty Read가 발생한다. (아래 이미지는 콘서트 좌석 예매라는 상황을 가정하였다.)
3. 조회
과정에서 트랜잭션 A가 커밋되지 않았는데 예매가 완료된 상태로 조회된다. 여기서 만약 트랜잭션 A가 롤백 되면 트랜잭션 B의 일관성이 깨지게 되므로 문제를 야기할 수 있다.
Read Committed
다른 트랜잭션에서 커밋 된 데이터만 읽을 수 있다. Read Uncomitted에서 볼 수 있는 Dirty Read는 발생하지 않지만 Non Repeatable Read
가 발생한다. 즉, 한 트랜잭션 내에서 동일 데이터에 대해 다른 상태 값이 조회될 수 있고 DB와 트랜잭션의 상태가 불일치 되어 논리적 일관성이 깨지게 되는 것이다.
- Non Repeatable Read :
트랜잭션 B
에서 두 번의 조회 결과가 다르므로 논리적 일관성이 깨지는 것을 확인할 수 있다.
Repeatable Read
같은 트랜잭션 내에서 동일 데이터에 대해 몇 번을 SELECT 하더라도 같은 결과를 보장한다. Dirty Read, Non Repeatable Read는 발생하지 않지만 Phantom Read
가 발생할 수 있다.
- Phantom Read : 트랜잭션 A에서 새로운
좌석 3
이 추가되었고, 트랜잭션 B 실행 도중 두 번째 조회 쿼리에좌석 3
이 새롭게 데이터 셋에 추가된 것이다. 첫 번째 조회 쿼리와 결과가 다르므로 일관성이 깨지게 된다. - 트랜잭션이 수행 되는 동안 계속 같은 조회 결과를 보장하는데에는 InnoDB의
MVCC(Multi-Version-Concurrency Control)
가 사용된다. MVCC는 각 레코드마다 버전을 부여한다. 트랜잭션은 시작 시점의 해당 레코드 버전만을 계속 읽기 때문에 동일한 결과를 보장할 수 있는 것이다. 일종의 스냅 샷을 읽는 것이라 할 수 있다.
Serializable
트랜잭션의 실행 순서를 보장하여 데이터의 일관성을 유지한다. 한 트랜잭션이 실행된 이후 다른 트랜잭션이 시작 되는 방식이다. 강한 동시성 제어로 인해 성능이 퍼포먼스가 좋지 않다.
어떤 Isolation Level을 선택해야 할까?
MySQL에서는 별도의 설정을 하지 않으면 기본 값으로 Repetable Read를 사용한다. 하지만 앞서 살펴본 것과 같이 Repeatable Read는 어느정도의 일관성을 보장하지만 Phantom Read를 문제를 피하지는 못한다.
트랜잭션 격리 수준만으로는 문제를 완벽히 제어할 수 없기 때문에 SELECT ... FOR UPDATE
, SELECT ... LOCK IN SHARE MODE
와 같은 보완재의 사용이 요구된다.
Isolation Level은 동시성을 제어하여 데이터가 일관성을 유지할 수 있도록 해준다. 그러나 처리 과정에서 발생하는 Lock과 같은 동작은 트랜잭션의 수행을 지연시킬 수 있다. 성능에 치중하면 동시성에 문제가 생기고, 동시성을 강하게 제어하면 성능이 하락하는 트레이드 오프 관계인 것이다.
References:
https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_acid https://product.kyobobook.co.kr/detail/S000001766482 https://www.postgresql.kr/blog/pgphantomread.html