Guava中的RateLimiter可以限制单进程中某个方法的速率,本文主要介绍如何使用,实现原理请参考文档:推荐:超详细的Guava RateLimiter限流原理解析推荐:RateLimiter 源码分析(Guava 和 Sentinel 实现)

1 基于spring-mvc的controller测试限流

完整代码可参考:https://github.com/sxpujs/spring-cloud-examples/tree/master/rest-service

1.1 增加Maven依赖:

<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>

1.2 AccessLimitService 限流Service类

@Service
public class AccessLimitService { // 每秒发出5个令牌
RateLimiter rateLimiter = RateLimiter.create(5.0); /**
* 尝试获取令牌
*/
public boolean tryAcquire() {
return rateLimiter.tryAcquire();
}
}

1.3 控制器类

@RestController
@Slf4j
public class HelloController { @Autowired
private AccessLimitService accessLimitService; @RequestMapping("/access")
public String access() {
if (accessLimitService.tryAcquire()) {
log.info("start");
// 模拟业务执行500毫秒
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "access success [" + LocalDateTime.now() + "]";
} else {
//log.warn("限流");
return "access limit [" + LocalDateTime.now() + "]";
}
}
}

1.4 使用wrk工具模拟客户端发起多个请求

我们使用HTTP基准工具wrk来生成大量HTTP请求。在终端输入如下命令来测试:

wrk -t1 -c10 -d2s http://127.0.0.1:8080/access

服务端日志如下所示(稍做简化),可以看出前6行的执行时间是一样的,这是因为RateLimiter的默认实现SmoothBursty会缓存1秒的许可,在定义RateLimiter实例时,每秒5个许可,加上新占用的1个许可,一共有6个。从第7行开始,每0.2秒执行1次,符合预期。

2020-07-05 15:46:16.605  INFO --- [nio-8080-exec-2] HelloController : start
2020-07-05 15:46:16.605 INFO --- [nio-8080-exec-3] HelloController : start
2020-07-05 15:46:16.605 INFO --- [nio-8080-exec-7] HelloController : start
2020-07-05 15:46:16.605 INFO --- [nio-8080-exec-8] HelloController : start
2020-07-05 15:46:16.605 INFO --- [nio-8080-exec-9] HelloController : start
2020-07-05 15:46:16.605 INFO --- [nio-8080-exec-4] HelloController : start
2020-07-05 15:46:16.804 INFO --- [nio-8080-exec-1] HelloController : start
2020-07-05 15:46:17.005 INFO --- [io-8080-exec-11] HelloController : start
2020-07-05 15:46:17.204 INFO --- [nio-8080-exec-9] HelloController : start
2020-07-05 15:46:17.404 INFO --- [nio-8080-exec-5] HelloController : start
2020-07-05 15:46:17.604 INFO --- [nio-8080-exec-8] HelloController : start
2020-07-05 15:46:17.804 INFO --- [nio-8080-exec-2] HelloController : start
2020-07-05 15:46:18.004 INFO --- [nio-8080-exec-7] HelloController : start
2020-07-05 15:46:18.204 INFO --- [nio-8080-exec-6] HelloController : start
2020-07-05 15:46:18.404 INFO --- [nio-8080-exec-5] HelloController : start

2 基于单个类的main方法测试限流

package com.demo.guava;

import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream; @Slf4j
public class RateLimiterDemo { static void submitTasks1() {
ExecutorService pool = Executors.newFixedThreadPool(10);
RateLimiter rateLimiter = RateLimiter.create(5); // rate is "5 permits per second"
IntStream.range(0, 10).forEach(i -> pool.submit(() -> {
if (rateLimiter.tryAcquire()) {
try {
log.info("start");
Thread.sleep(500);
} catch (InterruptedException e) {
}
} else {
log.warn("限流");
}
}));
pool.shutdown();
/*
16:18:18.784 [pool-1-thread-1] INFO RateLimiterDemo - start
16:18:18.784 [pool-1-thread-7] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-2] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-4] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-5] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-6] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-9] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-3] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-10] WARN RateLimiterDemo - 限流
16:18:18.784 [pool-1-thread-8] WARN RateLimiterDemo - 限流
*/
} static void submitTasks2() {
ExecutorService pool = Executors.newFixedThreadPool(10);
RateLimiter rateLimiter = RateLimiter.create(5); // rate is "5 permits per second"
IntStream.range(0, 10).forEach(i -> pool.submit(() -> {
rateLimiter.acquire();
log.info("start");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}));
pool.shutdown();
/*
16:18:56.030 [pool-1-thread-1] INFO RateLimiterDemo - start
16:18:56.227 [pool-1-thread-10] INFO RateLimiterDemo - start
16:18:56.428 [pool-1-thread-9] INFO RateLimiterDemo - start
16:18:56.627 [pool-1-thread-8] INFO RateLimiterDemo - start
16:18:56.827 [pool-1-thread-7] INFO RateLimiterDemo - start
16:18:57.028 [pool-1-thread-6] INFO RateLimiterDemo - start
16:18:57.226 [pool-1-thread-5] INFO RateLimiterDemo - start
16:18:57.426 [pool-1-thread-4] INFO RateLimiterDemo - start
16:18:57.629 [pool-1-thread-3] INFO RateLimiterDemo - start
16:18:57.826 [pool-1-thread-2] INFO RateLimiterDemo - start
*/
} static void submitTasks3() {
RateLimiter r = RateLimiter.create(5);
log.info("start");
for (;;) {
log.info("get 1 tokens: " + r.acquire() + "s");
}
/*
16:15:46.310 [main] INFO RateLimiterDemo - start
16:15:46.315 [main] INFO RateLimiterDemo - get 1 tokens: 0.0s
16:15:46.513 [main] INFO RateLimiterDemo - get 1 tokens: 0.193752s
16:15:46.709 [main] INFO RateLimiterDemo - get 1 tokens: 0.194875s
16:15:46.911 [main] INFO RateLimiterDemo - get 1 tokens: 0.199033s
16:15:47.113 [main] INFO RateLimiterDemo - get 1 tokens: 0.197833s
16:15:47.312 [main] INFO RateLimiterDemo - get 1 tokens: 0.195898s
*/
} static void submitTasks4() {
RateLimiter r = RateLimiter.create(5);
log.info("start");
for (;;) {
if (r.tryAcquire()) {
log.info("run");
}
}
/*
16:17:17.098 [main] INFO RateLimiterDemo - start
16:17:17.100 [main] INFO RateLimiterDemo - run
16:17:17.296 [main] INFO RateLimiterDemo - run
16:17:17.496 [main] INFO RateLimiterDemo - run
16:17:17.696 [main] INFO RateLimiterDemo - run
*/
} public static void main(String[] args) throws InterruptedException {
//submitTasks1();
submitTasks2();
//submitTasks3();
//submitTasks4();
}
}

参考文档:

Guava RateLimiter限流器使用示例的更多相关文章

  1. ☕【Java技术指南】「并发编程专题」针对于Guava RateLimiter限流器的入门到精通(含实战开发技巧)

    并发编程的三剑客 在开发高并发系统时有三剑客:缓存.降级和限流. 缓存 缓存的目的是提升系统访问速度和增大系统处理容量. 降级 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问题 ...

  2. Java技术开发专题系列之【Guava RateLimiter】针对于限流器的入门到精通(针对于源码分析介绍)

    Guava包中限流实现分析 RateLimiter 之前的文章中已经介绍了常用的限流算法,而google在Java领域中使用Guava包中的限流工具进行服务限流. 回顾使用案例 Google开源工具包 ...

  3. 超详细的Guava RateLimiter限流原理解析

    超详细的Guava RateLimiter限流原理解析  mp.weixin.qq.com 点击上方“方志朋”,选择“置顶或者星标” 你的关注意义重大! 限流是保护高并发系统的三把利器之一,另外两个是 ...

  4. 常用限流算法与Guava RateLimiter源码解析

    在分布式系统中,应对高并发访问时,缓存.限流.降级是保护系统正常运行的常用方法.当请求量突发暴涨时,如果不加以限制访问,则可能导致整个系统崩溃,服务不可用.同时有一些业务场景,比如短信验证码,或者其它 ...

  5. 使用Guava RateLimiter限流入门到深入

    前言 在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流 缓存: 缓存的目的是提升系统访问速度和增大系统处理容量 降级: 降级是当服务出现问题或者影响到核心流程时,需要暂时屏蔽掉,待高峰或者问 ...

  6. 限流 - Guava RateLimiter

    2019独角兽企业重金招聘Python工程师标准>>> 限流 限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦并发访问/请求达到限制速率或者 ...

  7. Guava RateLimiter实现接口API限流

    一.简介 Guava提供的RateLimiter可以限制物理或逻辑资源的被访问速率.RateLimit二的原理类似与令牌桶,它主要由许可发出的速率来定义,如果没有额外的配置,许可证将按每秒许可证规定的 ...

  8. 限流神器之-Guava RateLimiter 实战

    前段时间,项目中需要对某些访问量较高的路径进行访问并发数控制,以及有些功能,比如Excel导出下载功能,数据量很大的情况下,用户不断的点击下载按钮,重复请求数据库,导致线上数据库挂掉.于是在这样的情况 ...

  9. Guava之FluentIterable使用示例

    FluentIterable 是guava集合类中常用的一个类,主要用于过滤.转换集合中的数据:FluentIterable是一个抽象类,实现了Iterable接口,大多数方法都返回FluentIte ...

随机推荐

  1. java代码(10) ---Java8 Map中的computeIfAbsent方法

    Map中的computeIfAbsent方法 一.案例说明 1.概述 在JAVA8的Map接口中,增加了一个computeIfAbsent,此方法签名如下: public V computeIfAbs ...

  2. Volcano火山:容器与批量计算的碰撞

    [摘要] Volcano是基于Kubernetes构建的一个通用批量计算系统,它弥补了Kubernetes在“高性能应用”方面的不足,支持TensorFlow.Spark.MindSpore等多个领域 ...

  3. 总结梳理:webpack中如何使用vue

    1. 安装vue的包 cnpm i vue -S  2. 由于在webpack中,推荐使用 .vue这个组件模板文件定义的组件,所以,需要安装,   能解析这个文件的loader: cnpm i vu ...

  4. 【扯皮系列】一篇与众不同的 String、StringBuilder 和 StringBuffer 详解

    碎碎念 这是一道老生常谈的问题了,字符串是不仅是 Java 中非常重要的一个对象,它在其他语言中也存在.比如 C++.Visual Basic.C# 等.字符串使用 String 来表示,字符串一旦被 ...

  5. org.apache.maven.plugins:maven-archetype-plugin:RELEASE:generate——解决方案汇总

    近期将自己本地的 maven 仓库进行了迁移,idea 的版本也升级到了IntelliJ IDEA 2019.3.3 x64,但是遇到了 Plugins 报红的情况,尝试很多方法,终于解决,现在做一下 ...

  6. 构造函数,拷贝构造和赋值运算符调用时机,explicit,

    #include<iostream> #include <stdio.h> using namespace std; class test{ int mvalue; publi ...

  7. VS2019制作的安装包,默认安装到C盘快捷方式无法打开

    先讲讲如何制作安装包 1.下载Visual Studio Installer 1)下载链接https://marketplace.visualstudio.com/items?itemName=Vis ...

  8. logrotate 如何执行日志按照大小切分

    说在最先的话,logrotate要设置按照文件大小来配置日志切分,需要通过三个东西. 1.配置logrotate 的配置文件 命名未任意文件,在启动的时候指定,例如/etc/weblog.conf 参 ...

  9. 一个简单的CSS登录页

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. 在Unix系统中执行可执行文件

    这篇文章是我在一个叫做Charlotte数据挖掘的公众号上看到的文章,文首提到转载自"朱小厮的博客",当我今天执行一个自己编译的可执行文件后的运行阶段想到了这篇文章,直接一次成功. ...