Transaction, DeadLock, BLOCKING

유영·2023년 4월 20일
0

MYSQL

목록 보기
20/20

트랜잭션 : DBMS에서 데이터를 다루는 논리적인 작업의 단위

DB에서 데이터를 다룰 때 장애가 일어난 경우 데이터를 복구하는 작업의 단위가 된다.
DB에서 여러 작업이 동시에 같은 데이터를 다룰 때가 이 작업을 서로 분리하는 단위가 된다.
트랜잭션은 전체가 수행되거나 또는 전혀 수행되지 않아야 한다.(All or Nothing)

우리가 데이터베이스에 삽입, 수정, 삭제 등의 작업을 할 때, 여러 개의 작업들을 하나의 트랜잭션으로 묶습니다. 즉, 트랜잭션은 DBMS에서 데이터를 다루는 논리적인 작업의 단위가 됩니다.
예를 들어 A계좌(박지성)에서 B계좌(김연아)로 돈을 이체하는 경우에
이 업무는 A에서 돈을 빼고 B에서 돈을 더하는 2가지의 Update문으로 나뉘게 됩니다.
그리고 이것들은 개별적으로 수행되는 것이 아니라 하나의 트랜잭션으로 묶이게 되며 하나의 트랜잭션이 실행될 때 이 2개의 SQL문이 연속적으로 실행됩니다. 그러므로 2개의 UPDATE문이 하나의 트랜잭션으로 묶여있다고 가정할 때 1개의 SQL만 실행되는 상황은 발생하지 않고 이를 All or Nothing 이라 합니다. 이어서 위의 계좌 이체 트랜잭션이 일어나는 세부 과정에 대해서 알아보도록 하겠습니다.

[ 트랜잭션 수행 과정 ]
1. A계좌의 값을 하드디스크(데이터베이스)에서 주기억장치 버퍼로 읽어온다.
2. B계좌의 값을 하드디스크(데이터베이스)에서 주기억장치 버퍼로 읽어온다.
3. A 계좌에서 10000원을 인출한 값을 저장한다.
4. B 계좌에서 10000원을 입금한 값을 저장한다.
5. A 계좌의 값을 주기억장치 버퍼에서 하드디스크(데이터베이스)에 기록한다.
6. B 계좌의 값을 주기억장치 버퍼에서 하드디스크(데이터베이스)에 기록한다.

TCL이란

Transaction Control Language의 약어로써, DCL(Data Control Language)에서
트랜잭션을 제어하는 명령인 COMMIT과 ROLLBACK 만을 따로 분리해서 TCL이라고 표현하고 있다.

Commit이란 트랜잭션의 수행이 완료됨을 트랜잭션 관리자에게 알려 주는 연산
방법1의 실제 동작: ①-②-③-④-Commit(부분 완료)-⑤-⑥-완료
Syntax : COMMIT;


DBMS는 사용자에게 빠른 응답을 위해 방법1을 택한다고 합니다.

롤백(Rollback): 트랜잭션이 행한 모든 연산을 취소시키거나 트랜잭션을 재시작함.
Syntax : ROLLBACK TO 'SAVEPOINT_NAME';
DBMS는 일관성을 유지하기 위해 무결성 제약조건을 활용함.
DBMS는 고립성을 유지하기 위해 동시성 제어 알고리즘을 작동시킴.
DBMS는 지속성을 유지하기 위해 회복 관리자 프로그램을 이용함.

LOCK
트랜잭션이 수행되는 동안 특정 데이터에 대해서 다른 트랜잭션이 동시에 접근하지 못하도록 제한하는 기법

SAVEPOINT

  • SAVEPOINT는 현재의 트랜잭션을 작게 분할하는 명령어
  • 저장 된 SAVEPOINT는 ROLLBACK TO SAVEPOINT 문을 사용하여 지정한 곳까지 ROLLBACK 할 수 있다.
  • 여러개의 SQL문을 수반하는 트랜잭션의 경우, 사용자가 트랜잭션 중간 단계에서 SAVEPOINT를 지정할 수 있다.
  • 이 SAVEPOINT는 ROLLBACK과 함께 사용하며, 현재 트랜잭션 내의 특정 SAVEPOINT까지 ROLLBACK 할 수 있다.
    Syntax : SAVEPOINT 포인터명;
  • SAVEPOINT 유의사항
    SAVEPOINT 후 COMMIT 연산을 하게 된다면 COMMIT 연산 이전에 만든 SAVEPOINT들은 모두 사라진다.
    SAVEPOINT는 여러개 생성할 수 있다.

MySQL의 트랜잭션 고립성(Transaction Isolation Level)

고립성이란 실행중인 트랜잭션의 중간결과를 다른 트랜잭션에서는 접근할 수 없음을 나타냅니다.
MySQL에서는 고립성에 4개의 레벨을 부여했습니다.
이러한 각 레벨은 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, 그리고 SERIALIZABLE입니다.
이 4단계는 일반적인 DBMS와 동일한 표준을 따르고 있습니다.
또한 MySQL은 이 중 REPEATABLE READ를 기본으로 채택하고있습니다.
해당 단계는 Commit 된 것을 이전에 시작한 트랜잭션이 읽을 때 변경된 값을 읽는 것이 아니라
UNDO 로그에 있는 값을 읽는것을 기본으로하는 레벨입니다.
이렇게 하여 한 트랜잭션에 대해서 동일한 읽기를 가능하게 해줍니다.

여기에 Lock 매커니즘이 적용되게됩니다. 한 트랜잭션에서 5개의 row를 update한다고 하겠습니다.
REPEATABLE READ 레벨에서는 각 row에 대해서 update시 배타락을 겁니다.
하지만 업데이트가 되었다고 해서 lock을 풀지 않습니다.
이 lock은 트랜잭션이 마무리될때까지 가지고 있는 것입니다.

x-lock(1,2); retain x-lock
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); retain x-lock
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); retain x-lock

x-lock(1,2); block and wait for first UPDATE to commit or roll back

한단계 낮은 READ COMMITTED 레벨에서는 어떨까요?
READ COMMITED는 커밋된다면 다른 트랜잭션에서 업데이트된 상태값을 읽을 수 있는 레벨입니다.
이때는 update 되고 다음 row로 넘어갈 때 update된 row의 lock을 풀어줍니다.

x-lock(1,2); unlock(1,2)
x-lock(2,3); update(2,3) to (2,5); retain x-lock
x-lock(3,2); unlock(3,2)
x-lock(4,3); update(4,3) to (4,5); retain x-lock
x-lock(5,2); unlock(5,2)

[ 트랜잭션 스케줄(Transaction Schedule) ]

  • 직렬 스케줄(Serial Schedule)
  • 비직렬 스케줄(Nonserial Schedule)
  • 직렬 가능 스케줄(Serializable Schedule)

트랜잭션들은 삽입, 수정, 삭제 등과 같은 연산들로 이루어져있는데
여기서 트랜잭션 스케줄이란 그 연산들의 실행 순서를 의미합니다.
직렬 스케줄의 경우에는 트랜잭션의 연산을 모두 순차적으로 실행하는 유형을 의미합니다.
즉, 하나의 트랜잭션이 실행되면 해당 트랜잭션이 완료되어야 다른 트랜잭션이 실행될 수 있습니다.
비직렬 스케줄은 트랜잭션의 직렬 수행 순서와 상관없이 병행 수행하는 스케줄을 의미합니다.
그러므로 한 트랜잭션이 진행중인 상황에서 다른 트랜잭션이 실행될 수 있습니다.
마지막으로는 직렬가능 스케줄이 있는데 직렬 스케즐과 동등한 비직렬 스케줄을 의미합니다.
쉽게 설명하자면 서로 영향을 주지 않는 직렬 스케줄을 비직렬적으로 수행하겠다는 것입니다.

MySQL의 데드락(DeadLock) 처리

데드락(deadlock) : 두개 이상의 트랜잭션간 교착상태
두개의 트랜잭션 간에 각각의 트랜잭션이 갖고 있는 리소스 lock획득시 발생.
해결책 : 한쪽 트랜잭션 처리를 강제 종료

데드락은 트랜잭션을 지원하는 데이터베이스에서는 자주 발생하는 문제이다.
멀티 스레드(Multi-threaded) 어플리케이션에서 발생하는 데드락은 해당 어플리케이션을 완전히 멈추게 해버리기 때문에 위험하다.
하지만 일반적인 DBMS (Database Management System)에서는 데드락 탐지(Deadlock detection) 기능을 제공하기 때문에
데드락이 발견되면 자동으로 해소시켜준다.
(실제 데드락 상황이 아닐지라도 락에 대한 대기시간이 설정된 시간을 초과하면 이것도 데드락으로 처리)
이 과정에서 작업중이던 트랜잭션들 중 일부가 취소되는 경우가 발생 할 수 있기때문에
어플리케이션 레벨에서 해당 트랜잭션을 재실행 하여 작업을 완수할 수 있도록 구성해야한다.

MySQL에서 사용하는 InnoDB는 데드락 감지를 사용가능합니다. 이 설정은 디폴트로 설정되어있습니다.
MySQL의 데드락 감지 기능에 의해서 데드락으로 감지되면 2개의 트랜잭션 중
데이터 변화가 적은 트랜잭션을 rollback 시켜 데드락을 해소시킵니다.
하지만 높은 동시성을 사용하는 고성능 시스템에서는 데드락 감지기능은 속도 저하의 원인이 될 수 있습니다.
이럴 경우는 데드락 감지기능을 사용하기 보다는 innodb_lock_wait_timeout을 사용하는 것을 권장하고 있습니다.
innodb_lock_wait_timeout은 row lock을 걸고 특정시간이상 걸리면 자동으로 lock을 해재해버리는 매커니즘입니다.

BLOCKING

  • LOCK들의 경합이 발생하여 특정 세션이 작업을 진행하지 못하고 멈춰선 상태
    =>먼저 LOCK을 설정한 트랜잭션을 기다려야하기 때문에 이런 현상 반복시 빠른 서비스를 제공할 수 없다.
  • 공유LOCK - 배타적LOCK /배타적LOCK -배타적LOCK 끼리 발생가능
  • 해결방법 : TRANSACTION COMMIT 또는 ROLLBACK
  1. SQL 문장에 가장 빠르게 실행되도록 리펙토링 하는것
  2. 트랜잭션을 가능한 짧게 정의하면 경합 줄일수 있음
  3. 동일한 데이터를 동시에 변경하는 작업을 하지 않도록 설계 (트랜잭션이 활발한 주간에는 대용량 갱신 작업 수행하면 안됨)
  4. 대용량 작업이 불가피할 경우
    : 작업 단위를 쪼개거나 lock_timeout 설정하여 해당 lock 최대 시간 설정
set lock_timeout 3000

0개의 댓글