文章目录
- 什么是流量控制?
- 分布式系统流量控制策略
- 漏桶策略
- 令牌桶策略
- 两种策略对比
- Sentinel 流量控制工作原理
什么是流量控制?
- 流量控制,如果学过计算机网络的话,第一反应肯定是网络传输中的流量控制。网络传输中的流量控制,就是让发送方发送数据的速率不要太快,让接收方来得及接收数据,具体的实现方法就是滑动窗口。简单来讲,滑动窗口指的是,在任意时刻,发送方都维持一个连续的允许发送的数据大小,称为发送窗口;接收方也会维持一个连续的允许接收的数据大小,称为接收窗口。每次发送方给接收方发送数据后,必须收到接收方返回的确认消息,发送窗口才可向后移动,发送新的数据。
- 通过一个简单的例子,来看看滑动窗口在网络流量控制中,是如何发挥作用的吧。如图所示,发送窗口和接收窗口大小均为 1,发送方发送数据 D1 后,只有接收到来自接收方的确认消息 ACK,发送窗口才可向后移动,即发送方才可以发送后续数据 D2。
- 在双十一、双十二秒杀场景中,用户流量突增,在这种高并发、大流量的情况下,服务器的处理能力成为电商系统的瓶颈,处理不好就会导致系统崩溃,服务不可用。而分布式系统中的流量控制,就是解决这类问题的一种关键技术。
- 分布式流量控制就是在分布式系统下,控制每个服务器接收的请求数,以保证服务器来得及处理这些请求,也就是说尽可能保证用户请求持续地被处理,而不是让大量的用户请求“阻塞”在服务器中,等待被执行。这就好比“大禹治水,在疏不在堵”。
分布式系统流量控制策略
- 消息队列就是实现流量控制的一种方法,通过一个消息队列来存放用户的消息,然后服务器到消息队列中逐个消费,就可以避免消息过多时服务器处理不过来的情况。除此之外,分布式系统的流量控制策略还有很多,常用的主要包括两种:漏桶策略和令牌桶策略。
漏桶策略
- 如下图所示,有一个固定容量的水桶,桶底有一个小洞,水桶可以接收任意速率的水流,但无论水桶里有多少水,水从小洞流出的速率始终不变,桶里的水满了之后,水就会溢出。
- 漏桶策略借鉴上述原理,无论用户请求有多少,无论请求速率有多大,“漏桶”都会接收下来,但从漏桶里出来的请求是固定速率的,保证服务器可以处理得游刃有余。当“漏桶”因为容量限制放不下更多的请求时,就会选择丢弃部分请求。这种思路其实就是一种“宽进严出”的策略。
- 比如,在某段时间内,系统每秒会有 10 个用户发出请求,但这些请求经过漏桶后,每秒始终只流出 2 个请求,也就是说服务器每秒最多处理 2 个请求。这样的话,无论请求速率有多大,都能达到限流的目的,避免服务器在短暂时间内需要处理大量请求,但由于处理能力受限导致系统崩溃,从而保证了系统的高可靠。
- 这种策略的好处是,做到了流量整形,即无论流量多大,即便是突发的大流量,输出依旧是一个稳定的流量。但其缺点是,对于突发流量的情况,因为服务器处理速度与正常流量的处理速度一致,会丢弃比较多的请求。但是,当突发大流量到来时,服务器最好能够更快地处理用户请求,这也是分布式系统大多数情况下想要达到的效果。
- 漏桶策略适用于间隔性突发流量且流量不用即时处理的场景,即可以在流量较小时的“空闲期”,处理大流量时流入漏桶的流量;不适合流量需要即时处理的场景,即突发流量时可以放入桶中,但缺乏效率,始终以固定速率进行处理。
- 目前,漏桶算法已经用于很多框架了,比如阿里开源的流量控制框架 Sentinel 中的匀速排队限流策略,就采用了漏桶算法;分布式追踪系统 Jaeger 中,有一种采集策略是速率限制类型,内部使用的也是漏桶算法等。
令牌桶策略
- 令牌桶策略,也是一个很形象的名字,指的是桶里放着很多令牌,请求只有拿到令牌才能被服务器处理。
- 如图所示,有一个固定容量的存放令牌的桶,我们以固定速率向桶里放入令牌,桶满时会丢弃多出的令牌。每当请求到来时,必须先到桶里取一个令牌才可被服务器处理,也就是说只有拿到了令牌的请求才会被服务器处理。所以,你可以将令牌理解为门卡,只有拿到了门卡才能顺利进入房间。
- 这种策略的好处:当有突发大流量时,只要令牌桶里有足够多的令牌,请求就会被迅速执行。通常情况下,令牌桶容量的设置,可以接近服务器处理的极限,这样就可以有效利用服务器的资源。因此,这种策略适用于有突发特性的流量,且流量需要即时处理的场景。
- 在实际使用中,令牌桶算法也很常见。比如,Google 开源工具包 Guava 提供的限流工具类 RateLimiter,就是基于令牌桶算法来完成限流的。
两种策略对比
Sentinel 流量控制工作原理
- Sentinel 的核心是,监控应用的并发线程数或 QPS(请求数 / 每秒)指标,当达到系统设定的阈值时,Sentinel 可以采取一定的策略对流量进行控制,以避免应用被瞬时高流量击垮,从而保证应用高可靠。为此,在 Sentinel 中,关于流量控制有两种方式:一种是通过并发线程数进行流量控制,另一种是通过 QPS 指标进行流量控制。
- 通过并发线程数进行流量控制:过多的线程会消耗非常多的系统资源,包括线程资源消耗、线程调度消耗等。为了解决这个问题,引入了线程池。线程池维护了多个启动着的线程,随时等待着去执行系统分配的任务,即系统每次需要处理任务时,可以直接从线程池中取线程,从而避免了创建和销毁线程的时间和资源等消耗。同一时刻每个线程只能执行一个任务或请求,因此,可以通过并发线程数进行流量控制。
- 同一时刻每个线程只能执行一个任务或请求,因此,可以通过并发线程数进行流量控制。在分布式系统中,每个请求都会由一个线程去进行处理。当请求太多系统处理不过来时,意味着线程池可能已经被耗尽(线程池中无空闲线程),因此当请求过多时,执行请求的并发线程数自然会随之增加,当超过一定的阈值(比如线程池中线程总数)时,需要采取一定的策略来进行流量控制。
在 Sentinel 中,就采用了直接拒绝的方式,即新来的请求会直接拒绝。
- 同一时刻每个线程只能执行一个任务或请求,因此,可以通过并发线程数进行流量控制。在分布式系统中,每个请求都会由一个线程去进行处理。当请求太多系统处理不过来时,意味着线程池可能已经被耗尽(线程池中无空闲线程),因此当请求过多时,执行请求的并发线程数自然会随之增加,当超过一定的阈值(比如线程池中线程总数)时,需要采取一定的策略来进行流量控制。
- 通过 QPS 指标进行流量控制:QPS 是指每秒的请求数,大流量也就意味着 QPS 大。当 QPS 达到阈值时,Sentinel 提供了三种流量控制策略,分别是直接拒绝、预热(Warm Up)和匀速排队。直接拒绝,是最直接也是最暴力的方式,与并发线程数流量控制采取的方式一致,就是当 QPS 达到系统设定的阈值时,直接拒绝新来的请求。
- 这种策略乍一听起来确实不是很好,但对于系统处理能力确切已知的情况(即阈值设定为每秒能接受的最大处理请求数),却非常实用。当请求超出阈值时,可以直接拒绝,因为系统已经没有更多的能力来处理多余的请求了。因此,该策略适用于对系统处理能力确切已知的场景。
- 通过并发线程数进行流量控制:过多的线程会消耗非常多的系统资源,包括线程资源消耗、线程调度消耗等。为了解决这个问题,引入了线程池。线程池维护了多个启动着的线程,随时等待着去执行系统分配的任务,即系统每次需要处理任务时,可以直接从线程池中取线程,从而避免了创建和销毁线程的时间和资源等消耗。同一时刻每个线程只能执行一个任务或请求,因此,可以通过并发线程数进行流量控制。
知识扩展:什么是拥塞控制?它与流量控制的区别是什么?
流量控制,主要是指业务上的流量,即用户请求。而拥塞控制通常针对的是网络上传输的数据,即网络上数据传输出现拥塞时应当如何控制。所以,这两个概念不是一回事儿。但是,对于网络上数据的传输而言,流量控制与拥塞控制非常容易混淆。
网络数据传输中,流量控制是指控制发送方和接收方的传输和接收速率在双方都可以接受的范围,通常使用的方法是滑动窗口;而拥塞控制是通过检测网络状况,随时疏通网络,避免网络中过多数据堆积,导致无法传输数据,包括慢启动与拥塞避免方法。
你知道的越多,你不知道的越多。