其实,无论在实际工作生活中还是在之前学习过的知识中,你都可能对限流策略有过应用,我给你举几个例子。
限流策略就像是景区限制每天售卖门票数量或者地铁限制进站人数一样,通过控制一段时间内的流量,来避免系统或者场所因为拥挤而影响服务质量或者安全。这种策略可以确保系统或者场所在高峰时段不会被过多的用户或者游客挤爆,保证了服务的稳定性和可靠性。
TCP协议中的滑动窗口就像接收方的一个缓冲区,用来控制发送方发送数据的速度。如果接收方处理速度慢,滑动窗口就变小,限制发送方发送数据的量,避免数据堆积和网络拥塞。
在TCP协议中,接收方回复发送方的ACK消息中会携带滑动窗口的大小。这个滑动窗口大小告诉发送方,接收方目前的处理能力和缓冲区的剩余空间。发送方根据这个窗口大小来决定发送数据的速率。如果接收方处理了部分缓冲区的数据,滑动窗口就会增大,发送方可以加快发送数据的速率。反之,如果接收方的缓冲区快满了,滑动窗口就会减小,发送方会减慢发送数据的速率,以避免数据丢失或网络拥塞。
图片
你应该知道的限流算法
固定窗口与滑动窗口的算法
我们知道,限流的目的是限制一段时间内发向系统的总体请求量,比如,限制一分钟之内系统只能承接 1 万次请求,那么最暴力的一种方式就是记录这一分钟之内访问系统的请求量有多少,如果超过了 1 万次的限制,那么就触发限流的策略返回请求失败的错误。如果这一分钟的请求量没有达到限制,那么在下一分钟到来的时候先重置请求量的计数,再统计这一分钟的请求量是否超过限制。
图片
粗粒度控制: 固定窗口算法在限流时只考虑了一个固定的时间窗口,例如每秒或每分钟,这种粗粒度的控制可能会导致在时间窗口开始的瞬间发生突发的流量,而在窗口结束时没有流量的情况,无法灵活应对。
突发请求问题: 固定窗口算法无法很好地处理突发性的请求,在窗口期开始时可能会集中出现大量请求,导致瞬间达到限流阈值,而在接下来的时间段内无法再接受新的请求,造成了资源的浪费和服务的不公平性。
漏桶算法与令牌筒算法
漏桶算法的原理很简单,它就像在流量产生端和接收端之间增加一个漏桶,流量会进入和暂存到漏桶里面,而漏桶的出口处会按照一个固定的速率将流量漏出到接收端(也就是服务接口)。
令牌桶算法是一种流量控制算法,其基本原理如下:
图片
定义一个令牌桶,用来存放令牌。
每隔固定时间间隔(1/N秒),向令牌桶中放入一个令牌,直到达到令牌桶的最大容量。
处理请求时,需要从令牌桶中获取一个令牌,如果令牌桶中没有令牌,则拒绝服务或者等待直到有令牌可用。
如果令牌桶中的令牌数量超过了最大容量,新的令牌将不再被放入令牌桶中。
通过令牌桶算法,可以限制请求的处理速率,避免系统突发流量造成的问题。由于令牌桶中令牌的数量有限,因此可以有效控制系统的总体请求量。
图片
在分布式环境下使用令牌桶算法进行限流时,确实需要解决多台机器之间共享令牌数量的问题。通常可以借助分布式缓存或者分布式锁来实现。
对于使用Redis来存储令牌数量的情况,每次请求都需要向Redis请求令牌,可能会增加一定的延迟。为了减少请求Redis的次数,可以采取一些优化策略,比如在每次请求时一次性获取一批令牌,而不是逐个获取。这样可以减少与Redis的交互次数,提高性能。
另外,还可以通过合理设置令牌桶的容量和填充速率,以及调整令牌获取的频率,来平衡系统的稳定性和性能损耗。需要根据具体场景和性能需求进行合理的设计和调优。
总结:
限流是一种常见的服务保护策略,你可以在整体服务、单个服务、单个接口、单个 IP 或者单个用户等多个维度进行流量的控制;
基于时间窗口维度的算法有固定窗口算法和滑动窗口算法,两者虽然能一定程度上实现限流的目的,但是都无法让流量变得更平滑;
令牌桶算法和漏桶算法则能够塑形流量,让流量更加平滑,但是令牌桶算法能够应对一定的突发流量,所以在实际项目中应用更多。