RateLimiter速率了解

RateLimiter

pom 复制代码
<dependency>
	<groupId>com.google.guava</groupId>
	<artifactId>guava</artifactId>
	<version>22.0</version>
</dependency>

这个同名的类在nacos的jar包中也有出现。速率限制于java.util.concurrent.Semaphore功能相反,后者限制并发的访问数量,而不是速率(并发和速率密切相关)。见下面的Little定律

RateLimiter主要由颁发许可证的速率来定义。如果没有额外的配置,许可证将以固定的速率分配,以每秒的许可证定义。许可证将顺利分配,并调整各个许可证之间的延迟,以确保维持配置的费率。可以将RateLimiter配置为有一个预热期,在此期间,每秒发出的许可稳步增加,直到达到稳定的速率。

例如:任务每秒执行不超过2次

java 复制代码
final RateLimiter rateLimiter = RateLimiter.create(2.0); // 速率为"每秒2次许可"
void submitTasks(List<Runnable> tasks, Executor executor) {    
	for (Runnable task : tasks) {      
		rateLimiter.acquire(); // 等待
		executor.execute(task);    
	}  
}

例如:发送一个数据流,控制其速度在每秒为5kb,可以通过每个自己一个许可实现,并指定每秒5000个许可的速率

java 复制代码
final RateLimiter rateLimiter = RateLimiter.create(5000.0); // rate = 5000 permits per second  
void submitPacket(byte[] packet) {    
	rateLimiter.acquire(packet.length);    
	networkService.send(packet);  
}

for循环每秒打印一行,RateLimiter.create(1000);为什么会这样:

应为速率是指定为1000次/秒(类似频率),这个时候你一次要获取1000个凭证,因为这个会阻塞当前获取,所以你要算什么时候能获取到所有凭证的时间为:所需凭证数(1000)÷速率(1000次/秒) = 1秒

java 复制代码
public class TestRateLimiter {

    private static final Logger log = LoggerFactory.getLogger(PostExecutor.class);

    public static void main(String[] args) {
    	// 每秒最多允许1000个操作(每秒只能发送1000个凭证)
        RateLimiter limiter = RateLimiter.create(1000);
        log.info("start");
        for (int i = 0; i < 10; i++) {
        	// 获取1000个凭证,获取不到则等待
            limiter.acquire(1000);
            log.info("I: " + i);
        }
    }
}

在一定时间内获取对应的凭证 ,超时获取不到结束

java 复制代码
private static void tryAcquireTest1(RateLimiter limiter, int i){
	log.info("result: " + limiter.tryAcquire(20, 20000, TimeUnit.MILLISECONDS) + ", " + i);
}


这里的速率是2次每秒,可是我阻塞事件获取20个凭证,意味着10s执行一次,在多线程竞争的情况下,有一个线程多次false结束而且时间也没有达到20s(猜测是不是因为其他两个线程一共获取了40个凭证,意味着这20s之内不会再有新凭证了,所以他就不会非要等到20s才结束获取凭证,就提前结束了),启动两个线程,发现就会交替输出了,但是也出现了多次false的情况

java 复制代码
public class TestRateLimiter {

    private static final Logger log = LoggerFactory.getLogger(PostExecutor.class);

    public static void main(String[] args) {
        RateLimiter limiter = RateLimiter.create(2);
        log.info("start");
        
        Thread t1 = new Thread(()->{tryAcquireTest(limiter);});
        Thread t2 = new Thread(()->{tryAcquireTest(limiter);});
        Thread t3 = new Thread(()->{tryAcquireTest(limiter);});
        t1.start();
        t2.start();
        t3.start();

    }

    private static void tryAcquireTest(RateLimiter limiter){
        for (int i = 0; i < 10; i++) {
            tryAcquireTest1(limiter,i);
        }
    }

    private static void tryAcquireTest1(RateLimiter limiter, int i){
        log.info(Thread.currentThread().getName() + "result: " + limiter.tryAcquire(20, 20000, TimeUnit.MILLISECONDS) + ", " + i);
    }
}




相关推荐
Grey Zeng2 小时前
Java SE 25新增特性
java·jdk·jdk新特性·jdk25
雨白3 小时前
Java 线程通信基础:interrupt、wait 和 notifyAll 详解
android·java
架构师沉默7 小时前
设计多租户 SaaS 系统,如何做到数据隔离 & 资源配额?
java·后端·架构
Java中文社群8 小时前
重要:Java25正式发布(长期支持版)!
java·后端·面试
每天进步一点_JL10 小时前
JVM 类加载:双亲委派机制
java·后端
用户2986985301410 小时前
Java HTML 转 Word 完整指南
java·后端
渣哥10 小时前
原来公平锁和非公平锁差别这么大
java
渣哥10 小时前
99% 的人没搞懂:Semaphore 到底是干啥的?
java
J2K11 小时前
JDK都25了,你还没用过ZGC?那真得补补课了
java·jvm·后端
kfyty72511 小时前
不依赖第三方,不销毁重建,loveqq 框架如何原生实现动态线程池?
java·架构