본문 바로가기

IT/데이터베이스

트랜잭션과 동시성 제어

반응형

트랜잭션과 동시성 제어

트랜잭션이란?

  • 갱신은 단일 쿼리가 아닌 복수 쿼리를 연속적으로 수행하는 경우가 대부분
  • 또한 갱신 전에 조회를 포함해서 사용하는일이 많음
  • 이러한 쿼리들을 한 덩어리로 포함하여 다뤄야 함 → 이런 복수 쿼리를 한 단위로 묶은 것

원자성

  • 데이터의 변경을 수반하는 일련의 데이터 조작이 전부 성공할지, 전부 실패할지를 보증하는 구조
  • 예를 들어 A, B, C 작업이 순차적으로 있을 경우 A → B → C 가 하일련의 데이터 조작으로 묶임
  • 그리고 A, B, C 중 하나라도 실패할 경우 전부 롤백
  • A, B, C 를 하나의 원자 단위로 보는 관점

일관성

  • 기존의 데이터 베이스가 데이터 조작 전후에 그 상태를 유지하는 것을 보증
  • 이를 위해 데이터베이스에서는 오브젝트에 대해 각종 정합성 제약을 추가할 수 있다.
  • EX ) 유니크, NOT NULL 등등, 범위 등등
  • EX) 성별은 남/여 두가지로 만 설정한다, 잔액은 0보다 커야 한다.

고립성

  • 각각의 처리가 모순없이 실행되는 것을 보증하는것
  • '모순없이 실행된다' 라는 의미는 복수의 트랜잭션이 순서대로 실행되는 경우와 같은 결과를 얻을 수 있는 상태.
  • 즉 병렬로 실행이 되더라도 직렬로 실행된 상태와 동일하다면 '모순 없음'을 보장한다.
  • 다만 이런 직렬화 수준의 고립성은 동시에 동작하는 트랜잭션 1개와 동일한 수준 이며, 이는 성능에서 실용적이지가 않습니다.
  • 그렇기 때문에 이러한 수준을 완화해 제공하고 있다
    1. 커밋되지 않은 읽기
    2. 커밋된 읽기
    3. 반복 읽기
    4. 직렬화 가능
  • 4번 직렬화 가능 수준이 가장 엄격한 단계이며 1번 커밋되지 않은 읽기가 가장 완화된 단계이다.
  • 그러나 격리화 수준이 완화되면서 4단계에서 발생하지 않았던 현상이 생김
    1. 더티 읽기
      • 아직 커밋도지 않은 데이터를 다른 트랜잭션에서 읽는 현상
    2. 애매한 읽기
      • 어떤 트랜잭션이 이전에 읽어 들인 데이터를 다시 읽어 들일 때 2회 이후의 결과가 1회 때와 다른 현상
        1. TX1 이 특정 조건을 만족하는 행을 검색 → A 출력
        2. TX2 가 특정 조건에 만족하는 행을 UPDATE → A는 변경
        3. A는 TX2의 UPDATE 로 인해 특정 조건을 불충족 하는 데이터로 변경
        4. TX2가 COMMIT
        5. TX1이 특정 조건을 만족하는 행을 UPDATE를 실행
        6. A는 특정 조건을 만족하지 않음으로 UPDATE가 실행되지 않음
        7. TX1이 의도했떤 내용과는 다르게 데이터가 동작
      • TX1에서 최초 검색시 A가 특정 조건을 만족했지만 두번째 UPDATE 시에는 A는 특정 조건을 미충족
      • 최초 검색시와 UPDATE 시에 대상이 달라지는 현상이 발생
    3. 팬텀 읽기
      • 어떤 트랜잭션을 읽을 때 선택할 수 있는 데이터가 나타나거나 사라지는 현상이다.
        1. TX1이 INSERT 쿼리를 통해 A를 삽입
        2. TX2가 INSERT 쿼리를 통해 B를 삽입
        3. TX2 COMMIT
        4. TX1이 INSERT 쿼리를 통해 C를 삽입
        5. TX1 COMMIT
      • 위와 같은 경우에 TX1 입장에서는 총 삽입한 데이터가 2건, TX2 입장에서는 1건
      • 하지만 실제 조회시 총 3건이 나옴

지속성

  • 데이터 조작을 완료하고 COMMIT 이후 그 조작은 영구적이 되어 그 결과를 잃지 않는 것을 나타냄
  • 쉽게 DB서버를 내렸다 올려도 이전에 조작이 완료된 데이터는 보존이 되어 있어야 한다.
  • OS 이상종료, 시스템 장애 등등 이러한 상황에서도 지속성은 보장이 되어야 한다.

트랜잭션 격리 수준에 따른 외관상 차이

MVCC 에 따른 MySQL 의 특성

  • MySQL(InnoDB 형 테이블) 은 현재 DBMS 의 주류가 된 'MVCC'라는 기술을 사용하고 있다.
  • MVCC는 다음과 같은 특성을 지닌다.
    1. 읽기를 수행할 경우 갱신 중이라도 블록되지 않는다.
    2. 읽기 내용은 격리 수준에 따라 내용이 바뀌는 경우가 있다.
    3. 갱신 시 베타적 잠금을 얻는다.
    4. 갱신과 갱신은 나중에 온 트랜잭션이 잠금을 획득하려고 할 때 블록된다.
    5. 갱신 전 데이터를 UNDO 로그로 '롤벡 세그먼트' 라는 영역에 유지한다.
      1. UNDO 로그는 롤백시 갱신 전으로 되돌리기 위해
      2. UNDO 로그는 복수의 트랜잭션으로부터 격리 수준에 따라 대응하는 갱신 데이터를 참조 하는데 이용(다른 트랜잭션이 읽기를 수행한다면 해당 데이터를 제공)

트랜잭션 격리 수준별 외관

  • MVCC에 따른 MySQL 특성상 격리 수준의 기본값은 반복 읽기

반복 읽기

  • 반복 읽기는 최초 쿼리를 실행한 시점에 커밋된 데이터를 읽음
  • 복수 회 실행을 해도 최초 실행한 것과 동일한 결과를 반환
  • 복수 회 실행 중 다른 트랜잭션이 데이터를 변경해도 최초 실행한 것과 동일한 결과를 반환

커밋된 읽기

  • 쿼리를 실행한 시점에서 커밋된 데이터를 읽음
  • 복수 회 실행 중 다른 트랜잭션에서 커밋할때, 커밋된 데이터를 읽어옴

잠금 타임아웃과 교착 상태가 발생하는 이유

잠금 타임아웃이란?

  • 갱신과 참조는 서로를 블록하지 않음
  • 갱신과 갱신은 나중에 온 갱신이 잠금 대기 상태가 됨
  • 잠금 해제를 기다리고 있는 쪽에서는 잠금을 기다리거나, 기다리지 않거나, 기다린다면 어느정도 기다릴지를 설정할 수 있음
  • 잠금 대기로 타임아웃이 발생할 경우 DMBS로 부터 롤백되는 단위가 다를때가 있음
    • 해당 트랜잭션 전체 롤백
    • 타임아웃이 발생한 쿼리만 롤백 (MySQL 기본 설정)

교착 상태란?

  • TX1이 A 잠금을 얻음
  • TX2가 B 잠금을 얻음
  • 서로 잠금을 건 자원에 잠금이 필요한 처리 (UPDATE/INSERT/DELETE) 를 실행하면 아무리 기다려도 상황이 바뀌지 않는 상태가 됨
  • 이런 비슷한 상황들을 교착 상태라고 함

교착 상태의 빈도는 낮추는 대책

  • 잠금 타임아웃은 일정 시간 기다리면 상황이 개선될 가능성이 있음. (잠금을 건 쪽에서 잠금을 풀 경우)
  • 교착 상태는 상황이 개선될 가능성이 없음
  • 일반적으로 DBMS에서는 교착 상태를 독자적으로 감지해 상태를 보고함, 그후 한쪽 트랜잭션을 롤백함

교착 상태의 발생 빈도를 낮추기 위한 고려 사항

  1. 트랜잭션을 자주 커밋한다. 이에 따라 트랜잭션은 더 작은 단위가 되어 교착 상태의 가능성을 낮춘다.
  2. 정해진 순서로 테이블에 엑세스 하게 한다. 예를 들어서 테이블에 접근할때는 무조건 테이블 간 선행 관계를 정해 접근하도록 하는것
  3. 필요없는 경우 읽기 잠금 획득의 사용을 피한다.
  4. 쿼리에 의한 잠금 범위를 더 좁히거나 잠금 정도를 더 작은 것으로 한다. 예를 들어 잠금 단위를 행으로 변경하거나 격리 수준을 느슨하게 설정한다.(반복일기 → 커밋된 읽기)
  5. 복수 행을 복수 연결이 사용할 경우 테이블 단위 잠금을 획득해 갱신을 직렬화 하는 방법도 있음 → 동시성 저하
  6. MySQL(InnoDB)의 대책 : 적절한 인덱스를 추가해 해당 인덱스가 사용하게 한다. 인덱스가 없다면 스캔한 모든 행에 잠금이 걸리게 된다.

해서는 안 되는 트랜잭션 처리

1. 오토커밋

  • 간단한 쿼리의 실행과 테스트를 하는 경우에는 편리하지만 일정 수 이상의 갱신을 수행하거나 틀내잭션 기능등은 적절한 단위와 격리수준을 이용해 오토커밋을 피하도록 하자

2. 긴 트랜잭션

  • 긴 트랜잭션은 데이터베이스 트랜잭션의 동시성이나 자원의 유효성을 저하시킴

2.1 대량 처리를 한개의 트랜잭션이 실행한다.

  • 한개의 트랜잭션으로 대량의 갱신 처리를 실행하면 대량 갱신 처리를 롤백하기 위한 대량의 UNDO 로그를 트랜잭션 종료까지 유지해야 한다.
  • 적절한 크기를 생각해 트랜잭션을 설정해야 한다.

2.2 아무것도 하지 않는 트랜잭션을 유의한다.

  • SELECT를 하고 아무것도 하지 않고 있다면 이 테이블의 반복 읽기 유지를 위해 UNDO 로그가 계속 유지된 상태고 됨

2.3 트랜잭션 중에 대화 처리를 넣는다.

  • 효율 적으로 다루기 위해서는 언제 끝날지를 알 수 없는 불명확한 처리를 포함해서는 안됨
  • 불명확한 처리 중 가장 대표적인 것이 사용자와의 대화 처리
  • 일반적인 처리에 비해 타임아웃 설정을 하지 않는 이상 끝없이 사용자의 처리를 기다리게 됨
  • 시스템 전체 효율을 떨어트림

2.4. 처리 능력 이상의 트랜잭션 수

  • 트랜잭션이 많다면 잠금 타임아웃이나 교착 상태의 확률이 증가함
  • 테스트를 통한 설정이 상한선이 필요함
반응형

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

JPA 공부 - 0  (0) 2021.01.17
백업과 복구  (0) 2021.01.09
데이터베이스와 아키텍쳐 구성  (0) 2021.01.07
H2 Database not found  (2) 2019.12.03
ORACLE 전체 테이블 검색  (0) 2019.04.15