현재 테스트 중입니다: 완료되면 GitHub 코드를 오픈할 예정입니다.

펜싱 토큰

  • 획득 응답 Atoken단조 증가 u64입니다. 어떤 키든, 몇 번째 획득이든 이전에 발급된 어떤 토큰보다 큰 값이 나옵니다.
  • 싱글 모드에서는 현재 프로세스가 살아 있는 동안만 서버의 전역 카운터가 단조성을 보장합니다. 서버를 다시 띄우면 새 fencing domain이며, 이전 프로세스의 token보다 커진다는 보장은 없습니다.
  • 클러스터 모드에서는 합의로 복제되는 발급 번호가 단조성을 보장합니다. token은 커밋된 명령을 적용하는 시점에 결정적으로 부여되므로 리더가 바뀌어도 이어서 증가합니다. 단, 휘발 상태를 가진 voter의 과반을 잃은 클러스터는 같은 fencing domain으로 복구하거나 자동 재생성하지 않습니다.
  • 보호 대상 리소스가 "마지막으로 본 토큰보다 작은 토큰은 거부" 규칙을 지키면, lease 만료 뒤 뒤늦게 깨어난 옛 보유자의 접근(더 작은 토큰)을 리소스 측에서 차단할 수 있습니다 — 락 서버가 통제할 수 없는 클라이언트 측 지연(GC 멈춤 등)까지 막는 최종 방어선입니다.

왜 이 검증이 필요한지에 대한 시나리오는 동작 원리를 참고하세요.

persistent DB의 필수 계약

금융성 데이터나 재시작 뒤에도 남는 DB를 보호할 때는 token high-water 검사·갱신과 실제 업무 변경을 같은 DB transaction 또는 하나의 조건부 write 안에서 원자적으로 수행해야 합니다.

sql
BEGIN;

UPDATE ticketing_fence
   SET last_token = :token
 WHERE resource_key = :key
   AND last_token < :token;

-- 위 UPDATE가 정확히 1행을 바꾼 경우에만 같은 transaction에서 업무 데이터를 변경합니다.
UPDATE account
   SET balance = :new_balance
 WHERE account_id = :key;

COMMIT;

fencing row만 먼저 갱신하고 transaction을 끝낸 뒤 업무 write를 별도로 수행하면 안 됩니다. 같은 token으로 들어온 중복 호출의 처리는 fencing이 아니라 별도의 application idempotency 규칙으로 해결합니다. DB commit 또는 rollback이 DB 서버에서 끝났음을 확인하기 전에는 Ticket을 반납하지 않습니다.

이 계약을 지킬 수 없는 외부 API나 queue에는 lease가 지난 stale worker를 최종 차단한다는 보장을 제공할 수 없습니다. 재시작 가능한 싱글 서버 역시 persistent DB 보호 구성으로 지원하지 않으며, 살아 있는 quorum이 token high-water를 이어받는 3대 또는 5대 클러스터를 사용해야 합니다.