핵심 데이터조정

분산 락

스스로 만료되고 소유자가 안전하게 해제하는 락으로, 한 번에 하나의 워커만 작업을 실행하도록 보장합니다.

획득에 필요한 명령
1
안전한 해제에 필요한 명령
1
Lua 스크립트
0
단계 1 / 5
워커 A가 락 획득

NX는 아무도 갖고 있지 않을 때만 획득합니다. PX 30000은 A가 죽으면 30초 후 만료되게 합니다.

예시 세션playing
# 워커 A가 락 획득
hotkv> SET lock:billing-run tok-a81f NX PX 30000
OK

실제 HotKV 명령과 예시 응답으로 구성된 애니메이션 안내입니다. 원하는 단계를 클릭하면 해당 단계로 이동합니다. 명령과 응답은 HotKV에서 입력하고 보는 그대로 영어로 표시됩니다.

문제

여러 머신의 크론 작업, 결제 확정, 캐시 재구축은 동시에 두 번 실행되면 안 됩니다. 만료가 없는 락은 소유자가 충돌하면 영원히 잡혀 있고, 일반 DEL로 락을 해제하면 내 락이 만료된 뒤 다른 사람의 락을 지울 수 있습니다.

HotKV의 해결 방식

NX와 PX를 붙인 SET은 아무도 락을 갖고 있지 않을 때만 획득하고 만료를 지정하므로, 충돌한 소유자가 락을 영원히 쥘 수 없습니다. 각 소유자는 무작위 토큰을 값으로 저장합니다. IFEQ를 붙인 DELEX는 락이 아직 내 토큰을 담고 있을 때만 삭제하며, 이것이 예전에는 Lua 스크립트가 필요했던 안전한 해제입니다.

단계별 설명

명령 하나하나, 무슨 일이 일어나는가

  1. 01

    워커 A가 락 획득

    NX는 아무도 갖고 있지 않을 때만 획득합니다. PX 30000은 A가 죽으면 30초 후 만료되게 합니다.

    SET lock:billing-run tok-a81f NX PX 30000
  2. 02

    워커 B는 거절됨

    락이 이미 잡혀 있으므로 B는 nil을 받고 이번 실행을 건너뜁니다.

    SET lock:billing-run tok-b22c NX PX 30000
  3. 03

    A가 작업 수행

    청구 작업은 하나의 워커만 실행합니다.

    PTTL lock:billing-run
  4. 04

    자기 락만 해제

    DELEX는 값이 여전히 A의 토큰일 때만 키를 삭제합니다.

    DELEX lock:billing-run IFEQ tok-a81f
  5. 05

    잘못된 토큰은 아무 일도 하지 않음

    A가 너무 늦어 B가 지금 락을 갖고 있다면, A의 해제는 B의 락을 그대로 둡니다.

    DELEX lock:billing-run IFEQ tok-stale
적용 분야

실제 시나리오

예약 작업

같은 크론이 모든 인스턴스에서 실행되고, 락은 정확히 하나만 작업을 수행하도록 보장합니다.

결제

한 주문에 대한 확정과 환불 작업을 직렬화하여 절대 겹치지 않게 합니다.

캐시 스탬피드 방지

비싼 캐시 항목은 하나의 요청만 재구축하고, 나머지는 기다리거나 오래된 값을 제공합니다.

내장 기능

제공되는 기능

만료와 함께 획득

SET NX PX는 비어 있을 때만 타임아웃과 함께 락을 획득합니다.

SETNXPX

안전한 해제

DELEX IFEQ는 값이 내 토큰과 일치할 때만 삭제합니다.

DELEX

작업 중 연장

남은 시간을 확인하고 긴 작업에서는 연장합니다.

PTTLPEXPIRE

다이제스트로 비교

큰 값에는 DELEX IFDEQ가 전체 값 대신 다이제스트를 비교합니다.

DIGESTIFDEQ
레퍼런스:SETDELEXDIGEST

자주 묻는 질문

그냥 DEL로 락을 지우면 안 됩니까?

내 락이 만료되어 다른 워커가 가져갔다면, 일반 DEL은 그 워커의 락을 지웁니다. DELEX IFEQ는 락이 여전히 내 토큰을 담고 있을 때만 삭제합니다.

만료는 얼마로 해야 합니까?

작업이 보통 걸리는 시간보다 길게 잡으십시오. 긴 작업에서는 락을 쥐고 있는 동안 주기적으로 만료를 연장합니다.

안전한 해제에 Lua가 필요합니까?

아닙니다. DELEX가 비교와 삭제를 명령 하나로 처리합니다.

관련 사용 사례

직접 워크로드로 사용해 보십시오

HotKV는 Redis 프로토콜을 사용하므로 기존 클라이언트를 연결해 같은 명령을 그대로 실행할 수 있습니다.