Skip to content
isdnetworks
Go back

검색으로 안 잡히는 잠금

특정 작업이 도는 동안 다른 화면이 멈춰서 잠금 경합으로 보였다. 어느 코드가 그 테이블을 잠그는지부터 찾아야 했다.

Table of contents

Open Table of contents

갱신 코드가 0건인데 멈추는 화면

멈추는 화면이 건드리는 테이블을 확인하고 그 테이블을 갱신하는 코드를 전부 검색했지만 문제의 작업 쪽에서는 한 건도 나오지 않았다. 그 작업은 그 테이블을 고치는 코드를 갖고 있지 않았다.

그런데 실제로는 그 작업이 도는 동안에만 화면이 멈추므로 시간 상관관계는 분명했다. 코드에는 없고 현상에는 있는 상태에서 조사가 막혔다.

시간 상관관계를 인과로 단정한 보고

앞선 장애 보고서에는 그 작업이 카테고리 테이블을 갱신하면서 배타 잠금을 걸었다고 원인이 적혀 있었다. 그러나 코드 어디에도 그 갱신이 없으므로 그 문장은 관측이 아니라 추론이었다.

그것을 멈추니 풀렸다는 관측에서 그것이 갱신해서 잠갔다는 인과로 한 단계를 건너뛴 서술이었다. 시간 상관관계는 무엇이 관여했는지는 말해 주지만 어떤 방식으로 관여했는지는 말해 주지 않는다.

제약조건이 거는 암묵적 잠금

검토를 받으면서 외래키 제약이 거는 잠금이 아니냐는 지적을 받고 관계를 확인했다. 연결 테이블이 카테고리 테이블을 참조하는 외래키가 실제로 걸려 있었다.

연결 테이블에 행을 넣으면 참조 무결성을 확인하기 위해 부모 행에 공유 잠금이 걸리고 그것이 커밋까지 유지된다. 삽입 한 번이 부모 행을 잠그는 것인데 그 코드에는 카테고리를 갱신하는 문장이 한 줄도 없다.

잠금을 걸고 나서 하는 긴 작업

작업 구조를 보니 트랜잭션 안에서 연결을 먼저 넣고 그다음에 옵션 수십 개를 복제하고 있었다. 잠금을 먼저 잡은 뒤에 오래 걸리는 일을 하는 순서였다.

그동안 다른 쪽에서 그 카테고리를 편집하려 하면 배타 잠금을 요청하는데 공유와 배타는 함께 잡히지 않으므로 대기한다. 많이 쓰이는 카테고리일수록 그 충돌이 자주 일어난다.

진단 순서와 결함의 개수

이후로 잠금 경합을 볼 때 갱신 코드를 먼저 찾고 안 나오면 그 테이블을 참조하는 외래키를 확인하고 마지막으로 트랜잭션 범위를 보는 순서로 진행한다. 두 번째 단계를 빼면 이런 종류의 원인은 검색으로 끝까지 안 나온다.

파고 보니 독립된 결함이 셋이었는데 잠금 뒤의 긴 작업이라는 구조 문제와 그 안의 무거운 조회라는 성능 문제와 실제로 안 바뀌는 값이 변경으로 인식되는 표면 문제였다. 앞선 보고서는 세 번째만 원인으로 지목하고 있었고 표면에서 멈추면 구조가 안 보인다.

정리


Share this post on:

Previous Post
게이트가 둘일 때의 절반 통과
Next Post
무엇을 허용해야 하나