컴퓨터 과학에서 락(lock) 또는 뮤텍스(mutex, 상호 배제에서)는 여러 스레드를 실행하는 환경에서 자원에 대한 접근에 제한을 강제하기 위한 동기화 매커니즘이다.
락은 상호 배제 동시성 제어 정책을 강제하기 위해 설계된다.
-위키피디아(Wikipedia)-
위키피디아에는 위와 같이 다중 스레드 혹은 프로세스 환경에서 발생하는 락에 대해 설명하고 있다.
그런데 '한권으로 읽는 컴퓨터 구조와 프로그래밍' 책에서는
우리(개발자)가 실제로 처리해야 할 문제는 공유 자원이 아닌, 실제로 처리해야 할 문제는 여러 작은 연산으로 이뤄진 작업을 어떻게 원자적(Atomic) 으로 만들 수 있을까 하는 문제를 다뤄야 한다고 한다.
저자는 컴퓨터에 '은행 잔고를 조정하라' 와 같은 명령어가 있다면 위와 같은 문제를 논할 필요도 없을 것이라고 한다.
명령어를 만들고 처리하기 위해 우리는 코드에 중요한 부분을 상호 배제(mutual exculusion) 메커니즘을 통해 원자적으로 처리하게 만든다.
이런 목표의 프로그램을 만들면서 충돌을 피하기 위해 어드바이저리 락(advisory lock)을 만든다.
결국 우리는 요구사항들에 필요한 추상화된 원자 단위의 명령어로 만든다.
이 때 데이터의 무결성을 유지하고, 충돌을 방지하기 위해 락(Lock)을 사용하게 된다.
데드락(Deadlock, 교착 상태)는 여러 프로세스 간에 리소스를 공유할 때 발생할 수 있는 문제로 아무도 자원을 할당 받지 못하고, 무한히 대기하는 상태를 말한다.
위 사진은 데드락의 예시이다.
일반적으로 다중 프로세스, 스레드에 대해 얘기하지만 사용자, 트랜잭션, 분산 시스템에서도 데드락이 발생 할 수 있다.
트랜잭션 데드락이라고도 한다.
트랜잭션 A가 Accounts 테이블을 잡고 있다.
트랜잭션 B는 Orders 테이블을 잡고 있다.
둘 다 작업을 끝내기 위해서는 각 트랜잭션이 잡고 있는 테이블이 필요한 상황이다.
위와 같은 상황이 DB 데드락의 예시이다.
위 내용을 봤을 때 다중 스레드 데드락과 DB 데드락의 차이는 크게 보이지 않는다.
MySQL의 InnoDB 엔진을 예시로 들었을 때
InnoDB 스토리지 엔진은 내부적으로 잠금이 교착 상태에 빠지지 않았는지 체크하기 위해 잠금 대기 목록을 그래프(Wait-for-List 형태로 관리한다.
InnoDB는 데드락 감지 스레드를 가지고 있어서 주기적으로 잠금 대기 그래프를 검사해 교착 상태에 빠진 트랜잭션들을 찾아서 그 중 하나를 강제 종료한다.
트랜잭션의 언두 로그 양이며, 언두 로그 레코드를 더 적게 가진 트랜잭션이 일반적으로 롤백의 대상이 된다.
동시 처리 스레드가 매우 많아지거나 각 트랜잭션이 가진 잠금의 개수가 많아지면 데드락 감지 스레드가 느려진다.결국 서비스 쿼리를 처리 중인 스레드는 작업을 진행하지 못하고 대기하면서 서비스에 악영향을 미친다.
(동시 처리 스레드가 매우 많은 경우 데드락 감지 스레드는 더 많은 CPU 소모)
MySQL 서버는 innodb_deadlock_detect
시스템 변수를 off로 설정하면 데드락 감지 스레드가 작동하지 않는다고 한다.
데드락 감지 설정을 off 하면 데드락 상황에서 무한정 대기가 발생하게 되기 때문에 신중히 설정해야 한다.
나 : 엄마 저..
엄마 : 아빠한테 물어봐
나 : 아빠 저..
아빠 : 엄마한테 물어봐
...
라이브 락은 위와 같이 행동은 일어나지만 block된 것처럼 보이는 현상을 말한다.
한 길을 지나가는데 마주보는 사람이 서로 같은 방향으로 계속 비켜줘서 지나가지 못하는 상황도 하나의 예시다.
라이브 락 외에도 스핀 락, 공유 락, 베타 락, 업데이트 락 등등 상당히 많다.
이것을 전부 다루기는 어려울 것 같아서 예시가 재미있는 라이브 락만 다뤄봤다.
데드락이라는 키워드를 알게 되어 공부 할 때, 단순히 암기의 대상이 되고 싶지는 않았다.
그래서 이렇게 다양한 자료를 찾아보면서 공부를 하게 되었다.
그리고 위와 같은 인사이트를 얻게 된 것은 직접 찾아본 것도 있지만,
F-lab 멘토님이 키워드와 논의 내용을 주신 덕분에 조금 더 깊게 공부하게 되었다.