什么是雪崩效应
雪崩就是雪塌方。在山坡上的积雪,如果积雪的内聚力小于重力或其他力量,则积雪便向下滑动,从而逐渐引起积雪的崩塌。
在微服务架构中,服务之间通常存在级联调用。比如,服务A调用服务B,而服务B需要调用服务C,而服务C又需要调用服务D。如果其中任意-个点不可用,或者存在响应延时,则可能造成很多服务不可用,即产生级联故障。
如果这类请求很多,服务不可用导致积累的请求越来越多,则占用的计算机资源越来越多,太多的请求会很快耗尽系统的资源,从而导致系统瓶颈出现,造成其他的请求也不可用,最终造成整个系统不可用。这种现象被称为“服务雪崩”。
简单的理解就是:“服务提供者”不可用导致“服务消费者”(可能同时是服务提供者)不可用,并将不可用逐渐放大到整个微服务系统,进而造成系统崩溃。
在图8-1中,Service A、Service B都是“服务提供者”,同时ServiceB又是ServiceA的.“服务消费者”,Service B还为多个消费者提供服务。如果Service A不可用,则会引起Service B不可用,Service B会将不可能像滚雪球一样放大到多 个消费者,最终形成服务雪崩。
造成服务雪崩的原因
微服务等分布式架构已经可以达到非常高的可用状态,但依然有很多不可控的系统因素会导致雪崩。造成雪崩主要有以下7个原因。
1.流量激增
例如,新闻事件、促销活动、爬虫采集、恶意攻击、用户重试等导致的访问量突然增大。
2.硬件故障
例如,单点的硬件损坏使得集群的服务压力加大,从而出现服务延迟,服务延迟不断加剧导致雪崩。
3.程序中的Bug
程序中的Bug不可能完全避免。有的Bug并无大碍,但有的Bug则可能造成服务雪崩,例如,程序中有循环调用等逻辑问题,或是资源未释放引起的内存泄漏等都可能导致服务雪崩。
4.缓存问题
缓存穿透、缓存击穿、缓存雪崩也可能导致服务雪崩。
(1)缓存穿透。
产生缓存穿透的原因是:用户不断请求缓存或数据库中没有的数据。如,请求ID为“-1”的数据,或ID为特别大但不存在的数据。这种用户多半是攻击者或编写不严谨的爬虫,这会导致数据库压力过大。
对于缓存穿透,可以通过以下方法来处理:
●在接口层增加校验, 如用户鉴权校验、防止爬虫。
●增加ID 的基础校验,如设置当ID≤0或ID> max (从数据库中查询得到的最大ID )时直接拦截请求。
●将Key-Value对写为Key-Null对,缓存有效时间可以在合理范围内设置长点,但又不能设置得太长,因为太长可能导致其他正常情况也没法使用。
(2)缓存击穿。
缓存击穿是指,缓存中没有数据,但数据库中有数据( - -般是因为缓存时间到期了),这时并发用户特别多,去缓存中没读取到数据,又去数据库中读取数据,引起数据库压力瞬间增大。对于缓存击穿,可以通过设置热点数据永远不过期、加互斥锁等解决。
(3)缓存雪崩。
缓存雪崩是指,缓存中数据大批量过期,而此时的查询量巨大,从而引起数据库压力过大甚至宕机。
对于缓存雪崩,可以通过把缓存数据的过期时间设置为随机,防止同一时间有大量数据过期。如果缓存数据库是分布式部署的,则可以将热点数据均匀地分布在不同的缓存数据库中。还可以设置热点数据永远不过期。
5.资源耗尽
资源耗尽主要有以下两种原因:
(1)服务调用者不可用导致同步等待,进而造成资源耗尽。
(2)用户大量请求,以及重试流量(如用户重试,代码逻辑重试)加大。
6.线程同步等待
如果系统间采用的是同步服务调用模式,核心服务和非核心服务共用一个线程池和消息队列,若一个核心业务线程调用非核心线程,这个非核心线程(如第三方系统)出现问题,则会导致核心线程阻塞。进程间的调用是有超时限制的,如果这个核心线程断掉,则可能引发雪崩。
7.配套资源不可用
比如,数据中心掉线,电信基础网络服务出现城市集群故障。出现这类事故的概率较低,但是曾经也出现过一段时间几十个城市无法联网的状况。
对于可控的导致雪崩的因素一定要尽 量避免,比如优化代码、尽可能地做更多的资源冗余。在Spring Cloud架构中,我们可以使用Sentinel或Hystrix来解决雪崩问题。
主流的容错项目
在分布式系统中,系统的稳定性至关重要。而系统的稳定性又依赖很多不可控的因素,比如,网络连接不可用或变慢、资源繁忙难以响应或暂时不可用等。要构建稳定、可靠的分布式系统,必须有一套容错方法。目前主流的分布式容错解决框架有Sentinel、Resilience4j、 Hystrix。
流量防卫兵 Sentinel
2012年阿里巴巴集团开发出Sentinel,于2018年正式将其开源。Sentinel 是一款面向分布式服务架构的轻量级流量控制组件,主要以流量为切入点,从限流、流量整形、熔断降级、系统自适应保护、系统负载保护等多个维度来保障微服务的稳定性。
Sentinel的核心思想是:根据设置的规则来为资源执行相应的流控、降级、系统保护策略。在Sentinel中,资源定义和规则配置是分离的。用户可以先通过Sentinel API给对应的业务逻辑定义资源,然后在需要时动态配置规则。
它的核心库( Java客户端)不依赖任何框架/库,能够运行在所有Java环境中,同时对Dubbo.Spring Cloud等框架也有较好的支持。
它的控制台( Dashboard)是基于Spring Boot开发的,打包后可以直接运行,不需要额外的Tomcat等应用容器。
Sentinel的开源生态如图8-2所示(该图来自Sentinel官方)。
容错框架 Resilience4j
Resilience4j是一一个比较轻量的、模块化的熔断降级库。它由熔断、限速器、自动重试等功能组成,这些功能都被拆成了单独的模块,这样整体结构很清晰,用户可以根据需要引入相应功能的依赖。它针对函数式编程设计,API比较简洁优雅。有简单的限速器和自动重试特性,使用场景丰富。
Resilience4j的模块都是独立编译的,可以根据需要独立引入。Resilience4j主要有以下模块。
●熔断器(Circuit breaking ) : resilience4j-circuitbreaker.
●限流( Rate limiting ) : resilience4j-ratelimiter。
●隔离舱(Bulkheading) : resilience4j-bulkhead.
●同步和异步重试 ( Automatic retrying) : resilience4j-retry。
●缓存(Response caching) : resilience4j-cache.
●超时处理( Timeout handling) : resilience4j-timelimiter.
Resilience4j在较小的项目中使用比较方便,但是Resilience4j只适用于限流降级的基本场景,无法适用于非常复杂的企业级服务架构。另外,Resilience4j 缺乏生产级别的配套设施(如提供规则管理和实时监控能力的控制台)。
容错框架 Hystrix
Hystrix是由Netlix开源的一款容错框架,包含隔离( 线程池隔离、信号量隔离)、熔断、降级回退和缓存容错、缓存、批量处理请求、主从分担等常用功能。
对比Sentinel、Hystrix 和Resilience4j
Sentinel、Hystrix 和Resilience4j对比情况见表