redis 기반 분포 식 잠 금 의 원리 와 방법

머리말
시스템 이 계속 확대 되 고 분포 식 자 물 쇠 는 가장 기본 적 인 보장 이다.한 기계 의 다 중 스 레 드 와 달리 분포 식 은 여러 기계 에 걸 쳐 있다.스 레 드 의 공유 변 수 는 기 계 를 뛰 어 넘 을 수 없습니다.
자바 병렬 처 리 는 높 은 병렬 저장 장면 에서 같은 스 레 드 로 만 작 동 할 수 있 도록 ReentrantLock 또는 Synchronized 를 제공 하여 상호 배척 통 제 를 제공 합 니 다.하지만 이 는 단기 환경 에 만 효과 가 있다.우 리 는 분포 식 자 물 쇠 를 대략 세 가지 방식 으로 실현 한다.
redis 분포 식 잠 금 실현데이터 베 이 스 는 분포 식 잠 금 을 실현 한다분포 식 잠 금 실현
오늘 우 리 는 redis 를 통 해 분포 식 자 물 쇠 를 실현 하 는 것 을 소개 한다.실제로 이 세 가 지 는 자바 와 비교 해 보면 한 종류 에 속한다.모두 프로그램 외부 자물쇠 에 속 합 니 다.
원리 분석
4.567917.상기 세 가지 분포 식 자 물 쇠 는 모두 각자 의 근 거 를 통 해 각 요구 에 대해 자 물 쇠 를 잠 그 고 자 물 쇠 를 풀 어 놓 는 것 을 제어 하 는 것 입 니 다.redis 잠 금 은 setnx 명령 을 기반 으로 합 니 다4.567917.setnx 는 키 만 존재 하지 않 습 니 다.주어진 키 가 존재 한다 면 setnx 는 동작 을 하지 않 습 니 다.setnx 는 원자 적 인 조작 이다4.567917.데이터베이스 분포 식 에 비해 redis 메모리 가 가 볍 기 때 문 입 니 다.그래서 redis 분산 잠 금 성능 이 더 좋 습 니 다.
이루어지다
원 리 는 간단 하 다.springboot 프로젝트 와 결합 하여 우 리 는 주해 형식 을 통 해 인 터 페 이 스 를 재고 잠 금 사례 로 이해 하 는 것 을 실현 합 니 다.
주 해 를 쓰다
우 리 는 주 해 를 쓴다.인터페이스 에 주 해 를 추가 하여 차단 정 보 를 제공 하 는 데 편리 합 니 다.

/**
 * @author    
 * @version V1.0
 * @Package com.ay.framework.order.redis.product
 * @date 2020 03 26 , 0026 10:29
 * @Copyright © 2020         
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface StockLock {

  /**
   * @author zxhtom
   * @Description  key   
   * @Date 15:25 2020 03 25 , 0025
   * @Param []
   * @return java.lang.String
   */
  String prefix() default "";
  /**
   * @author zxhtom
   * @Description key    
   * @Date 15:27 2020 03 25 , 0025
   * @Param []
   * @return java.lang.String
   */
  String delimiter() default ":";
}

/**
 * @author    
 * @version V1.0
 * @Package com.ay.framework.order.redis.product
 * @date 2020 03 26 , 0026 11:09
 * @Copyright © 2020         
 */
@Target({ElementType.PARAMETER , ElementType.METHOD , ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface StockParam {
  /**
  * @author zxhtom
  * @Description   key
  * @Date 11:11 2020 03 26 , 0026
  * @Param []
  * @return java.lang.String[]
  */
  String[] names() default {""};
}
차단기
redis 분산 잠 금 실현 의 관건 은 차단기 의 작성 이다.위의 주 해 는 단지 차단 을 실현 하기 위 한 보조 일 뿐이다.

@Around("execution(public * *(..)) && @annotation(com.ay.framework.order.redis.product.StockLock)")
springboot 의 Around 를 통 해 StockLock 주 해 를 차단 합 니 다.차단 을 통 해 차단 하 는 방법,파라미터,그리고 필요 한 자물쇠 의 인 자 를 얻 을 수 있 습 니 다.
잠 금 이 필요 한 이름 을 가 져 왔 습 니 다.
우리 가 재 고 를 삭감 할 때 재 고 를 갱신 하 는 것 을 편리 하 게 하기 위해 서.우 리 는 재 고 를 점차 줄 이기 전에 또 다른 자 물 쇠 를 빌려 야 한다.이 자 물 쇠 는[a]라 고 합 니 다.key】
다시 말 하면 우리 인터페이스 가 방문 하려 면[a]자 물 쇠 를 가 져 와 야 하고[a]자 물 쇠 를 가 져 오 려 면 재 고 를 줄 여야 합 니 다.재 고 를 줄 이기 전에 획득[a열쇠
자 물 쇠 를 가 져 온 후에 논 리 를 처리 한 후에 우 리 는 대응 하 는 자 물 쇠 를 풀 어야 한다.

RedisAtomicLong entityIdCounter = new RedisAtomicLong(lockKey, redisTemplate.getConnectionFactory());
  if (redisTemplate.hasKey(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey)) {
    //  lockKey        。        
    throw new BusinessException("    。     ");
  }
  Long increment = entityIdCounter.decrementAndGet();
  if (increment >= 0) {
    try {
      Object proceed = pjp.proceed();
    } catch (Throwable throwable) {
      //            
      while (!redisLock.tryGetLock(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey, "")) {

      }
      //  lockKey        。        
      long l = entityIdCounter.incrementAndGet();
      if (l < 1) {
        redisTemplate.opsForValue().set(lockKey,1);
      }
      redisLock.unLock(CoreConstants.UPDATEPRODUCTREDISLOCKKEY + lockKey);
      throwable.printStackTrace();
    }
  } else {
    redisTemplate.opsForValue().set(lockKey,0);
    throw new BusinessException("    !    ");
  }
우리 가 자 물 쇠 를 채 우려 면 자 물 쇠 를 풀 어야 하기 때문이다.그러나 프로그램 이 중간 에 업 무 를 처리 하 는 것 은 이상 이 발생 하여 자 물 쇠 를 풀 어 주 는 절차 에 이 르 지 못 했다.이 럴 때 우리 의 분포 식 자물쇠 가 계속 잠 겨 있다.속칭[자물쇠]라 고 한다.이런 장면 을 피하 기 위해 서우 리 는 항상 자 물 쇠 를 채 울 때 유효기간 을 준다.유효기간 이 지나 자 자동 으로 자 물 쇠 를 풀 었 습 니 다.이 특성 은 redis 의 만 료 전략 과 일치 하지 않 습 니 다.
상기 언급 도구
RedisLock

public Boolean tryGetLock(String key , String value) {
  return tryGetLock(key, value, -1, TimeUnit.DAYS);
}
public Boolean tryGetLock(String key , String value, Integer expire) {
  return tryGetLock(key, value, expire, TimeUnit.SECONDS);
}
public Boolean tryGetLock(String key , String value, Integer expire , TimeUnit timeUnit) {
  ValueOperations operations = redisTemplate.opsForValue();
  if (operations.setIfAbsent(key, value)) {
    //   redis   key ,                    
    if (expire > 0) {
      redisTemplate.expire(key, expire, timeUnit);
    }
    return true;
  }
  return false;
}

public Boolean unLock(String key) {
  return redisTemplate.delete(key);
}
StockKeyGenerator

@Component()
@Primary
public class StockKeyGenerator implements CacheKeyGenerator {
  @Override
  public String getLockKey(ProceedingJoinPoint pjp) {
    //      
    MethodSignature signature = (MethodSignature) pjp.getSignature();
    Method method = signature.getMethod();
    //    cacheLock  
    StockLock stockLock = method.getAnnotation(StockLock.class);
    //      
    Object[] args = pjp.getArgs();
    Parameter[] parameters = method.getParameters();
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < parameters.length; i++) {
      StockParam stockParam = parameters[i].getAnnotation(StockParam.class);
      Object arg = args[i];
      if (arg instanceof Map) {
        Map<String, Object> temArgMap = (Map<String, Object>) arg;
        String[] names = stockParam.names();
        for (String name : names) {
          if (builder.length() > 0) {
            builder.append(stockLock.delimiter());
          }
          builder.append(temArgMap.get(name));
        }
      }

    }
    return builder.toString();
  }
}
문제 분석
위 에서 자물쇠 가 없 는 장면 을 분 석 했 는데 이론 적 으로 자물쇠 가 나 왔 다.우리 redis 분포 자 물 쇠 는 분포 식 문 제 를 잘 해결 했다.그래도 문제 가 생 길 수 있 습 니 다.다음은 편집장 이 만난 문 제 를 열거 하 겠 습 니 다.
업무 처리 시간>잠 금 만 료 시간
a 라인 에서 자 물 쇠 를 가 져 오고 업무 처 리 를 시작 하려 면 8S 가 필요 합 니 다.
8S 에서 자물쇠 의 유효기간 은 5S 이 고 자물쇠 가 만 료 된 후에 6S 입 니 다.b 스 레 드 가 들 어가 자 물 쇠 를 얻 기 시 작 했 을 때 b 는 새로운 자 물 쇠 를 얻 을 수 있 습 니 다.이 럴 때 문제 야.
b 스 레 드 업무 처리 에 3S 만 필요 하 다 고 가정 하지만 a 스 레 드 가 자 물 쇠 를 풀 었 기 때문에 8S 에 b 스 레 드 가 자 물 쇠 를 풀 지 않 았 고 b 의 자물쇠 도 기한 이 지나 지 않 았 지만 이때 도 자물쇠 가 없 었 다.이 로 인해 C 라인 도 들 어 갈 수 있다
총결산
여기 서 redis 를 바탕 으로 분포 식 잠 금 을 실현 하 는 원리 와 방법 을 바탕 으로 하 는 이 글 은 여기까지 소개 되 었 습 니 다.더 많은 관련 redis 분포 식 잠 금 내용 은 우리 의 이전 글 을 검색 하거나 아래 의 관련 글 을 계속 조회 하 시기 바 랍 니 다.앞으로 많은 응원 바 랍 니 다!

좋은 웹페이지 즐겨찾기