비관적 Lock, 낙관적 Lock 이해하기
lock과 관련된 이슈를 겪어본적/본적(간접)은 회사생활을 통틀어
1번 정도 있는것 같다. 사실 그만큼 내가 접할 일이 별로 없었다.
주니어 이기도했고,
프론트와 관련된 로직을 주로 다뤄서 트랜젝셔널한 상황들 자체가 없었다.
-> 개인적으로 취약한 부분이였고, 아쉬웠던 부분이다.
그래서 더 이해하기 어려웠고(상황적 예시가 없어서) 해결책을 도출하기에는 더 어려웠다.
최근 DDD관련 서적을 읽는데 우연히 이를 아주 간단하게 잘 설명해 둔 내용을 접했다. (해당 서적은 락을 다루는 책은 아니다. 간단한 상황을 다루다가 포암되었을뿐) . DDD Start! 라는 책이다.
그래서 해당 내용을 간단하게 남겨두려고 한다.
여러 글과 서적을 통해 락에 대해서 비관적/낙관적 (Pessimistic/optimistic)으로 나누고 있고 어떤식으로 처리하는지는 잘 알고 있지만, 좋은 내용이니 적어둔다.
Pessimistic Lock(비관적 락 / 선점 락)
의문 : 왜 비관적/선점 이라는 단어를 사용하는가?
나는 이게 가장 헷갈렸다. 왜 용어가 저렇지? 그리고 그게 실제 처리 방식과 어떤 연관이 있지?
자원에 대한 동시 요청이 발생 할 것이고, 그래서 일관성에 문제가 생길 것이다. 라고 비관적으로 생각하고 이를 방지 하기 위해 자원을 선점 하도록 하는 방식으로 이를 해결 한다. 라는 의미를 담고 있다.
자원 = db에 저장된 레코드 라고 생각해도 좋다.
예를 들면 주문 정보가 저장되어 있고, 이 정보는 배송지 정보를 포함한다.
동시에 한명만 읽어가서 사용 하도록 하는 방식으로 주로 해결한다.
DB Query 중 SELECT FOR UPDATE 를 사용하는 방식이 주 해결책이다.
때문에 한 자원을 누군가 읽어가서 변경하고 있다면 다른 자원을 요청한 사용자는 해당 사용자가 업데이트를 마칠 때 까지 해당 자원을 사용하지 못한다.
무조건 잠금을 하고 선점 시킨다. 그래서 용어가 저렇다.
근데 이걸로 모든 상황이 해결되는 건 아니라고 한다.
일관성을 깨는 상황들도 충분히 발생 가능하다.
그리고 자원의 순환참조로 교착상태에 빠질 수 도 있다.
(솔직히 요즘 같은 MSA 같은 설계에서 모든 문제를 이 방식으로 해결하긴 불가능하다. 설계 자체가 서비스 별로 DB를 나눠버리기 때문이다.)
Optimistic Lock(낙관적 락 / 비선점 락)
역시나 용어를 짚고 넘어가자
낙관적 / 비선점 이라는 용어는
락을 해야하는 상황의 발생이 일어나면 그때 대응하자, 자원을 선점 시키지 말자. 라는 의미이다. 그럼 도대체 어떻게 해결 할 건데?
Version을 통해 해결한다. (이보다 더 다양한 방법들이 있을 것이다.)
애당초 DB 테이블에 version 정보를 갖고 있고,
해당 자원을 Read 할 때 version 정보도 함께 가져온다.
그리고 Update 할 필요가 있다면 정보를 수정하면서
UPDATE teablename SET version = version + 1, 수정할 컬럼들…,
WHERE keyid = ? AND version = 읽어올 때 가져온 현재 버전
위와 같이 처리하면 (읽을 때 버전 정보로 대상을 찾고 버전을 올려준다.)
누군가 내가 수정 하는 사이에 건드리지 않았다면 정상적으로 업데이트가
될 것이고, 그렇지 않다면 적용된 로우가 0 으로 리턴 될 것이다.
JPA(hibernate)의 경우에는 이런 상황에서 Optimistic Lock exception을 던져준다. 때문에 어플리케이션 단에서 충돌이 발생 했음을 인지 가능하며,
처리하면 된다.
무튼… 내가 헷갈렸던 부분 위주로 기록을 남기기 위해 간단히 적었다.
추후 이미지나 필요한 내용은 업데이트 할지도..?