스 레 드 를 해결 하고 redisson 에서 만 나 는 구 덩이 를 사용 합 니 다.

레 디 슨 구덩이
배경
업무 상의 구 매 수요 때문에 재 고 를 일정 보호 하고 초과 판매 의 발생 을 방지 해 야 한다(우 리 는 전자상거래 회사 가 아니다).조사 연 구 를 통 해 최종 적 으로 Redission 을 사용 하여 통 제 를 해 야 한다.
주로 Redission 의 풍부 한 API,오픈 소스 프레임 워 크 가 실제 생산 환경 에 널리 활용 되 었 기 때문이다.
문제 설명
Ression 에서 Lock.lock()방법 을 사용 한 후에 스 레 드 와 자주 발생 하 는 상황 이 있 으 면 다음 과 같은 이상 이 발생 합 니 다.
java.lang.IllegalMonitorStateException: attempt to unlock lock, not locked by current thread by node id: 9f178836-f7e1-44fe-a89d-2db52f399c0d thread-id: 22
문제 분석
thread-1 이 아직 끝나 지 않 았 을 때,즉 thread-1 이 자 물 쇠 를 얻 었 으 나 아직 자 물 쇠 를 풀 지 않 았 을 때,'thread-2 는 다른 스 레 드 에 의 해 중단 되 어 lock.try Lock 의 차단 상태 에서 다음 논 리 를 계속 실행 하 기 를 기다 리 고 있 습 니 다.또한 스 레 드 thread-1 에 속 하 는 자 물 쇠 를 풀 려 고 시도 하여 운행 시 이상 을 던 져 서 이 스 레 드 thread-2 가 끝 났 습 니 다.그러나 thread-2 는 일련의 조작 을 완성 한 후에 스 레 드 thread-1 은 자신의 자 물 쇠 를 풀 었 다.
그래서 thread-2 는 자 물 쇠 를 얻 지 못 했 지만 동기 화가 필요 한 내용 을 실 행 했 고 자 물 쇠 를 풀 려 고 시도 했다.
그 해결 방식 을 우 리 는 알 수 있 습 니 다.현재 스 레 드 에 추 가 된 자 물 쇠 는 현재 스 레 드 에서 잠 금 을 풀 수 있 습 니 다.즉,우리 가 lock.unlock 을 사용 할 때 스 레 드 의 판단 을 추가 하면 됩 니 다.
문제 해결

 RLock lock = redissonClient.getLock(key);
    if(lock.isLocked()){ //         
      if(lock.isHeldByCurrentThread()){ //            
        lock.unlock(); //    
      }
    }
redisson 사용 주의사항
Redisson 은 Redis 를 바탕 으로 실 현 된 자바 메모리 데이터 그리드 로 바 텀 작업 을 노출 하 는 Jedis 에 비해 Redisson 은 일련의 분포 식 자바 상용 대상 을 제공 하고 분포 식 서 비 스 를 많이 제공 했다.
특성&기능:
  • Redis 단일 노드(single)모드,보초병(sentinel)모드,주종(Master/Slave)모드 와 집단(Redis Cluster)모드
  • 지원
  • 프로그램 인터페이스 호출 방식 은 비동기 실행 과 비동기 실행 두 가지 방식
  • 을 사용한다.
  • 데이터 직렬 화,Redisson 의 대상 인 코딩 류 는 대상 을 직렬 화 와 반 직렬 화 시 켜 이 대상 이 Redis 에서 읽 고 저장 하 는 것 을 실현 하 는 데 사용 된다
  • .
  • 단일 집합 데이터 분할,클 러 스 터 모드 에서 Redisson 은 단일 Redis 집합 유형 에 자동 분할 기능 을 제공 합 니 다
  • Object Bucket,Bitset,AtomicLong,Bloom Filter 와 HyperLogLog 등 다양한 분포 식 대상 을 제공 합 니 다
  • 지도,Multimap,Set,SortedSet,List,Deque,Queue 등 다양한 분포 식 집합 을 제공 합 니 다
  • .
  • 분산 식 잠 금 및 동기 화 장치 의 실현,잠 금(Reentrant Lock),공정 잠 금(Fair Lock),잠 금(MultiLock),빨 간 잠 금(Red Lock),신 호 량(Semaphonre),기한 이 지난 신호 잠 금(PermitExpirableSemaphore)등
  • 분포 식 원 격 서비스(Remote Service),분포 식 실시 간 대상(Live Object)서비스,분포 식 실행 서비스(Executor Service),분포 식 스케줄 링 임무 서비스(Schedule Service)와 분포 식 매 핑 귀납 서비스(MapReduce)
  • 등 선진 적 인 분포 식 서 비 스 를 제공한다.
  • 더 많은 기능 과 기능,홈 페이지 를 주목 하 세 요:http://redisson.org
  • 실현 원리
    redis 자 체 는 상기 분포 식 대상 과 집합 을 지원 하지 않 습 니 다.Redisson 은 redis 의 특성 을 이용 하여 클 라 이언 트 에서 고급 데이터 구조 와 특성 을 실현 합 니 다.예 를 들 어 우선 대기 열의 실현 은 클 라 이언 트 정렬 을 통 해 정리 한 다음 에 redis 에 저장 합 니 다.
    클 라 이언 트 가 실 현 된 것 은 클 라 이언 트 가 온라인 에 없 을 때 이러한 모든 데이터 구조 와 특성 이 보존 되 지 않 고 자동 으로 효력 이 발생 하지 않 는 다 는 것 을 의미한다.예 를 들 어 만 료 된 이벤트 의 트리거 나 원래 우선 대기 열의 요소 가 증가 하 는 것 이다.
    주의 사항
    실시 간성
    RMap 에는 키 쌍 의 만 료 시간 을 설정 하고 키 쌍 의 이벤트 모니터 를 등록 할 수 있 는 기능 이 있 습 니 다.
    원소 도태 기능(Eviction)
    Redisson 의 분포 식 RMapCache Java 대상 은 RMap 을 바탕 으로 한 요소 에 대한 도태 체 제 를 실현 했다.요소 의 삽입 순 서 를 유지 합 니 다.RMapCache 는 RMap 을 기반 으로 이 루어 졌 기 때문에 자바 util.concurrent.Concurrent Map 인터페이스 와 자바 util.Map 인 터 페 이 스 를 동시에 계승 하 였 습 니 다.Redisson 이 제공 하 는 Spring Cache 통합 과 JCache 는 바로 이러한 기능 을 바탕 으로 이 루어 진 것 이다.
    현재 Redis 자체 가 해시(Hash)의 요소 탈락 을 지원 하지 않 기 때문에 모든 만 료 요 소 는 org.redisson.EvictionScheduler 인 스 턴 스 를 통 해 정기 적 으로 청 소 됩 니 다.자원 의 효율 적 인 이용 을 위해 매번 운행 할 때마다 최대 300 개의 만 료 요 소 를 정리 합 니 다.작업 의 시작 시간 은 지난번 실제 청소 수량 에 따라 자동 으로 조정 되 며 간격 은 1 초 에서 1 시간 사이 입 니 다.예 를 들 어 이번 청소 때 300 개의 요 소 를 삭 제 했 으 면 다음 청소 시간 은 1 초 이후(최소 간격)입 니 다.이번 청소 수량 이 지난번 청소 수량 보다 적 으 면 시간 간격 이 1.5 배 증가한다.
    공식 위 키 에서 말 한 바 와 같이 이 기능 은 백 스테이지 스 레 드 를 통 해 정 해진 시간 에 정리 되 기 때문에 이것 은 비 실시 간(issue-1234:on expired event is not executed in real-time)이 고 5 초 에서 2 시간 사이 지연 되 기 때문에 실시 간 요구 가 높 은 장면 은 스스로 평가 해 야 한다.
    만 료 시간의 비 실시 성 으로 인해 만 료 사건 의 발생 도 비 실시 간 입 니 다.해당 하 는 모니터 가 잠시 지연 되 어서 야 통 지 를 받 을 수 있 습 니 다.제 테스트 에서 ttl 은 초 급 오차 가 비교적 크 고 분 급 ttl 은 괜 찮 습 니 다(왼쪽 설정 값,오른쪽 실제 시간 소모).
    1s _ 5s
    3s _ 5s
    4s _ 5s
    5s _ 9s
    6s _ 10s
    10s _ 15s
    1m _ 1m11s
    서열 화
    Redisson 의 기본 인 코더 가 JSonJackson Codec 이 고,JSonJackson 은 양 방향 참조 대상 을 직렬 화 할 때 무한 순환 이상 이 발생 합 니 다.한편,fastjson 은 양 방향 인용 을 검사 한 후 자동 으로 인용 부호$ref 로 교체 하여 순환 을 종료 합 니 다.
    제 상황 에서 저 는 service 를 직렬 화 했 습 니 다.이 서 비 스 는 spring 에 의 해 위탁 되 었 고 다른 service 와 도 서로 주입 되 었 습 니 다.fastjson 으로 redis 로 정상적으로 직렬 화 할 수 있 고 Json Jackson 은 무한 순환 이상 을 던 졌 습 니 다.
    직렬 화 된 내용 을 볼 수 있 기 때문에 redition 의 다른 바 이 너 리 인 코더 없 이 자체 적 으로 인 코딩 기 를 실현 합 니 다.
    
    import com.alibaba.fastjson.JSON;
    import com.alibaba.fastjson.serializer.SerializerFeature;
    import io.netty.buffer.ByteBuf;
    import io.netty.buffer.ByteBufAllocator;
    import io.netty.buffer.ByteBufInputStream;
    import io.netty.buffer.ByteBufOutputStream;
    import org.redisson.client.codec.BaseCodec;
    import org.redisson.client.protocol.Decoder;
    import org.redisson.client.protocol.Encoder;​
    import java.io.IOException;​
    public class FastjsonCodec extends BaseCodec {​
     private final Encoder encoder = in -> {
     ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
     try {
     ByteBufOutputStream os = new ByteBufOutputStream(out);
     JSON.writeJSONString(os, in,SerializerFeature.WriteClassName);
     return os.buffer();
     } catch (IOException e) {
     out.release();
     throw e;
     } catch (Exception e) {
     out.release();
     throw new IOException(e);
     }
     };
    ​
     private final Decoder<Object> decoder = (buf, state) ->
     JSON.parseObject(new ByteBufInputStream(buf), Object.class);
    ​
     @Override
     public Decoder<Object> getValueDecoder() {
     return decoder;
     }
    ​
     @Override
     public Encoder getValueEncoder() {
     return encoder;
     }
    }
    구독 발표
    Redisson 이 구독 게시 에 대한 패 키 징 은 RTopic 이 고 이것 은 Redisson 에서 많은 사건 감청 의 실현 원리(예 를 들 어 키 값 이 맞 는 사건 감청)이기 도 합 니 다.
    유닛 테스트 를 사용 할 때 이벤트 가 발 표 된 후에 구독 자 는 시간 을 좀 끌 어야 이 벤트 를 받 을 수 있 습 니 다.구체 적 인 원인 은 조사 할 필요 가 있다.
    이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.

    좋은 웹페이지 즐겨찾기