자세 한 설명 은 redis 기반 분포 식 잠 금 실현

머리말
자바 병렬 처 리 는 높 은 병렬 저장 장면 에서 같은 스 레 드 로 만 작 동 할 수 있 도록 ReentrantLock 또는 Synchronized 를 제공 하여 상호 배척 통 제 를 제공 합 니 다.하지만 이 는 단기 환경 에 만 효과 가 있다.우 리 는 분포 식 자 물 쇠 를 대략 세 가지 방식 으로 실현 한다.
  • redis 분포 식 잠 금 실현
  • 데이터 베 이 스 는 분포 식 잠 금
  • 을 실현 한다.
  • zk 분포 식 잠 금 실현
  • 원리 분석
    상기 세 가지 분포 식 자 물 쇠 는 모두 각자 의 근 거 를 통 해 각 요구 에 대해 자 물 쇠 를 잠 그 고 자 물 쇠 를 풀 어 놓 는 지 거부 하 는 지 제어 한다.redis 잠 금 은 setnx 명령 을 기반 으로 합 니 다.
    setnx 는 key 만 존재 하지 않 습 니 다.주어진 키 가 존재 한다 면 setnx 는 동작 을 하지 않 습 니 다.setnx 는 원자 적 인 조작 이다.
    데이터베이스 분포 식 에 비해 redis 메모리 가 가 볍 기 때 문 입 니 다.그래서 redis 분산 잠 금 성능 이 더 좋 습 니 다.
    이루어지다
    원 리 는 간단 하 다.springboot 프로젝트 와 결합 하여 우 리 는 주해 형식 을 통 해 인 터 페 이 스 를 재고 잠 금 사례 로 이해 하 는 것 을 실현 합 니 다.
    주 해 를 쓰다
    우 리 는 주 해 를 쓴다.인터페이스 에 주 해 를 추가 하여 차단 정 보 를 제공 하 는 데 편리 합 니 다.
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface StockLock {
    
        /**
         * 
         * @Description  key   
         * @Date 15:25 2020 03 25 , 0025
         * @Param []
         * @return java.lang.String
         */
        String prefix() default "";
        /**
         *
         * @Description key    
         * @Date 15:27 2020 03 25 , 0025
         * @Param []
         * @return java.lang.String
         */
        String delimiter() default ":";
    }
    
    @Target({ElementType.PARAMETER , ElementType.METHOD , ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    public @interface StockParam {
        /*
        * @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 를 바탕 으로 분포 식 잠 금 을 실현 하 는 자 료 는 우리 의 다른 관련 글 에 관심 을 가 져 주 십시오!

    좋은 웹페이지 즐겨찾기