访问频率限制——桶相关算法

其实业务被攻击过一次之后,我就概览过限流算法一次,当时发现所用的库主要是利用了Golang现成的标准库来做的,没很深入继续研究下去。
前几周回头看这个问题,发现这个库的Readme赫然写着“以前的版本弄错啦,根本提供不了之前说的那些功能, 大家赶紧改改吧”。顿时心里一惊,决定这次抽空好好研究一下。

简单点说,常用的限流算法有两种:令牌桶(token bucket)和漏桶(leaky bucket)。
漏桶:比较像街边小摊的叫号,甭管排了多少人,只能隔一小段时间买一次商品
令牌桶:比较像餐馆的叫号,本来餐馆有一定的容量, 填满之前,顾客都可以进,填满之后,就跟漏桶差不多了。

一般情况下,令牌桶就够用了。你可以定义最初有多少个令牌(burst),并且定义令牌增加的频率(每秒多少个),每次请求来的时候看有没有令牌可用。Golang库里一个好的实现是tollbooth,除了实现限流算法外,还附带了很多方便的方法取ip,header域等。另外,要说明一点,虽然令牌桶算法是一定时间放一个令牌,但是实现的时候,并不需要新开一个goroutine去隔一段时间增加计数(事实上,用户量很小的情况下,完全可以这么做,见官方例子),而是逻辑上计算时间差对应的令牌差额即可,详细可见golang.org/x/time/rate的实现,对CPU和Memory非常友好,所以不用担心并发量大了要怎么办。

不过,上述包里的令牌桶算法有几个限制:

  1. 从写法上看,频率规则必须是以秒为单位。其实他们都会转化成令牌增加速度。例如,1秒10次,那么逻辑上令牌桶里面每0.1秒会增加一个令牌(除非已经满了)。你当然可以设置成1分钟60次,但最终都会转化成1秒1次。
  2. 从定义上可以看出,它并不能精确限制每个时间单位的个数。例如,定义桶里3个令牌, 每秒新增2个令牌, 那么一秒内(闭区间的话,意味着首尾跨越了一个间隔),可能有2(0 + 2,对应开始时是空桶)到 5(3 + 2, 对应开始时是满桶)个令牌,设定值时,需要注意这点。

有点迷糊?不要慌,下面举个栗子。比如,需要实现“每分钟60个请求”,可能令牌桶并不能特别好的胜任。 假设桶满是20个(相当于一个buffer), 每分钟新增40, 那么就是60个了。但是,爆发的最大值(几乎同一时刻请求)其实达不到60, 因为桶最多就20。同时,如果桶空了,其后的一分钟最多只能接受40个请求。
所以, 爆发值太大,会造成每分钟的请求限制抖动很大。爆发值设置太小,又可能扛不住突然的大量访问。

这该如何是好?下面要讲的东西还有一些,那就下回分解吧。


更新:
重读文章的时候发现之前的理解有误。

对于每分钟60次这样的限制,其实就是设置每秒1次的速率即可。桶大小(Burst)只是用来处理突发的大请求的,即最多一次处理满桶那么多请求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 一、写在最前 轰轰烈烈的双十二已经过去小半个月了,程序猿的我坐在办公桌上思考,双十二这么大的访问量,这群电商是怎么...
    爱情小傻蛋阅读 12,457评论 0 13
  • 摘要:在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。而有些场景并不能用缓存和降级来解决,因此需有一种...
    落羽成霜丶阅读 6,466评论 0 18
  • 最近一直都在研究压力测试客户端的问题,如果突破客户端压力测试线程,端口等问题,如果服务器端处理网络请求处理不过来,...
    望月成三人阅读 12,756评论 1 25
  • 聊聊高并发系统限流特技-1来自开涛的博客 在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。缓存的目的是...
    meng_philip123阅读 11,705评论 1 20
  • 三十立什么? 三十岁的人,应该能依靠自己的本领独立承担起自己应承受的责任,并已经确定自己的人生目标与发展方向。简单...
    小叶榕阅读 3,499评论 0 0

友情链接更多精彩内容