之前在学习的时候也接触不到高并发/大流量这种东西,所以限流当然是没接触过的了。在看公司项目的时候,发现有用到限流(RateLimiter),顺带了解一波。

一、限流基础知识介绍

为啥要限流,相信就不用我多说了。

  • 比如,我周末去饭店吃饭,但是人太多了,我只能去前台拿个号,等号码到我的时候才能进饭店吃饭。如果饭店没有限流怎么办?一到饭点,人都往里冲,而饭店又处理不了这么多人流,很容易就出事故(饭店塞满了人,无路可走。饭店的工作人员崩溃了,处理不过来)
  • 回到代码世界上也是一样的,服务器能处理的请求数有限,如果请求量特别大,我们需要做限流(要么就让请求等待,要么就把请求给扔了)

在代码世界上,限流有两种比较常见的算法:

  • 令牌桶算法
  • 漏桶算法

1.1 什么是漏桶算法

比如,现在我有一个桶子,绿色那块是我能装水的容量,如果超过我能装下的容量,再往桶子里边倒水,就会溢出来(限流):

我们目前可以知道的是:

  • 桶子的容量是固定的(是图上绿色那块)
  • 超出了桶子的容量就会溢出(要么等待,要么直接丢弃)

OK,现在我们在桶子里挖个洞,让水可以从洞子里边流出来:

桶子的洞口的大小是固定的,所以水从洞口流出来的速率也是固定的

所以总结下来算法所需的参数就两个:

  • 桶子的容量
  • 漏水的速率

漏桶算法有两种实现:

  1. 不允许突发流量的情况:如果进水的速率大于出水的速率,直接舍弃掉多余的水。比如,我的桶子容量能装100L,但我的桶子出水速率是10L/s。此时,如果现在有100L/s的水进来,我只让10L的水进到桶子,其余的都限流。(限定了请求的速度
  2. 允许一定的突发流量情况:我的桶子能装100L,如果现在我的桶子是空的,那么这100L的水都能进我的桶子。我以10L/s的速率将这些水流出,如果还有100L的水进来,只能限流了。

经过上面的分析我们就知道:

漏桶算法可以平滑网络上的突发流量(因为漏水的速率是固定的)

1.2 什么是令牌桶算法

现在我有另外一个桶子,这个桶子不用来装水,用来装令牌:

令牌会一定的速率扔进桶子里边,比如我1秒扔10个令牌进桶子:

桶子能装令牌的个数有上限的,比如我的桶子最多只能装1000个令牌。

每个请求进来,就会去桶子拿一个令牌

  • 比如这秒我有1001个请求,我就去桶子里边拿1001个令牌,此时可能会出现两种情况:

    • 桶子里边没有1001个令牌,只有1000个,那没拿到令牌的请求只能被阻塞了(等待)
    • 桶子里边有1001个令牌,所有请求都可以执行。

令牌桶算法支持网络上的突发流量

漏桶和令牌桶的区别:从上面的例子估计大家也能看出来了,漏桶只能以固定的速率去处理请求,而令牌桶可以以桶子最大的令牌数去处理请求

二、RateLimiter使用

RateLimiter是Guava的一个限流组件,我这边的系统就有用到这个限流组件,使用起来十分方便。

引入pom依赖:

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>20.0</version>
</dependency>

RateLimiter它是基于令牌桶算法的,API非常简单,看以下的Demo:

public static void main(String[] args) {//线程池ExecutorService exec = Executors.newCachedThreadPool();//速率是每秒只有3个许可final RateLimiter rateLimiter = RateLimiter.create(3.0);for (int i = 0; i < 100; i++) {final int no = i;Runnable runnable = new Runnable() {@Overridepublic void run() {try {//获取许可rateLimiter.acquire();System.out.println("Accessing: " + no + ",time:"+ new SimpleDateFormat("yy-MM-dd HH:mm:ss").format(new Date()));} catch (Exception e) {e.printStackTrace();}}};//执行线程exec.execute(runnable);}//退出线程池exec.shutdown();}

我们可以从结果看出,每秒只能执行三个:

三、分布式限流

RateLimiter是一个单机的限流组件,如果是分布式应用的话,该怎么做?

可以使用Redis+Lua的方式来实现,大致的lua脚本代码如下:

local key = "rate.limit:" .. KEYS[1] --限流KEY
local limit = tonumber(ARGV[1])        --限流大小
local current = tonumber(redis.call('get', key) or "0")
if current + 1 > limit then --如果超出限流大小return 0
else  --请求数+1,并设置1秒过期redis.call("INCRBY", key,"1")redis.call("expire", key,"1")return current + 1
end

Java代码如下:

public static boolean accquire() throws IOException, URISyntaxException {Jedis jedis = new Jedis("127.0.0.1");File luaFile = new File(RedisLimitRateWithLUA.class.getResource("/").toURI().getPath() + "limit.lua");String luaScript = FileUtils.readFileToString(luaFile);String key = "ip:" + System.currentTimeMillis()/1000; // 当前秒String limit = "5"; // 最大限制List<String> keys = new ArrayList<String>();keys.add(key);List<String> args = new ArrayList<String>();args.add(limit);Long result = (Long)(jedis.eval(luaScript, keys, args)); // 执行lua脚本,传入参数return result == 1;
}

解释:

  • Java代码传入key和最大的限制limit参数进lua脚本
  • 执行lua脚本(lua脚本判断当前key是否超过了最大限制limit)
    • 如果超过,则返回0(限流)
    • 如果没超过,返回1(程序继续执行)

什么是限流?你真的了解吗?相关推荐

  1. 接口限流:限制接口的访问频率

    限流,顾名思义,就是限制对 API 的调用频率.每一次 API 调用,都要花费服务器的资源,因此很多 API 不会对用户无限次地开放,请求达到某个次数后就不再允许访问了,或者一段时间内,最多只允许访问 ...

  2. 你真的懂Spring Cloud+Nginx秒杀实战,Nginx高性能秒杀和限流吗?

    Nginx高性能秒杀和限流 从性能上来说,内部网关Zuul限流理论上比外部网关Nginx限流的性能会差一些.和Zuul一样,外部网关Nginx也可以通过Lua脚本的形式执行缓存在Redis内部的令牌桶 ...

  3. 面试官:说说RabbitMQ 消费端限流、TTL、死信队列

    欢迎关注方志朋的博客,回复"666"获面试宝典 1. 为什么要对消费端限流 假设一个场景,首先,我们 Rabbitmq 服务器积压了有上万条未处理的消息,我们随便打开一个消费者客户 ...

  4. 面试限流、熔断、高可用,好多人一脸懵!

    欢迎关注方志朋的博客,回复"666"获面试宝典 日常生活中,有哪些需要限流的地方? 像我旁边有一个国家景区,平时可能根本没什么人前往,但是一到五一或者春节就人满为患,这时候景区管理 ...

  5. Alibaba Sentinel限流功能

    以下文章来源方志朋的博客,回复"666"获面试宝典 前言 上周经历了合作方未按照约定在客户端进行缓存,以高QPS调用我这边某个接口的问题,当时带来的影响是接口RT变高,当时如果QP ...

  6. 不得不了解系列之限流

    点击关注公众号,Java干货及时送达 来源:https://my.oschina.net/qiangmzsx/blog/4277685 限流简介 现在说到高可用系统,都会说到高可用的保护手段:缓存.降 ...

  7. 实战:使用Nginx限流

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:深入浅出大型网站架构设计 Nginx不仅可以做Web服务器. ...

  8. 阿里巴巴开源限流降级神器Sentinel大规模生产级应用实践

    作者:丁浪,目前在创业公司担任高级技术架构师.曾就职于阿里巴巴大文娱和蚂蚁金服.具有丰富的稳定性保障,全链路性能优化的经验.架构师社区特邀嘉宾! 前言 互联网上关于限流算法.Sentinel功能介绍. ...

  9. 令牌桶算法和漏桶算法有什么区别_高并发之限流,到底限的什么鬼 (精品长文)...

    你可能知道高并发系统需要限流这个东西,但具体是限制的什么,该如何去做,还是模凌两可.我们接下来系统性的给它归个小类,希望对你有所帮助. google guava中提供了一个限流实现: RateLimi ...

最新文章

  1. Community Server系列之九:CS2中的用户管理1(MemberRole)
  2. Asp.Net统一前后端提示信息方案
  3. 【原创】【专栏】《Linux设备驱动程序》--- LDD3源码目录结构和源码分析经典链接
  4. 结对编程——四则运算过程
  5. 使用Mybatis Generator自动生成代码
  6. redis生产环境持久化_在SageMaker上安装持久性Julia环境
  7. 计算机科学与技术pdf,计算机科学与技术(.PDF
  8. Nordic Collegiate Programming Contest (NCPC) 2016
  9. python自动化常用数字_Python全栈自动化系列之Python编程基础(基本数据类型)
  10. angualr8观察者模式_观察者模式
  11. C++对类或结构体进行指定规则排序
  12. 下个一个语音,计算机.,中国计算机产业的下一个亮点——汉语语音合成的实用化...
  13. UVa 10129 - Play on Words (欧拉回路, DFS)
  14. 电脑拖机,win10一台电脑两人用
  15. opencv下载百度网盘链接及安装
  16. LCD和LED屏幕的工作原理总结
  17. 基于三维激光雷达的二维占据栅格地图构建-简介
  18. 如何给文件夹自定义图标?
  19. 注塑工艺需要考虑的7个因素
  20. Django REST Framework中的Serializer relations

热门文章

  1. 关注各种高级语言虚拟机(high-level language virtual machine,HLL VM)的设计与实现,泛化至各种高级语言的运行时的设计与实现,也会涉及动态编译、GC、动态语言的编
  2. js encodeuricomponent php解码,Javascript下的urlencode编码解码方法附decodeURIComponent
  3. 云渲染是什么?云渲染对于物理渲染有什么好处?
  4. angular $http 参数传递
  5. 美国国家搜索与救援联合会推荐的最低装备表
  6. Canoe中的CAPL代码加密
  7. ijkPlayer播放器快速集成使用
  8. linux c语言 getline,C语言中getline()函数的深入理解
  9. 【无标题】HTML写简单网页
  10. LeetCode之855_考场就座