이 글에서는 Redis에서 전류 제한을 구현하는 세 가지 방법을 소개합니다. 도움이 필요한 친구들이 모두 참고할 수 있기를 바랍니다.
【관련 권장 사항: Redis 비디오 튜토리얼】
동시성 시나리오가 점점 많아지는 상황에서 전류 제한 표시는 특히 중요합니다.
물론 전류 제한을 구현하는 방법은 여러 가지가 있습니다. Redis에는 매우 강력한 기능이 있습니다. 저는 Redis를 사용하여 비교적 간단한 방법으로 구현할 수 있는 세 가지 구현 방법을 연습했습니다. Redis는 전류 제한을 수행할 수 있을 뿐만 아니라 나중에 작성할 수 있는 데이터 통계, 주변 사람 및 기타 기능도 수행할 수 있습니다.
첫 번째: Redis 기반 Setnx 작업
Redis 분산 잠금을 사용할 때 CAS(비교 및 교환) 작업 중에 setnx 지침에 의존하고 동시에 만료 시간을 설정한다는 사실을 모두가 알고 있습니다. 지정된 키에 대한 연습(만료) 전류 제한의 주요 목적은 단위 시간 내에 N개의 요청만 내 코드 프로그램에 액세스하도록 허용하는 것입니다. 따라서 setnx를 사용하면 이 기능을 쉽게 얻을 수 있습니다.
예를 들어 10초 내에 20개의 요청을 제한해야 한다면 nx를 설정할 때 만료 시간을 10으로 설정할 수 있습니다. 요청된 setnx 수가 20에 도달하면 현재 제한 효과가 달성됩니다. 코드는 비교적 간단하므로 표시하지 않습니다.
구체적인 setnx 사용법은 내 다른 블로그인 RedisTemplate의 Redis 분산 잠금으로 인한 일련의 문제를 참조하세요.
물론 이 접근 방식에는 많은 단점이 있습니다. 예를 들어 1-10초를 계산할 때 2- 11개는 셀 수 없습니다. N초 내에 M개의 요청을 계산해야 한다면 Redis
두 번째: Redis 기반 데이터 구조 zset
에 N 키와 기타 문제를 유지해야 합니다. 전류 제한에는 슬라이딩 윈도우가 포함됩니다. 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 데이터 구조를 결합하여 이러한 코드를 쉽게 구현할 수 있습니다. 이는 단순한 구현일 뿐입니다.
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 토큰에서 토큰도 고유해야 하므로 여기서는 여전히 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 전류 제한의 세 가지 구현 방법에 대한 간략한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!