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实现 LeetCode 16 最接近的三数之和

    16. 最接近的三数之和 给定一个包括 n 个整数的数组 nums 和 一个目标值 target.找出 nums 中的三个整数,使得它们的和与 target 最接近.返回这三个数的和.假定每组输入只存 ...

  2. java实现自行车行程

    ** 自行车行程** 计算行程 低碳生活,有氧运动.骑自行车出行是个好主意.小明为自己的自行车装了个计数器,可以计算出轮子转动的圈数.在一次骑车旅行中,出发时计算器的示数为begin,到达目的地时的示 ...

  3. JS变量小总

    变量分类:1.栈内存(stack)和堆内存(heap)2.基本类型和引用类型 #栈内存(stack) 一般为静态分配内存,其分配的内存系统自动释放. #堆内存(heap) 一般为动态分配内存,其分配的 ...

  4. springboot实现定时任务,异步操作,统一结果返回,全局异常处理,拦截器及事务处理

    本文是作者原创,版权归作者所有.若要转载,请注明出处. 本文都是springboot的常用和实用功能,话不多说开始吧 定时任务 1.启动类开启注解 @EnableScheduling //开启基于注解 ...

  5. (前言一)HTTP报文

    01 概述 客户端与服务器端之间的通信,通过HTTP协议,以HTTP报文的形式来实现数据的交互. HTTP报文是HTTP通信时发送的数据块,本文主要从以下几个方面介绍HTTP报文:HTTP报文结构.方 ...

  6. JSP基础知识点(转传智)

    一.JSP概述    1.JSP:Java Server Pages(运行在服务器端的页面).就是Servlet.    学习JSP学好的关键:时刻联想到Servlet即可.    2.JSP的原理  ...

  7. css布局相关:涉及到常见页面样式难点

    一.display:table用法 Table:display:tableBody:table-row-group;Tr: table-row;Td: table-cell https://www.c ...

  8. Excel怎样根据出生日期,快速计算出其年龄呢?

    问题:怎样根据出生日期,快速计算出其年龄呢? 方法:DATEDIF函数 Step1:在编辑栏中输入公式:=DATEDIF(E2,TODAY(),”Y”),按回车键. Step2:用鼠标向下拖拽复制公式 ...

  9. selenium获取图片验证码

    # encoding:utf-8 from PIL import Image from selenium import webdriver url = '网站地址' driver = webdrive ...

  10. 曹工改bug:centos下,mongodb开机不能自启动,systemctl、rc.local都试了,还是不行,要不要放弃?

    问题背景 最近装个centos 7.6的环境,其中,基础环境包括,redis.nginx.mongodb.fastdfs.mysql等,其中,自启动使用的是systemctl,其他几个组件,都没啥问题 ...