关于限流的一些学习与思考

最近在做库存的时候,写了一篇文章http://blog.csdn.net/love_onon/article/details/51384386 ,之后发现还是有点lower,就想着再学习学习。

当时使用了线程池来做限流的一种方式,也就是服务器固定处理这么多,再多你就在队列等着,其实这是一种容量控制的方式,关于容量java有Semaphore(信号量)和Metux 2种,关于Semaphore和Mutex2有一个很好的比喻,也就是厕所钥匙理论。

Semaphore是一个拥有N个蹲位的厕所,每个蹲位都需要钥匙才能打开,也就是说这个厕所最多能够容纳N个人来上厕所,再多就只能排队了,对于这N个人呢,厕所有一个机制,每一个人能够去蹲坑了,就给他发一枚钥匙,他自己拿着就行,然后进去之后,锁上门即可,他离开之后呢,把钥匙一起带走,再下一个人来的时候呢,厕所给这个新来人的人也是一把钥匙。

那这里其实是有一个问题的,使用semaphore我要去排队的时候,我得预估一下我要等多久,这点可以做一个系统超时的处理,使用Little原理,初步估算出我还要等多久我才能得到钥匙然后去蹲坑,如果他自己觉得估算的时间我还没有得到钥匙,那他就要拉到裤子里了,这样的话,要排队的时候就不会继续去排队了,直接去找别的厕所。

上面的比喻可以看出,Semaphore是不需要再本进程关闭的。

pool是Semaphore的一种实现,这样就可以理解了,其实我一开始写的那篇文章,就是类似于Semaphore的。他是固定容量的。

Metux是一个只有一把钥匙一个蹲位的厕所,每一个人需要获得钥匙才能蹲坑,他蹲完了,需要把钥匙给排队的人,获得钥匙的人才能蹲坑,这一点决定了Metux只能在本进程释放锁。

Semaphore主要用于固定资源的处理,就那么多,都占满了,就只能等着。也可以用做在远程通信的时候,如果所调用的系统的性能是有瓶颈的,我们可以设置一个阈值,当超过这个阈值,就只能等待了,因为所调用系统就这么点处理量,再多,调用系统就会有压力,进而影响本身系统。当然对于这种漏桶算法也是可以的,只是Semaphore保证我就只有这么多资源,我能保证这么多资源一直都处理着,而漏桶算法是我以固定速度给你放请求,不管你处理完没有,系统还行不行。使用哪一种,需要根据自己的业务区定。

用信号量来做限流,如果你有10台服务器,需要控制每台的限流机制都不一样,即动态调整限流量:因为Semaphore是初始化的时候给定流量,我们可以设定阈值,如果超过再去创建Semaphore,这里的信号量值,可以根据IP去配置,但是也只能是人为去判断值的大小。

再仔细研究会发现,其实在流量限制方面有2种算法是比较流行的,漏桶算法和令牌算法。

漏桶关注的是固定的处理,


就像一个大桶下面有一个洞,不管桶里面有多少水,他永远只会一直流这个洞这么多量的水,一直流,直到流完为止。

至于漏桶算法,我们可以有简单的实现,就是每秒定时从一个容器中拿出N条来处理,我拿出这N条马上就处理,不用管上一次的N条执行到什么程度。

图1(慢慢再画)

令牌算法是对处理速率的限制,思想是每秒往一个容器里面放固定量的令牌即固定速率放令牌,每一个进入系统的请求都需要获取到令牌才能进行处理。

图2(慢慢再画)

他关注的是系统每秒处理的量,限制速率,有2种限制方式,一种是限制入的速率(CAR),一种是限制出的速率(GTS),关于CAR其实就是没有获取到令牌就丢弃,而GTS的话,是获取到令牌,如果超过我们固定的速率的话,就放到队里里面,当然如果队列满了依然丢弃。

从上面2种算法可以看出,都可以限制流量,但是对于有业务突增这样的场景,显然漏桶算法是不合理的,令牌算法能够满足,因为令牌是一个固定速率放令牌,就意味着他可以积累令牌。

令牌算法的实现有Guava有RateLimiter实现。但是漏桶算法的实现还没有找到合适的,当然了RateLimiter也可以去实现漏桶算法。


当然对于限流方面来说,缓存也是需要考虑的,能复用的就复用,Guava cache 、redis 、memcache都是不错的,根据存储数据去选择。对于请求的执行也可以分库分表。



你可能感兴趣的:(限流)