限流
高并发系统中有三把利器用来保护系统:缓存、降级、限流。缓存的目的是提升系统访问速度和增大系统能处理的容量即吞吐量,可谓是抗高并发流量的银弹;而降级是当服务出问题或者影响到核心流程的性能则需要暂时屏蔽掉,待高峰或者问题解决后再打开;而有些场景并不能用缓存和降级来解决,比如稀缺资源(秒杀、抢购)、写服务(如评论、下单)、频繁的复杂查询(评论的最后几页),因此需有一种手段来限制这些场景的并发/请求量,即限流。
限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务(定向到错误页或告知资源没有了)、排队或等待(比如秒杀、评论、下单)。
高并发系统常见的限流有:限制并发数(线程池+队列,Semaphone信号量 )、限制单位时间内并发数(计数器,带滑动窗口的计数器,令牌桶,漏桶)。
- 计数器算法
-
实现:采用计数器实现限流有点简单粗暴,一般我们会限制一秒钟的能够通过的请求数,比如限流qps为100,算法的实现思路就是从第一个请求进来开始计时,在接下去的1s内,每来一个请求,就把计数加1,如果累加的数字达到了100,那么后续的请求就会被全部拒绝。等到1s结束后,把计数恢复成0,重新开始计数。
-
弊端:如果我在单位时间1s内的前10ms,已经通过了100个请求,后面的990ms,只能眼巴巴的把请求拒绝,这种现象称为“突刺现象”,不平滑;
2. 滑动窗口计数器算法
- 实现:为了防止突刺现象,滑动窗口(单位时间切的足够小)原理是在每次有访问进来时,先判断前N个单位时间内的总访问量是否超过了设置的阈值,并对当前时间片上的请求数+1 。 每一个格式表示一个固定的时间(比如1s),每个格子一个计数器,要获取前3s的请求量,就是对当前时间片i ~ i-2的时间片上计数器进行累加。 代码实现思路:( 每一个时间片(单位时间)就是一个独立的计数器,用以数组保存。将当前时间以某种方式(比如取模)映射到数组的一项中。每次访问先对当前时间片上的计数器+1,再计算前N个时间片的访问量总合,超过阈值则限流)。
- 弊端: 但由于访问量的不可预见性,会发生单位时间的前半段大量请求涌入,而后半段则拒绝所有请求的情况(通常,需要可以将单位时间切的足够的小来缓解)
3. 漏桶
- 为了消除"突刺现象",可以采用漏桶算法实现限流,漏桶算法这个名字就很形象,算法内部有一个容器,类似生活用到的漏斗,当请求进来时,相当于水倒入漏斗,然后从下端小口慢慢匀速的流出。不管上面流量多大,下面流出的速度始终保持不变。不管服务调用方多么不稳定,通过漏桶算法进行限流,例如每10毫秒处理一次请求。因为处理的速度是固定的,请求进来的速度是未知的,可能突然进来很多请求,没来得及处理的请求就先放在桶里,既然是个桶,肯定是有容量上限,如果桶满了,那么新进来的请求就丢弃。
- 实现:可以准备一个队列,用来保存请求,另外通过一个线程池定期从队列中获取请求并执行,也可以一次性获取多个并发执行。
- 弊端:无法应对短时间的突发流量。
4. 令牌桶
- 令牌桶算法是对漏桶算法的一种改进,令牌桶算法能够限制请求调用的速率,而令牌桶算法能够在限制调用的平均速率的同时还允许一定程度的突发调用。在令牌桶算法中,存在一个桶,用来存放固定数量的令牌。算法中存在一种机制,以一定的速率往桶中放令牌。每次请求调用需要先获取令牌,只有拿到令牌,才有机会继续执行,否则选择选择等待可用的令牌、或者直接拒绝。放令牌这个动作是持续不断的进行,如果桶中令牌数达到上限,就丢弃令牌,所以就存在这种情况,桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,所以,只有桶中没有令牌时,请求才会进行等待,最后相当于以一定的速率执行。
- 实现: 1.可以准备一个队列,用来保存令牌,另外通过一个线程池定期生成令牌放到队列中,每来一个请求,就从队列中获取一个令牌,并继续执行。2.通过Google开源的guava包,使用它可以很轻松的创建一个令牌桶算法的限流器。
熔断
微服务架构中,微服务是完成一个单一的业务功能,这样做的好处是可以做到解耦,每个微服务可以独立演进。但是,一个应用可能会有多个微服务组成,微服务之间的数据交互通过远程过程调用完成。这就带来一个问题,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务。如果调用链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”。熔断机制是应对雪崩效应的一种微服务链路保护机制。务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用
熔段解决如下几个问题:
- 当所依赖的对象不稳定时,能够起到快速失败的目的;
- 快速失败后,能够根据一定的算法动态试探所依赖对象是否恢复
降级
服务降级是从整个系统的负荷情况出发和考虑的,对某些负荷会比较高的情况,为了预防某些功能(业务场景)出现负荷过载或者响应慢的情况,在其内部暂时舍弃对一些非核心的接口和数据的请求,而直接返回一个提前准备好的fallback(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。
例如:当双11活动时,把无关交易的服务统统降级,如查看蚂蚁深林,查看历史订单,商品历史评论,只显示最后100条等等
降级( 人工操作: 开关预置 ,自动化:比如熔断后自动降级)。
主流框架
- Sentinel
- Hystrix
- Resilience4j