[db]01.lock

8382 단어 dbdb

DB에 대해 지식이 매우 부족한 사람이 모르는 키워드에 대해 검색하고 그저 번역하고 개인적인 생각을 써 놓은 글입니다

Users,Sessions, Transaction Control (거의 Transaction과 lock관련내용)

Transaction

  • [하나의 논리적 기능] 을 수행하는 [연산들의 모임] 이다.

ACID원칙

자주나오는게 은행 입출금 예시... A 계좌를 출금계좌, B계좌를 입금계좌라고하면 -> A에서 출금이 있어났다 == B에서 입금이 일어났다.

  • 즉, 입금과 출금이 [ 모두 발생] 하던지 [ 일체 일어나지 않아야 ] 한다 --> Atomicity(원자성)
  • 이체의 실행은, DB의 일관성을 보존해야한다 : A의 잔고 + B의 잔고를 합한 값이 (입출금행위 이전과 동일 ) --> Consistency(일관성)
  • DB system은 반드시, 한 트랜잭션이 [ ✋동시에 수행되는 다른 트랜잭션에 의한 변경에 영향을 받지 않도록 ] 하는 방법을 제공해야 한다-> Isolation(독립성)
    • 여러 트랜잭션이 동시 수행되는 DB system에서, 만약 [ transaction들 간 공유되는 데이터에 대한 갱신 ] 을 제어하지 못할 경우 --> [ 다른 트랜잭션에 의해 "변경 중인!" 불완전한 상태의 데이터를! 액세스하는 문제 ] 발생 가능하다.
    • (즉, A계좌에서 출금이 되어, 줄어든 금액 상태이고, B에는 아직 입금이 되지 않은 상태를 다른 transaction에서 read해서는 안 된다 )
  • 예금 이체 성공 후, A잔고와 B잔고의 새로운 값이 유지되어야 한다. 즉, 시스템에 오류가 발생하더라도, 이미 성공적으로 완료된 트랜잭션의 결과는 계속 유지되어야 한다. -> Durability(영속성)

Lock

  • 트랜잭션은 database에서 [전체가 하나로 ] processing되는 [ 일의 단위 ] 이다.

    • Database session은, 하나 이상의 트랜잭션으로 이루어져 있다.
  • app에서 [ 한 명 이상의 사용자가 같은 시간에 db와 interact ]를 하려고 하는 경우 : 그들의 transaction이 concurrently하게 running하는 것. ( 동시성 상황)

  • Concurrent transactions는 두 가지 방법 중 하나로 run하게 된다.

    • serially 하게 run : 하나의 transaction이 자신의 work를 모두 끝내고 나서야 두 번째 transaction이 시작되는 것.
    • interleaved하게 run : (OS의 스케줄링 생각) 서로 다른 transaction들의 action이 번갈아가며 이뤄지는 것.
  • 여느 동시성 상황처럼 이러한 문제가 생기게 된다.

    동시에 두 고객으로부터 같은 양의 책을 주문하는 전화가 걸려옴.

    첫 번째 고객을 응대하는 첫 번째 직원은, 그 주문양을 보고 , 서점의 db에 쿼리하여 , 아직 팔리지 않았다는 말을 해 준다.

    두 번째 고객을 응대하는 두 번째 직원은, 그 주문양을 보고, 서점의 db에 쿼리한 후 , 아직 팔리지 않았다는 말을 해 준다.

    두 번째 직원의 쿼리 이후, 첫 번째 고객이 그 책을 사기로 하여 , 첫 번째 직원이 db에 update 쿼리를 날린다. → 그 책이 다 팔린 것으로 update된다.

    조금 후에, 두 번째 고객 역시 그 책을 사기로 하면, 두 번째 직원과 두 번째 고객 모두 아직 DB에는 그 책이 남아있는 것으로 아는 상태였기에 → DB에 update 쿼리를 날린다

    • 즉, 두 번째 직원의 update는 [ old data ] 에 기반한 update를 하게 되는 것
  • 해결법 또한, 여느 동시성 상황같은 해결법이 제시된다.. 시스템 프로그래밍 및 OS 를 공부했다면 DB도 같구나... 라는 생각이 들게 된다.

  • 이런 상황에서 common solution은 [ locking ] 을 사용하는 것 : 마치 critical section 에 먼저 접근한 thread( or process)가 critical section에 대한 control을 획득 하던 것 처럼.

    먼저 db element에 접근한 transaction이 그 DB element에 대한 control을 획득하고, 다른 transaction이 [ same data에 대한 updating이나 viewing 하는 것을 ] 방지시키는 것.

    • 즉, data를 modify시키는 transaction은 보통 [ 독점적인(exclusive) lock ] 을 획득하여,이런식으로 이미 locks이 쓰이고 있는 동안에는, 다른 transaction이 data를 수정하거나 참조하는 것 모두를 못하게 한다.

    • 자 그럼, 이 locking이 위의 [ 책 구매 문제 ] 를 어떻게 해결하는지 보자
      - 이번에는, 첫 번째 직원이 "구매 양에 대한 data"를 받았을 때, [ transaction이 그 책에 대한 data의 lock을 획득 ] 한다. =⇒ 두 번째 직원이 그 데이터에 access하는 것을 막는다.
      - 두 번째 직원의 transaction은 DBMS에 의해, [wait state ] 에 놓여진다.
      - [ lock을 갖고 있는(holding중인) transaction이 일을 마치고, lock을 release ] 하는 순간, 두 번째 직원의 transaction이 일을 처리(proceed)할 수 있게 된다. : 이 번에는, 이미 품절이라는 data를 보게 된다.

      ( 두 번째 고객이 책을 살 수 없게 된 것은 안타깝지만, 살 수 있을 줄 알았는데 못 사는 것 보단 행복하다는 결과라고 한다 )

  • locking이 효율적이기 위해서, 하나의 transaction은 [ 그 transaction 전체 기간 동안 ][ 그 모든 locks들을 hold하고 있어야 ] 한다.

  • transaction이 끝나는 시기는, 그 모든 locks들을 release하는 시간 → 그 transaction에 의해 잡혀 있던 데이터들이 다른 transaction에 의해 사용가능해 지는 시간.

  • 앞의 lock은 [ exclusive lock(독점적인 락)] 으로, db의 일부분이 updating뿐만 아니라 viewing 조차도 prevent되었다.

  • DBMS 중에는 [exclusive lock ] 뿐만 아니라 [ shared,read locks] 도 존재함.

    • 다수의 transaction이 [ 그 db의 part ]를 view 하는 것은 허용되지만, modify하는 것은 허용 하지 않는 것 .
    • DBMS는 이런 [ shared lock ] 을 가능하다면 [ exclusive lock ] 대신에 사용함. 왜냐하면, shared lock이 좀 더 [ db resources에 대한 concurrent use ]를 가능하게 하기 때문.
    • Two - phase locking :
      • 개념: 많은 상황에서, 한 transaction이 data를 획득하면 , DBMS는 [ 그 데이터에게 " shared lock" ] 을 줄 것이다. 그런데, 그 transaction이 [ data modification command ]를 issue한다면!! —> DBMS는 [ 그 lock을 exclusive lock 으로 upgrade ] 해 줄 것이다.
      • 이러한 two-phase locking은 [ exclusive lock 이 가능한 적은 시간동안만 held 되도록] 해 주기 때문에, 동시 사용의 효율을 더 높여주게 된다. ( exclusive lock은 viewing하는 것 조차 막아, conccurent use가 아예 불가능하니까.. lock이 exclusive lock 상태로 held되어있으면 효율이 안좋아 지겠지. 따라서 exclusive lock 상태로 held되어있는 것을 최대한 줄여 주기 위함인것)
  • [ lock이 걸리는 DB element의 크기](즉, [ lock의 granularity]) 는, DBMS마다 다르고, 현재 transaction에서 하려는 action마다 다르다. 이는 [ disk의 전체 page ] 만 할 수도 있고, [ 전체 table ] 만할 수도 , [ 한 table의 하나의 row] 만 할 수도 있다.

    • 1️⃣granularity가 작으면 작을 수록=⇒ lock을 걸 pieces들이 많아지고 =⇒ db가 지원할 수 있는 conccurent use가 더 많아진다.

      ( code에서도 critical section의 크기를 최대한 작게 유지하는게 좋다고 하는 것 처럼)

    • 💥 하지만, DBMS는 [ locks를 유지하기 위한 비용 (시간) ]을 들여야만 함 + DBMS는 [ lock을 waiting하고 있는 transaction들을 추적하고 있어야 한다 ]

      ( OS에서는, task(process, thread)의 state 별로 큐를 두어서, 각 task들의 상태를 추적하고 있었던 것처럼)

    • 2️⃣ 따라서 [ lock의 granularity가 작고, lock의 개수가 많을 수록 ], DBMS가 [ data manipulation에 들이는 시간보다, locks을 처리하는데 시간이 많이 들어가게 된다. ] ( 무조건 뭐보다 더 많이 들어간다 라기보다는, DBMS는 data manipulation에 시간을 들여야 하는데, locks를 처리하는데 시간이 많이 들어가게 되어버린다는거지)

Transaction의 isolation level

(myddy the waters : 상황을 더 복잡하게 만드는.. 이해할 수 없게 만드는 것을 말함.. 숙어를 배워가자 )

  • 처음에는, concurrency control이 매우 직관적인 것 처럼 보일 거임.

  • 하지만, SQL 표준에서는, 상황을 좀 더 복잡하게 만들어 놓았다!! → 이런것을 허용해 놓음 : 다른 [ 💥uncommitted💥 transaction에 의해 data가 modified ]되었더러라도 , 어떤 transaction이 그 data를 read할 수 있도록 명시하는 것을 허용해 놓음.

  • isolation level : 어떤 transaction이 [ 그런 데이터에 대해 가질 수 있는 access의 정도(degree) ]

  • 4가지 isolation level이 존재한다.

    • SERIALIZABLE (default) : SERIALIZABLE transaction 은 [ 다른 transaction으로부터 fully isolated ]되어있다. 앞에서 말했던 것 처럼 행동함.

      ( default로는 shared lock을 사용하다가 update같은 modification command를 issue하려고 하면, exclusive lock으로 변환하여 , 다른 transaction은 read조차도 못 하게 되는 것을 말하는 듯 )

    • REPEATABLE READ : REPEATABLE READ transaction은 WHERE 절을 만족하는 row를 retrieving하면서, 같은 data를 한 번 이상 read 할 수 있다. 만약 다른 transaction이 rows를 update하거나 insert 하였고, 이것이 [ 이 transaction의 첫 번째 read 이후의 반복되는 read 들 사이에 commit ] 되었다면,

      첫 번째 read 결과와 그 뒤의 read 결과가 다르게 나올 수가 있겠다.

      • transaction 의 특징에 따라 이런 현상이 바람직할 수도 있지..
      • 이거를 phantom read라고 함..
    • READ COMMITTED : READ COMMITTED transaction 또한, 같은 data를 한 번 이상 read 할 수 있다. 하지만 ! 이 경우에는, 그 read는 [ 같은 rows를 반환!] . 만약, 첫 번째 , 두 번째 read 사이에 다른 transaction에 의한 update가 commit되었다면, 두 번째 read는 원래 다른 값을 줄 수도 있음. 이 역시 transaction의 특징에 따라 .. 이런 결과를 원할 수도 있지..
      • nonrepeatable read 현상이라고 알려짐. 그런 transactions들은 phantom reads도 허용함.
    • READ UNCOMMITTED : READ UNCOMMITTED transaction은 같은 데이터를 한 번 이상 read하면서, [다른 uncommitted transactions에 의한, data에 대한 updates를] read 한다.
      • 여기가 딱 봐도 위험해 보인다. [ uncommitted transaction ]은 rolled back될 수가 있음..
      • 만약 이렇게 될 경우, 이것을 [ dirty read ] 라고 한다 .

        dirty read : transaction 작업이 완료(되어 commit되거나 롤백되거나) 하지도 않았는데, 다른 transaction에서 볼 수 있게 되는 것.

      • 이런 transactions들은 [ nonrepeatable reads와 phantom reads] 를 허용한다.
  • 말했듯이, default isolation level은 SERIALIZABLE임. 더 낮은 level로 설정하려면

    SET TRANSACTION ISOLATION LEVEL isolation_level
    
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; 이런식으로 

개인적으로 conccurency상황에 대해 생각할 때 주의할 것

  • 예를들어 10000명의 사용자가 나의 app을 사용한다고, 💥동시에 사용하는 사용자가 10000명인 것은 아니라는 것💥을 항상 생각한다.
  • 따라서 예를들어, 동시성 상황에 대비하는 시나리오를 작성하고 그에 맞는 connection pool등을 구성할 때도 이에 알맞은 것으로 구성해야 할 것 이다.

좋은 웹페이지 즐겨찾기