背景算法
最近了解到不少朋友对限流、熔断、降级、隔离、超时重试的概念和应用场景理解的不是很到位,因此想用五篇的篇幅稍微系统的介绍一下。编程
本篇是第一篇,是限流作详解,若是反馈好的话,我会继续写下面四篇。很差的话就算了,算我理解不够,再本身总结总结。编程语言
限流的概念微服务
有朋友问我限流和熔断有什么区别,个人理解很简单。限流做用是防护上游流量超过处理能力的手段,熔断做用是容错下游的快速失败手段。工具
举个生活中的限流例子:ui
小A最近打算找个女友,他拜托了不少朋友帮本身介绍,朋友们也很给力,不少姑娘都愿意和小A聊一聊。小A发现时间忙不开了,他就制定了一个计划,一天见2个。这就是限流。3d
举个生活中的熔断例子:对象
小A在见这些姑娘的时候,若是有的姑娘不守时,超过约定时间半小时尚未出现,那小A就会离开。否则会耽误见下一位姑娘,这是一种熔断手段。另外,若是有的姑娘特别能说,聊天超过了3小时,小A也会打断姑娘,把姑娘先送走,否则也会耽误见下一位姑娘。这也是须要的熔断措施。blog
限流的原理token
无论任何编程语言的实现,目前主流的底层就是基于令牌桶算法和漏斗算法。这两种算法达到的效果有所不一样。
令牌桶算法
令牌桶算法是先有个固定容量的桶,一个任务会以固定的速率往桶里放token,请求来了会去取token。若是桶满了,token就溢出了。多出来的token就不要了。若是请求太快,token生产速度跟不上消费速率,桶空了,有的请求取不到token,这时候就会直接返回错误而不继续处理。
举个例子:
好比小A最后找到了心仪的女友小C。他俩相处融洽,一块儿包饺子吃。小A负责擀皮,小C负责包。小A会把擀好的皮放到一块案板上。这个案板能够放20张皮。若是皮擀多了,就放不下,这时候小A就会停下来等。若是皮擀的慢,小C没的包,也就只能停下来。这里的皮就至关因而token,包饺子就至关因而处理业务的请求。用图表示以下:
漏斗算法
漏斗算法也是先有个固定容量的桶,请求来了先通过桶,从桶里出去的速率是必定的。若是请求量让桶满了,多出来的请求就不处理了。若是桶是空的,新来的请求就能立刻处理。
事实上,各类MQ好比kafka就是典型漏斗算法。broker就是这个固定容量的桶,生产者会不断的将数据写到broker里,消费者是采用的拉取模式,老是以固定的速率来消费。
令牌桶算法和漏洞算法的比较
限流的实现
基础实现
在Java中业界用的比较多的是Google出品的Guava RateLimiter和另外的一款resilience4j-ratelimiter来实现限流。原理差很少。
下面以RateLimiter为例进行讲解。要实现一个限流总共须要用到RateLimiter的两个方法:
1>RateLimiter.create() 静态方法建立对象,初始化桶容量
2>acquire()或者tryAcquire() 获取请求token,二者使用一个便可。acquire方法是阻塞式的,用来实现漏斗算法;tryAcquire是非阻塞式的,用来实现令牌桶算法。
阻塞式是若是到达指定条件前一直不返回结果,经过下面的源码可看到内部其实是用sleep来实现的阻塞。由于全部的请求获取权限时都会sleep固定的时间才返回,就达到了匀速的目的。
非阻塞是当即返回是否获取到权限(token)。这时候请求若是获取权限成功就处理请求,获取权限失败就直接返回一个自定义的快速失败处理方式。平时请求速率小于token产生速率,桶渐渐满了。一旦有突发流量,由于桶里有存量token,也能够直接获取到权限,就是为何令牌桶算法能够应对突发流量的原理。
高阶实现
上面实现里讲的是工具组件,若是只使用工具组件有个问题。限流实际上须要按期进行容量评估,是一个动态的过程,若是只使用工具组件就须要每次修改代码。固然也能够将每一个值写到一个统一配置里,好比zookeeper来进行管理。
若是规模大的状况下更好的一个解决方法是使用专门的平台。这个平台能够支撑更多维度的配置,好比集群维度的限流。集群维度和单机维度的区别是若是设置了一个总的阈值,系统能够根据机器资源状况自动计算出每台机器的限流状况。
在业界,阿里有个sentinel,有人称为微服务哨兵。它是一套更完整的生态,除了我上面提到的功能以外,还提供了动态系统保护、热点限流等功能。