티스토리 뷰

TIL

"이것이 MySQL이다"를 읽고 공부한 내용과 추가적으로 알아야 할 내용을 정리하고자 합니다. 

망나니개발자의 게시글을 기반으로 추가적인 내용을 더하였습니다!  

기본적인 내용은 정리하지 않을 것이기에 첨부된 링크로 대체하겠습니다.

 

책 : 이것이 MySQL이다 / Real MySQL(절판)

블로그 : 망나니 개발자, victolee 등등.. (Reference참고)


공부 키워드

#MySQL #Isolation #persistence #영속성 #ACID #DeadLock

#트랜잭션 #동시성제어 #회복


트랜잭션

트랜잭션이란 "질의를 처리하다" 실행이 중단되었을 경우 Rollback하거나, 실행 중 오류가 없을경우 commit을 하는 실행단위를 의미합니다. 즉, 간단하게 "작업수행의 논리적 단위" 입니다.

 

트랜잭션이 이해되지 않는다면 아래 링크를 참고해 주세요!

https://victorydntmd.tistory.com/129

https://mangkyu.tistory.com/30?category=761304 

 

 

트랜잭션을 사용해야 하는 이유

DB를 여러 클라이언트가 동시에 액세스하거나 데이터를 처리하는 과정에서 중단되었을때 Rollback하지 않는다면 데이터 부정합이 발생할 수 있습니다. 간단하게 설명하자면, A사용자와 B사용자가 사용하는 데이터가 다를 수 있습니다. 만약 대용량 트래픽을 처리하는 서비스이거나 금융, 개인정보를 다루는 서비스에서 이러한 데이터 부정합이 발생하는 것은 매우 위험한 일입니다.

 

부정합이 발생하지 않기 위해 프로세스를 병렬로 처리하지 않는 것은 효율이 떨어지기에 병렬로 처리할 수 밖에 없습니다. 병렬처리과정에서 발생하는 부정합을 방지하기 위해 트랜잭션을 사용하고 이 과정에서 발생할 수 있는 오류가 데드락과 관련이 있습니다. 추후 이부분에 대해 설명하도록 하겠습니다.

 

 

ACID

트랜잭션의 4가지 특성입니다. 자성, 관성, 격리성(= 립성), 속성

정보처리기사를 공부하였다면 많이 보았을 내용인데 저는 간단하게 외우기 위해 앞글자만 따서 지독한 1원 이라고 외웠습니다.

 

 

  • 원자성(Atomicity): 트랜잭션에 포함된 작업은 전부 수행되거나 전부 수행되지 않아야 한다.
  • 일관성(Consistency): 트랜잭션을 수행하기 전이나 후나 데이터베이스는 항상 일관된 상태를 유지해야 한다.
  • 고립성(Isolation): 수행 중인 트랜잭션에 다른 트랜잭션이 끼어들어 변경중인 데이터 값을 훼손하지 않아야한다.
  • 지속성(Durability): 수행을 성공적으로 완료한 트랜잭션은 변경한 데이터를 영구히 저장해야 한다

https://mangkyu.tistory.com/30?category=761304  (망나니 개발자)

ACID의 개념이 부족하다면 링크를 통해 이해해 주세요!

 

 

 

트랜잭션과 DBMS

 

  • DBMS는 원자성을 유지하기 위해 회복(복구)관리자 프로그램을 작동시킴.
  • DBMS는 일관성을 유지하기 위해 동시성 제어 알고리즘과 무결성 제약조건을 활용함.
  • DBMS는 고립성을 유지하기 위해 동시성 제어 알고리즘을 작동시킴.
  • DBMS는 지속성을 유지하기 위해 회복 관리자 프로그램을 이용함.

쿼리를 실행하다 오류가 발생 했을때 부분완료가 된다면 원자성과 지속성을 위배하게 된다. DBMS는 부분완료가 발생하지 않도록 하기 위해 회복 관리자 프로그램을 이용하여 트랜잭션 이전 상태로 복원시켜 지속성을 유지시켜 줍니다. 또한 일관성과 고립성을 유지하기 위해 어떠한 자원에 동시에 접근하지 못하도록 동시성제어를 이용합니다. 또한 DBMS는 잘못된 값에 대한 입력이 오면 일관성을 유지하기 위해 무결성 제약 조건을 활용한다.

 

 

 

동시성 제어(Currency Control)

  • 다중 사용자 환경에서 둘 이상의 트랜잭션이 동시에 수행될 때, 일관성을 해치지 않도록 트랜잭션의 데이터 접근 제어
  • 다중 사용자 환경을 지원하는 DBMS의 경우, 반드시 지원해야 하는 기능

고립성은 상호 간의 트랜잭션을 독립적으로 만들어 준다. 하지만 2개 이상의 트랜잭션이 하나의 값에 접근하는 경우에 문제가 있을 수 있다. 2개의 트랜잭션이 모두 읽는 경우에는 문제가 발생하지 않지만, 1개의 트랜잭션은 쓰고 1개의 트랜잭션은 읽는 경우에 상황에 따라 오손 읽기, 반복불가능 읽기, 유령데이터 읽기 문제가 발생할 수 있으며, 2개의 트랜잭션이 모두 쓰기(Write) 시 무제어 병행 수행을 하는 경우에 갱신 손실, 모순성, 연쇄 복귀 등의 문제가 발생할 수 있습니다.

 

ex) 아이폰 별명을 지정할 수 있는 테이블이 있다. A사용자는 아이폰을 "A"라고 지정하고 동시에 B사용자는 "B"라고 지정했다. 두 작업이 동시에 일어난다면 무엇을 지정해야 할까? 이런 상황에서 오는 문제가 갱신분실, 오손판독, 팬텀문제 등이다.

 

 

갱신 손실 (Lost Update)

  • 하나의 트랜잭션이 갱신한 내용을 다른 트랜잭션이 덮어씀으로써 갱신이 무효화가 되는 것을 의미
  • 두 개의 트랜잭션이 한 개의 데이터를 동시에 갱신(Update)할 때 발생
  • 데이터베이스에서 절대 발생하면 안되는 현상

ex) 코로나 확진자 수를 저장한다고 가정한다. A관리자는 +300이라고 했고 B관리자는 +500이라고 했을때, 일반적으로 0에서 A의 300을 더하고 B의 500을 더하면 800이라고 생각할 것이다. 하지만 동시에 접근할 경우 A의 300이 더했지만 B는 300에서 500을 더하는 것이 아닌! 0에서 500을 더한다. 즉 결과값은 800이 되지 않고 500이 된다.  T1과 T2가 순차적으로 값을 저장하여 덮어씌워지는 값의 손실을 갱신손실이라 합니다. 

 

 

모순성(Inconsistency)

  • 다른 트랜잭션들이 해당 항목 값을 갱신하는 동안 한 트랜잭션이 두 개의 항목 값 중 어떤 것은 갱신되기 전의 값을 읽고 다른 것은 갱신된 후의 값을 읽게 되어 데이터의 불일치가 발생하는 상황

초기값 X=1500, Y=1000이 있고, 트랜잭션 T1은 X와 Y를 300 증가, 트랜잭션 T2는 X와 Y를 3배씩 증가시킨다고 합시다. 트랜잭션 T1이 수행될 때 X와 Y는 각각 1500과 1000이 읽혀야 합니다. T1이 수행되면서 X만을 1800으로 증가시키고 Write된 다음에 Y를 수행하는 것이 아닌 트랜잭션 T2가 수행된다고 합시다. 그러면 T2에 의해 X와 Y는 각각 5400과 3000이 되고 다시 T1의 Y가 Read를 해야하는 상황에서 1000이 아니라 3000이 읽히게 됩니다. 이렇게 어떤 값은 갱신 전의 값을, 다른 값은 갱신 후의 값을 읽어 데이터가 불일치하는 것을 모순성이라 합니다. 

 

 

 

연쇄 복귀(Cascading Rollback)

  • 두 트랜잭션이 동일한 데이터 내용을 접근할 때 발생
  • 한 트랜잭션이 데이터를 갱신한 다음 실패하여 Rollback 연산을 수행하는 과정에서 갱신과 Rollback 연산을 실행하고 있는 사이에 해당 데이터를 읽어서 사용할 때 발생할 수 있는 문제

초기값 X=1500, Y=1000과 X를 300 증가시키고 Y를 200 감소시키는 트랜잭션 T1과 X항목을 3배 증가시키는 트랜잭션 T2가 있다고 합시다. T1이 X를 300 증가시키고 Write 하여 1800이 된 상황에서 T2 트랜잭션이 실행되어 X를 3배하여 Write한 후 종료되었다고 가정합시다. 그리고 T1이 이제 Rollback 연산을 하여 X를 1500으로 다시 돌려놓으려고 하는데 T2는 이미 해당 트랜잭션을 완료하여 종료되었으므로 롤백할 수가 없게 되버리는 문제가 발생합니다. 

 

트랜잭션 스케줄(Transaction Schedule) 

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

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

 

 

직렬 가능 스케줄

  • 두 개의 트랜잭션이 Read 연산만을 수행할 것이라면, 상호 간섭이 발생되지 않으며 연산의 순서도 중요하지 않다.
  • 두 개의 트랜잭션이 같은 데이터 항목에 접근하지 않는다면 상호 간섭이 발생되지 않으며 연산의 순서도 중요하지 않다.
  • T1이 X에 Write연산을 하고 T2가 X에 Read 또는 Write 연산을 한다면 실행 순서는 중요하다.

 

 

락(Lock) 

과 트랜잭션이 고립성을 보장하는 방법에 대해 이해하기 위해서는 병행 트랜잭션에 대해 먼저 알아야 합니다.

https://victorydntmd.tistory.com/129 링크에서 고립성 보장 부분을 조금 읽어 보고 다시 넘어오세요!

 

  • 로킹(Locking)기법: 트랜잭션들이 동일한 데이터 항목에 대해 임의적인 병행 접근을 하지 못하도록 제어하는 것
  • 트랜잭션 T가 데이터 항목 X에 대해 Read(X) or Write(X)연산을 수행하려면 반드시 lock(X) 연산을 해주어야 함
  • 트랜잭션 T가 실행한 lock(X)에 대해서는 해당 트랜잭션이 종료되기 전에 반드시 unlock(x)연산을 해주어야 함
  • 트랜잭션 T는 다른 트랜잭션에 의해 이미 lock이 걸려 있는 X에 대해 다시 lock(X)를 수행시키지 못한다.
  • 트랜잭션 T가 X에 lock을 걸지 않았다면, unlock(X)를 수행시키지 못한다.

즉 여러 개의 트랜잭션들이 하나의 데이터로 동시에 접근하려고 할 때 이를 제어해주는 도구가 바로 Lock이다. 락은 트랜잭션이 읽기를 할 때 사용하는 공유락(LS, Shared Lock) 읽고 쓰기를 할 때 사용하는 배타락(LX, Exclusive Lock)으로 나뉩니다. 트랜잭션 T가 데이터 항목 X에 대하여 Shared-Lock을 설정할 경우, 트랜잭션 T는 해당 데이터 항목에 대해서 읽을 수 있지만 기록할 수 없습니다. 그리고 Read는 서로 영향을 주지 않으므로 다른 트랜잭션도 Shared-Lock이 설정된 X에 대해서 Shared-Lock을 동시에 설정할 수 있습니다. 트랜잭션 T가 데이터 항목 X에 대하여 Exclusive-Lock을 설정할 경우, 트랜잭션 T는 해당 데이터 항목에 대해서 읽을 수도 있고, 기록할 수도 있습니다. Write는 영향을 주는 작업이므로 다른 트랜잭션은 Exclusive-Lock을 설정한 데이터 항목 X에 대해서 어떠한 lock도 설정할 수 없습니다.

 

  • Shared Lock : 트랜잭션이 데이러를 읽을때, 여러 트랜잭션이 읽을 수 있도록 허용
  • Exclusive Lock : 데이터를 쓸때는 다른 트랜잭션이 읽을 수 없도록 금지

락은 Intention Lock도 있고 락이 적용되는 상황에 따라 Record Lock과 Gap Lock이 있다. 추가적인 내용을 알고 싶으면 

링크를 참조하도록 하자! https://www.letmecompile.com/mysql-innodb-lock-deadlock/ 

 

 

공유락과 베타락을 사용하는 규칙

  • 데이터에 락이 걸려있지 않으면 트랜잭션은 데이터에 락을 걸 수 있다.
  • 트랜잭션이 데이터 X를 읽기만 할 경우 LS(X)를 요청하고, 읽거나 쓸 경우 LX(X)를 요청한다.
  • 다른 트랜잭션이 데이터에 LS(X)를 걸어둔 경우, LS(X)의요청은 허용하고 LX(X)는 허용하지 않는다.
  • 다른 트랜잭션이 데이터에 LX(X)를 걸어둔 경우, LS(X)와 LX(X) 모두 허용하지 않는다.
  • 트랜잭션이 락을 허용받지 못하면 대기 상태가 된다.

 

2단계 락킹 (2PL Locking)

  • 로킹 단위: 로킹 기법에서 사용하는 lock 연산의 대상
  • 2단계 로킹 규약: 락을 걸고 해제하는 시점에 제한을 두지 않으면 두 개의 트랜잭션이 동시에 실행될 때 데이터의 일관성이 깨질 수 있어서 로킹 단계를 2개로 구분하여 이를 방지하는 방법
  • 확장 단계(Growing Phase): 트랜잭션은 새로운 lock 연산만 할 수 있고, unlock 연산은 할 수 없는 단계
  • 축소 단계(Shrinking Phase): 트랜잭션은 unlock 연산만 실행할 수 있고, lock 연산은 실행할 수 없는 단계

로킹단위가 속성->튜플->릴레이션->데이터베이스로 커질수록 구현이 용이하고 록의 수가 적어지며 제어가 간단하지만 병행성이 떨어지는 반면 로킹단위가 작을수록 구현이 복잡하고 로크의 수가 많고 제어 기법이 복잡하여도 병행성을 높일 수 있습니다. 2단계 로킹 규약(2PLP: Two-Phase Locking Protocol)은 트랜잭션들이 lock하는 시간과 unlock을 하는 시간을 구분하여 수행하도록 하는 것입니다. 2단계 로킹 규약을 사용하지 않으면 아래의 그림과 같이 일관성이 위배되는 문제가 발생할 수 있습니다. 그래서 임의의 시간에 lock 또는 unlock을 하는 것이 아니라 확장 단계와 축소 단계를 두어 이를 해결해줍니다. 2PLP는 직렬 가능성을 보장할 수 있는 규약으로 가장 많이 사용되지만 교착상태가 발생할 가능성이 있지만 교착상태(데드락, Deadlock)에 빠질 수 있으므로 이를 해결해주어야 합니다.

 

 

2PL 락킹에 대해 이해하기 어려워 다른 블로그를 참고하여 요약된 설명을 하도록 하겠습니다.

2PL 프로토콜이란 여러 트랜잭션이 공유하고 있는 데이터에 동시에 접근할 수 없도록 하기위한 목적을 가진 프로토콜이다. 성능을 위해 병행처리를 해야하는데, 트랜잭션의 고립성을 보장하기 위해서는 2PL을 사용해야 한다는 것이다.

 

locking에도 두 가지 방법이 있다.

  • 보수적 locking ( conservative locking )
    • 트랜잭션이 시작되면 모든 lock을 얻는 방식으로서, 데드락이 발생하지 않지만 병행성이 좋지 못함
  • 엄격한 locking ( strict locking )
    • 트랜잭션이 commit을 만날 때까지 lock을 갖고 있다가 commit을 만날때 unlock을 하는 방식으로 데드락이 발생하지만 병행성이 좋음
    • 일반적으로 병행성이 좋은 strict 방식을 사용

 

 

데드락(Deadlock) 

  • 데드락(Deadlock): 두 개 이상의 트랜잭션이 각각 자신의 데이터에 대하여 락을 획득하고 상대방 데이터에 대하여 락을 요청하면 무한 대기 상태에 빠질 수 있는 현상
  • 데드락은 교착상태라고도 한다.

데이터베이스의 데드락과 운영체제의 데드락은 상당히 비슷하다. 위의 정의를 풀어 설명하면 공통된 자원을 이용하기 위해 여러 개의 트랜잭션이 서로 lock을 걸어주다가 무한 대기 상태에 빠지는 것을 데드락이라 한다. 예를 들어 먼저 T1에서 A에 대해 락을 걸고 T2에서 B에 대해 락을 건다고 가정한다. 그리고 나서 T1에서 B에 대해 락을 걸고 T2가 A에 대해 락을 건다면 T1과 T2는 서로 A, B에 대한 락을 유지하며 무한루프에 빠지게 된다. 일반적으로 데드락이 발생하면 DBMS가 T1 혹은 T2 중 하나를 강제로 중지시켜 한 트랜잭션은 정상적으로 실행되며 중지된 트랜잭션에서 변경한 데이터는 원래 상태로 되돌려 놓는다.

 

 

데드락에 대해 조금 더 알아 보도록 하겠습니다. 아래 링크를 참조하여 정리하였습니다.

https://www.letmecompile.com/mysql-innodb-lock-deadlock/

  • 트랜잭션을 지원하는 데이터베이스에서 자주 발생
  • 멀티 스레드 어플리케이션에서 발생하는 데드락은 어플리케이션을 완전히 멈추게 한다.
  • 일반적인 DBMS에서는 데드락 탐지 기능을 제공하며 데드락이 발견되면 자동으로 해소
  • DBMS의 데드락 해소 과정에서 작업중이던 트랜잭션들 중 일부가 취소되는 경우 어플리케이션에서 해당 트랜잭션을 재실행 하여 작업을 완수할 수 있도록 구성해야한다.

데드락을 줄일 수 있는 방법을 알고 싶다면 링크를 눌려 글을 읽어 보도록 하자!

 

 

트랜잭션 고립 수준 (Isolation level)

오손읽기(Dirty Read) 

  • 읽기 작업을 하는 트랜잭션 1이 쓰기 작업을 하는 트랜잭션2가 작업한 중간 데이터를 읽기 때문에 발생하는 문제
  • 작업중인 트랜잭션 2가 작업을 Rollback한 경우 트랜잭션 1은 무효가 된 데이터를 읽게 되고 잘못된 결과를 도출한다.

아래의 그림과 같이 T1이 T2가 Rollback되기 전의 데이터를 읽었고, T2가 Rollback이 되면 T1이 의미가 없는 값을 갖게 되므로 문제가 발생합니다. 그리고 이러한 무효가 된 데이터를 읽게되어 발생하는 문제를 오손읽기(Dirty Read)라고 합니다.

 

 

 

반복불가능 읽기(Non-repeatable Read)

  • 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(Update) 르랜잭션 1이 다시 한번 데이터를 읽을 때 생기는 문제
  • 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전의 결과와 다른 결과가 나오는 현상

아래의 그림과 같이 T1이 먼저 값을 읽었고 T2가 값을 갱신(Update)하였다고 합시다. 그리고 T1이 다시 값을 읽으려고 하면 바로 전에 읽은 값이 달라지는데 이를 반복불가능 읽기라고 합니다. 

 

 

 

 

유령데이터 읽기(Phantom Read)

  • 트랜잭션 1이 데이터를 읽고 트랜잭션 2가 데이터를 쓰고(Insert) 트랜잭션 1이 다시 한번 데이터를 읽을 때 생기는 문제
  • 트랜잭션 1이 읽기 작업을 다시 한 번 반복할 경우 이전에 없던 데이터(유령 데이터)가 나타나는 현상

아래의 그림과 같이 T1이 먼저 값을 읽었고, T2가 값을 삽입(Insert)하였다고 합시다. 그리고 T1이 다시 값을 읽으려고 하면 바로 전에는 없었던 값이 읽히게 되는데 이를 유령데이터 읽기라고 합니다.

 

 

 

 

트랜잭션 고립 수준 명령어(Transaction Isolation Level Instruction)

  • DBMS는 트랜잭션을 동시에 실행시키면서 락보다 좀 더 완화된 방법으로 문제를 해결하기 위해 제공하는 명령어

MySQL DB는 일반적인 운영환경에서 뛰어난 성능을 제공합니다. 특히 적은 양의 자료가 빈번하게 교류되는 환경에서는 더욱 빛을 발하죠. 국내에서는 주로 작은 규모의 웹사이트를 구축할 때 MySQL을 사용합니다. 그런데 문제는 사이트의 규모가 커지면서부터 생긴다는 것이죠. 조금씩 느려지는 Query가 생기면 원인도 파악하고, Query를 튜닝하고, 설계도 변경하지만 MySQL의 특징적인 문제를 곧 만나게 됩니다.

 

테이블을 복제(CREATE SELECT)하거나 다른 테이블로 옮기면(INSERT SELECT) 작업을 하는 동안 SELECT 절에 있는 테이블들이 Lock이 걸립니다. 게다가 다른 Session에서 해당 테이블을 수정(UPDATE / DELETE)하면 복제와 이동을 마칠 때까지 대기 상태로 있어야 한다는 것입니다. 이러한 문제는 시스템을 구축하고 자료가 일정량 쌓이기 전까지는 알 수 없습니다. 또한 Oracle과 같은 DB를 사용하던 사용자가, MySQL을 사용하면 이와 같은 문제가 있을 것이라고 생각하기도 어렵습니다.

 

트랜잭션이 작업을 수행하다 보면 위의 오손 읽기, 반복불가능 읽기, 유령데이터 읽기와 같은 문제를 직면할 수 있습니다. 그래서 Lock보다는 완화된 방법으로 트랜잭션을 동시에 실행시키면서, 발생하는 문제를 해결하기 위해 DBMS가 제공하는 명령어가 바로 트랜잭션 고립 수준 명령어(Transaction Isolation Level Instruction)입니다. 여기에는 고립 수준을 나타내는 READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE과 같은 명령어들이 있습니다.

 

 

[ READ UNCOMMITTED ]

  • 고립 수준이 Level 0으로 가장 낮은 명령어로, 자신의 데이터에 아무런 공유락을 걸지 않는다.

READ UNCOMMITTED는 자신의 데이터에 아무런 공유락도 걸지 않지만 배타락은 데이터의 갱신손실 문제 때문에 걸어주어야 합니다. 또한 다른 트랜잭션에 공유락과 배타락이 걸린 데이터를 대기하지 않고 읽습니다. SELECT 문을 수행하는 경우 해당 데이터에 Shared Lock이 걸리지 않는 Level입니다. 따라서, 어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안 다른 사용자는 B라는 아직 완료되지 않은 데이터(오손 데이터) B를 읽을 수 있습니다.

 

 

[ READ COMMITTED ]

  • 고립 수준이 Level 1인 명령어로, 오손 페이지의 참조를 피하기 위해 자신의 데이터를 읽는 동안 공유락을 걸지만 트랜잭션이 끝나기 전에라도 해지 가능하다.

다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행됩니다. SQL Server가 Default로 사용하는 Isolation Level으로 SELECT 문이 수행되는 동안에 Shared Lock이 걸리게됩니다. 그러므로 어떤 사용자가 A라는 데이터를 B라는 데이터로 변경하는 동안에 다른 사용자는 해당 데이터에 접근할 수 없습니다. 

 

 

[ REPEATABLE READ ]

  • 고립 수준이 Level 2인 명령어로, 자신의 데이터에 설정된 공유락과 배타락을 트랜잭션이 종료될 때까지 유지하여 다른 트랜잭션이 자신의 데이터를 갱신(Update)할 수 없도록 한다.

다른 트랜잭션 데이터는 락 호환성 규칙에 따라 진행됩니다. 다른 고립화 수준에 비해 데이터의 동시성(Concurrency)이 낮아 특별하지 않은 상황이라면 사용하지 않는 것이 좋습니다. 즉, 트랜잭션이 완료될 때까지 SELECT문이 사용하는 모든 데이터에 Shared Lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정이 불가능합니다. 예를 들어 SELECT number FROM A WHERE number BETWEEN 1 and 10을 수행하였고, 이 범위에 해당하는 number가 2 or 3이 있는 경우 다른 사용자가 number가 2 or 3인 행에 대한 UPDATE가 불가능하지만 나머지 범위에 대해서 행을 INSERT하는 것이 가능합니다. 

 

 

[ SERIALIZABLE ]

  • 고립 수준이 Level 3으로 가장 높은 명령어로, 실행 중인 트랜잭션은 다른 트랜잭션으로부터 완벽하게 분리된다.

데이터 집합에 범위를 지어 잠금을 설정할 수 있기 때문에 다른 사용자가 데이터를 변경(UPDATE) 또는 삽입(Insert)하려고 할 때 트랜잭션을 완벽하게 분리할 수 있습니다. 이 명령어는 가장 제한이 심하고 동시성도 낮습니다. 즉, SELECT 문이 사용하는 모든 데이터에 Shared Lock이 걸리므로 다른 사용자는 그 영역에 해당되는 데이터에 대한 수정(UPDATE) 및 입력(INSERT)가 불가능합니다. 앞의 Repeatable Read의 경우에는 1에서 10사이의 number에 대한 삽입이 가능하였지만 SERIALIZABLE은 SELECT의 대상이 되는 모든 테이블에 Shared Lock을 설정하는 것과 같아서 나머지 범위에 대한 INSERT가 불가능합니다. 

 

 

 

 

회복(Recovery)

[ 장애의 유형 ]

  • 트랜잭션 장애: 트랜잭션의 실행 시 논리적인 오류로 발생할 수 있는 에러 상황
  • 시스템 장애: H/W 시스템 자체에서 발생할 수 있는 에러 상황
  • 미디어 장애: 디스크 자체의 손상으로 발생할 수 있는 에러 상황

트랜잭션 실행 시 발생할 수 있는 에러 상황의 원인으로는 트랜잭션 내에 잘못된 데이터 입력, 데이터의 부재, 오버플로우(Overflow), 자원의 한계 초과 요청, 어떤 수를 0으로 나누게 되는 연산 등이 있습니다. 시스템 장애는 하드웨어 자체에서 발생할 수 있는 에러로 하드웨어의 잘못된 작동으로 메인 메모리에 저장되어 있는 정보가 손실되거나 교착 상태의 발생으로 더 이상 트랜잭션 작업이 수행될 수 없는 상황에서 발생합니다. 마지막으로 미디어 장애는 디스크의 손상으로 발생할 수 있는 에러로 디스크 헤드 손상이나 고장으로 인해 저장장치 내의 정보가 일부 또는 전부 손상될 수 있는 상태입니다.

 

 

 

[ 회복(Recovery) ]

  • 데이터베이스를 장애가 발생했던 이전의 상태로 복구시켜서 일관된 데이터베이스 상태를 만드는 것

데이터베이스를 갱신하는 과정에서 장애가 발생한 경우 회복절차를 수행하여 장애 발생 이전의 데이터베이스로 만드는 것을 회복이라고 합니다. 회복을 위한 데이터 복사본을 만드는 방법에는 덤프(Dump)를 이용하는 방법과 로그(Log)를 이용하는 방법 2가지가 있습니다. 덤프는 가장 기본적인 기법으로 일정 주기로 원본의 데이터베이스의 모든 내용을 다른 저장장치에 복사하는 것입니다. 로그는 변경 이전의 데이터베이스를 기준으로 변경 연산이 발생할 때 마다 로그 파일을 작성하여 기록하고, 회복할 때 로그에 적힌 내용을 사용하여 복원하는 방법입니다.

 

 

[ 로그파일(Log File) ]

  • 트랜잭션이 반영한 모든 데이터의 변경사항을 데이터베이스에 기록하기 전에 미리 기록해두는 별도의 데이터베이스
  • 안전한 하드디스크에 저장되며 전원과 관계없이 기록이 존재
  • 로그의 구조: <트랜잭션 번호, 로그의 타입, 데이터 항목 이름, 수정 전 값, 수정 후 값>
  • 로그의 타입: START, INSERT, UPDATE, DELETE, ABORT, COMMIT 등 트랜잭션의 연산 타입

로그(Log)란 트랜잭션이 데이터의 변경사항을 데이터베이스에 직접 기록하기 전에 미리 기록해두는 별도의 데이터베이스로 특정한 구조를 가지고 기록이 되며 장애 발생 시 복원을 위해서 사용됩니다. 실제로 아래와 같은 형식으로 로그가 기록됩니다. 또한 트랜잭션이 기록되는 정보들은 아래의 그림에서 참고할 수 있습니다.

<T1, START>

<T1, UPDATE, Customer(박지성).balance, 10000, 9000>

<T1, UPDATE, Customer(김연아).balance, 10000, 11000>

<T1, COMMIT>

 

[ 로그 파일을 이용한 회복 ]

  • 데이터의 변경이 발생할 때 마다 생성되는 로그 파일을 이용하는 것
  • 데이터의 변경 기록을 저장해 둔 로그 파일을 이용하면 시스템 장애도 복구 가능

DBMS는 트랜잭션이 종료되었는지 혹은 중단되었는지 여부를 판단하여 종료된 경우에는 종료를 확정하기 위하여 REDO(재실행)을 하고 중단된 경우에는 없던 일로 되돌리기 위해 UNDO(취소)를 진행합니다. REDO는 장애가 발생한 후 시스템을 다시 가동을 했을 때, 로그 파일에 트랜잭션의 시작(START)이 있고 종료(COMMIT)이 있는 경우 로그를 보면서 트랜잭션이 변경한 내용을 다시 기록하는 과정입니다. UNDO는 장애가 발생한 후 시스템을 재가동했을때, 로그 파일에 트랜잭션의 시작(START)만 있고 종료(COMMIT)이 없는 경우 완료하지 못했지만 버퍼의 변경 내용이 데이터베이스에 기록되어 있을 가능성이 있기 때문에 로그를 보면서 트랜잭션이 변경한 내용을 원상복구시키는 과정입니다. REDO의 경우에는 T1에 의해 변경된 모든 데이터 항목들을 로그 파일에 있는 새로운 값(New Value)으로 대체시켜야 하고 이를 T1의 첫 번째 로그 레코드 부터 진행합니다. 하지만 UNDO의 경우에는 T1에 의해 변경된 모든 데이터 항목들을 로그 파일에 있는 예전 값(Old Value)로 대체하여야 하고 장애가 발생한 마지막 로그 레코드부터 거꾸로 진행합니다.

 

 

 

트랜잭션이 시작하면 변경연산에 대해서 계속 로그 파일에만 기록을 하고 실제 데이터베이스에는 반영을 하지 않습니다. 그러다가 부분 완료까지 성공을 하면 로그 파일을 참조하여 실제 데이터베이스의 값을 변경시킵니다. 트랜잭션이 실패한 경우에는 연산이 로그파일에만 저장이 되어있고 데이터베이스에는 반영되어있지 않으므로 추가 작업이 필요 없지만 중간에 부분 완료를 거친 후에 트랜잭션 실패가 발생한다면, 데이터베이스에 일부 기록된 내용이 있을 수 있으므로 이러한 경우에는 UNDO를 해주어야 합니다. 아래의 그림에서 왼쪽은 트랜잭션이 성공한 경우이며 오른쪽은 트랜잭션이 실패한 경우에 해당합니다.

 

 

[ 로그 파일의 회복 방법 ]

  • 즉시 갱신(Immediate Update): 갱신 데이터->로그, 버퍼->데이터베이스 작업이 부분완료 전에 동시에 진행될 수 있으며, 부분 완료가 되면 갱신 데이터는 로그에 기록이 끝난 상태
  • 지연 갱신(Deferred Update): 갱신 데이터->로그가 끝난 후 부분 완료를 하고 버퍼->데이터베이스 작업이 진행되는 방법

즉시 갱신은 갱신된 데이터를 로그에 기록하는 작업과 버퍼의 데이터를 데이터베이스에 옮기는 작업이 동시에 진행수 있으며 부분완료가 된 경우는 로그에 기록이 끝난 상태인 반면에 지연 갱신은 갱신된 데이터를 로그에 작성하는 작업이 끝난 후에야 버퍼의 데이터를 데이터베이스로 옮기는 작업이 진행될 수 있습니다.

 

[ 체크포인트(CheckPoint, 검사점) ]

  • 로그는 그대로 기록을 유지하면서, 회복 관리자가 정하는 일정한 시간 간격으로 검사 시점을 생성하는 것
  • 회복 시 많은  양의 로그를 검색하고 갱신하는 시간을 줄이기 위함
  • 체크포인트가 있으면 로그를 이용한 회복 기법은 좀 더 간단해짐

DBMS에서 회복을 할 때 처음부터 마지막 로그 기록까지 한번에 처리하려면 시간적으로 오래 걸릴 수 밖에 없습니다. 그러므로 특정 시간 마다 검사를 하여 문제가 없음을 확인하면 다음번 에러 발생 시 회복을 시작하는 시점을 앞으로 당길 수 있습니다. 그래서 체크 포인트 시점에는 다음과 같은 작업을 수행하게 됩니다. 먼저 주기억장치의 로그 레코드를 모두 하드디스크의 로그 파일에 저장합니다. 그리고 트랜잭션 수행 중에 변경된 버퍼 내의 내용을 하드디스크의 데이터베이스에 저장합니다. 그리고 나서 체크포인트를 로그 파일에 다음과 같이 표시합니다. <Checkpoint T_List>: T_list는 현재 수행 중인 트랜잭션의 리스트입니다.

 

  • 체크포인트 이전에 [Commit] 기록이 있는 경우: 아무 작업이 필요 없다.
  • 체크포인트 이후에 [Commit] 기록이 있는 경우: REDO(T)를 진행한다.
  • 체크포인트 이후에 [Commit] 기록이 없는 경우: 즉시 갱신 방법 사용시 UNDO(T) 진행

체크포인트 이전에 Commit이 있는 경우는 로그에 체크포인트가 나타나는 시점은 이미 변경 내용이 데이터베이스에 모두 기록된 후이기 때문에 아무런 작업도 필요하지 않습니다. 체크포인트 이후에 Commit 기록이 있는 경우는 체크포인트 이후에 변경 내용이 데이터베이스에 반영되지 않았으므로 REDO를 진행합니다. 체크포인트 이후에 Commit 기록이 없고 즉시 갱신 방법을 사용한 경우는 갱신 데이터를 로그에 작성하는 과정과 버퍼의 내용을 데이터베이스에 기록하는 작업이 동시에 이루어지므로 버퍼의 내용이 데이터베이스에 반영됐을 수도 있기 때문에 원상복구 시켜야하므로 UNDO를 해야합니다. 하지만 체크포인트 이후에 Commit 기록이 없고 지연 갱신 방법을 사용한 경우는 갱신 데이터를 로그에 작성한 후 Commit을 시작해야 버퍼의 내용을 데이터베이스에 기록하는 작업이 이루어지므로 아무 작업도 해줄 필요가 없습니다. 

 

 

 

 

m/24 



출처: https://mangkyu.tistory.com/30?category=761304 [MangKyu's Diary]

 

 

 

 

 

 

 

 

 

 

 

Reference

https://medium.com/prnd/%ED%97%A4%EC%9D%B4%EB%94%9C%EB%9F%AC-%EA%B0%9C%EB%B0%9C%ED%8C%80-%EB%AA%A8%EB%91%90%EA%B0%80-%ED%96%89%EB%B3%B5%ED%95%9C-%EA%B0%9C%EB%B0%9C-pr%EA%B4%80%EB%A6%AC-%EB%B0%A9%EB%B2%95-7%EA%B0%80%EC%A7%80-1d4cd5d091f0 (헤이딜러 개발 블로그 / PR작업 7가지 팁)

https://blog.ploeh.dk/2015/01/15/10-tips-for-better-pull-requests/ (Agile Pull Request)

https://blog.ploeh.dk/2021/06/21/agile-pull-requests/#7c5640fbc0a8418799e4b7a6266a01b2 (PR작업 10가지 팁)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함