예를 들어 애플리케이션의 QPS가 1000을 초과하지 않기를 바라는 경우 RateLimiter가 속도를 1000으로 설정한 후에는 초당 1000개의 토큰이 버킷에 던져지는 경우가 많습니다. 일부 물리적 리소스 또는 논리적 리소스의 액세스 속도의 영향을 제한합니다.
현재 독립 실행형 버전의 제한을 위해 Google의 오픈 소스 Guava 프로젝트를 사용할 수 있습니다. 이 프로젝트는 컬렉션, 캐싱 및 동시 프로그래밍 라이브러리(동시성)를 포함하여 Google이 Java 프로젝트에서 사용하는 일부 핵심 라이브러리를 제공합니다. ), 일반적인 주석, 문자열 작업 및 I/O 작업의 매우 실용적인 여러 기능을 제공합니다.
이 프로젝트에는 토큰 버킷 알고리즘을 기반으로 구현된 전류 제한 기능도 포함되어 있습니다.
는 두 가지 전류 제한 전략을 제공합니다.
● 부드러운 버스트 전류 제한(SmoothBursty)
● 부드러운 예열 전류 제한(SmoothWarmingUp) 구현.
종속성:
<dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>29.0-jre</version> </dependency>
방법 설명:
시나리오 1:
특정 인터페이스의 초당 방문 횟수가 10회를 넘지 않기를 바라는 경우
package org.xhs.test; import org.apache.curator.shaded.com.google.common.util.concurrent.RateLimiter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.*; /** * @Author: hu.chen * @Description: **/ public class Test { /** * 存储接口名和令牌生成器的对应关系 */ private static Map<String, RateLimiter> interfaces = new ConcurrentHashMap<>(); /** * 线程池 */ private static ExecutorService threadPool = new ThreadPoolExecutor(10,15,3,TimeUnit.SECONDS,new ArrayBlockingQueue<>(100)); public static void main(String[] args) throws InterruptedException { List<UserRequest> tasks = new ArrayList<UserRequest>(); // 准备工作,先初始化 10个线程(用户),这10个用户同时访问一个接口 for (int i = 1; i <= 12; i++) { String ip = "127.0.0." + i; String userName="chenhu_"+i; String interfaceName="user/find_"; tasks.add(new UserRequest(ip,userName,interfaceName)); } // 先初始化好令牌生成器 for (UserRequest request : tasks) { // 根据接口名限流 RateLimiter rateLimiter = interfaces.get(request.getInterfaceName()); if(rateLimiter==null){ // 创建一个令牌生成器,每秒产生10个令牌 synchronized (interfaces) { if(rateLimiter==null) { rateLimiter = RateLimiter.create(10); // 将这个令牌生成器和具体的接口进行绑定 interfaces.put(request.getInterfaceName(),rateLimiter); } } } } // 休眠一秒,让令牌生成器先生成令牌 Thread.sleep(1000); for (UserRequest request : tasks) { // 根据接口名限流 RateLimiter rateLimiter = interfaces.get(request.getInterfaceName()); // 获取令牌桶中一个令牌,如果获取不到,则等待 timeout 时间,如果还获取不到,则返回false,反之则返回true // timeout设置为0,表示不等待 if(rateLimiter.tryAcquire(1,0,TimeUnit.SECONDS)){ // 得到令牌,处理请求 threadPool.execute(()->{ System.err.println("接口:"+request.getInterfaceName()+" 访问还未达到上限,"+request.getUserName()+"可以访问"); }); }else { // 已经等待了10秒还获取不到令牌,进行其他业务处理 System.err.println("当前时间访问失败,"+request.getUserName()+"无法获取令牌"); } } } private static class UserRequest { /** * 请求用户ip */ private String ip; /** * 用户名 */ private String userName; /** * 请求的接口名 */ private String interfaceName; public UserRequest(String ip, String userName, String interfaceName) { this.ip = ip; this.userName = userName; this.interfaceName = interfaceName; } public String getIp() {return ip;} public String getUserName() { return userName;} public String getInterfaceName() {return interfaceName;} } }
시나리오 2:
특정 사용자나 IP의 초당 방문 횟수가 10회를 넘지 않기를 원하는 경우
package org.xhs.test; import org.apache.curator.shaded.com.google.common.util.concurrent.RateLimiter; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.*; /** * @Author: hu.chen * @Description: **/ public class Test { /** * 存储用户名和令牌生成器的对应关系 */ private static Map<String, RateLimiter> interfaces = new ConcurrentHashMap<>(); /** * 线程池 */ private static ExecutorService threadPool = new ThreadPoolExecutor(10,15,3,TimeUnit.SECONDS,new ArrayBlockingQueue<>(100)); public static void main(String[] args) throws InterruptedException { List<UserRequest> tasks = new ArrayList<UserRequest>(); // 准备工作,先初始化 10个线程(用户),这10个用户同时访问一个接口 for (int i = 1; i <= 12; i++) { String ip = "127.0.0." + i; String userName="chenhu_"; String interfaceName="user/find_"+i; tasks.add(new UserRequest(ip,userName,interfaceName)); } // 先初始化好令牌生成器 for (UserRequest request : tasks) { // 根据接口名限流 RateLimiter rateLimiter = interfaces.get(request.getUserName()); if(rateLimiter==null){ // 创建一个令牌生成器,每秒产生5个令牌 synchronized (interfaces) { if(rateLimiter==null) { rateLimiter = RateLimiter.create(10); // 将这个令牌生成器和具体的接口进行绑定 interfaces.put(request.getUserName(),rateLimiter); } } } } // 休眠一秒,让令牌生成器先生成令牌 Thread.sleep(1000); for (UserRequest request : tasks) { // 根据接口名限流 RateLimiter rateLimiter = interfaces.get(request.getUserName()); // 获取令牌桶中一个令牌,如果获取不到,则等待 timeout 时间,如果还获取不到,则返回false,反之则返回true // timeout设置为0,表示不等待 if(rateLimiter.tryAcquire(1,0,TimeUnit.SECONDS)){ // 得到令牌,处理请求 threadPool.execute(()->{ System.err.println("用户:"+request.getUserName()+" 当前时间访问次数还未达到上限,可以访问"); }); }else { // 已经等待了10秒还获取不到令牌,进行其他业务处理 System.err.println("当前时间访问失败,"+request.getUserName()+"无法获取令牌"); } } } private static class UserRequest { /** * 请求用户ip */ private String ip; /** * 用户名 */ private String userName; /** * 请求的接口名 */ private String interfaceName; public UserRequest(String ip, String userName, String interfaceName) { this.ip = ip; this.userName = userName; this.interfaceName = interfaceName; } public String getIp() {return ip;} public String getUserName() { return userName;} public String getInterfaceName() {return interfaceName;} } }
위 내용은 Java에서 단일 머신 전류 제한을 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!