>  기사  >  데이터 베이스  >  Redis는 전류 제한을 어떻게 구현합니까? 3가지 구현 방법 소개

Redis는 전류 제한을 어떻게 구현합니까? 3가지 구현 방법 소개

青灯夜游
青灯夜游앞으로
2020-07-21 17:06:284160검색

Redis는 전류 제한을 어떻게 구현합니까? 3가지 구현 방법 소개

첫 번째 유형: Redis 기반의 setnx 연산

Redis의 분산 잠금을 사용할 때 setnx 명령어와 CAS(비교 및 교환) 연산에 의존한다는 것은 누구나 알고 있습니다. 만료 관행(만료)은 지정된 키에 대해 설정됩니다. 전류 제한의 주요 목적은 단위 시간 내에 N개의 요청만 내 코드 프로그램에 액세스하도록 허용하는 것입니다. 따라서 setnx를 사용하면 이 기능을 쉽게 얻을 수 있습니다.

예를 들어 10초 내에 요청 20개를 제한해야 한다면 nx를 설정할 때 만료 시간을 10으로 설정할 수 있습니다. 요청된 setnx 수가 20에 도달하면 현재 제한 효과가 달성됩니다. 코드는 비교적 간단하므로 표시하지 않습니다.

물론 이 접근 방식에는 많은 단점이 있습니다. 예를 들어 1~10초를 계산할 때 N초 내에 M개의 요청을 계산해야 한다면 N을 유지해야 합니다. Redis Key 및 기타 문제

두 번째 유형: Redis 기반 데이터 구조 zset

실제로 전류 제한과 관련된 가장 중요한 것은 슬라이딩 윈도우(sliding window)입니다. 위에서도 1-10이 2-가 되는 방식을 언급했습니다. 11. 실제로 시작 값과 끝 값은 모두 각각 +1입니다.

그리고 Redis의 목록 데이터 구조를 사용하면 이 기능을 쉽게 구현할 수 있습니다.

요청을 zset 배열로 작성할 수 있으며, 각 요청이 들어올 때 값은 고유하게 유지되며 UUID를 사용하여 생성될 수 있습니다. 점수를 사용할 수 있습니다. 현재 타임스탬프 내의 요청 수를 계산하는 데 점수를 사용할 수 있기 때문에 현재 타임스탬프가 나타납니다. zset 데이터 구조는 2 타임스탬프 내의 요청 수를 쉽게 얻을 수 있도록 범위 메서드도 제공합니다

코드는 다음과 같습니다

public Response limitFlow(){
 Long currentTime = new Date().getTime();
 System.out.println(currentTime);
 if(redisTemplate.hasKey("limit")) {
 Integer count = redisTemplate.opsForZSet().rangeByScore("limit", currentTime -  intervalTime, currentTime).size();        // intervalTime是限流的时间
 System.out.println(count);
 if (count != null && count > 5) {
 return Response.ok("每分钟最多只能访问5次");
 }
 }
 redisTemplate.opsForZSet().add("limit",UUID.randomUUID().toString(),currentTime);
 return Response.ok("访问成功");
 }

위 코드는 슬라이딩 윈도우 효과를 얻을 수 있으며 N초마다 대부분의 M 요청의 단점은 zset의 데이터 구조가 점점 더 커진다는 것입니다. 구현 방법은 비교적 간단합니다.

세 번째 유형: Redis 기반 토큰 버킷 알고리즘

전류 제한에 관해서라면 토큰 버킷 알고리즘을 언급해야 합니다. 토큰 버킷 알고리즘은 버킷 알고리즘이라고도 합니다. 자세한 내용은 Du Niang의 토큰 버킷 알고리즘 설명을 참조하세요

토큰 버킷 알고리즘은 입력 속도와 출력 속도를 언급합니다. 트래픽 제한이 초과되었습니다.

즉, 요청에 액세스할 때마다 Redis에서 토큰을 얻을 수 있다는 것은 토큰을 얻을 수 없다면 한도를 초과하지 않았다는 의미입니다. .

위의 아이디어를 바탕으로 Redis의 List 데이터 구조를 결합하여 이러한 코드를 쉽게 구현할 수 있습니다

목록의 leftPop을 사용하여 토큰을 얻습니다

// 输出令牌
public Response limitFlow2(Long id){
 Object result = redisTemplate.opsForList().leftPop("limit_list");
 if(result == null){
 return Response.ok("当前令牌桶中无令牌");
 }
 return Response.ok(articleDescription2);
 }

그런 다음 Java의 예약된 작업을 사용하여 정기적으로 rightPush를 수행합니다. List 는 물론 토큰도 고유해야 하므로 여기서는 여전히 UUID를 사용하여 생성합니다.

// 10S的速率往令牌桶中添加UUID,只为保证唯一性
 @Scheduled(fixedDelay = 10_000,initialDelay = 0)
 public void setIntervalTimeTask(){
 redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());
 }

요약하자면, 이러한 현재 제한 방법의 경우 처음에 코드를 구현하는 것은 어렵지 않습니다. 인터페이스의 흐름을 제한하고 궁극적으로 웹 사이트를 보호하기 위해 위의 코드를 AOP 또는 필터에 사용합니다.

Redis는 실제로 캐싱 및 분산 잠금에만 사용되는 것이 아닙니다. 데이터 구조는 단순히 String, Hash, List, Set 및 Zset이 아닙니다. 관심 있는 사람들은 그의 GeoHash 알고리즘, BitMap, HLL 및 Bloom 필터 데이터(Redis 4.0 이후에 추가됨, Docker를 사용하여 redislabs/rebloom을 직접 설치할 수 있음) 구조에 대해 후속 조치를 취할 수 있습니다.

더 많은 Redis 지식을 보려면 redis 소개 튜토리얼 칼럼을 참고하세요.

위 내용은 Redis는 전류 제한을 어떻게 구현합니까? 3가지 구현 방법 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제