728x90
📌 알림
해당 글은 공부 목적으로 작성한 글입니다.
📌 트랜잭션(Transaction)
데이터베이스의 상태를 변화시키는 하나의 논리적인 작업 단위를 말한다.
📌 트랜잭션 ACID 원칙
ACID
데이터베이스 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 트랜잭션 시스템의 특성을 정의한 약어이다.
원자성(Atomicity)
트랜잭션을 구성하는 연산 전체는 모두 정상적으로 실행되거나 모두 취소되어야 한다.
일관성(Consistency)
트랜잭션 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지해야 한다.
독립성(Isolation)
두 개 이상의 트랜잭션이 동시에 발생할 때는 서로의 연산에 영향을 주어서는 안된다.
지속성(Durability)
커밋된 트랜잭션의 내용은 데이터베이스에 영구히 반영되어야 한다.
📌 Commit과 Rollback
Commit
트랜잭션이 성공하여 트랜잭션 결과를 영구적으로 반영하는 연산을 말한다.
Rollback
트랜잭션의 실행을 취소하였음을 알리는 연산으로, 트랜잭션이 수행한 결과를 원래의 상태로 복귀시킨다.
📌 트랜잭션 상태
트랜잭션의 상태로 활동, 장애, 철회, 부분 완료, 완료가 존재한다.
활동(Active)
트랜잭션이 실행 중인 상태
장애(Fail)
트랜잭션이 실행에 오류가 발생하여 중단한 상태
철회(Aborted)
트랜잭션이 비정상적으로 종료되어 Rollback을 수행하는 상태
부분 완료(Partially Commit)
트랜잭션이 마지막 연산까지 실행됐지만 Commit 연산이 실행되기 직정 상태
완료(Committed)
트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태
📌 트랜잭션 격리 수준
트랜잭션 격리가 성공하는 정도의 척도를 말하며, 트랜잭션 격리 수준으로 Read Uncommitted, Read Committed, Repeatable Read, Serializable이 존재한다.
Read Uncommitted
어떤 트랜잭션의 변경 내용이 Commit이나 Rollback과 상관없이 다른 트랜잭션에서 보여지는 정도의 격리 수준이다.
- 조회 시 커밋하지 않은 내용을 조회하는 DIRTY READ가 발생할 수 있다.
- 데이터 정합성 문제가 발생할 가능성이 많다.
- 트랜잭션 Lock 발생 X
Read Committed
트랜잭션의 변경 내용이 Commit 되어야만 다른 트랜잭션에서 해당 내용을 조회할 수 있는 격리 수준이다.
- 데이터의 값이 변경됐을 때 하나의 트랜잭션 내에서 똑같은 SELECT을 수행했을 경우 다른 결과를 반환하는 NON_REPETABLE READ가 발생할 수 있다.
- 트랜잭션 Lock 발생 X
Repeatable Read
Commit이 완료된 데이터만 읽을 수 있으며, 트랜잭션 범위 내에서 조회한 내용이 항상 동일함을 보장하는 격리 수준이다.
- 일정 범위의 레코드를 두 번 이상 읽을 때, 첫 번째 쿼리에서 없던 유령 레코드가 두 번째 쿼리에 나타나는 PHANTOM READ가 발생할 수 있다.
- 트랜잭션 Lock 발생 O
Serializable
한 트랜잭션에서 사용하는 데이터는 다른 트랜잭션에서 접근이 불가능한 격리 수준이다.
- 가장 단순하고 가장 엄격한 격리수준이다.
- 엄격한 격리 수준 때문에 동시처리 능력이 상대적으로 떨어지고, 성능 저하가 발생한다.
- 트랜잭션 Lock 발생 O
📌 동시성 제어(Concurrency Controll)
동시성 제어(Concurrency Control)
동시에 여러 개의 트랜잭션이 수행될 때, 트랜잭션들이 DB의 일관성을 파괴하지 않도록 트랜잭션 간의 상호작용을 제어하는 것을 의미한다.
동시성 제어를 하지 않은 경우 다음과 같은 문제점이 발생한다.
갱신 손실(Lost Update)
하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효화 되는 현상으로, 두 개 이상의 트랜잭션이 한 개의 데이터를 동시넹 갱신할 때 발생하는 문제이다.
현황 파악 오류(Dirty Read)
읽기 작업을 하는 트랜잭션이 쓰기 작업을 하는 다른 트랜잭션이 작업한 중간 데이터를 읽기 때문에 발생하며 작업 중인 트랜잭션이 작업을 Rollback한 경우 작업을 하고 있던 다른 트랜잭션은 무효화가 된 데이터를 읽게 되고 잘못된 결과를 도출하는 문제이다.
모순성(Inconsistency)
다른 트랜잭션들이 해당 항목 값을 갱신하는 동안 한 트랜잭션이 두 개의 항목 값 중 어떤 것은 갱신되기 전의 값을 읽고, 다른 것은 갱신된 후의 값을 읽게 되어 데이터의 불일치가 발생하는 문제이다.
연쇄복귀(Cascading Rollback)
두 트랜잭션이 동일한 데이터 내용을 접근할 때 발생하며, 한 트랜잭션이 데이터를 갱신한 다음 실패하여 Rollback 연산을 수행하는 과정에서 갱신과 Rollback 연산을 실행하고 있는 사이에 해당 데이터를 읽어서 사용할 때 발생하는 문제이다.
📌 동시성 제어기법의 종류
구분 | 제어 기법 | 내용 |
Locking | Shared Lock | 데이터 항목에 대해 읽기(read) 가능 |
Exclusive Lock | 데이터 항목에 대해서 읽기와 기록(입력/삭제)가 모두 불가능 | |
2 Phase Locking | 모든 트랜잭션들이 lock과 unlock 연산을 확장 단계와 수축 단계로 구분하여 수행함 | |
Timestamp Ordering | DB 시스템에 들어오는 트랜잭션 순서대로 System Clock / Logical Counter 할당하고 순서를 부여하여 동시성 제어의 기준으로 사용됨 | |
Validation(낙관적 검증) | 트랜잭션 수행 동안은 어떠한 검사도 하지 않고, 트랜잭션 종료 시 일괄적으로 검사하는 기법 | |
MVCC (다중버전 동시성 제어) |
트랜잭션의 타임스탬프와 접근 데이터의 여러 버전 타임스탬프를 비교하여 직렬 가능성이 보장되는 버전 선택 |
📌 락킹(Locking)
락킹(Locking)
트랜잭션이 데이터에 접근하기 전에 Lock을 요청해서 Lock이 허락되면 해당 데이터에 접근할 수 있도록 하는 기법
📌 비관적 락(Pessimistic Lock)
비관적 락(Pessimistic Lock)
자원 요청에 따른 동시성문제가 발생할것이라고 예상하고 락을 걸어버리는 방법론
공유 락(Shared Lock)
데이터를 읽을 때 사용되어지는 락으로 공유 락끼리의 동시 접근은 가능하지만 배타 락과는 불가능하다. 하나의 데이터를 읽는 것은 여러 사용자가 동시에 접근할 수 있다는 의미를 가진다.
배타 락(Exclusive Lock)
데이터를 변경하고자 할 때 사용되며, 트랜잭션이 완료될 때까지 유지된다. 배타 락은 락이 해제될 때까지 해당 리소스에 접근할 수 없으며 다른 트랜잭션이 수행되고 있는 데이터에 대해서는 접근하여 함께 락을 설정할 수 없다.
데이터 수정 즉시 트랜잭션 충돌을 감지할 수 있다.
Rollback을 개발자가 일일이 하는 것이 힘든 경우나 충돌이 일어났을 때 롤백 비용이 많이 드는 경우 사용
(주문 시 쿠폰 사용, 알림 제공, 주문서 작성 등의 여러 기능이 한 트랜잭션에 묶여 있는 경우에 적합)
📌 낙관적 락(Optimistic Lock)
낙관적 락(Optimistic Lock)
데이터 갱신 시 충돌이 발생하지 않을 것으로 가정하여 락을 걸지 않는 방법론
트랜잭션의 충돌이 발생하지 않을 것이라고 기대하며, 일단 충돌이 나는 것을 막지 않고, 충돌이 난 것을 감지하면 그 때 처리한다. 락이 아닌 버전 관리 기능을 통해서 트랜잭션 격리성을 관리하며 Version 컬럼을 별도로 추가해서 충돌을 방지하고, 최초 커밋만 인정된다. DB 단에서 동시성을 처리하는 것이 아닌 애플리케이션 단에서 처리한다.
충돌이 안난다는 가정 하에 동시 요청에 대해서 처리 성능이 좋으며, 데이터 충돌이 자주 일어나지 않을 것이라고 예상되는 시나리오에 사용하기 좋다. 단, 잦은 충돌이 일어나는 경우 롤백 처리에 대한 비용이 많이 들어 오히려 성능에서 손해를 볼 수 있다. 또한 롤백 처리를 구현하는 것이 조금 복잡하다.
📌 모의 면접
트랜잭션과 ACID 원칙에 대해 설명해주세요.
트랜잭션은 데이터베이스의 상태를 변화시키는 하나의 논리적인 작업 단위를 말하며, ACID 원칙은 트랜잭션이 안전하게 수행된다는 것을 보장하기 위한 트랜잭션 시스템의 특성을 정의한 약어입니다.
ACID 원칙으로는
트랜잭션을 구성하는 연산 전체는 모두 정상적으로 실행되거나 모두 취소되어야 한다는 원자성,
트랜잭션 실행을 성공적으로 완료하면 언제나 일관성 있는 데이터베이스 상태로 유지해야 한다는 일관성,
그리고 두 개 이상의 트랜잭션이 동시에 발생할 때는 서로의 연산에 영향을 주어서는 안된다는 독립성,
커밋된 트랜잭션의 내용은 데이터베이스에 영구히 반영되어야 한다는 내용의 지속성이 있습니다.
Commit과 Rollback에 대해 설명해주세요.
Commit은 트랜잭션이 성공하여 트랜잭션 결과를 영구적으로 반영하는 연산을 말합니다.
Rollback은 트랜잭션의 실행을 취소하였음을 알리는 연산으로, 트랜잭션이 수행한 결과를 원래의상태로 복귀시키는 연산입니다.
트랜잭션 상태에 대해서 설명해주세요.
트랜잭션 상태의 종류는 다섯가지로,
먼저 트랜잭션이 실행 중인 상태인 Active,
트랜잭션이 실행에 오류가 발생하여 중단한 Fail,
트랜잭션이 비정상적으로 종료되어 Rollback을 수행하는 Aborted,
트랜잭션이 마지막 연산까지 실행됐지만 Commit 연산이 실행되기 직전인 상태를 말하는 Partially Committed,
트랜잭션이 성공적으로 종료되어 Commit 연산을 실행한 후의 상태를 말하는 Committed 상태가 있습니다.
트랜잭션 격리 수준에 대해 설명해주세요.
트랜잭션 격리 수준은 트랜잭션 격리가 성공하는 정도의 척도를 말하며, 트랜잭션 격리 수준으로 Read Uncommitted, Read Committed, Repeatable Read, Serializable이 존재합니다.
Read Committed 수준은 어떤 트랜잭션의 변경 내용이 Commit이나 Rollback과 상관없이 다른 트랜잭션에서 보여지는 정도의 격리 수준입니다.
트랜잭션 락은 발생하지 않으며, 조회 시 커밋하지 않은 내용을 조회하는 DIRTY READ가 발생할 수 있어 데이터 정합성이 어긋날 확률이 많아 현재 잘 사용되지 않습니다.
Read Committed 수준은 트랜잭션의 변경 내용이 Commit 되어야만 다른 트랜잭션에서 해당 내용을 조회할 수 있는 격리 수준
입니다.
트랜잭션 락은 발생하지 않으며, 데이터의 값이 변경됐을 때 하나의 트랜잭션 내에서 똑같은 SELECT을 수행했을 경우 다른 결과를 반환하는 NON_REPETABLE READ가 발생할 수 있습니다.
Repeatable Read 수준은 Commit이 완료된 데이터만 읽을 수 있는 격리 수준입니다.
트랜잭션의 락이 발생하며, 트랜잭션 범위 내에서 조회한 내용이 항상 동일함을 보장합니다. 그러나 일정 범위의 레코드를 두 번 이상 읽을 때, 첫 번째 쿼리에서 없던 유령 레코드가 두 번째 쿼리에 나타나는 PHANTOM READ가 발생할 수 있습니다.
Serializable 수준은 한 트랜잭션에서 사용하는 데이터는 다른 트랜잭션에서 접근이 불가능한 격리 수준입니다.
트랜잭션의 발생하며, 다른 트랜잭션에서 접근이 불가능하기 때문에 가장 단순하고 가장 엄격한 격리 수준입니다. 그러나 엄격한 격리 수준 때문에 동시처리 능력이 상대적으로 떨어지고, 성능 저하가 발생한다는 문제점이 있습니다.
동시성 제어에 대한 설명과 동시성 제어를 하지 않았을 떄 발생할 수 있는 문제들에 대해 설명해주세요.
동시에 여러 개의 트랜잭션이 수행될 때, 트랜잭션들이 DB의 일관성을 파괴하지 않도록 트랜잭션 간의 상호작용을 제어하는 것을 말합니다.
동시성 제어를 하지 않았을 때 발생하는 문제로
하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효화 되는 갱신 손실 문제,
작업 중인 트랜잭션이 작업을 Rollback한 경우 작업을 하고 있던 다른 트랜잭션은 무효화가 된 데이터를 읽게 되고 잘못된 결과를 도출되는 현황 파악 오류 문제,
어떤 것은 갱신되기 전의 값을 읽고, 다른 것은 갱신된 후의 값을 읽게 되어 데이터의 불일치가 발생하는 모순성 문제
한 트랜잭션이 데이터를 갱신한 다음 실패하여 Rollback 연산을 수행하는 과정에서 갱신과 Rollback 연산을 실행하고 있는 사이에 해당 데이터를 읽어서 사용할 때 발생하는 연쇄복귀 문제가 발생할 수 있습니다.
갱신 분실 문제에 대한 설명과 이를 해결할 수 있는 방법에 대해 설명해주세요. (+⍺)
A와 B가 동시에 제목이 같은 공지사항을 동시에 수정한다고 했을 때 A가 먼저 수정을 완료하고 B가 이후에 완료버튼을 눌렀다면 B의 수정사항만 남게되는데 이것을 갱신 분실 문제라고 합니다.
갱실 분실 문제는 데이터베이스 트랜잭션의 범위를 넘어서는 문제로 트랜잭션으로만은 해결할 수 없고 마지막 커밋만을 인정하는 방법, 최초 커밋만 인정하는 방법, 충돌하는 갱신 내용을 병합하는 방법이 있습니다.
락킹(Locking)에 대해 설명해주세요.
Locking은 트랜잭션이 데이터에 접근하기 전에 Lock을 요청해서 Lock이 허락되면 해당 데이터에 접근할 수 있도록 하는 기법입니다.
락킹의 종류로는 크게 자원 요청에 따른 동시성문제가 발생할것이라고 예상하고 락을 걸어버리는 비관적 락과
자원 요청에 따른 동시성문제가 발생할것이라고 예상하고 락을 걸어버리는 낙관적 락이 존재합니다.
비관적 락은 데이터 수정 즉시 트랜잭션 충돌을 감지할 수 있으며, Rollback을 개발자가 일일이 하는 것이 힘든 경우나 주문 시 쿠폰 사용, 알림 제공, 주문서 작성 등의 트랜잭션이 많이 묶여 있어 충돌이 일어났을 때 롤백 비용이 많이 드는 경우 사용합니다.
낙관적 락은 충돌이 안난다는 가정 하에 동시 요청에 대해서 처리 성능이 좋으며, 데이터 충돌이 자주 일어나지 않을 것이라고 예상되는 시나리오에 사용하기 좋습니다.
MVCC(격리 수준 제어) 대신 락을 사용하는 이유가 무엇인가요? (+⍺)
낙관적 락이나 비관적 락은 다른 트랜잭션이 수정하는 것 자체를 막아버립니다. 반면에 MVCC는 다른 트랜잭션이 수정하는 것 자체는 막지 못하고, 트랜잭션 격리 레벨에 따라 일관된 읽기 를 제공하기 때문에 두 개의 트랜잭션이 동시에 수정할 때 처음의 수정사항만 반영하도록 하여 갱신 분실 문제를 예방 하기 위해서는 락을 사용해야 합니다. MVCC가 일관된 읽기를 사용할 수 있는 이유는 변경되기 이전의 내용을 보관하고 있는 언두 로그 에서 데이터를 가져오기 때문입니다.
DB 트랜잭션 레벨을 Repeatable Read로 하지 않고 낙관적 락을 사용하는 이유가 무엇인가요? (+⍺)
Repeatable read는 선행 트랜잭션이 종료시까지 다른 트랜잭션이 update, delete하지 못하도록 완전히 락을 걸어버립니다. 반면에 낙관적인 락은 애플리케이션 단에서 락을 걸지 않아 트랜잭션 자체를 blocking하지 않으면서도 다른 트랜잭션이 수정하는 것을 막아줍니다. 락을 거는 것 자체가 성능에 영향을 줄 수 있기 때문에 읽기 작업의 비율이 높은 경우 격리 레벨을 조정하는 것보다 낙관적인 락을 사용하는게 더 좋습니다.
댓글