一、限流是高可用的利器之一
众所皆知,限流是通过对某段时间(如双11)的大流量请求进行限速,以此达到保护系统的目的。大促之前,我们可以通过压测等手段测出系统当前最大承受的处理阈值,即峰值QPS/TPS,一旦流量达到峰值,我们可以实施降级,比如让用户排队等待,稍后再试。下面就来详细聊聊限流的常用算法和实施策略。
二、限流算法
常见的限流算法有令牌桶,漏桶。计数器、信号量也可以用来做简单的限流。
1.令牌桶算法
令牌桶算法的基本过程如下(摘自百度百科):
1.假如用户配置的平均发送速率为r,则每隔1/r秒一个令牌被加入到桶中;
2.假设桶最多可以存发b个令牌。如果令牌到达时令牌桶已经满了,那么这个令牌会被丢弃;
3.当一个n个字节的数据包到达时,就从令牌桶中删除n个令牌,并且数据包被发送到网络;
4.如果令牌桶中少于n个令牌,那么不会删除令牌,并且认为这个数据包在流量限制之外;
5.算法允许最长b个字节的突发,但从长期运行结果看,数据包的速率被限制成常量r。对于在流量限制外的数据包可以以不同的方式处理:
它们可以被丢弃;
它们可以排放在队列中以便当令牌桶中累积了足够多的令牌时再传输;
它们可以继续发送,但需要做特殊标记,网络过载的时候将这些特殊标记的包丢弃。
2.漏通算法
漏桶算法的基本过程如下(摘自百度百科):
1、队列接收到准备转发的数据包。
2、队列被调度,得到转发机会。由于队列配置了流量整形,队列中的数据包首先进入漏桶中。
3、根据数据包到达漏桶的速率与漏桶的输出速率关系,确定数据包是否被转发。漏桶的输出速率是恒定的。
如果到达速率≤输出速率,则漏桶不起作用。
如果到达速率>输出速率,则需考虑漏桶是否能承担这个瞬间的流量。
1) 若数据包到达的速率-漏桶流出的速率≤配置的漏桶突发速率,则数据包可被不延时的送出。
2) 若数据包到达的速率-漏桶流出的速率>配置的漏桶突发速率,则多余的数据包被存储到漏桶中。暂存在漏桶中的数据包在不超过漏桶容量的情况下延时发出。
3) 若数据包到达的速率-漏桶流出的速率>配置的漏桶突发速率,且数据包的数量已经超过漏桶的容量,则这些数据包将被丢弃。
3.令牌桶算法和漏桶算法的区别
漏桶算法与令牌桶算法在表面看起来类似,很容易将两者混淆。但事实上,这两者具有截然不同的特性,且为不同的目的而使用。漏桶算法与令牌桶算法的区别在于:
1.漏桶算法能够强行限制数据的传输速率。
2.令牌桶算法能够在限制数据的平均传输速率的同时还允许某种程度的突发传输。
需要说明的是:在某些情况下,漏桶算法不能够有效地使用网络资源。因为漏桶的漏出速率是固定的,所以即使网络中没有发生拥塞,漏桶算法也不能使某一个单独的数据流达到端口速率。因此,漏桶算法对于存在突发特性的流量来说缺乏效率。而令牌桶算法则能够满足这些具有突发特性的流量。通常,漏桶算法与令牌桶算法结合起来为网络流量提供更高效的控制。
三、应用级限流
1.限流系统总并发/连接/请求数
峰值QPS/TPS
2.限制总资源数
数据库连接池,线程池等
3.限制某个接口的总并发/请求数
秒杀抢购业务接口
4.限制某个接口的时间窗请求数
限制每秒/每分钟/每天调用接口的请求数
平滑限流某个接口的请求数
流量速率整形,突发流量整形为平均速度流量,常见的有Guava的RateLimter令牌桶算法实现。
四、分布式限流
实现方案:Redis+Lua
Redis放计数器,Lua写原子化的脚本
五、接入层限流
nginx的limit_conn模块和limit_req模块,对连接数和请求数进行限制。
参考资料:
《亿级流量网站架构核心技术》
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。