DataBase의 데이터 영속성을 유지하기 위해 사용되는 Lock 종류를 알아보고자 합니다.
거대한 DataBase 시스템은 여러 곳에서 동시에 접근할 수 밖에 없는 구조로 되어 있습니다. 동시에 접근하는 경우 필연적으로 데이터가 오염 될 가능성이 있습니다. DataBase는 데이터의 일관성과 무결성을 유지하기 위해 Lock를 사용하게 됩니다. Lock를 사용함으로써 여러 유저가 동시에 접근하더라도 1명씩 요청을 처리되도록 합니다.
Lock은 트랜잭션 처리의 순차성을 보장해주는 기능을 제공합니다. 트랜잭션은 DB가 처리하는 가장 작은 단위의 처리 단위입니다. Lock은 하나의 트랜잭션이 완벽하게 끝날 때까지 다른 요청을 막아줍니다.
Lock의 종류는 Shared Lock, Exclusive Lock이 있습니다.
Read Lock라고도 하는 공유락은 데이터를 읽을 때 사용하는 Lock입니다. Read Lock은 같은 Read Lock 끼리는 동시에 접근이 가능합니다. Database의 주요 기능인 데이터 일관성과 무결성을 해치지 않기 때문입니다. 사용자가 데이터를 읽어 갈 뿐, 데이터 변경이 없기 때문에 가능합니다.
대신 그 다음에 나올 Exclusive Lock의 접근을 막습니다.
Write Lock이라고도 하는 베타락은 데이터를 변경할 때 사용하는 Lock입니다. 트랜잭션이 완료될 때까지 유지됩니다. Exclusive Lock이 끝나기 전까지 어떠한 접근도 허용하지 않습니다. 이 Lock은 다른 트랜잭션이 수행되고 있는 데이터에 대해서 접근하여 Lock을 걸 수 없습니다.
데이터베이스 - 전체 데이터베이스를 기준으로 Lock이 걸립니다. 1개의 세션이 하나의 데이터베이스의 데이터에 접근할 수 있습니다. DB 전체에 영향이 있는 DB 업데이트와 같은 작업에서만 사용합니다.
파일 - 데이터베이스 파일을 기준으로 Lock이 걸립니다. 데이터베이스에서 파일이란, 테이블 등과 같이 실제 데이터가 쓰여지는 물리적인 저장소를 뜻합니다. 파일 전체를 백업할 때 사용합니다.
테이블 - 테이블 기준으로 Lock이 걸립니다. 전체 테이블의 대한 데이터 변경이 있을 경우 사용합니다. 테이블을 제어하는 DDL 구문을 사용할 때 Lock이 걸린다고 DDL Lock이라고도 합니다.
페이지와 블럭 - 파일을 구성하는 페이지와 블록을 기준으로 Lock이 걸립니다.
컬럼(Column) - 컬럼 기준으로 Lock이 걸립니다. 다만 Lock 설정 및 해제 시 리소스가 많이 듭니다. 그래서 잘 사용하지 않습니다.
행(Row) - 행 수준의 Lock을 겁니다. 가장 많이 사용되는 Lock 입니다.
Blocking은 Lock간의 결합이라고 보시면 됩니다. 즉, 특정 트랜잭션 끝나지 않아 Lock이 걸린 상태로 멈춰있는 상태를 의미합니다. Exclusive - Exclusive나 Shared - Exclusive 끼리 Blocking이 발생할 수 있습니다. 이를 해결하기 위해서는 Transaction commit 또는 rollback를 사용해야 합니다.
1. SQL 문장이 복잡하면 리펙토링을 통해 빠르게 실행되도록 합시다.
2. 트랜잭션 처리 시간이 짧으면 경합을 줄일 수 있습니다. 즉, 길다면 쪼개줍시다.
3. 동일 데이터를 동시에 변경하는 작업을 배제합니다. 트랜잭션이 많을 시간에는 대용량 갱신 작업을 자제해야 합니다. (배치 대용량 처리 FOR DBMS 여러차례 호출하는 것 지양할 것)
4. 대용량 작업은 2번에서 말한 것 처럼 쪼개거나 lock_timeout 설정을 통해 Lock 최대 시간을 지정해줍니다.
Dead Lock은 Blocking 보다 심각한 교착상태입니다. 두 트랜잭션이 각각 Lock을 설정하고, 서로의 Lock에 접근하여 값을 얻어오려고 할 때, 서로의 Lock으로 인해 양쪽 트랜잭션이 영원히 처리되지 않는 상태를 말합니다. 상대방 Lock이 끝나야 원하는 데이터를 가져오는데 바라보고 있는 서로의 Lock이 같은 상태가 되다보니 영원히 끝나지 않는 상황이 발생하게 됩니다.
그렇다면 이러한 교착 상태를 방지하기 위해서는 어떻게 해야할까?
Oracle의 경우, Dead Lock을 감지하면 한쪽 Transaction을 풀어버린다. TRANSACTION A의 마지막 UPDATE 내용에 오류가 발생되고 COMMIT을 먼저 하도록 유도한다. TRANSACTION B는 아직 WAITING 상태로 남아있고, TRANSACTION A의 COMMIT을 기다리게 된다.
잘읽고 갑니다. 정리를 잘하셨네요 !
코딩하는 은행원과 비슷한 IT 알려주는 은행원이란 블로그도 있더라구요 !?