php redis 기반 분포 식 잠 금 실례 상세 설명

분포 식 자 물 쇠 를 사용 하여 상호 배척 자원 방문 을 할 때 우 리 는 많은 방안 을 redis 로 실현 하 는 것 이다.
물론 redis 의 단일 노드 가 극단 적 인 상황 에 잠 겨 있 는 것 도 문제 가 있 습 니 다.만약 에 귀하 의 업무 가 가끔 실 효 를 허용 한다 고 가정 하면 단일 노드 의 redis 잠 금 방안 을 사용 하면 충분 하고 간단 하 며 효율 이 높 습 니 다.
redis 잠 금 이 실 효 된 경우:
클 라 이언 트 1 마스터 노드 에서 자 물 쇠 를 가 져 왔 습 니 다.
master 가 다운 되 었 습 니 다.자 물 쇠 를 저장 하 는 key 가 아직 slave 노드 에 동기 화 되 지 않 았 습 니 다.
slave 마스터 로 승급
클 라 이언 트 2 새로운 master 에서 같은 자원 의 자 물 쇠 를 가 져 옵 니 다.
그래서 클 라 이언 트 1 과 클 라 이언 트 2 동료 가 같은 자원 의 자 물 쇠 를 가지 고 자물쇠 의 안전성 이 깨 졌 다.
만약 에 우리 가 이런 극단 적 인 상황 을 고려 하지 않 는 다 면 단일 노드 redis 자 물 쇠 를 바탕 으로 하 는 대체적인 절 차 를 실현 해 야 한다.

set cache_key random_seed NX PX 30000
위의 이 set 명령 을 분해 하면:

setnx cache_key random_seed 
expire cache_key 30
이 두 조 의 명령 이 실 행 된 효 과 는 같 지만 두 번 째 는 비 원자 적 인 작업 입 니 다.setnx 를 실 행 했 지만 expire 가 실패 하면 이 key 는 계속 존재 하고 풀 수 없 는 상황 이 발생 합 니 다.
redis 의 작가 도 단일 노드 redis 자 물 쇠 를 사용 할 때 무 작위 피 드 를 key 의 값 으로 설정 하 는 것 이 필요 하 다 고 지적 했다.클 라 이언 트 가 풀 어 준 자 물 쇠 는 반드시 자신 이 가지 고 있 는 자물쇠 여야 한다 고 보장 했다.자 물 쇠 를 가 져 올 때 set 는 난수 가 아니 라 고정 값 이 라 고 가정 합 니 다.
그러면 다음 과 같은 상황 이 발생 할 수 있 습 니 다.
클 라 이언 트 1 잠 금 획득 성공
클 라 이언 트 1 은 어떤 조작 에서 오랫동안 막 혔 다.
만 료 시간 이 되 었 습 니 다.자 물 쇠 는 자동 으로 풀 립 니 다.(그러나 클 라 이언 트 1 에서 볼 때 자 물 쇠 를 가지 고 있 는 것 같 습 니 다)
클 라 이언 트 2 가 같은 자원 에 대한 자 물 쇠 를 가 져 왔 습 니 다.
클 라 이언 트 1 은 차단 에서 회복 되 었 고 자신 이 가지 고 있 는 자 물 쇠 를 풀 었 습 니 다.즉,클 라 이언 트 2 가 가지 고 있 는 자 물 쇠 를 풀 었 습 니 다.
클 라 이언 트 2 의 잠 금 이 클 라 이언 트 1 에 의 해 안전성 을 잃 었 는 지 여부 입 니 다.
자 물 쇠 를 풀 어 주 는 작업 은 많은 사람들 이 직접 del 명령 을 사용 합 니 다.이것 은 매우 큰 문제 가 있 을 것 입 니 다.이 key 가 자 물 쇠 를 채 워 서 삭제 되 는 것 을 보장 할 수 없습니다.이 럴 때 는 임 의 수 를 써 야 한다.
잠 금 해제 동작 은 세 단계 입 니 다:
get 보유 자물쇠
이 자물쇠 가 자신 이 가지 고 있 는 지 아 닌 지 를 판단 하 세 요.
보유 자물쇠 삭제
그래서 이 세 단 계 는 원자 성 을 확보 해 야 한다.lua 스 크 립 트 로 실행 합 니 다.redis 공식 에서 스 크 립 트 파일 을 제공 하 였 습 니 다.

if redis.call("get",KEYS[1]) == ARGV[1] then
  return redis.call("del",KEYS[1])
else
  return 0
end
이 스 크 립 트 를 실행 할 때 앞의 무 작위 수 를 argv[1]의 값 으로 전송 하고 cachekey 는 keys[1]의 값 으로 전 달 됩 니 다.

public class RedisLockHelper {
  @Resource
  private R2mClusterClient r2mClusterClient;

  /**
   *    setNx   ,         expire  
   *
   * @param key    key
   * @param value              
   * @param expire         
   * @return
   */
  private String setLock(String key, String value, long expire) {
    return this.set(key, value, "NX", "PX", expire);
  }

  /**
   *     key value
   *    r2m  key    value==value     1
   *    r2m  key    value!=value     0
   *
   * @param key
   * @return
   */
  private boolean atomDelete(String key, String value) {
    List<String> values = new ArrayList<>();
    values.add(value);
    String sb = "if redis.call('get',KEYS[1])==ARGV[1] then " +
        " return redis.call('del',KEYS[1]) " +
        " else " +
        " return 0" +
        " end";
    if (this.eval(sb, key, values) == 1) {
      return true;
    }
    return false;
  }

  private Long eval(String mobel, String key, List<String> value) {
    return (Long) this.r2mClusterClient.eval(mobel, key, value);
  }

  private String set(String key, String value, String nxxx, String expx, long time) {
    return this.r2mClusterClient.set(key, value, nxxx, expx, time);
  }
}
r2m ClusterClient 는 jedis 클 라 이언 트 의 패키지 입 니 다.
phop 기반 redis 의 분포 식 잠 금 인 스 턴 스 에 대한 상세 한 설명 은 여기까지 입 니 다.더 많은 phop 기반 redis 의 분포 식 잠 금 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기