redis 를 바탕 으로 하 는 네 가지 흔 한 흐름 제한 전략 을 상세 하 게 설명 합 니 다.

머리말
  • 은 웹 개발 에서 기능 이 초석 이 고 기능 을 제외 하고 외부 운송 과 보호 가 중요 한 요리 이다.사이트 가 운영 되 는 동안 갑 작 스 러 운 방 문 량 으로 인해 업무 이상 이 발생 할 수도 있 고,다른 사람의 악의 적 인 공격 을 받 을 수도 있 기 때문이다.
  • 그래서 우리 의 인 터 페 이 스 는 유량 을 제한 해 야 한다.속칭 QPS 도 데이터 에 대한 묘사
  • 이다.
  • 은 제한 흐름 에 대해 현재 대부분 토 큰 통 알고리즘 이 어야 한다.왜냐하면 더 많은 스루풋 을 확보 할 수 있 기 때문이다.토 큰 통 알고리즘 외 에 그의 전신 누 출 통 알고리즘 과 간단 한 계산 알고리즘
  • 도 있다.
  • 다음은 이 네 가지 알고리즘
  • 을 살 펴 보 겠 습 니 다.
    2.고정 시간 창 알고리즘
  • 고정 시간 창 알고리즘 도 단순 계수 알고리즘 이 라 고 할 수 있다.인터넷 상에 서 계산 알고리즘 을 단독으로 추출 하 는 경우 가 많다.그러나 필 자 는 계산 알고리즘 은 하나의 사상 이 고 고정 시간 창 알고리즘 은 그의 실현
  • 이 라 고 생각한다.
  • 은 아래 미끄럼 시간 창 알고리즘 을 포함 하 는 것 도 계산법 의 실현 이다.계산 이 시간 과 연결 되 지 않 으 면 흐름 제한 의 본질 을 잃 기 때문이다.거절 이 됐어 요.
  • .

    장점:
  • 은 고정된 시간 내 에 유량 이 넘 치면 즉시 흐름 을 제한 할 수 있다.모든 시간 창 은
  • 에 영향 을 주지 않 습 니 다.
  • 시간 단위 내 에서 시스템 의 안정 을 보장 합 니 다.보 장 된 시간 단위 내 시스템 의 물동량 상한 선
  • 단점:
  • 그림 처럼 그의 가장 큰 문 제 는 임계 상태 다.임계 상태 최 악의 경우 두 배의 유량 요청
  • 은 임계 상황 을 제외 하고 한 단원 시간 창 에서 전기 에 요청 한도 값 을 빨리 소모 하면 된다.그럼 남 은 시간 은 요청 할 수 없습니다.이렇게 하면 한 순간의 데이터 로 인해 한동안 시스템 이 사용 되 지 않 을 것 이다.이것 은 인터넷 에서 사용 가능 한 시스템 에서 받 아들 일 수 없다.
  • 실현:
  • 좋 습 니 다.원리 소개 와 장단 점 에 대해 우 리 는 이미 알 고 있 습 니 다.다음은
  • 을 실현 하 겠 습 니 다.
  • 우선 우리 가 이런 계 수 를 실현 할 때 redis 를 사용 하 는 것 은 매우 좋 은 선택 이다.여기 서 우 리 는 redis 를 통 해
  • 을 실현 한다.
    controller
    
    @RequestMapping(value = "/start",method = RequestMethod.GET)
    public Map<string,object> start(@RequestParam Map<string, object=""> paramMap) {
        return testService.startQps(paramMap);
    }
    service
    
    @Override
    public Map<string, object=""> startQps(Map<string, object=""> paramMap) {
        //       qps  
        Integer times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.valueOf(paramMap.get("times").toString());
        }
        String redisKey = "redisQps";
        RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory());
        int no = redisAtomicInteger.getAndIncrement();
        //             1S
        if (no == 0) {
            redisAtomicInteger.expire(1, TimeUnit.SECONDS);
        }
        //        time=2   qps=3
        if (no > times) {
            throw new RuntimeException("qps refuse request");
        }
        //      
        Map<string, object=""> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }
    결과 테스트:

    우리 가 설정 한 qps=3,우 리 는 다섯 개의 병발 이 들 어 온 후 세 개의 정상 적 인 방문 을 볼 수 있 습 니 다.뒤의 두 개 는 실 패 했 습 니 다.잠시 만 기 다 려 주세요.우 리 는 동시 방문 을 하고 있 습 니 다.앞의 세 개 는 다시 정상적으로 방문 할 수 있 습 니 다.설명 이 다음 시간 창 에 도 착 했 습 니 다.


    3.미끄럼 시간 창 알고리즘
  • 고정 시간 창의 단점 인 임계값 에 대해 두 배의 데이터 문제 가 발생 한다.우리 의 미끄럼 시간 창 이 생 겼 다.
  • 사실은 잘 이해 할 수 있 습 니 다.바로 고정 시간 창 에 대해 시간 창 통 계 를 원래 의 고정 간격 에서 더욱 세밀 한 단원 으로 바 꾸 었 습 니 다.
  • 위 에 있 는 고정 시간 창 프레젠테이션 에서 우리 가 설정 한 시간 단원 은 1S 입 니 다.1S 에 대하 여 우 리 는 1S 를 타임스탬프 로 뜯 었 다.
  • 고정 시간 창 은 통계 단위 가 시간 이 지 날수 록 계속 뒤로 진행 된다.그리고 미끄럼 시간 창 은 우리 가 생각 하 는 시간 단원 이 상대 성 이론 사상 에 따라 시간 을 고정 시 키 고 우리 의 추상 적 인 시간 단원 이 스스로 이동 하 는 것 을 상상 하 는 것 이다.추상 적 인 시간 단원 은 실제 시간 단원 보다 더 작다.
  • 독 자 는 아래 의 동 도 를 보면 이해 할 수 있다.

  • 장점:
  • 은 실질 적 으로 고정 시간 창 알고리즘 의 개선 이다.그래서 고정 시간 창의 단점 은 그의 장점 이다.
  • 내부 에서 미 끄 러 지 는 시간 창 을 추상 화하 여 시간 을 더욱 작 게 한다.국경 에 존재 하 는 문 제 는 더욱 작다.고객 의 감지 가 더욱 약 해 졌 다.
  • 단점:
  • 고정 시간 창 알고리즘 이 든 미끄럼 시간 창 알고리즘 이 든 모두 카운터 알고리즘 을 바탕 으로 최적화 되 었 으 나 그들 은 흐름 제한 전략 에 대해 너무 거 칠 었 다.
  • 은 왜 난폭 하 다 고 말 합 니까?일단 제한 흐름 에 도달 하면 바로 거절 할 것 이다.이렇게 하면 우 리 는 일부 요 구 를 손해 볼 것 이다.이것 은 한 제품 에 있어 서 그다지 우호 적 이지 않다.
    실현:
  • 미끄럼 시간 창 은 시간 을 더욱 세분 화 합 니 다.위 에서 우 리 는 redis\#setnx 를 통 해 이 루어 집 니 다.여기 서 우 리 는 그 를 통 해 통일 적 으로 기록 할 수 없다.우 리 는 더 작은 시간 단원 을 더 해서 집합 집합 집합 에 저장 해 야 한다.그리고 집합 총량 에 따라 제한 흐름 을 계산한다.redis 의 zsett 데이터 구 조 는 우리 의 요구 에 부합 합 니 다.
  • 은 왜 zset 를 선 택 했 습 니까?redis 의 zset 에는 값 외 에 또 하나의 가중치 가 있 기 때 문 입 니 다.이 가중치 에 따라 정렬 합 니 다.만약 우리 가 우리 의 시간 단위 와 시간 스탬프 를 우리 의 가중치 로 한다 면,우 리 는 통 계 를 얻 을 때 하나의 시간 스탬프 범위 에 따라 만 하면 된다.
  • zset 내 요소 가 유일한 것 이기 때문에 우리 의 값 은 uid 또는 눈꽃 알고리즘 과 같은 id 생 성기
  • 을 사용 합 니 다.
    controller
    
    @RequestMapping(value = "/startList",method = RequestMethod.GET)
    public Map<string,object> startList(@RequestParam Map<string, object=""> paramMap) {
        return testService.startList(paramMap);
    }
    service
    
    String redisKey = "qpsZset";
    Integer times = 100;
    if (paramMap.containsKey("times")) {
        times = Integer.valueOf(paramMap.get("times").toString());
    }
    long currentTimeMillis = System.currentTimeMillis();
    long interMills = inter * 1000L;
    Long count = redisTemplate.opsForZSet().count(redisKey, currentTimeMillis - interMills, currentTimeMillis);
    if (count > times) {
        throw new RuntimeException("qps refuse request");
    }
    redisTemplate.opsForZSet().add(redisKey, UUID.randomUUID().toString(), currentTimeMillis);
    Map<string, object=""> map = new HashMap<>();
    map.put("success", "success");
    return map;
    결과 테스트:
  • 과 고정 시간 창 은 같은 병행 을 사용 합 니 다.왜 위 에서 도 임계 상황 이 나타 날 까요?코드 에 서 는 시간 단위 의 간격 이 고정 시간 간격 보다 더 크기 때문이다.고정 시간 창 시간 셀 을 보 여 주 는 것 은 1S 가 최 악의 상황 을 보 여 주 는 것 입 니 다.미끄럼 시간 창 디자인 은 간격 이 더 짧 아야 한다.저 는 10S 로 설 치 했 는데 도 나 쁘 지 않 았 어 요.
  • .
  • 여 기 는 미끄럼 이 고정된 것 보다 좋 은 점 을 설명 한다.만약 우리 가 더 작 게 조정 한다 면 더욱 임계 문제 가 발생 하지 않 을 것 이다.그러나 결국 그 는 임계 에 발생 하 는 문 제 를 피 할 수 없 을 것 이다.
  • 4.누 출 통 알고리즘
  • 미끄럼 시간 창 은 임계값 문 제 를 최대한 피 할 수 있 지만
  • 을 피 할 수 없습니다.
  • 또 다른 시간 알고리즘 은 치 명 적 인 문제 가 있다.그 는 갑 작 스 러 운 대량의 유량 에 직면 할 수 없다.왜냐하면 그 는 제한 흐름 에 도달 한 후에 다른 추가 유량
  • 을 직접 거절 하기 때문이다.
  • 이 문제 에 대해 우 리 는 우리 의 제한 알고리즘 을 계속 최적화 시 켰 다.누 출 통 알고리즘 은 운 에 따라
  • 이 생 겨 났 다.

    장점:
  • 은 제한 흐름 에 더욱 유연성 을 가지 고 거 친 거절 을 하지 않 는 다.
  • 인터페이스의 수신 성
  • 을 증가 시 켰 다.
  • 은 하류 서비스 수신 의 안정성 을 확보한다.균등 하 게 하 발
  • 단점:
  • 단점 이 없다 고 생각 합 니 다.굳이 계란 에서 뼈 를 골 라 야 한다 면 저 는 통 이 새 는 용량 이 단판 이 라 고 할 수 밖 에 없어 요.
  • .
    실현:
    controller
    
    @RequestMapping(value = "/startLoutong",method = RequestMethod.GET)
    public Map<string,object> startLoutong(@RequestParam Map<string, object=""> paramMap) {
        return testService.startLoutong(paramMap);
    }
    서 비 스 는 서비스 에서 redis 의 list 기능 을 통 해 통 의 효 과 를 모 의 합 니 다.이곳 의 코드 는 실험실 성질 이다.실제 사용 에서 우 리 는 병발 문 제 를 고려 해 야 한다.
    
    @Override
    public Map<string, object=""> startLoutong(Map<string, object=""> paramMap) {
        String redisKey = "qpsList";
        Integer times = 100;
        if (paramMap.containsKey("times")) {
            times = Integer.valueOf(paramMap.get("times").toString());
        }
        Long size = redisTemplate.opsForList().size(redisKey);
        if (size >= times) {
            throw new RuntimeException("qps refuse request");
        }
        Long aLong = redisTemplate.opsForList().rightPush(redisKey, paramMap);
        if (aLong > times) {
            //        。            。                  。      
            redisTemplate.opsForList().trim(redisKey, 0, times-1);
            throw new RuntimeException("qps refuse request");
        }
        Map<string, object=""> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }
    하류 소비
    
    @Component
    public class SchedulerTask {
    
        @Autowired
        RedisTemplate redisTemplate;
    
        private String redisKey="qpsList";
    
        @Scheduled(cron="*/1 * * * * ?")
        private void process(){
            //       
            System.out.println("    。。。。。。");
            redisTemplate.opsForList().trim(redisKey, 2, -1);
        }
    
    }
    테스트:
  • 우 리 는 50 번 의 병행 을 통 해 10 번 의 방문 을 반복 합 니 다.우 리 는 처음부터 만 비교적 높 은 물동량 에 이 를 수 있다 는 것 을 발견 할 수 있다.그 후에 통 의 용량 이 가득 찬 후에하류 물방울 속도 가 상류 요청 속도 보다 느 린 경우.아래 의 일정 속도 로 만 접근 을 받 을 수 있 습 니 다.
  • 그의 문제 도 뚜렷하게 드 러 났 다.시간 창의 부족 한 누 출 통 에 대한 진행 이 부족 하지만 부족 합 니 다.요청 이 넘 치 는 문 제 를 철저히 피 할 수 없다.
  • 요청 이 넘 치 는 것 자체 가 재난 적 인 문제 다.모든 알고리즘 은 현재 이 문 제 를 해결 하지 못 했다.다만 그 가 가 져 온 문 제 를 늦 추고 있 을 뿐이다.

    5.영패 통 알고리즘
  • 영패 통 과 누 통 법 은 같다.단지 통 의 작용 방향 을 바 꾸 었 을 뿐이다.
  • 누 출 통 의 출 수 속 도 는 일정 하 다.만약 유량 이 갑자기 증가 하면 우 리 는 연못 에 들 어 가 는 것 을 거절 할 수 밖 에 없다.
  • 그러나 영패 통 은 영패 를 통 에 넣 는 것 이다.우 리 는 정상 적 인 상황 에서 영패 가 한 줄 의 문자 라 는 것 을 알 고 있다.통 이 가득 차 면 영패 의 입 지 를 거절 하지만 높 은 유량 에 직면 할 때 정상 적 인 시간 초과 시간 을 더 하면 충분 한 시간 생산 과 소비 영패 가 남는다.이렇게 하면 가능 한 한 요 구 를 거절 하지 않 을 것 입 니 다.
  • .
  • 마지막 으로 토 큰 통 에 대해 토 큰 을 받 지 못 하고 거절당 하 든 통 이 새 는 물이 넘 치 든 대부분 유량 의 정상 적 인 사용 을 확보 하기 위해 일부 유량
  • 을 희생 했다.
    
    public Map<string, object=""> startLingpaitong(Map<string, object=""> paramMap) {
        String redisKey = "lingpaitong";
        String token = redisTemplate.opsForList().leftPop(redisKey).toString();
        //            ,    
        if (StringUtils.isEmpty(token)) {
            throw new RuntimeException("     ");
        }
        Map<string, object=""> map = new HashMap<>();
        map.put("success", "success");
        return map;
    }
    
    @Scheduled(cron="*/1 * * * * ?")
    private void process(){
        //       
        System.out.println("    。。。。。。");
        for (int i = 0; i < 2; i++) {
            redisTemplate.opsForList().rightPush(redisKey, i);
        }
    }
    이상 은 redis 를 바탕 으로 하 는 네 가지 흔히 볼 수 있 는 흐름 제한 전략 에 대한 상세 한 내용 입 니 다.redis 의 흐름 제한 전략 에 관 한 자 료 는 우리 의 다른 관련 글 을 주목 하 십시오!

    좋은 웹페이지 즐겨찾기