본문 바로가기

데이터베이스 DataBase

chapter 08 트랜잭션, 동시성 제어, 회복

트랜잭션 : 데이터를 다루는 작업의 단위로, 거래가 일어나는 동안 변경될 데이터가 모두 변경되던지 아니면 아예 없던 일이 되어야 한다. DBMS가 데이터베이스를 다룰 때 사용하는 논리적인 작업(프로그램)의 단위로 보통 단일 SQL 문을 사용하여 데이터를 다루기도 하지만, 여러 개의 SQL 문을 순차적으로 수행하여 데이터를 다루기도 한다. 데이터베이스의 무결성을 유지해야 한다. 원자성(Atomicity), 일관성(Consistency), 고립성(Isolation), 지속성(Durability)의 성질을 가지며(ACID라 부름), DBMS는 트랜잭션이 이러한 성질을 유지할 수 있도록 지원해 준다. 데이터베이스에서 트랜잭션을 정의하는 이유는 장애 시 데이터를 복구하는 작업의 단위 및 데이터베이스에서 여러 작업이 동시에 같은 데이터를 다룰 때 작업을 서로 분리하는 단위가 되기 때문이다. DBMS에서 트랜잭션을 사용할 때, BEGIN TRANSACTION 문과 COMMIT TRANSACTION 문을 사용하여 트랜잭션의 시작과 끝을 표시한다. DBMS가 트랜잭션을 수행하는 구조를 살펴보면, 먼저 DBMS의 실제 데이터는 하드디스크에 저장되어 있고, 처리를 위해서 반드시 주기억장치 버퍼로 사본을 읽어와야 한다. COMMIT 문이 나오면 DBMS는 버퍼의 내용을 해당하는 명령으로 만든 다음 디스크에 데이터를 적지 않고 사용자에게 완료 사실을 알린다. 대신 주기억장치의 버퍼에서 디스크에 기록하는 것은 DBMS가 책임지고 수행한다. 이렇게 함으로 각각의 트랜잭션이 하드디스크에 개별 접근하는 것을 피하고 DBMS가 일괄적으로 접근하여 사용자에게 빠른 응답성을 제공한다. 다시 정리하자면 트랜잭션의 수행 과정은 시작->수행->부분완료(사용자 혹은 다른 트랜잭션에 알림)->버퍼내용 기록->완료를 거친다. 부분완료 단계를 거치면 트랜잭션이 변경한 내용이 주기억장치의 버퍼뿐만 아니라 재해에 대비하여 로그(임시 디스크)에도 저장된다. 만약 트랜잭션이 중간에 작업을 멈추면 회복 알고리즘을 이용하여 변경한 내용을 취소한다. 또는 자의적으로 ROLLBACK을 사용하여 트랜잭션을 취소 시킬 수 있다.

 

부분완료 : 트랜잭션 수행은 완료되었지만 변경 내용이 데이터베이스에 기록되었는지 확실하지 않은 상태다. 이 상태에서는 DBMS가 최종적으로 변경 내용을 데이터베이스에 기록해야 완료 상태가 된다. 만약 시스템 내부 문제 혹은 시스템 다운 등으로 DBMS가 변경 내용을 데이터베이스에 기록하지 못하면 실패 상태가 된다.

 

실패 : 트랜잭션을 중간에 중단하였거나, 부분완료 상태에서 변경 내용을 데이터베이스에 저장하지 못한 상태를 말한다. 실패 상태에서 DBMS는 트랜잭션이 수행한 작업을 모두 원상복구 시킨다.

 

트랜잭션 제어 명령어 : 트랜잭션을 제어하는 명령어를 TCL ; Transaction Control Language라 하며 BEGIN, COMMIT, ROLLBACK, SAVE 가 있다.

 

BEGIN : 트랜잭션의 시작을 표시하는 트랜잭션 제어 명령어.

 

COMMIT : 트랜잭션의 종료를 표시하는 트랜잭션 제어 명령어.

 

ROLLBACK : 트랜잭션을 전체 혹은 savepoint 까지 무효화 시키는 트랜잭션 제어 명령어.

 

SAVE : savepoint를 만드는 트랜잭션 제어 명령어.

 

savepoint : 트랜잭션의 길이가 길 경우 트랜잭션의 중간 지점에 수정내용을 반영하는 point를 만드는데, 이를 savepoint(저장점)라고 한다. 이 경우 ROLLBACK을 하면 트랜잭션의 처음이 아니라 savepoint까지 되돌아간다. 즉 ROLLBACK으로 전체가 취소 되는 것을 막는다. 한 트랜잭션 안에 여러 개의 savepoint를 만들 수 있다.

 

원자성 : 트랜잭션의 성질 중 하나로 트랜잭션이 원자처럼 더 이상 쪼개지지 않는 하나의 프로그램 단위로 동작해야 한다는 의미로 전체가 수행되거나 또는 전혀 수행되지 않아야 한다. DBMS는 원자성을 유지하기 위해 회복(복구) 관리자 프로그램을 작동시킨다.

 

일관성 : 트랜잭션의 성질 중 하나로 트랜잭션을 수행하기 전이나 수행한 후나 데이터베이스는 항상 일관된 상태를 유지해야 한다. 트랜잭션은 데이터베이스의 일관성을 유지해야 한다. 일관성은 테이블이 생성될 때 CREATE 문과 ALTER 문의 무결성 제약조건을 통해 명시된다. 다만 수행 중 일시적으로 일관성을 유지하지 못하는 상태가 있을 수 있다. 무결성 제약조건이 명시되어 있지 않은 데이터가 있다면 일관성을 유지하기 위한 프로그래머의 역할이 중요하다. 동시에 같은 데이터를 접근하는 트랜잭션들이 질서 있게 접근하여 데이터베이스의 일관성을 유지하도록 하기 위해선 동시성 제어 알고리즘을 작동시켜 일관성을 유지한다.

 

고립성 : 트랜잭션의 성질 중 하나로 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경 중인 데이터 값을 훼손하는 일이 없어야 한다. 즉, 동시에 수행되는 트랜잭션은 상호 존재를 모르고 독립적으로 수행된다. 만약 동시에 수행되는 트랜잭션이 같은 데이터를 가지고 작업을 한다면, 그들이 서로 충돌하지 않도록 제어하는 작업이 필요하다. 이 작업을 동시성 제어라고 한다. 동시성 제어보다 완화된 방법으론 트랜잭션 고립 수준에 따라 트랜잭션의 상호 간섭을 배제시키는 방법도 있다.

 

지속성 : 트랜잭션의 성질 중 하나로 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히 저장해야 한다. 저장된 데이터베이스는 저장 직후 혹은 어느 때나 발생할 수 있는 정전, 장애, 오류에 영향을 받지 않도록 해야 한다. DBMS 복구 시스템은 트랜잭션이 작업한 내용을 수시로 로그 데이터베이스에 기록하였다가 문제가 발생하면 로그 파일을 이용해 복구작업을 수행한다. 즉 시스템이 고장나더라도 유지된다.

 

동시성 제어 : 트랜잭션이 동시에 수행될 때, 일관성을 해치지 않도록 트랜잭션의 데이터 접근을 제어하는 DBMS의 기능을 동시성 제어라고 한다. 두 개의 트랜잭션이 한 개의 테이블에 동시에 접근하는 경우의 시나리오는 (트랜잭션1, 트랜잭션2)의 순서대로 (읽기, 읽기)와 (읽기, 쓰기), (쓰기, 쓰기)가 가능하다. 이때 (읽기, 읽기)의 경우엔 아무 문제가 없다. (읽기, 쓰기)의 경우 오손 읽기, 반복불가능 읽기, 유령 데이터 읽기 문제가 발생하고, (쓰기, 쓰기)의 경우 갱신손실이라는 치명적인 문제가 발생한다.

 

갱신손실 : 두 개의 트랜잭션이 한 개의 데이터를 동시에 갱신할 때 발생한다. 갱신손실 문제는 데이터베이스에서 절대 발생하면 안 되는 현상이다. 데이터베이스에 저장된 데이터 값을 주기억장치의 버퍼로 가져와야 읽을 수 있기 때문에 트랜잭션1에서 데이터베이스의 값을 읽어와 버퍼에서 수정하고 기록을 하지 않은 상태에서 트랜잭션2가 동일한 데이터를 데이터베이스에서 주기억장치의 버퍼로 읽어와 갱신하는 경우 트랜잭션1의 갱신은 손실된다. 갱신손실 문제를 해결하기 위해선 트랜잭션의 처리 순서를 정해야 하지만 이는 데이터베이스의 공유와 빠른 응답처리를 불가능하게 한다. 갱신손실 문제를 해결하기 위해선 데이터에 락을 걸어 갱신 중임을 알리는 방법이 있다.

 

락 : 트랜잭션이 데이터를 읽거나 수정할 때 데이터에 표시하는 잠금 장치다. 락을 이용할 경우 데이터를 잠금으로 다른 트랜잭션은 잠금이 풀릴 때까지 기다린다. 락을 이용하여 데이터에 대한 갱신을 순차적으로 진행한다. 락은 트랜잭션이 다루는 데이터를 다른 트랜잭션이 중간에 접근하지 못하도록 막아, 다른 트랜잭션을 대기 상태로 만든다. 그러나 다른 트랜잭션이 대기 상태로 되는 것은 사용자의 응답시간에 영향을 주기 때문에 가능한 최소화해야 한다. 트랜잭션이 다루는 데이터를 읽기만 하는가, 읽고 쓰는가, 쓰기만 하는가에 따라 어느 정도 작업을 허용할 수 있는 여지가 있기 때문에 락의 유형을 구분해 공유락, 배타락 두 가지로 나눈다. 공유락, 배타락의 허용관계는 락 호환행렬로 표현되고 트랜잭션의 공유락은 상호 허용이 되지만 배타락은 허용되지 않는다.

 

공유락 : 트랜잭션이 읽기를 할 때 사용하는 락.

 

배타락 : 트랜잭션이 읽고 쓰기를 할 때 사용하는 락.

 

2단계 락킹 : 락을 이용하면 갱신손실 문제를 해결할 수 있으나, 락을 걸고 해제하는 시점에 제한을 두지 않으면 두 개의 트랜잭션이 동시에 실행될 때 데이터의 일관성이 깨질 수 있다. 이것을 방지하기 위하여 2단계 락킹 기법을 사용한다. 2단계란 확장단계와 수축단계를 말한다.

 

확장단계 : 2단계 락킹에서 트랜잭션이 필요한 락을 획득하는 단계로, 이 단계에서는 이미 획득한 락을 해제하지 않는다.

 

수축단계 : 트랜잭션이 락을 해제하는 단계로, 이 단계에서는 새로운 락을 획득하지 않는다.

 

데드락 : 두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고 상대방 데이터에 대하여 락을 요청하는 경우 무한 대기 상태에 빠진다. 이러한 현상을 데드락 혹은 교착상태라 한다. 일반적으로 데드락이 발생하면 DBMS는 두 개의 트랜잭션 중 하나를 강제로 중지시킨다. Oracle DBMS의 경우 교착상태를 감지하고 교착상태를 유발시킨 명령문을 강제적으로 ROLLBACK 시켜 자동적으로 교착상태를 해결한다.

 

오손 읽기 : 읽기 작업을 하는 트랜잭션1이 쓰기 작업을 하는 트랜잭션2가 작업한 중간 데이터를 읽기 때문에 생기는 문제로 작업 중인 트랜잭션2가 어떤 이유에서 작업을 철회할 경우 트랜잭션1은 무효가 된 데이터를 읽게 되고 잘못된 결과를 도출한다. 이를 오손 읽기라고 한다.

 

반복불가능 읽기 : 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고 트랜잭션 1이 다시 한 번 데이터를 읽을 때 생기는 문제로 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전의 결과와 다른 결과가 나오는 현상을 반복불가능 읽기라 한다.

 

유령데이터 읽기 : 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고 트랜잭션 1이 다시 한 번 데이터를 읽을 때 생기는 문제다. 반복불가능 읽기와 비슷하지만 없던 데이터가 삽입되었기 때문에 다르게 구분한다.

 

트랜잭션 고립 수준 명령어 : DBMS는 트랜잭션을 동시에 실행시키면서 락보다 좀 더 완화된 방법으로 문제를 해결하는 명령어를 제공한다. 명령어에는 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE이 있다.

 

READ UNCOMMITTED : 고립 수준이 가장 낮은 명령어로, 자신의 데이터에 아무런 공유락을 걸지 않는다. SELECT 문에 공유락을 걸지 않고, UPDATE 문에 배타락을 설정한다. 다른 트랜잭션의 공유락과 배타락이 걸린 데이터를 읽을 수 있다. 오손 읽기, 반복불가능 읽기, 유령데이터 읽기 문제가 발생한다.

 

READ COMMITTED : SQL Server의 기본 설정으로 오손 읽기를 피하기 위해 자신의 데이터를 읽는 동안 공유락을 걸지만 트랜잭션이 끝나기 전에라도 해지 가능하다. SELECT 문에 공유락을 걸고 끝나면 바로 해지하고 UPDATE 문엔 배타락을 설정한다. 다른 트랜잭션이 설정한 공유락은 읽지만 배타락은 읽지 못한다. 반복불가능 읽기 문제와 유령데이터 읽기 문제가 발생할 수 있다.

 

REPEATABLE READ : 다른 고립화 수준에 비해 데이터의 동시성이 낮아 특별하지 않은 상황이라면 사용하지 않는다. SELECT 문 공유락을 걸고 트랜잭션을 끝까지 유지, UPDATE 문 배타락을 설정한다. 다른 트랜잭션이 설정한 공유락은 읽지만 배타락은 읽지 못한다. 유령데이터 읽기 문제가 발생할 수 있다.

 

SERIALIZABLE : 고립 수준이 가장 높은 명령어로 실행 중인 트랜잭션은 다른 트랜잭션으로부터 완벽하게 분리된다. 그만큼 동시성도 낮다. SELECT 문에 공유락을 걸고 트랜잭션의 끝까지 유지하고 UPDATE 문에 배타락을 설정한다. 다른 트랜잭션이 설정한 공유락은 읽지만 배타락은 읽지 못한다. 인덱스에 공유락을 설정하여 다른 트랜잭션의 INSERT 문이 금지된다.

 

회복 : 데이터베이스에 장애가 발생했을 때 데이터베이스를 일관성 있는 상태로 되돌리는 DBMS의 기능이다. 주로 시스템 충돌, 미디어 장애, 응용 소프트웨어 오류로 인한 장애에 초점을 맞추어 변경 중인 데이터베이스 버퍼를 갖고 있는 주기억 장치의 손실 상황이나 데이터베이스가 저장된 하드디스크의 손실 상황으로부터 데이터를 복구한다.

 

로그 파일 : DBMS는 트랜잭션이 수행 중이거나 수행이 종료된 후 발생하는 데이터베이스 손실을 방지하기 위해 트랜잭션의 데이터베이스 기록을 추적하는 로그 파일을 사용한다. 이 파일에는 트랜잭션이 반영한 모든 데이터의 변경사항을 데이터베이스에 기록하기 전에 미리 기록 해두는 별도의 데이터베이스이다. 로그 파일에 저장된 로그의 구조는 다음과 같다. <트랜잭션번호, 로그의 타입, 데이터 항목 이름, 수정 전 값, 수정 후 값> 여기서 로그의 타입이란 트랜잭션의 START, INSERT, UPDATE, DELETE 등과 같은 연산 타입을 나타낸다. 데이터의 변경 기록을 저장해 둔 로그 파일을 이용하면 시스템 장애도 복구할 수 있다. 시스템 운영 중 장애가 발생하면 시스템이 다시 가동되었을 때 DBMS는 로그파일을 가장 먼저 살펴보고 DBMS는 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단하여 종료된 트랜잭션은 종료를 확정하기 위하여 재실행(REDO)을 진행하고, 중단된 트랜잭션은 없던 일로 되돌리기 위해 취소(UNDO)를 진행한다.

 

재실행(REDO) : 장애 발생 후 시스템을 다시 가동 했을 때, 로그 파일에 트랜잭션의 시작(START)이 있고 종료(COMMIT)가 있는 경우엔 트랜잭션이 모두 완료되었다는 의미지만 변경 내용이 버퍼에서 데이터베이스에 기록되지 않았을 가능성이 있으므로 재실행 과정을 거친다.

 

취소(UNDO) : 장애 발생 후 시스템을 다시 가동했을 때, 로그 파일에 트랜잭션의 시작(START)만 있고 종료(COMMIT)가 없는 경우로 COMMIT 연산이 로그에 없다는 뜻은 트랜잭션이 완료되지 못했다는 의미로, 트랜잭션이 한 일을 모두 취소해야 한다. 그러므로 취소라고 한다.

 

즉시 갱신 방법 : '갱신 데이터->로그', '버퍼->데이터베이스' 작업이 부분완료 전에 동시에 진행될 수 있으며, 부분완료가 되면 갱신 데이터는 로그에 기록이 끝난 상태다. 시스템 운영 시 데이터베이스에 입출력 연산이 증가하는 단점이 있다.

 

지연 갱신 방법 : '갱신 데이터->로그'가 끝난 후 부분완료를 하고 '버퍼->데이터베이스' 작업이 진행되는 방법이다. 시스템 복구 시 복구시간이 좀 더 걸린다는 단점이 있다.

 

체크포인트 : 회복 시 많은 양의 로그를 검색하고 갱신하는 시간을 줄이기 위하여 몇 십 분 단위로 데이터베이스와 트랜잭션 로그 파일을 동기화한 후 동기화한 시점을 로그 파일에 기록해두는 방법 혹은 그 시점을 체크포인트라고 한다. 체크포인트 시점에서는 주기억장치의 로그 레코드를 모두 하드디스크의 로그 파일에 저장한다. 버퍼에 있는 변경된 내용을 하드디스크의 데이터베이스에 저장한다. 체크포인트를 로그 파일에 표시한다. 체크포인트가 있으면 로그를 이용한 회복 기법이 좀 더 간단해진다.

 

'데이터베이스 DataBase' 카테고리의 다른 글

chapter 09 데이터베이스 보안과 관리  (0) 2013.09.09
chapter 07 정규화  (0) 2013.09.06
chapter 06 데이터 모델링  (0) 2013.09.04
chapter 05 데이터베이스 응용  (0) 2013.09.02
chapter 04 SQL 고급  (0) 2013.08.30