분산 락을 얻은 워커가 오래 멈췄다가 락 만료 후 다시 실행됐습니다. 새 소유자와 동시에 쓰는 일을 어떻게 막나요?
잠깐, 답변을 보기 전에
먼저 내 말로 설명해 볼까요?
답변과 점검 포인트 펼치기답변 접기
구두 답변
정의를 외우기보다, 원리와 조건을 연결해 설명해 보세요.
락 만료는 죽은 작업자가 자원을 영원히 잡는 문제를 줄이지만, 만료된 작업자가 다시 실행되는 것까지 막지는 않습니다. 긴 정지나 네트워크 지연 뒤 원래 작업자가 돌아오면 새 락 소유자와 동시에 쓰기를 할 수 있습니다. 락 서비스에서 소유권이 하나라는 것과 실제 저장소의 쓰기가 하나라는 것은 다릅니다.
펜싱은 오래된 소유자의 쓰기를 실제 저장 지점에서 거절하는 장치입니다. 새 소유자의 토큰 12를 저장소가 받아들인 뒤 옛 워커의 토큰 11이 오면 거절하는 식입니다. 단순히 워커가 시작 전에 락을 확인하는 것과 다르게, 늦게 도착한 쓰기 자체를 검사해야 합니다. 토큰 검증과 실제 변경도 같은 원자적 경계에 있어야 합니다.
예를 들어 첫 워커가 락을 얻고 파일 생성 작업 중 멈췄다고 하겠습니다. 락이 만료돼 두 번째 워커가 새 결과를 저장한 뒤, 첫 워커가 예전 결과를 덮을 수 있습니다. 이때 락을 얻을 때마다 증가하는 펜싱 토큰을 주고 저장하는 쪽이 이전 토큰의 쓰기를 거절하면 낡은 작업자를 막을 수 있습니다. 토큰을 워커가 확인하는 것만으로는 부족하고 실제 변경을 집행하는 계층이 검증해야 합니다.
저는 DB의 조건부 갱신이나 고유 제약으로 직접 보호할 수 있는 작업이라면 분산 락을 먼저 추가하지 않겠습니다. 외부 시스템이 토큰 검증을 지원하지 않으면 락만으로 얻는 보장의 한계를 명시하고 중복 방지나 대사 경로를 설계해야 합니다. 테스트에서는 정상 동시 요청뿐 아니라 락 만료 뒤 멈췄던 워커를 재개시켜 보겠습니다. 갱신 주기를 늘려 문제를 숨기기보다 오래된 소유자가 돌아와도 데이터가 깨지지 않는지가 중요합니다.
유효 기간은 프로세스를 정지시키는 권한이 아닙니다
일정 시간만 자원을 사용할 수 있게 하고 갱신하지 않으면 다른 소유자에게 넘길 수 있는 권한을 임대(lease)라고 부릅니다. 실패한 워커 때문에 자원이 영원히 잠기는 것을 줄이는 진행성 장치입니다. 하지만 정지한 워커가 임대 만료를 알아차리기 전에 이미 준비한 쓰기를 보낼 수 있습니다. GC 정지·가상 머신 일시 중단·네트워크 지연은 락 서비스의 시간과 워커의 실행을 서로 어긋나게 만듭니다. 소유자가 하나라는 락 서비스의 판단을 실제 저장소가 강제하지 않으면 안전성은 완성되지 않습니다.
워커가 ‘아직 내 락인가’를 조회한 뒤 잠깐 멈춰도 같은 틈이 생깁니다. 확인한 시점과 실제 사용 시점이 다르다는 TOCTOU 경쟁입니다. TTL을 더 길게 잡으면 발생 가능성을 낮출 수 있지만, 임의의 정지를 감당하는 논리적 보장이 생기지는 않습니다. 반대로 너무 길면 실패한 작업을 넘겨받는 시간이 늘어납니다. 임대 시간은 정확성의 대체재가 아니라 정상 지연과 장애 회복 목표를 반영하는 운영 값으로 정하겠습니다.
저장소가 오래된 요청을 거절해야 합니다
새 소유권마다 증가하는 번호를 부여하고 실제 변경 지점이 더 오래된 번호를 거절하는 방식을 펜싱(fencing)이라고 합니다. 저장소가 토큰 12를 받아들인 뒤 11이 도착하면 거절합니다. 이 검사는 토큰 저장과 데이터 변경을 원자적으로 해야 합니다. 번호 확인만 별도로 한 뒤 나중에 쓰면 그 사이 새 번호가 들어와 다시 경쟁합니다. 임의의 UUID는 서로 다른 소유권을 식별할 수는 있어도 어느 쪽이 최신인지 순서를 주지 않으므로 그대로 펜싱 토큰을 대체하지는 못합니다.
중요한 한계도 있습니다. 저장소가 아직 12를 본 적이 없다면 11이 임대상 만료됐다는 사실을 번호 비교만으로 알 수 없습니다. 따라서 요구가 ‘새 소유권 발급 즉시 이전 소유자의 모든 쓰기를 차단’이라면 발급과 저장소 권한 등록 사이의 계약을 더 강하게 연결해야 합니다. 흔한 단조 토큰 방식은 새 토큰이 저장 지점에 반영된 뒤 오래된 결과가 덮어쓰는 일을 막습니다. 같은 소유자가 여러 번 쓰는 경우 같은 토큰을 허용할지, 개별 요청 ID로 중복까지 검사할지도 별도 정책입니다.
잠금 소유권과 작업 결과는 별개입니다
락 해제에도 자신이 얻은 소유권 값과 현재 값을 비교한 뒤 삭제해야 합니다. 오래된 워커가 키 이름만 보고 삭제하면 새 워커의 락을 지울 수 있습니다. 이 비교와 삭제 역시 원자적으로 수행해야 합니다. 토큰 발급기의 재시작이나 백업 복원으로 번호가 뒤로 가면 정상 새 워커가 거절되거나 오래된 워커와 구분이 깨질 수 있어, 토큰 생성과 보존의 장애 가정도 확인하겠습니다.
여러 저장소에 쓰는 작업에서는 각 변경 지점이 검증을 지원해야 하며 일부 저장소만 펜싱한다고 전체가 한 트랜잭션이 되지 않습니다. 외부 API가 이를 지원하지 않으면 제공되는 멱등 키·조건부 갱신·결과 조회 등으로 범위를 제한하고, 강한 보장을 만들 수 없는 부분은 명확히 설명해야 합니다. 테스트는 옛 워커를 멈춰 두고 새 워커가 쓰게 한 다음 옛 워커를 재개하는 순서를 반드시 포함하겠습니다. 락 획득 성공 횟수가 아니라 오래된 결과가 실제로 거절됐는지가 검증 기준입니다.
득점 포인트
이해가 드러나는 지점을 확인해 보세요.
- lease와 실제 실행을 구분한다. 만료된 워커가 살아날 수 있음을 설명한다.
- 집행 지점의 펜싱을 설명한다. 저장 계층에서 낡은 토큰을 거절한다.
- 단순한 대안을 비교한다. DB 조건부 변경과 락의 한계를 판단한다.
감점 포인트
놓치기 쉬운 조건과 오해를 짚어 보세요.
- 만료되면 기존 워커가 자동 중단된다고 말한다. 프로세스 실행은 별개다.
- 워커만 토큰을 확인하면 충분하다고 말한다. 확인 뒤 지연될 수 있다.
- 타임아웃을 길게 하면 정확성이 해결된다고 말한다. 임의의 중단 가능성은 남는다.
더 파고들 거리
하나 더 질문하며 이해의 범위를 넓혀 보세요.
- 펜싱 번호 발급기가 재시작해 번호가 작아졌습니다. 오래된 writer를 막으려면 어떤 내구·세대 조건이 필요한가요?
- 한 작업자가 DB와 객체 저장소에 씁니다. 한곳의 펜싱 검사만으로 전체 작업을 보호할 수 있나요?
- 락 해제 시 다른 워커의 락을 지우지 않으려면 무엇을 비교해야 할까요?
득점·감점 포인트는 학습용 자기 점검 기준이며, 특정 회사의 실제 채점표가 아닙니다.
원리부터 공부하고 싶다면
답변을 보충하는 개념·예제·슈도코드를 읽어 보세요.