分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。
如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,
无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。
针对上述的常见场景,需要给出不同的策略来应对,主要有如下几个方面,参考如下:
综合上述的内容可知,如果一个服务不能对自己依赖以及产生的故障进行隔离,那么它自己本身就会处在雪崩风险中。要想构建稳定健壮的分布式系统,我们的服务应当具有自我保护能力和容错的能力。
避免造成更大的故障设置服务雪崩。而这种自我保护的模式就是熔断、限流、异常驱逐等能力。
计数算法是指再一定的时间间隔里,记录请求次数,当时间间隔到期之后,就把计数清零,重新计算。如果请求次数超过统计周期内额定的最大次数时,直接拒绝访问,简单粗暴。
计数器的值要是存在内存中就算单机限流算法,类似 Atomic 等原子类。如果存放在类似Redis的第三方缓存服务服务中就是分布式限流了,类似 Redis incr、Redis decr。
如下图所示:
可能存在的问题是:请求分布的不均衡,比如在时间周期1分钟的第1秒,就把100次请求用完了,那么最后59秒都是空白的。也可能直到最后1秒才有大批量的流量
涌入,造成系统的不稳定。
相对于上一个 计数限流,多了个时间窗口的概念,计数器每过一个时间窗口就重置,重新开始计算
固定窗口计数算法的步骤是:
滑动窗口限流解决固定窗口临界值的问题,可以保证在任意时间窗口内都不会超过阈值。
相对于固定窗口,滑动窗口除了需要引入计数器之外还需要记录时间窗口内每个请求到达的时间点,因此对内存的占用会比较多。
上图中每个时间窗口限流8个req,滑动窗口计数算法的步骤如下:
类似沙漏思维,大家都用过,沙子是匀速流出得。对于漏桶来说,由于它的出水口的速度是恒定的,也就是消化处理请求的速度是恒定的,所以它可以保证组件以恒定的速率来处理请求,
这对一些对处理速度或者资源有严格要求的系统是非常实用的。原理如下:
宽进严出是它最大的特点,无论请求多少,请求的速率有多大,都按照固定的速率流出(定速输出),而服务也只能按照固定速率处理,有点像固定延时的消息队列。
如果有处理不过来的请求,那就按照队列进行排队,避免巨大输出把服务搞挂掉,队列满了就refuse。
令牌桶和漏桶的原理类似,只不过漏桶是定速流出,令牌桶是定速流入(即往桶里塞入令牌),每个请求进来,分配一个令牌,只有拿到了令牌才能进入服务器处理,拿不到令牌的就被拒绝了。
因为令牌桶的大小也是有限制的,所以一旦令牌桶满,后续生成的令牌就会被丢弃,拿不到令牌的服务请求就被拒绝了,达到限流的目的。执行原理如下:
相对于漏洞的定速流程那种的匀速消费模式,令牌桶可以将积压的令牌一下子花掉,所以在应对流量洪峰的时候,他的表现比露铜算法更优异。
Google Guava 提供的限流工具类 RateLimiter,是基于令牌桶实现的,并且扩展了算法,支持预热功能。
阿里开源的限流框架Sentinel 中的匀速排队限流策略,就采用了漏桶算法。
Sentinel 被称为高可用流量管理框架,分布式系统流量卫兵。假如对一个接口QPS(每秒请求数)最大限制为10000,在QPS超过10000之后的请求我们就要限制其访问,并给出友好的提示。
不限制QPS无限的次数就会造成服务器超量访问而宕机。在服务调用的过程中,如果调用链路中的某个资源出现了不稳定,比如错误数增加,请求平响升高,则大概率会导致请求堆积,进而诱发整个链路的雪崩,解决办法就是熔断、限流、降级。熔断限流就是当检测到调用链路中某个服务出现不稳定时,对服务的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联故障。
Sentinel是分布式系统的流量防卫兵,他有如下优秀特质:
丰富的应用场景:
Sentinel承接了阿里近十年的双11、618等重大活动的流量核心场景,经典如秒杀、竞拍 (即突发流量控制在系统容量可以承受的范围),消息削峰填谷,集群流量控制,实时熔断下游等应用场景
完美的实时监控:
Sentinel同时提供实时、丰富的监控功能,可以在控制台看到接入应用的单台机器秒级流量数据,甚至几百台规模的集群的汇总运行情况
广泛的开源生态:
Sentinel提供开箱即用的,可与其他框架/库的快速整合的模块,例如与SpringCloud,Dubbo,gRPC的整合,引入相应的maven依赖即可快速接入Sentinel。
完美的SPI扩展点:
Sentinel提供简单易用的,完美的SPI扩展接口,可以通过实现扩展接口来快速定制逻辑,例如定制规则管理,适配动态数据源等.。
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时、异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。“断路器”本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方无法处理的异常,这样就保证了服务调用方的线程不会被长时间、不必要地占用,从而避免了故障在分布式系统中的蔓延,乃至雪崩。