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中ReentrantLock类的详细介绍(详解)

    博主如果看到请联系小白,小白记不清地址了 简介 ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与synchronized关键字 ...

  2. Java实现二分图的最大权匹配

    1 问题描述 何为二分图的最大权匹配问题? 最大权二分匹配问题就是给二分图的每条边一个权值,选择若干不相交的边,得到的总权值最大. 2 解决方案 解决这个问题可以用KM算法.理解KM算法需要首先理解& ...

  3. Okapi BM25算法

    引言 Okapi BM25,一般简称 BM25 算法,在 20 世纪 70 年代到 80 年代,由英国一批信息检索领域的计算机科学家发明.这里的 BM 是"最佳匹配"(Best M ...

  4. 从linux源码看socket(tcp)的timeout

    从linux源码看socket(tcp)的timeout 前言 网络编程中超时时间是一个重要但又容易被忽略的问题,对其的设置需要仔细斟酌.在经历了数次物理机宕机之后,笔者详细的考察了在网络编程(tcp ...

  5. 滴滴HBase大版本滚动升级之旅

    桔妹导读:滴滴HBase团队日前完成了0.98版本 -> 1.4.8版本滚动升级,用户无感知.新版本为我们带来了丰富的新特性,在性能.稳定性与易用性方便也均有很大提升.我们将整个升级过程中面临的 ...

  6. 「从零单排canal 02」canal集群版 + admin控制台 最新搭建姿势(基于1.1.4版本)

    canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据 订阅 和 消费.应该是阿里云DTS(Data Transfer Service)的开 ...

  7. css3中的@font-face你真的了解吗

    css3中的自定义字体方法@font-face @font-face属性可以让我们自定义网站字体属性,然后引用到想要应用该字体的元素上. 基本语法: @font-face { font-family: ...

  8. CSS文本相关之水平排列[4]

    在正常流中,文本都是从左往右.自上而下排列显示,如果想要改变排列方向的话,可以通过CSS属性来改变. text-align属性 文本排列(text-align)可改变文本在水平上的方向,但不改变内部的 ...

  9. iOS开发实践-OOM治理

    概览 说起iOS的OOM问题大家第一想到的应该更多的是内存泄漏(Memory Leak),因为无论是从早期的MRC还是2011年Apple推出的ARC内存泄漏问题一直是iOS开发者比较重视的问题,比如 ...

  10. 百度文本编辑器的toolbars属性值描述

    toolbars: [    [        'anchor', //锚点        'undo', //撤销        'redo', //重做        'bold', //加粗   ...